diff --git a/.mailmap b/.mailmap index c24773db04a7ab3ee9ddd5e8472796363f720be1..00581c1f09838af86edba1ff7abd9bedd216a428 100644 --- a/.mailmap +++ b/.mailmap @@ -276,3 +276,5 @@ Gustavo Padovan Gustavo Padovan Changbin Du Changbin Du +Steve Wise +Steve Wise diff --git a/Documentation/admin-guide/device-mapper/dm-integrity.rst b/Documentation/admin-guide/device-mapper/dm-integrity.rst index 594095b54b296567d09d1650d281b5a7e4f44c1f..c00f9f11e3f3f6133d4b741244e034ae2a3c430e 100644 --- a/Documentation/admin-guide/device-mapper/dm-integrity.rst +++ b/Documentation/admin-guide/device-mapper/dm-integrity.rst @@ -144,7 +144,7 @@ journal_crypt:algorithm(:key) (the key is optional) Encrypt the journal using given algorithm to make sure that the attacker can't read the journal. You can use a block cipher here (such as "cbc(aes)") or a stream cipher (for example "chacha20", - "salsa20", "ctr(aes)" or "ecb(arc4)"). + "salsa20" or "ctr(aes)"). The journal contains history of last writes to the block device, an attacker reading the journal could see the last sector nubmers diff --git a/Documentation/admin-guide/device-mapper/index.rst b/Documentation/admin-guide/device-mapper/index.rst index 4872fb6d29524593849fbe68491e372d0901dfc3..ec62fcc8eeceed83a1cfd3020ff87595affc6ad0 100644 --- a/Documentation/admin-guide/device-mapper/index.rst +++ b/Documentation/admin-guide/device-mapper/index.rst @@ -8,6 +8,7 @@ Device Mapper cache-policies cache delay + dm-clone dm-crypt dm-dust dm-flakey diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml index 8a1e38a1d7ab196debe1feb614109598a35928f0..cffe8bb0bad106b35586956649dab8476e2fa5a8 100644 --- a/Documentation/devicetree/bindings/arm/sunxi.yaml +++ b/Documentation/devicetree/bindings/arm/sunxi.yaml @@ -8,7 +8,7 @@ title: Allwinner platforms device tree bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: $nodename: diff --git a/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml b/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml index d2a872286437e4c65c12f94f506283aed588bd4b..f0b3d30fbb76f7401b3f41b2d583b05de58fe278 100644 --- a/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml +++ b/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml @@ -8,7 +8,7 @@ title: Allwinner A64 Display Engine Bus Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: $nodename: diff --git a/Documentation/devicetree/bindings/bus/allwinner,sun8i-a23-rsb.yaml b/Documentation/devicetree/bindings/bus/allwinner,sun8i-a23-rsb.yaml index be32f087c529303e02db711f4d88a5f44f33be6d..9fe11ceecdba004c5546f30711be002eaca64694 100644 --- a/Documentation/devicetree/bindings/bus/allwinner,sun8i-a23-rsb.yaml +++ b/Documentation/devicetree/bindings/bus/allwinner,sun8i-a23-rsb.yaml @@ -8,7 +8,7 @@ title: Allwinner A23 RSB Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#address-cells": diff --git a/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml b/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml index 64938fdaea554973d960bd1c3b4f01e130747167..4d382128b711c8cace6414831a0a6ff07238a77e 100644 --- a/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml +++ b/Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml @@ -8,7 +8,7 @@ title: Allwinner Clock Control Unit Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#clock-cells": diff --git a/Documentation/devicetree/bindings/crypto/allwinner,sun4i-a10-crypto.yaml b/Documentation/devicetree/bindings/crypto/allwinner,sun4i-a10-crypto.yaml index 80b3e7350a732b8e2fbe4ab39a9a99f7b539bc28..33c7842917f629c8176df1f94ad52e4fc629a271 100644 --- a/Documentation/devicetree/bindings/crypto/allwinner,sun4i-a10-crypto.yaml +++ b/Documentation/devicetree/bindings/crypto/allwinner,sun4i-a10-crypto.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 Security System Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: compatible: diff --git a/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml b/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml index dafc0980c4fa7a241722430c6df62f4f331d1601..9e90c2b009609b1c3603d3113c8cc3c9dd446efa 100644 --- a/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml +++ b/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml @@ -8,14 +8,16 @@ title: Allwinner A31 MIPI-DSI Controller Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#address-cells": true "#size-cells": true compatible: - const: allwinner,sun6i-a31-mipi-dsi + enum: + - allwinner,sun6i-a31-mipi-dsi + - allwinner,sun50i-a64-mipi-dsi reg: maxItems: 1 @@ -24,6 +26,8 @@ properties: maxItems: 1 clocks: + minItems: 1 + maxItems: 2 items: - description: Bus Clock - description: Module Clock @@ -63,13 +67,38 @@ required: - reg - interrupts - clocks - - clock-names - phys - phy-names - resets - vcc-dsi-supply - port +allOf: + - if: + properties: + compatible: + contains: + const: allwinner,sun6i-a31-mipi-dsi + + then: + properties: + clocks: + minItems: 2 + + required: + - clock-names + + - if: + properties: + compatible: + contains: + const: allwinner,sun50i-a64-mipi-dsi + + then: + properties: + clocks: + minItems: 1 + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml b/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8f373029f5d217a07b2c0b37e988ea4cef559b92 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml @@ -0,0 +1,131 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/lvds-codec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Transparent LVDS encoders and decoders + +maintainers: + - Laurent Pinchart + +description: | + This binding supports transparent LVDS encoders and decoders that don't + require any configuration. + + LVDS is a physical layer specification defined in ANSI/TIA/EIA-644-A. Multiple + incompatible data link layers have been used over time to transmit image data + to LVDS panels. This binding targets devices compatible with the following + specifications only. + + [JEIDA] "Digital Interface Standards for Monitor", JEIDA-59-1999, February + 1999 (Version 1.0), Japan Electronic Industry Development Association (JEIDA) + [LDI] "Open LVDS Display Interface", May 1999 (Version 0.95), National + Semiconductor + [VESA] "VESA Notebook Panel Standard", October 2007 (Version 1.0), Video + Electronics Standards Association (VESA) + + Those devices have been marketed under the FPD-Link and FlatLink brand names + among others. + +properties: + compatible: + oneOf: + - items: + - enum: + - ti,ds90c185 # For the TI DS90C185 FPD-Link Serializer + - ti,ds90c187 # For the TI DS90C187 FPD-Link Serializer + - ti,sn75lvds83 # For the TI SN75LVDS83 FlatLink transmitter + - const: lvds-encoder # Generic LVDS encoder compatible fallback + - items: + - enum: + - ti,ds90cf384a # For the DS90CF384A FPD-Link LVDS Receiver + - const: lvds-decoder # Generic LVDS decoders compatible fallback + - enum: + - thine,thc63lvdm83d # For the THC63LVDM83D LVDS serializer + + ports: + type: object + description: | + This device has two video ports. Their connections are modeled using the + OF graph bindings specified in Documentation/devicetree/bindings/graph.txt + properties: + port@0: + type: object + description: | + For LVDS encoders, port 0 is the parallel input + For LVDS decoders, port 0 is the LVDS input + + port@1: + type: object + description: | + For LVDS encoders, port 1 is the LVDS output + For LVDS decoders, port 1 is the parallel output + + required: + - port@0 + - port@1 + + powerdown-gpios: + description: + The GPIO used to control the power down line of this device. + maxItems: 1 + +required: + - compatible + - ports + +examples: + - | + lvds-encoder { + compatible = "ti,ds90c185", "lvds-encoder"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lvds_enc_in: endpoint { + remote-endpoint = <&display_out_rgb>; + }; + }; + + port@1 { + reg = <1>; + + lvds_enc_out: endpoint { + remote-endpoint = <&lvds_panel_in>; + }; + }; + }; + }; + + - | + lvds-decoder { + compatible = "ti,ds90cf384a", "lvds-decoder"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lvds_dec_in: endpoint { + remote-endpoint = <&display_out_lvds>; + }; + }; + + port@1 { + reg = <1>; + + lvds_dec_out: endpoint { + remote-endpoint = <&rgb_panel_in>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt deleted file mode 100644 index 60091db5dfa5218958ff35133df0e3c02b4fdc5c..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt +++ /dev/null @@ -1,66 +0,0 @@ -Parallel to LVDS Encoder ------------------------- - -This binding supports the parallel to LVDS encoders that don't require any -configuration. - -LVDS is a physical layer specification defined in ANSI/TIA/EIA-644-A. Multiple -incompatible data link layers have been used over time to transmit image data -to LVDS panels. This binding targets devices compatible with the following -specifications only. - -[JEIDA] "Digital Interface Standards for Monitor", JEIDA-59-1999, February -1999 (Version 1.0), Japan Electronic Industry Development Association (JEIDA) -[LDI] "Open LVDS Display Interface", May 1999 (Version 0.95), National -Semiconductor -[VESA] "VESA Notebook Panel Standard", October 2007 (Version 1.0), Video -Electronics Standards Association (VESA) - -Those devices have been marketed under the FPD-Link and FlatLink brand names -among others. - - -Required properties: - -- compatible: Must be "lvds-encoder" - - Any encoder compatible with this generic binding, but with additional - properties not listed here, must list a device specific compatible first - followed by this generic compatible. - -Required nodes: - -This device has two video ports. Their connections are modeled using the OF -graph bindings specified in Documentation/devicetree/bindings/graph.txt. - -- Video port 0 for parallel input -- Video port 1 for LVDS output - - -Example -------- - -lvds-encoder { - compatible = "lvds-encoder"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - lvds_enc_in: endpoint { - remote-endpoint = <&display_out_rgb>; - }; - }; - - port@1 { - reg = <1>; - - lvds_enc_out: endpoint { - remote-endpoint = <&lvds_panel_in>; - }; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/display/bridge/thine,thc63lvdm83d.txt b/Documentation/devicetree/bindings/display/bridge/thine,thc63lvdm83d.txt deleted file mode 100644 index fee3c88e1a176e6388a49806ed65dca4471e7d42..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/display/bridge/thine,thc63lvdm83d.txt +++ /dev/null @@ -1,50 +0,0 @@ -THine Electronics THC63LVDM83D LVDS serializer ----------------------------------------------- - -The THC63LVDM83D is an LVDS serializer designed to support pixel data -transmission between a host and a flat panel. - -Required properties: - -- compatible: Should be "thine,thc63lvdm83d" - -Optional properties: - -- powerdown-gpios: Power down control GPIO (the /PWDN pin, active low). - -Required nodes: - -The THC63LVDM83D has two video ports. Their connections are modeled using the -OFgraph bindings specified in Documentation/devicetree/bindings/graph.txt. - -- Video port 0 for CMOS/TTL input -- Video port 1 for LVDS output - - -Example -------- - - lvds_enc: encoder@0 { - compatible = "thine,thc63lvdm83d"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - lvds_enc_in: endpoint@0 { - remote-endpoint = <&rgb_out>; - }; - }; - - port@1 { - reg = <1>; - - lvds_enc_out: endpoint@0 { - remote-endpoint = <&panel_in>; - }; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/display/bridge/ti,ds90c185.txt b/Documentation/devicetree/bindings/display/bridge/ti,ds90c185.txt deleted file mode 100644 index e575f996959a09bcf195e050d0ee7a5c7cc7511f..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/display/bridge/ti,ds90c185.txt +++ /dev/null @@ -1,55 +0,0 @@ -Texas Instruments FPD-Link (LVDS) Serializer --------------------------------------------- - -The DS90C185 and DS90C187 are low-power serializers for portable -battery-powered applications that reduces the size of the RGB -interface between the host GPU and the display. - -Required properties: - -- compatible: Should be - "ti,ds90c185", "lvds-encoder" for the TI DS90C185 FPD-Link Serializer - "ti,ds90c187", "lvds-encoder" for the TI DS90C187 FPD-Link Serializer - -Optional properties: - -- powerdown-gpios: Power down control GPIO (the PDB pin, active-low) - -Required nodes: - -The devices have two video ports. Their connections are modeled using the OF -graph bindings specified in Documentation/devicetree/bindings/graph.txt. - -- Video port 0 for parallel input -- Video port 1 for LVDS output - - -Example -------- - -lvds-encoder { - compatible = "ti,ds90c185", "lvds-encoder"; - - powerdown-gpios = <&gpio 17 GPIO_ACTIVE_LOW>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - lvds_enc_in: endpoint { - remote-endpoint = <&lcdc_out_rgb>; - }; - }; - - port@1 { - reg = <1>; - - lvds_enc_out: endpoint { - remote-endpoint = <&lvds_panel_in>; - }; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/display/dsi-controller.yaml b/Documentation/devicetree/bindings/display/dsi-controller.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fd986c36c7373889a5da1494bb0ffbb922fc5e23 --- /dev/null +++ b/Documentation/devicetree/bindings/display/dsi-controller.yaml @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/dsi-controller.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Common Properties for DSI Display Panels + +maintainers: + - Linus Walleij + +description: | + This document defines device tree properties common to DSI, Display + Serial Interface controllers and attached panels. It doesn't constitute + a device tree binding specification by itself but is meant to be referenced + by device tree bindings. + + When referenced from panel device tree bindings the properties defined in + this document are defined as follows. The panel device tree bindings are + responsible for defining whether each property is required or optional. + + Notice: this binding concerns DSI panels connected directly to a master + without any intermediate port graph to the panel. Each DSI master + can control one to four virtual channels to one panel. Each virtual + channel should have a node "panel" for their virtual channel with their + reg-property set to the virtual channel number, usually there is just + one virtual channel, number 0. + +properties: + $nodename: + pattern: "^dsi-controller(@.*)?$" + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^panel@[0-3]$": + description: Panels connected to the DSI link + type: object + + properties: + reg: + minimum: 0 + maximum: 3 + description: + The virtual channel number of a DSI peripheral. Must be in the range + from 0 to 3, as DSI uses a 2-bit addressing scheme. Some DSI + peripherals respond to more than a single virtual channel. In that + case the reg property can take multiple entries, one for each virtual + channel that the peripheral responds to. + + clock-master: + type: boolean + description: + Should be enabled if the host is being used in conjunction with + another DSI host to drive the same peripheral. Hardware supporting + such a configuration generally requires the data on both the busses + to be driven by the same clock. Only the DSI host instance + controlling this clock should contain this property. + + enforce-video-mode: + type: boolean + description: + The best option is usually to run a panel in command mode, as this + gives better control over the panel hardware. However for different + reasons like broken hardware, missing features or testing, it may be + useful to be able to force a command mode-capable panel into video + mode. + + required: + - reg + +examples: + - | + #include + dsi-controller@a0351000 { + reg = <0xa0351000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "sony,acx424akp"; + reg = <0>; + vddi-supply = <&ab8500_ldo_aux1_reg>; + reset-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/ingenic,lcd.txt b/Documentation/devicetree/bindings/display/ingenic,lcd.txt index 7b536c8c6ddef88054482978a66c0dd81ba8a8a3..01e3261defb6a97a3bbaf41604b6693e74b18b2f 100644 --- a/Documentation/devicetree/bindings/display/ingenic,lcd.txt +++ b/Documentation/devicetree/bindings/display/ingenic,lcd.txt @@ -4,6 +4,7 @@ Required properties: - compatible: one of: * ingenic,jz4740-lcd * ingenic,jz4725b-lcd + * ingenic,jz4770-lcd - reg: LCD registers location and length - clocks: LCD pixclock and device clock specifiers. The device clock is only required on the JZ4740. diff --git a/Documentation/devicetree/bindings/display/panel/leadtek,ltk500hd1829.yaml b/Documentation/devicetree/bindings/display/panel/leadtek,ltk500hd1829.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4ebcea7d0c6399335bee21b23217b30436709d8e --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/leadtek,ltk500hd1829.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/leadtek,ltk500hd1829.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Leadtek LTK500HD1829 5.0in 720x1280 DSI panel + +maintainers: + - Heiko Stuebner + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: leadtek,ltk500hd1829 + reg: true + backlight: true + reset-gpios: true + iovcc-supply: + description: regulator that supplies the iovcc voltage + vcc-supply: + description: regulator that supplies the vcc voltage + +required: + - compatible + - reg + - backlight + - iovcc-supply + - vcc-supply + +additionalProperties: false + +examples: + - | + dsi@ff450000 { + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "leadtek,ltk500hd1829"; + reg = <0>; + backlight = <&backlight>; + iovcc-supply = <&vcc_1v8>; + vcc-supply = <&vcc_2v8>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/logicpd,type28.yaml b/Documentation/devicetree/bindings/display/panel/logicpd,type28.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2834287b8d8877a826c23d5a069f807cadff534b --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/logicpd,type28.yaml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/logicpd,type28.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Logic PD Type 28 4.3" WQVGA TFT LCD panel + +maintainers: + - Adam Ford + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: logicpd,type28 + + power-supply: true + enable-gpios: true + backlight: true + port: true + +required: + - compatible + +additionalProperties: false + +examples: + - | + lcd0: display { + compatible = "logicpd,type28"; + enable-gpios = <&gpio5 27 0>; + backlight = <&backlight>; + port { + lcd_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/ronbo,rb070d30.yaml b/Documentation/devicetree/bindings/display/panel/ronbo,rb070d30.yaml index 0e7987f1cdb799ad01257b445b25f21876ffe65f..d67617f6f74ab10eabd05a1830e9ac448c113f69 100644 --- a/Documentation/devicetree/bindings/display/panel/ronbo,rb070d30.yaml +++ b/Documentation/devicetree/bindings/display/panel/ronbo,rb070d30.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Ronbo RB070D30 DSI Display Panel maintainers: - - Maxime Ripard + - Maxime Ripard properties: compatible: diff --git a/Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml b/Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml new file mode 100644 index 0000000000000000000000000000000000000000..185dcc8fd1f93def1934009f387c86449316a928 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/sony,acx424akp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sony ACX424AKP 4" 480x864 AMOLED panel + +maintainers: + - Linus Walleij + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: sony,acx424akp + reg: true + reset-gpios: true + vddi-supply: + description: regulator that supplies the vddi voltage + enforce-video-mode: true + +required: + - compatible + - reg + - reset-gpios + +additionalProperties: false + +examples: + - | + #include + + dsi-controller@a0351000 { + compatible = "ste,mcde-dsi"; + reg = <0xa0351000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "sony,acx424akp"; + reg = <0>; + vddi-supply = <&foo>; + reset-gpios = <&foo_gpio 0 GPIO_ACTIVE_LOW>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/xinpeng,xpp055c272.yaml b/Documentation/devicetree/bindings/display/panel/xinpeng,xpp055c272.yaml new file mode 100644 index 0000000000000000000000000000000000000000..186e5e1c8fa3b7c836eb35adb4c797413adada48 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/xinpeng,xpp055c272.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/xinpeng,xpp055c272.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xinpeng XPP055C272 5.5in 720x1280 DSI panel + +maintainers: + - Heiko Stuebner + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: xinpeng,xpp055c272 + reg: true + backlight: true + reset-gpios: true + iovcc-supply: + description: regulator that supplies the iovcc voltage + vci-supply: + description: regulator that supplies the vci voltage + +required: + - compatible + - reg + - backlight + - iovcc-supply + - vci-supply + +additionalProperties: false + +examples: + - | + dsi@ff450000 { + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "xinpeng,xpp055c272"; + reg = <0>; + backlight = <&backlight>; + iovcc-supply = <&vcc_1v8>; + vci-supply = <&vcc3v3_lcd>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/renesas,cmm.yaml b/Documentation/devicetree/bindings/display/renesas,cmm.yaml new file mode 100644 index 0000000000000000000000000000000000000000..a57037b9e9bad12eb0b41b824020c0896fd06116 --- /dev/null +++ b/Documentation/devicetree/bindings/display/renesas,cmm.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: GPL-2.0-only +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/renesas,cmm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas R-Car Color Management Module (CMM) + +maintainers: + - Laurent Pinchart + - Kieran Bingham + - Jacopo Mondi + +description: |+ + Renesas R-Car color management module connected to R-Car DU video channels. + It provides image enhancement functions such as 1-D look-up tables (LUT), + 3-D look-up tables (CLU), 1D-histogram generation (HGO), and color + space conversion (CSC). + +properties: + compatible: + oneOf: + - items: + - enum: + - renesas,r8a7795-cmm + - renesas,r8a7796-cmm + - renesas,r8a77965-cmm + - renesas,r8a77990-cmm + - renesas,r8a77995-cmm + - const: renesas,rcar-gen3-cmm + - items: + - const: renesas,rcar-gen2-cmm + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - resets + - power-domains + +additionalProperties: false + +examples: + - | + #include + #include + + cmm0: cmm@fea40000 { + compatible = "renesas,r8a7796-cmm", + "renesas,rcar-gen3-cmm"; + reg = <0 0xfea40000 0 0x1000>; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + clocks = <&cpg CPG_MOD 711>; + resets = <&cpg 711>; + }; diff --git a/Documentation/devicetree/bindings/display/renesas,du.txt b/Documentation/devicetree/bindings/display/renesas,du.txt index 17cb2771364bc818f9b53f7fae9766f775f6e451..eb4ae41fe41f83c73d0269146e20d55f0349b115 100644 --- a/Documentation/devicetree/bindings/display/renesas,du.txt +++ b/Documentation/devicetree/bindings/display/renesas,du.txt @@ -41,10 +41,14 @@ Required Properties: supplied they must be named "dclkin.x" with "x" being the input clock numerical index. - - vsps: A list of phandle and channel index tuples to the VSPs that handle - the memory interfaces for the DU channels. The phandle identifies the VSP - instance that serves the DU channel, and the channel index identifies the - LIF instance in that VSP. + - renesas,cmms: A list of phandles to the CMM instances present in the SoC, + one for each available DU channel. The property shall not be specified for + SoCs that do not provide any CMM (such as V3M and V3H). + + - renesas,vsps: A list of phandle and channel index tuples to the VSPs that + handle the memory interfaces for the DU channels. The phandle identifies the + VSP instance that serves the DU channel, and the channel index identifies + the LIF instance in that VSP. Required nodes: @@ -92,7 +96,8 @@ Example: R8A7795 (R-Car H3) ES2.0 DU <&cpg CPG_MOD 722>, <&cpg CPG_MOD 721>; clock-names = "du.0", "du.1", "du.2", "du.3"; - vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>; + renesas,cmms = <&cmm0>, <&cmm1>, <&cmm2>, <&cmm3>; + renesas,vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>; ports { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt index ce4c1fc9116c65a8690756016198bb73e24bf068..151be3bba06f178d3e86390a57f21c80fc6bc7e1 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt @@ -4,13 +4,16 @@ Rockchip specific extensions to the Synopsys Designware MIPI DSI Required properties: - #address-cells: Should be <1>. - #size-cells: Should be <0>. -- compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi". - "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi". +- compatible: one of + "rockchip,px30-mipi-dsi", "snps,dw-mipi-dsi" + "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi" + "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi" - reg: Represent the physical address range of the controller. - interrupts: Represent the controller's interrupt to the CPU(s). - clocks, clock-names: Phandles to the controller's pll reference - clock(ref) and APB clock(pclk). For RK3399, a phy config clock - (phy_cfg) and a grf clock(grf) are required. As described in [1]. + clock(ref) when using an internal dphy and APB clock(pclk). + For RK3399, a phy config clock (phy_cfg) and a grf clock(grf) + are required. As described in [1]. - rockchip,grf: this soc should set GRF regs to mux vopl/vopb. - ports: contain a port node with endpoint definitions as defined in [2]. For vopb,set the reg = <0> and set the reg = <1> for vopl. @@ -18,6 +21,8 @@ Required properties: - video port 1 for either a panel or subsequent encoder Optional properties: +- phys: from general PHY binding: the phandle for the PHY device. +- phy-names: Should be "dphy" if phys references an external phy. - power-domains: a phandle to mipi dsi power domain node. - resets: list of phandle + reset specifier pairs, as described in [3]. - reset-names: string reset name, must be "apb". diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-lvds.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-lvds.txt index 7849ff039229636a9df5dd3d8bf8cd57aba7bd08..aaf8c44cf90fd2b2d2d3fb3cc50ed55e5fa547cf 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-lvds.txt +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-lvds.txt @@ -4,6 +4,7 @@ Rockchip RK3288 LVDS interface Required properties: - compatible: matching the soc type, one of - "rockchip,rk3288-lvds"; + - "rockchip,px30-lvds"; - reg: physical base address of the controller and length of memory mapped region. @@ -18,6 +19,9 @@ Required properties: - rockchip,grf: phandle to the general register files syscon - rockchip,output: "rgb", "lvds" or "duallvds", This describes the output interface +- phys: LVDS/DSI DPHY (px30 only) +- phy-names: name of the PHY, must be "dphy" (px30 only) + Optional properties: - pinctrl-names: must contain a "lcdc" entry. - pinctrl-0: pin control group to be used for this controller. diff --git a/Documentation/devicetree/bindings/display/tilcdc/tfp410.txt b/Documentation/devicetree/bindings/display/tilcdc/tfp410.txt deleted file mode 100644 index a58ae7756fc6989902fcb48a8c23e33398378070..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/display/tilcdc/tfp410.txt +++ /dev/null @@ -1,21 +0,0 @@ -Device-Tree bindings for tilcdc DRM TFP410 output driver - -Required properties: - - compatible: value should be "ti,tilcdc,tfp410". - - i2c: the phandle for the i2c device to use for DDC - -Recommended properties: - - pinctrl-names, pinctrl-0: the pincontrol settings to configure - muxing properly for pins that connect to TFP410 device - - powerdn-gpio: the powerdown GPIO, pulled low to power down the - TFP410 device (for DPMS_OFF) - -Example: - - dvicape { - compatible = "ti,tilcdc,tfp410"; - i2c = <&i2c2>; - pinctrl-names = "default"; - pinctrl-0 = <&bone_dvi_cape_dvi_00A1_pins>; - powerdn-gpio = <&gpio2 31 0>; - }; diff --git a/Documentation/devicetree/bindings/dma/allwinner,sun4i-a10-dma.yaml b/Documentation/devicetree/bindings/dma/allwinner,sun4i-a10-dma.yaml index 15abc0f9429fcd8b813d620d8e8a0f115b70a6de..83808199657b731544c5fd0059b9f6639bcdf92b 100644 --- a/Documentation/devicetree/bindings/dma/allwinner,sun4i-a10-dma.yaml +++ b/Documentation/devicetree/bindings/dma/allwinner,sun4i-a10-dma.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 DMA Controller Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard allOf: - $ref: "dma-controller.yaml#" diff --git a/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml b/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml index 387d599522c708eaef3a201f8afbf7382c88aab2..9e53472be1947d0dcf4aa0fc26ab32f6b6c8031f 100644 --- a/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml +++ b/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml @@ -8,7 +8,7 @@ title: Allwinner A64 DMA Controller Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard allOf: - $ref: "dma-controller.yaml#" diff --git a/Documentation/devicetree/bindings/dma/allwinner,sun6i-a31-dma.yaml b/Documentation/devicetree/bindings/dma/allwinner,sun6i-a31-dma.yaml index 740b7f9b535b29267d834e35181d9782f24b5280..c1676b96daac7e13d370c7c1f32a71f4ea7df3cb 100644 --- a/Documentation/devicetree/bindings/dma/allwinner,sun6i-a31-dma.yaml +++ b/Documentation/devicetree/bindings/dma/allwinner,sun6i-a31-dma.yaml @@ -8,7 +8,7 @@ title: Allwinner A31 DMA Controller Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard allOf: - $ref: "dma-controller.yaml#" diff --git a/Documentation/devicetree/bindings/i2c/allwinner,sun6i-a31-p2wi.yaml b/Documentation/devicetree/bindings/i2c/allwinner,sun6i-a31-p2wi.yaml index 9346ef6ba61b681e0dd303d58ade4a252a3594cb..6097e8ac46c1f5a9cfdfdb503b92380f28e2cf46 100644 --- a/Documentation/devicetree/bindings/i2c/allwinner,sun6i-a31-p2wi.yaml +++ b/Documentation/devicetree/bindings/i2c/allwinner,sun6i-a31-p2wi.yaml @@ -8,7 +8,7 @@ title: Allwinner A31 P2WI (Push/Pull 2 Wires Interface) Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard allOf: - $ref: /schemas/i2c/i2c-controller.yaml# diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml index b68be3aaf587c94401783878d9a21fc809ef7c3b..e1f6d64bdccd188497b33b67ab744293810bfab0 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-only +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- $id: http://devicetree.org/schemas/iio/adc/adi,ad7292.yaml# @@ -53,7 +53,8 @@ patternProperties: description: | The channel number. It can have up to 8 channels numbered from 0 to 7. items: - maximum: 7 + - minimum: 0 + maximum: 7 diff-channels: description: see Documentation/devicetree/bindings/iio/adc/adc.txt diff --git a/Documentation/devicetree/bindings/iio/adc/allwinner,sun8i-a33-ths.yaml b/Documentation/devicetree/bindings/iio/adc/allwinner,sun8i-a33-ths.yaml index d74962c0f5ae367a8a023a24277b356f5e9b317e..15c514b83583b81cce8ac27bda28d5be6b65bab9 100644 --- a/Documentation/devicetree/bindings/iio/adc/allwinner,sun8i-a33-ths.yaml +++ b/Documentation/devicetree/bindings/iio/adc/allwinner,sun8i-a33-ths.yaml @@ -8,7 +8,7 @@ title: Allwinner A33 Thermal Sensor Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#io-channel-cells": diff --git a/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml b/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml index b3bd8ef7fbd6101bc110fbd5cc101e9e865d8465..5b3b71c9c0183ccfe8eb00649de1d4ad7e5fdaf4 100644 --- a/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml +++ b/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 LRADC Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: compatible: diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-a10-ic.yaml b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-a10-ic.yaml index 23a202d24e437bc8c0c098c28a22e5f55d37ba06..953d875b5e74aab183787caf6aec267b9a9e7322 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-a10-ic.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-a10-ic.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 Interrupt Controller Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard allOf: - $ref: /schemas/interrupt-controller.yaml# diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml index 8cd08cfb25bef7e1b1388e898bb51f97e8469086..cf09055da78b2c95a3548860e2bd04d179e33570 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml @@ -8,7 +8,7 @@ title: Allwinner A20 Non-Maskable Interrupt Controller Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard allOf: - $ref: /schemas/interrupt-controller.yaml# diff --git a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml index d3e423fcb6c2ee643529f67527eda8ba88c3d32c..0f6374ceaa697164fe55f58185ec0eeb99c0cc36 100644 --- a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml +++ b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 CMOS Sensor Interface (CSI) Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard description: |- The Allwinner A10 and later has a CMOS Sensor Interface to retrieve diff --git a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-ir.yaml b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-ir.yaml index dea36d68cdbedf312ee80ea5d7e5a50e1bb3f427..7838804700d66a2bfa7661280bd96ce65b7308fd 100644 --- a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-ir.yaml +++ b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-ir.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 Infrared Controller Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard allOf: - $ref: "rc.yaml#" diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra124-mc.yaml b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra124-mc.yaml index 30d9fb193d7fce7a6d550a165b4842a24783a891..22a94b6fdbdee478366360a412dbc54ced745071 100644 --- a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra124-mc.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra124-mc.yaml @@ -60,7 +60,8 @@ patternProperties: maximum: 1066000000 nvidia,emem-configuration: - $ref: /schemas/types.yaml#/definitions/uint32-array + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array description: | Values to be written to the EMEM register block. See section "15.6.1 MC Registers" in the TRM. diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml index 7fe0ca14e324f3afe603dba11c704dc961590383..e4135bac6957344b36aa42664d6c723448b66aa8 100644 --- a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml @@ -56,7 +56,8 @@ patternProperties: maximum: 900000000 nvidia,emc-auto-cal-interval: - $ref: /schemas/types.yaml#/definitions/uint32 + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 description: Pad calibration interval in microseconds. minimum: 0 @@ -78,7 +79,8 @@ patternProperties: Mode Register 0. nvidia,emc-zcal-cnt-long: - $ref: /schemas/types.yaml#/definitions/uint32 + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 description: Number of EMC clocks to wait before issuing any commands after sending ZCAL_MRW_CMD. @@ -96,7 +98,8 @@ patternProperties: FBIO "read" FIFO periodic resetting enabled. nvidia,emc-configuration: - $ref: /schemas/types.yaml#/definitions/uint32-array + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array description: EMC timing characterization data. These are the registers (see section "18.13.2 EMC Registers" in the TRM) whose values diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.yaml b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.yaml index 84fd57bcf0dcd723e73f8182f718f23c717b8804..4b9196c832915f08adde760272762b7a83f73dbc 100644 --- a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.yaml @@ -77,7 +77,8 @@ patternProperties: maximum: 900000000 nvidia,emem-configuration: - $ref: /schemas/types.yaml#/definitions/uint32-array + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array description: | Values to be written to the EMEM register block. See section "18.13.1 MC Registers" in the TRM. diff --git a/Documentation/devicetree/bindings/mfd/allwinner,sun4i-a10-ts.yaml b/Documentation/devicetree/bindings/mfd/allwinner,sun4i-a10-ts.yaml index 4b1a09acb98b7e59c61437221d95e2e2fff3c4d1..39afacc447b208f149d8b0ef9cb2ab981be633e2 100644 --- a/Documentation/devicetree/bindings/mfd/allwinner,sun4i-a10-ts.yaml +++ b/Documentation/devicetree/bindings/mfd/allwinner,sun4i-a10-ts.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 Resistive Touchscreen Controller Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#thermal-sensor-cells": diff --git a/Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml b/Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml index 64bca41031d513d2e766fff40ded84961239d82b..e82c9a07b6fb020f773984b3b50754af2d6f2780 100644 --- a/Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml +++ b/Documentation/devicetree/bindings/mmc/allwinner,sun4i-a10-mmc.yaml @@ -11,7 +11,7 @@ allOf: maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#address-cells": true diff --git a/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml b/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml index b5b3cf5b1ac236770c0a741c934f6edea65dee00..5d3fa412aabd3f91b12463af68990517e3466df5 100644 --- a/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml +++ b/Documentation/devicetree/bindings/mtd/allwinner,sun4i-a10-nand.yaml @@ -11,7 +11,7 @@ allOf: maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#address-cells": true diff --git a/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-emac.yaml b/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-emac.yaml index ae4796ec50a0a6612bfc26e70b898d1237713971..8d8560a67abf2750787afa144c06c2e43b702a62 100644 --- a/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-emac.yaml +++ b/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-emac.yaml @@ -11,7 +11,7 @@ allOf: maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: compatible: diff --git a/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-mdio.yaml b/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-mdio.yaml index e5562c525ed94baecc2ef24f7b313b01fb1e8a76..767193ec1d3285ec0ebe71a505c543c92c876de9 100644 --- a/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-mdio.yaml +++ b/Documentation/devicetree/bindings/net/allwinner,sun4i-a10-mdio.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 MDIO Controller Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard allOf: - $ref: "mdio.yaml#" diff --git a/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml b/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml index f683b7104e3eb424092324a4ea5783b1b59a15c9..703d0d8868846dde2ce14a0fafef6acd264bce28 100644 --- a/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml +++ b/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml @@ -11,7 +11,7 @@ allOf: maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: compatible: diff --git a/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml b/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml index 11654d4b80fb7616c73c81660dec001729b9806f..db36b4d8648449927a419961e7308c2151582a76 100644 --- a/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml +++ b/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml @@ -8,7 +8,7 @@ title: Allwinner A83t EMAC Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: compatible: diff --git a/Documentation/devicetree/bindings/net/can/allwinner,sun4i-a10-can.yaml b/Documentation/devicetree/bindings/net/can/allwinner,sun4i-a10-can.yaml index 770af7c46114024880da0f5d0e137296b7546b69..a95960ee3feba1077ae7ed0aa6c4d43c8d6e5467 100644 --- a/Documentation/devicetree/bindings/net/can/allwinner,sun4i-a10-can.yaml +++ b/Documentation/devicetree/bindings/net/can/allwinner,sun4i-a10-can.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 CAN Controller Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: compatible: diff --git a/Documentation/devicetree/bindings/net/ti,cpsw-switch.yaml b/Documentation/devicetree/bindings/net/ti,cpsw-switch.yaml index 81ae8cafabc1444b584d8cfc393b433287fbe2ff..ac8c76369a867b55e37a01fa51446e611889c13f 100644 --- a/Documentation/devicetree/bindings/net/ti,cpsw-switch.yaml +++ b/Documentation/devicetree/bindings/net/ti,cpsw-switch.yaml @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0 +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- $id: http://devicetree.org/schemas/net/ti,cpsw-switch.yaml# @@ -44,7 +44,6 @@ properties: description: CPSW functional clock clock-names: - maxItems: 1 items: - const: fck @@ -70,7 +69,6 @@ properties: Phandle to the system control device node which provides access to efuse IO range with MAC addresses - ethernet-ports: type: object properties: @@ -82,8 +80,6 @@ properties: patternProperties: "^port@[0-9]+$": type: object - minItems: 1 - maxItems: 2 description: CPSW external ports allOf: @@ -91,23 +87,20 @@ properties: properties: reg: - maxItems: 1 - enum: [1, 2] + items: + - enum: [1, 2] description: CPSW port number phys: - $ref: /schemas/types.yaml#definitions/phandle-array maxItems: 1 description: phandle on phy-gmii-sel PHY label: - $ref: /schemas/types.yaml#/definitions/string-array - maxItems: 1 description: label associated with this port ti,dual-emac-pvid: - $ref: /schemas/types.yaml#/definitions/uint32 - maxItems: 1 + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 minimum: 1 maximum: 1024 description: @@ -136,7 +129,6 @@ properties: description: CPTS reference clock clock-names: - maxItems: 1 items: - const: cpts @@ -201,7 +193,7 @@ examples: phys = <&phy_gmii_sel 1>; phy-handle = <ðphy0_sw>; phy-mode = "rgmii"; - ti,dual_emac_pvid = <1>; + ti,dual-emac-pvid = <1>; }; cpsw_port2: port@2 { @@ -211,7 +203,7 @@ examples: phys = <&phy_gmii_sel 2>; phy-handle = <ðphy1_sw>; phy-mode = "rgmii"; - ti,dual_emac_pvid = <2>; + ti,dual-emac-pvid = <2>; }; }; diff --git a/Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml b/Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml index 659b02002a35c24148cad4dbdf12e43627a19143..daf1321d76ad8356bd7f636ad4c101e39a102549 100644 --- a/Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml +++ b/Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 Security ID Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard allOf: - $ref: "nvmem.yaml#" diff --git a/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml b/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml index fa46670de2992dd1bde4809e397a905e8f77e72f..d0b541a461f365d2b47278a79447d7ad0dade56d 100644 --- a/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml +++ b/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml @@ -8,14 +8,18 @@ title: Allwinner A31 MIPI D-PHY Controller Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#phy-cells": const: 0 compatible: - const: allwinner,sun6i-a31-mipi-dphy + oneOf: + - const: allwinner,sun6i-a31-mipi-dphy + - items: + - const: allwinner,sun50i-a64-mipi-dphy + - const: allwinner,sun6i-a31-mipi-dphy reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml index cd0503b6fe36fff23f47ab53c03da3b8ab534257..bfefd09d8c1e43ab3abba75930decf004b7a95af 100644 --- a/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 Pin Controller Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#gpio-cells": diff --git a/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml b/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml index 0ac52f83a58cce4f222f20a266fc2d4528416284..4a21fe77ee1d34e650183704b671b74de222e23c 100644 --- a/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml +++ b/Documentation/devicetree/bindings/pwm/allwinner,sun4i-a10-pwm.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 PWM Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#pwm-cells": diff --git a/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml index acf18d170352d242812d43338974a92ff85d7c93..c0d83865e933a2cbe896c5ae847ee7640cbc5637 100644 --- a/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml +++ b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml @@ -50,6 +50,8 @@ properties: description: Should contain the WWDG1 watchdog reset interrupt maxItems: 1 + wakeup-source: true + mboxes: description: This property is required only if the rpmsg/virtio functionality is used. diff --git a/Documentation/devicetree/bindings/rtc/allwinner,sun4i-a10-rtc.yaml b/Documentation/devicetree/bindings/rtc/allwinner,sun4i-a10-rtc.yaml index 46d69c32b89b89506f28a3a73dc1803fa9490a21..478b0234e8fa97416db572c50ce58fed4c5b88c7 100644 --- a/Documentation/devicetree/bindings/rtc/allwinner,sun4i-a10-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/allwinner,sun4i-a10-rtc.yaml @@ -11,7 +11,7 @@ allOf: maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: compatible: diff --git a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml index d7a57ec4a6400bec0f0107fb1aeba516a1175bb1..37c2a601c3fa8ab075cbc2a7817876386a0600f3 100644 --- a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml @@ -8,7 +8,7 @@ title: Allwinner A31 RTC Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#clock-cells": diff --git a/Documentation/devicetree/bindings/serio/allwinner,sun4i-a10-ps2.yaml b/Documentation/devicetree/bindings/serio/allwinner,sun4i-a10-ps2.yaml index ee9712f1c97d44b23bd2cf61b0cbe0c60f7b85fe..2ecab8ed702a20abfa5d1e44b89e267852df1c06 100644 --- a/Documentation/devicetree/bindings/serio/allwinner,sun4i-a10-ps2.yaml +++ b/Documentation/devicetree/bindings/serio/allwinner,sun4i-a10-ps2.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 PS2 Host Controller Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard description: A20 PS2 is dual role controller (PS2 host and PS2 device). These diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml index b8f89c7258ebc853a1c416a75c8dc08f634aa8aa..ea1d2efb2aaa36d79790132db1ad6a170a55220e 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 Codec Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#sound-dai-cells": diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml index eb3992138eecce3cf0283754b9c47a9ab6f8f4ee..112ae00d63c1d6576583b1542705b6a8a7ef500b 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-i2s.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 I2S Controller Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#sound-dai-cells": diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml index 38d4cede0860dd5aed5402e4cdb34dff5f39a677..444a432912bb4ec7970a2a61e26e33b2b09fac24 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml @@ -10,7 +10,7 @@ maintainers: - Chen-Yu Tsai - Liam Girdwood - Mark Brown - - Maxime Ripard + - Maxime Ripard properties: "#sound-dai-cells": diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun50i-a64-codec-analog.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun50i-a64-codec-analog.yaml index f290eb72a8781e7b0f2138ac74271cd087583716..3b764415c9abf7a696c7f965cbb36abfac4264d0 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun50i-a64-codec-analog.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun50i-a64-codec-analog.yaml @@ -8,7 +8,7 @@ title: Allwinner A64 Analog Codec Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: compatible: diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun8i-a23-codec-analog.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun8i-a23-codec-analog.yaml index 85305b4c2729b74759d319eef9ac5d9cb88234e7..9718358826abdaebd02260385519c7a5b7d34898 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun8i-a23-codec-analog.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun8i-a23-codec-analog.yaml @@ -8,7 +8,7 @@ title: Allwinner A23 Analog Codec Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: compatible: diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml index 5e7cc05bbff1dc5f3705b58930f3674f89e67e15..55d28268d2f4ff5c0860b02609185311b42b90ce 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml @@ -8,7 +8,7 @@ title: Allwinner A33 Codec Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#sound-dai-cells": diff --git a/Documentation/devicetree/bindings/spi/allwinner,sun4i-a10-spi.yaml b/Documentation/devicetree/bindings/spi/allwinner,sun4i-a10-spi.yaml index 6d1329c281707fbefe0aa403b860c6105d5a4a71..8036499112f5a858e00f8edf0fa425eacf7db76f 100644 --- a/Documentation/devicetree/bindings/spi/allwinner,sun4i-a10-spi.yaml +++ b/Documentation/devicetree/bindings/spi/allwinner,sun4i-a10-spi.yaml @@ -11,7 +11,7 @@ allOf: maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#address-cells": true diff --git a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml index f36c46d236d7a6afdf82ee2a7af704ecbf68e1a6..0565dc49e44940dc6326f2ee2c1672542df653d2 100644 --- a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml +++ b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml @@ -11,7 +11,7 @@ allOf: maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: "#address-cells": true diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun4i-a10-timer.yaml b/Documentation/devicetree/bindings/timer/allwinner,sun4i-a10-timer.yaml index 20adc1c8e9cccb33a94f385966c02df961f0fa59..23e989e0976630382d70ab5ddaeeb3b4c3542b61 100644 --- a/Documentation/devicetree/bindings/timer/allwinner,sun4i-a10-timer.yaml +++ b/Documentation/devicetree/bindings/timer/allwinner,sun4i-a10-timer.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 Timer Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: compatible: diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.yaml b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.yaml index dfa0c41fd261d166b95af163f195f45358798bc8..40fc4bcb31457db7374f4266839894469cd2366f 100644 --- a/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.yaml +++ b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.yaml @@ -8,7 +8,7 @@ title: Allwinner A13 High-Speed Timer Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: compatible: diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml index 0af70fc8de5a764003f08e6cf940f52d4d84c86b..d9207bf9d8946e4ee9c799f1adc92ec5906d0359 100644 --- a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml +++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml @@ -8,7 +8,7 @@ title: Allwinner A10 mUSB OTG Controller Device Tree Bindings maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: compatible: diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 6046f45558525f78d028df514d17b2e320feba72..4e6248ec5ed9a8a5a8954fcecbdf15aa8de1e64c 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -513,6 +513,8 @@ patternProperties: description: Lantiq Semiconductor "^lattice,.*": description: Lattice Semiconductor + "^leadtek,.*": + description: Shenzhen Leadtek Technology Co., Ltd. "^leez,.*": description: Leez "^lego,.*": @@ -1056,6 +1058,8 @@ patternProperties: description: Extreme Engineering Solutions (X-ES) "^xillybus,.*": description: Xillybus Ltd. + "^xinpeng,.*": + description: Shenzhen Xinpeng Technology Co., Ltd "^xlnx,.*": description: Xilinx "^xunlong,.*": diff --git a/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml b/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml index 3a54f58683a0ed01292c43b2554f63d295461a5d..e8f226376108178037de849d474715ce2d6d678c 100644 --- a/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml @@ -11,7 +11,7 @@ allOf: maintainers: - Chen-Yu Tsai - - Maxime Ripard + - Maxime Ripard properties: compatible: diff --git a/Documentation/fb/fbcon.rst b/Documentation/fb/fbcon.rst index ebca41785abea977ebd2e00cd7abfa2ae0c6a28c..e57a3d1d085ad6e5dc0c43cc582456e2eec56c36 100644 --- a/Documentation/fb/fbcon.rst +++ b/Documentation/fb/fbcon.rst @@ -127,7 +127,7 @@ C. Boot options is typically located on the same video card. Thus, the consoles that are controlled by the VGA console will be garbled. -4. fbcon=rotate: +5. fbcon=rotate: This option changes the orientation angle of the console display. The value 'n' accepts the following: @@ -152,21 +152,21 @@ C. Boot options Actually, the underlying fb driver is totally ignorant of console rotation. -5. fbcon=margin: +6. fbcon=margin: This option specifies the color of the margins. The margins are the leftover area at the right and the bottom of the screen that are not used by text. By default, this area will be black. The 'color' value is an integer number that depends on the framebuffer driver being used. -6. fbcon=nodefer +7. fbcon=nodefer If the kernel is compiled with deferred fbcon takeover support, normally the framebuffer contents, left in place by the firmware/bootloader, will be preserved until there actually is some text is output to the console. This option causes fbcon to bind immediately to the fbdev device. -7. fbcon=logo-pos: +8. fbcon=logo-pos: The only possible 'location' is 'center' (without quotes), and when given, the bootup logo is moved from the default top-left corner @@ -174,6 +174,11 @@ C. Boot options displayed due to multiple CPUs, the collected line of logos is moved as a whole. +9. fbcon=logo-count: + + The value 'n' overrides the number of bootup logos. 0 disables the + logo, and -1 gives the default which is the number of online CPUs. + C. Attaching, Detaching and Unloading Before going on to how to attach, detach and unload the framebuffer console, an diff --git a/Documentation/fb/modedb.rst b/Documentation/fb/modedb.rst index 9c4e3fd39e6d2dcf37364f28e24d702c0e9fd05a..624d08fd285621ec5e6cdf33ae56b155d74fda34 100644 --- a/Documentation/fb/modedb.rst +++ b/Documentation/fb/modedb.rst @@ -65,6 +65,9 @@ Valid options are:: - reflect_y (boolean): Perform an axial symmetry on the Y axis - rotate (integer): Rotate the initial framebuffer by x degrees. Valid values are 0, 90, 180 and 270. + - panel_orientation, one of "normal", "upside_down", "left_side_up", or + "right_side_up". For KMS drivers only, this sets the "panel orientation" + property on the kms connector as hint for kms users. ----------------------------------------------------------------------------- diff --git a/Documentation/filesystems/erofs.txt b/Documentation/filesystems/erofs.txt index b0c085326e2e68f4ead9063af48beeda0b48dcf9..db6d39c3ae715ee90b876c4660346581f3b67171 100644 --- a/Documentation/filesystems/erofs.txt +++ b/Documentation/filesystems/erofs.txt @@ -24,11 +24,11 @@ Here is the main features of EROFS: - Metadata & data could be mixed by design; - 2 inode versions for different requirements: - v1 v2 + compact (v1) extended (v2) Inode metadata size: 32 bytes 64 bytes Max file size: 4 GB 16 EB (also limited by max. vol size) Max uids/gids: 65536 4294967296 - File creation time: no yes (64 + 32-bit timestamp) + File change time: no yes (64 + 32-bit timestamp) Max hardlinks: 65536 4294967296 Metadata reserved: 4 bytes 14 bytes @@ -39,7 +39,7 @@ Here is the main features of EROFS: - Support POSIX.1e ACLs by using xattrs; - Support transparent file compression as an option: - LZ4 algorithm with 4 KB fixed-output compression for high performance; + LZ4 algorithm with 4 KB fixed-sized output compression for high performance. The following git tree provides the file system user-space tools under development (ex, formatting tool mkfs.erofs): @@ -85,7 +85,7 @@ All data areas should be aligned with the block size, but metadata areas may not. All metadatas can be now observed in two different spaces (views): 1. Inode metadata space Each valid inode should be aligned with an inode slot, which is a fixed - value (32 bytes) and designed to be kept in line with v1 inode size. + value (32 bytes) and designed to be kept in line with compact inode size. Each inode can be directly found with the following formula: inode offset = meta_blkaddr * block_size + 32 * nid @@ -117,10 +117,10 @@ may not. All metadatas can be now observed in two different spaces (views): |-> aligned with 4B Inode could be 32 or 64 bytes, which can be distinguished from a common - field which all inode versions have -- i_advise: + field which all inode versions have -- i_format: __________________ __________________ - | i_advise | | i_advise | + | i_format | | i_format | |__________________| |__________________| | ... | | ... | | | | | @@ -129,12 +129,13 @@ may not. All metadatas can be now observed in two different spaces (views): |__________________| 64 bytes Xattrs, extents, data inline are followed by the corresponding inode with - proper alignes, and they could be optional for different data mappings, - _currently_ there are totally 3 valid data mappings supported: + proper alignment, and they could be optional for different data mappings. + _currently_ total 4 valid data mappings are supported: - 1) flat file data without data inline (no extent); - 2) fixed-output size data compression (must have extents); - 3) flat file data with tail-end data inline (no extent); + 0 flat file data without data inline (no extent); + 1 fixed-sized output data compression (with non-compacted indexes); + 2 flat file data with tail packing data inline (no extent); + 3 fixed-sized output data compression (with compacted indexes, v5.3+). The size of the optional xattrs is indicated by i_xattr_count in inode header. Large xattrs or xattrs shared by many different files can be @@ -182,8 +183,8 @@ introduce another on-disk field at all. Compression ----------- -Currently, EROFS supports 4KB fixed-output clustersize transparent file -compression, as illustrated below: +Currently, EROFS supports 4KB fixed-sized output transparent file compression, +as illustrated below: |---- Variant-Length Extent ----|-------- VLE --------|----- VLE ----- clusterofs clusterofs clusterofs diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.rst similarity index 99% rename from Documentation/filesystems/overlayfs.txt rename to Documentation/filesystems/overlayfs.rst index 845d689e0fd711672416669e501f68757e498a8f..e443be7928db2b674ad4272d6d4adf74bacd356f 100644 --- a/Documentation/filesystems/overlayfs.txt +++ b/Documentation/filesystems/overlayfs.rst @@ -1,3 +1,5 @@ +.. SPDX-License-Identifier: GPL-2.0 + Written by: Neil Brown Please see MAINTAINERS file for where to send questions. @@ -181,7 +183,7 @@ Kernel config options: worried about backward compatibility with kernels that have the redirect_dir feature and follow redirects even if turned off. -Module options (can also be changed through /sys/module/overlay/parameters/*): +Module options (can also be changed through /sys/module/overlay/parameters/): - "redirect_dir=BOOL": See OVERLAY_FS_REDIRECT_DIR kernel config option above. @@ -263,7 +265,7 @@ top, lower2 the middle and lower3 the bottom layer. Metadata only copy up --------------------- +--------------------- When metadata only copy up feature is enabled, overlayfs will only copy up metadata (as opposed to whole file), when a metadata specific operation @@ -286,10 +288,10 @@ pointed by REDIRECT. This should not be possible on local system as setting "trusted." xattrs will require CAP_SYS_ADMIN. But it should be possible for untrusted layers like from a pen drive. -Note: redirect_dir={off|nofollow|follow(*)} conflicts with metacopy=on, and +Note: redirect_dir={off|nofollow|follow[*]} conflicts with metacopy=on, and results in an error. -(*) redirect_dir=follow only conflicts with metacopy=on if upperdir=... is +[*] redirect_dir=follow only conflicts with metacopy=on if upperdir=... is given. Sharing and copying layers diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index 966bd2d9f0ccd5fd39d826012f750c94163d7479..a73320576ca9a18e71705694dd3c833c83b62a47 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst @@ -24,9 +24,9 @@ Driver Initialization At the core of every DRM driver is a :c:type:`struct drm_driver ` structure. Drivers typically statically initialize a drm_driver structure, and then pass it to -:c:func:`drm_dev_alloc()` to allocate a device instance. After the +drm_dev_alloc() to allocate a device instance. After the device instance is fully initialized it can be registered (which makes -it accessible from userspace) using :c:func:`drm_dev_register()`. +it accessible from userspace) using drm_dev_register(). The :c:type:`struct drm_driver ` structure contains static information that describes the driver and features it diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 23a3c986ef6d4abed2b4987df09c4183e034e0d8..906771e03103240fd6fa2051631ff45ce7358ef7 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -3,7 +3,7 @@ Kernel Mode Setting (KMS) ========================= Drivers must initialize the mode setting core by calling -:c:func:`drm_mode_config_init()` on the DRM device. The function +drm_mode_config_init() on the DRM device. The function initializes the :c:type:`struct drm_device ` mode_config field and never fails. Once done, mode configuration must be setup by initializing the following fields. @@ -181,8 +181,7 @@ Setting`_). The somewhat surprising part here is that properties are not directly instantiated on each object, but free-standing mode objects themselves, represented by :c:type:`struct drm_property `, which only specify the type and value range of a property. Any given property can be attached -multiple times to different objects using :c:func:`drm_object_attach_property() -`. +multiple times to different objects using drm_object_attach_property(). .. kernel-doc:: include/drm/drm_mode_object.h :internal: @@ -260,7 +259,8 @@ Taken all together there's two consequences for the atomic design: drm_connector_state ` for connectors. These are the only objects with userspace-visible and settable state. For internal state drivers can subclass these structures through embeddeding, or add entirely new state - structures for their globally shared hardware functions. + structures for their globally shared hardware functions, see :c:type:`struct + drm_private_state`. - An atomic update is assembled and validated as an entirely free-standing pile of structures within the :c:type:`drm_atomic_state ` @@ -269,6 +269,14 @@ Taken all together there's two consequences for the atomic design: to the driver and modeset objects. This way rolling back an update boils down to releasing memory and unreferencing objects like framebuffers. +Locking of atomic state structures is internally using :c:type:`struct +drm_modeset_lock `. As a general rule the locking shouldn't be +exposed to drivers, instead the right locks should be automatically acquired by +any function that duplicates or peeks into a state, like e.g. +drm_atomic_get_crtc_state(). Locking only protects the software data +structure, ordering of committing state changes to hardware is sequenced using +:c:type:`struct drm_crtc_commit `. + Read on in this chapter, and also in :ref:`drm_atomic_helper` for more detailed coverage of specific topics. @@ -479,6 +487,9 @@ Color Management Properties .. kernel-doc:: drivers/gpu/drm/drm_color_mgmt.c :export: +.. kernel-doc:: include/drm/drm_color_mgmt.h + :internal: + Tile Group Property ------------------- diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 59619296c84bff029456bb6f9538bcf2d24aca12..c77b326012606413493c76efd52d7622eebba296 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -149,19 +149,19 @@ struct :c:type:`struct drm_gem_object `. To create a GEM object, a driver allocates memory for an instance of its specific GEM object type and initializes the embedded struct :c:type:`struct drm_gem_object ` with a call -to :c:func:`drm_gem_object_init()`. The function takes a pointer +to drm_gem_object_init(). The function takes a pointer to the DRM device, a pointer to the GEM object and the buffer object size in bytes. GEM uses shmem to allocate anonymous pageable memory. -:c:func:`drm_gem_object_init()` will create an shmfs file of the +drm_gem_object_init() will create an shmfs file of the requested size and store it into the struct :c:type:`struct drm_gem_object ` filp field. The memory is used as either main storage for the object when the graphics hardware uses system memory directly or as a backing store otherwise. Drivers are responsible for the actual physical pages allocation by -calling :c:func:`shmem_read_mapping_page_gfp()` for each page. +calling shmem_read_mapping_page_gfp() for each page. Note that they can decide to allocate pages when initializing the GEM object, or to delay allocation until the memory is needed (for instance when a page fault occurs as a result of a userspace memory access or @@ -170,20 +170,18 @@ when the driver needs to start a DMA transfer involving the memory). Anonymous pageable memory allocation is not always desired, for instance when the hardware requires physically contiguous system memory as is often the case in embedded devices. Drivers can create GEM objects with -no shmfs backing (called private GEM objects) by initializing them with -a call to :c:func:`drm_gem_private_object_init()` instead of -:c:func:`drm_gem_object_init()`. Storage for private GEM objects -must be managed by drivers. +no shmfs backing (called private GEM objects) by initializing them with a call +to drm_gem_private_object_init() instead of drm_gem_object_init(). Storage for +private GEM objects must be managed by drivers. GEM Objects Lifetime -------------------- All GEM objects are reference-counted by the GEM core. References can be -acquired and release by :c:func:`calling drm_gem_object_get()` and -:c:func:`drm_gem_object_put()` respectively. The caller must hold the -:c:type:`struct drm_device ` struct_mutex lock when calling -:c:func:`drm_gem_object_get()`. As a convenience, GEM provides -:c:func:`drm_gem_object_put_unlocked()` functions that can be called without +acquired and release by calling drm_gem_object_get() and drm_gem_object_put() +respectively. The caller must hold the :c:type:`struct drm_device ` +struct_mutex lock when calling drm_gem_object_get(). As a convenience, GEM +provides drm_gem_object_put_unlocked() functions that can be called without holding the lock. When the last reference to a GEM object is released the GEM core calls @@ -194,7 +192,7 @@ free the GEM object and all associated resources. void (\*gem_free_object) (struct drm_gem_object \*obj); Drivers are responsible for freeing all GEM object resources. This includes the resources created by the GEM core, which need to be released with -:c:func:`drm_gem_object_release()`. +drm_gem_object_release(). GEM Objects Naming ------------------ @@ -210,13 +208,11 @@ to the GEM object in other standard or driver-specific ioctls. Closing a DRM file handle frees all its GEM handles and dereferences the associated GEM objects. -To create a handle for a GEM object drivers call -:c:func:`drm_gem_handle_create()`. The function takes a pointer -to the DRM file and the GEM object and returns a locally unique handle. -When the handle is no longer needed drivers delete it with a call to -:c:func:`drm_gem_handle_delete()`. Finally the GEM object -associated with a handle can be retrieved by a call to -:c:func:`drm_gem_object_lookup()`. +To create a handle for a GEM object drivers call drm_gem_handle_create(). The +function takes a pointer to the DRM file and the GEM object and returns a +locally unique handle. When the handle is no longer needed drivers delete it +with a call to drm_gem_handle_delete(). Finally the GEM object associated with a +handle can be retrieved by a call to drm_gem_object_lookup(). Handles don't take ownership of GEM objects, they only take a reference to the object that will be dropped when the handle is destroyed. To @@ -258,7 +254,7 @@ The mmap system call can't be used directly to map GEM objects, as they don't have their own file handle. Two alternative methods currently co-exist to map GEM objects to userspace. The first method uses a driver-specific ioctl to perform the mapping operation, calling -:c:func:`do_mmap()` under the hood. This is often considered +do_mmap() under the hood. This is often considered dubious, seems to be discouraged for new GEM-enabled drivers, and will thus not be described here. @@ -267,23 +263,22 @@ The second method uses the mmap system call on the DRM file handle. void offset); DRM identifies the GEM object to be mapped by a fake offset passed through the mmap offset argument. Prior to being mapped, a GEM object must thus be associated with a fake offset. To do so, drivers -must call :c:func:`drm_gem_create_mmap_offset()` on the object. +must call drm_gem_create_mmap_offset() on the object. Once allocated, the fake offset value must be passed to the application in a driver-specific way and can then be used as the mmap offset argument. -The GEM core provides a helper method :c:func:`drm_gem_mmap()` to +The GEM core provides a helper method drm_gem_mmap() to handle object mapping. The method can be set directly as the mmap file operation handler. It will look up the GEM object based on the offset value and set the VMA operations to the :c:type:`struct drm_driver -` gem_vm_ops field. Note that -:c:func:`drm_gem_mmap()` doesn't map memory to userspace, but -relies on the driver-provided fault handler to map pages individually. +` gem_vm_ops field. Note that drm_gem_mmap() doesn't map memory to +userspace, but relies on the driver-provided fault handler to map pages +individually. -To use :c:func:`drm_gem_mmap()`, drivers must fill the struct -:c:type:`struct drm_driver ` gem_vm_ops field -with a pointer to VM operations. +To use drm_gem_mmap(), drivers must fill the struct :c:type:`struct drm_driver +` gem_vm_ops field with a pointer to VM operations. The VM operations is a :c:type:`struct vm_operations_struct ` made up of several fields, the more interesting ones being: @@ -298,9 +293,8 @@ made up of several fields, the more interesting ones being: The open and close operations must update the GEM object reference -count. Drivers can use the :c:func:`drm_gem_vm_open()` and -:c:func:`drm_gem_vm_close()` helper functions directly as open -and close handlers. +count. Drivers can use the drm_gem_vm_open() and drm_gem_vm_close() helper +functions directly as open and close handlers. The fault operation handler is responsible for mapping individual pages to userspace when a page fault occurs. Depending on the memory @@ -312,12 +306,12 @@ Drivers that want to map the GEM object upfront instead of handling page faults can implement their own mmap file operation handler. For platforms without MMU the GEM core provides a helper method -:c:func:`drm_gem_cma_get_unmapped_area`. The mmap() routines will call -this to get a proposed address for the mapping. +drm_gem_cma_get_unmapped_area(). The mmap() routines will call this to get a +proposed address for the mapping. -To use :c:func:`drm_gem_cma_get_unmapped_area`, drivers must fill the -struct :c:type:`struct file_operations ` get_unmapped_area -field with a pointer on :c:func:`drm_gem_cma_get_unmapped_area`. +To use drm_gem_cma_get_unmapped_area(), drivers must fill the struct +:c:type:`struct file_operations ` get_unmapped_area field with +a pointer on drm_gem_cma_get_unmapped_area(). More detailed information about get_unmapped_area can be found in Documentation/nommu-mmap.txt diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 94f90521f58c07f499baf3bc07e4df5323402bd2..56fec6ed1ad860276fe3ffa71b3d86f6f65c3bbf 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -254,36 +254,45 @@ Validating changes with IGT There's a collection of tests that aims to cover the whole functionality of DRM drivers and that can be used to check that changes to DRM drivers or the core don't regress existing functionality. This test suite is called IGT and -its code can be found in https://cgit.freedesktop.org/drm/igt-gpu-tools/. +its code and instructions to build and run can be found in +https://gitlab.freedesktop.org/drm/igt-gpu-tools/. -To build IGT, start by installing its build dependencies. In Debian-based -systems:: +Using VKMS to test DRM API +-------------------------- - # apt-get build-dep intel-gpu-tools +VKMS is a software-only model of a KMS driver that is useful for testing +and for running compositors. VKMS aims to enable a virtual display without +the need for a hardware display capability. These characteristics made VKMS +a perfect tool for validating the DRM core behavior and also support the +compositor developer. VKMS makes it possible to test DRM functions in a +virtual machine without display, simplifying the validation of some of the +core changes. -And in Fedora-based systems:: +To Validate changes in DRM API with VKMS, start setting the kernel: make +sure to enable VKMS module; compile the kernel with the VKMS enabled and +install it in the target machine. VKMS can be run in a Virtual Machine +(QEMU, virtme or similar). It's recommended the use of KVM with the minimum +of 1GB of RAM and four cores. - # dnf builddep intel-gpu-tools +It's possible to run the IGT-tests in a VM in two ways: -Then clone the repository:: + 1. Use IGT inside a VM + 2. Use IGT from the host machine and write the results in a shared directory. - $ git clone git://anongit.freedesktop.org/drm/igt-gpu-tools +As follow, there is an example of using a VM with a shared directory with +the host machine to run igt-tests. As an example it's used virtme:: -Configure the build system and start the build:: + $ virtme-run --rwdir /path/for/shared_dir --kdir=path/for/kernel/directory --mods=auto - $ cd igt-gpu-tools && ./autogen.sh && make -j6 +Run the igt-tests in the guest machine, as example it's ran the 'kms_flip' +tests:: -Download the piglit dependency:: + $ /path/for/igt-gpu-tools/scripts/run-tests.sh -p -s -t "kms_flip.*" -v - $ ./scripts/run-tests.sh -d - -And run the tests:: - - $ ./scripts/run-tests.sh -t kms -t core -s - -run-tests.sh is a wrapper around piglit that will execute the tests matching -the -t options. A report in HTML format will be available in -./results/html/index.html. Results can be compared with piglit. +In this example, instead of build the igt_runner, Piglit is used +(-p option); it's created html summary of the tests results and it's saved +in the folder "igt-gpu-tools/results"; it's executed only the igt-tests +matching the -t option. Display CRC Support ------------------- diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 6792fa9b6b6bd1dd058ef6f76ba6b85428ee182b..bc869b23fc39449ce36394cba846dd192fb39ba2 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -142,14 +142,14 @@ Contact: Daniel Vetter, respective driver maintainers Level: Advanced -Convert instances of dev_info/dev_err/dev_warn to their DRM_DEV_* equivalent ----------------------------------------------------------------------------- +Convert logging to drm_* functions with drm_device paramater +------------------------------------------------------------ For drivers which could have multiple instances, it is necessary to differentiate between which is which in the logs. Since DRM_INFO/WARN/ERROR don't do this, drivers used dev_info/warn/err to make this differentiation. We -now have DRM_DEV_* variants of the drm print macros, so we can start to convert -those drivers back to using drm-formwatted specific log messages. +now have drm_* variants of the drm print functions, so we can start to convert +those drivers back to using drm-formatted specific log messages. Before you start this conversion please contact the relevant maintainers to make sure your work will be merged - not everyone agrees that the DRM dmesg macros @@ -171,23 +171,40 @@ Contact: Maintainer of the driver you plan to convert Level: Intermediate -Convert drivers to use drm_fb_helper_fbdev_setup/teardown() ------------------------------------------------------------ +Convert drivers to use drm_fbdev_generic_setup() +------------------------------------------------ -Most drivers can use drm_fb_helper_fbdev_setup() except maybe: +Most drivers can use drm_fbdev_generic_setup(). Driver have to implement +atomic modesetting and GEM vmap support. Current generic fbdev emulation +expects the framebuffer in system memory (or system-like memory). -- amdgpu which has special logic to decide whether to call - drm_helper_disable_unused_functions() +Contact: Maintainer of the driver you plan to convert + +Level: Intermediate -- armada which isn't atomic and doesn't call - drm_helper_disable_unused_functions() +drm_framebuffer_funcs and drm_mode_config_funcs.fb_create cleanup +----------------------------------------------------------------- -- i915 which calls drm_fb_helper_initial_config() in a worker +A lot more drivers could be switched over to the drm_gem_framebuffer helpers. +Various hold-ups: -Drivers that use drm_framebuffer_remove() to clean up the fbdev framebuffer can -probably use drm_fb_helper_fbdev_teardown(). +- Need to switch over to the generic dirty tracking code using + drm_atomic_helper_dirtyfb first (e.g. qxl). -Contact: Maintainer of the driver you plan to convert +- Need to switch to drm_fbdev_generic_setup(), otherwise a lot of the custom fb + setup code can't be deleted. + +- Many drivers wrap drm_gem_fb_create() only to check for valid formats. For + atomic drivers we could check for valid formats by calling + drm_plane_check_pixel_format() against all planes, and pass if any plane + supports the format. For non-atomic that's not possible since like the format + list for the primary plane is fake and we'd therefor reject valid formats. + +- Many drivers subclass drm_framebuffer, we'd need a embedding compatible + version of the varios drm_gem_fb_create functions. Maybe called + drm_gem_fb_create/_with_dirty/_with_funcs as needed. + +Contact: Daniel Vetter Level: Intermediate @@ -328,8 +345,8 @@ drm_fb_helper tasks these igt tests need to be fixed: kms_fbcon_fbt@psr and kms_fbcon_fbt@psr-suspend. -- The max connector argument for drm_fb_helper_init() and - drm_fb_helper_fbdev_setup() isn't used anymore and can be removed. +- The max connector argument for drm_fb_helper_init() isn't used anymore and + can be removed. - The helper doesn't keep an array of connectors anymore so these can be removed: drm_fb_helper_single_add_all_connectors(), @@ -351,6 +368,23 @@ connector register/unregister fixes Level: Intermediate +Remove load/unload callbacks from all non-DRIVER_LEGACY drivers +--------------------------------------------------------------- + +The load/unload callbacks in struct &drm_driver are very much midlayers, plus +for historical reasons they get the ordering wrong (and we can't fix that) +between setting up the &drm_driver structure and calling drm_dev_register(). + +- Rework drivers to no longer use the load/unload callbacks, directly coding the + load/unload sequence into the driver's probe function. + +- Once all non-DRIVER_LEGACY drivers are converted, disallow the load/unload + callbacks for all modern drivers. + +Contact: Daniel Vetter + +Level: Intermediate + Core refactorings ================= diff --git a/Documentation/process/coding-style.rst b/Documentation/process/coding-style.rst index ada573b7d703bca0b0ab725e2714f84f6dd2bd1f..edb296c52f61e4b6c1b7b67a30302260ffcb015c 100644 --- a/Documentation/process/coding-style.rst +++ b/Documentation/process/coding-style.rst @@ -988,7 +988,7 @@ Similarly, if you need to calculate the size of some structure member, use .. code-block:: c - #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) + #define sizeof_field(t, f) (sizeof(((t*)0)->f)) There are also min() and max() macros that do strict type checking if you need them. Feel free to peruse that header file to see what else is already diff --git a/Documentation/scsi/smartpqi.txt b/Documentation/scsi/smartpqi.txt index 201f80c7c0506e5e5772006b9f874d4081920d6f..df129f55ace5e768740312b0b60b903b76872ab6 100644 --- a/Documentation/scsi/smartpqi.txt +++ b/Documentation/scsi/smartpqi.txt @@ -29,7 +29,7 @@ smartpqi specific entries in /sys smartpqi host attributes: ------------------------- /sys/class/scsi_host/host*/rescan - /sys/class/scsi_host/host*/version + /sys/class/scsi_host/host*/driver_version The host rescan attribute is a write only attribute. Writing to this attribute will trigger the driver to scan for new, changed, or removed diff --git a/Documentation/translations/it_IT/process/coding-style.rst b/Documentation/translations/it_IT/process/coding-style.rst index 8995d2d19f202e65d37d960705991c314a5bfcaa..8725f2b9e96032d37ac6a3c379ce254fd652e5d8 100644 --- a/Documentation/translations/it_IT/process/coding-style.rst +++ b/Documentation/translations/it_IT/process/coding-style.rst @@ -1005,7 +1005,7 @@ struttura, usate .. code-block:: c - #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) + #define sizeof_field(t, f) (sizeof(((t*)0)->f)) Ci sono anche le macro min() e max() che, se vi serve, effettuano un controllo rigido sui tipi. Sentitevi liberi di leggere attentamente questo file diff --git a/Documentation/translations/zh_CN/process/coding-style.rst b/Documentation/translations/zh_CN/process/coding-style.rst index 4f6237392e65ad33b393a337d4d898314c600290..eae10bc7f86f2a096f970e6464087c7f31b9aea8 100644 --- a/Documentation/translations/zh_CN/process/coding-style.rst +++ b/Documentation/translations/zh_CN/process/coding-style.rst @@ -826,7 +826,7 @@ inline gcc 也可以自动使其内联。而且其他用户可能会要求移除 .. code-block:: c - #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) + #define sizeof_field(t, f) (sizeof(((t*)0)->f)) 还有可以做严格的类型检查的 min() 和 max() 宏,如果你需要可以使用它们。你可以 自己看看那个头文件里还定义了什么你可以拿来用的东西,如果有定义的话,你就不应 diff --git a/MAINTAINERS b/MAINTAINERS index bd5847e802defb11887f45dd17412e1e98d054e8..bfebe689ea7eb93aeb533ee8e1d6376c7d5ce9e2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4970,6 +4970,25 @@ F: include/linux/dma-buf* F: include/linux/reservation.h F: include/linux/*fence.h F: Documentation/driver-api/dma-buf.rst +K: dma_(buf|fence|resv) +T: git git://anongit.freedesktop.org/drm/drm-misc + +DMA-BUF HEAPS FRAMEWORK +M: Sumit Semwal +R: Andrew F. Davis +R: Benjamin Gaignard +R: Liam Mark +R: Laura Abbott +R: Brian Starkey +R: John Stultz +S: Maintained +L: linux-media@vger.kernel.org +L: dri-devel@lists.freedesktop.org +L: linaro-mm-sig@lists.linaro.org (moderated for non-subscribers) +F: include/uapi/linux/dma-heap.h +F: include/linux/dma-heap.h +F: drivers/dma-buf/dma-heap.c +F: drivers/dma-buf/heaps/* T: git git://anongit.freedesktop.org/drm/drm-misc DMA GENERIC OFFLOAD ENGINE SUBSYSTEM @@ -5177,6 +5196,12 @@ T: git git://anongit.freedesktop.org/drm/drm-misc S: Maintained F: drivers/gpu/drm/bochs/ +DRM DRIVER FOR BOE HIMAX8279D PANELS +M: Jerry Han +S: Maintained +F: drivers/gpu/drm/panel/panel-boe-himax8279d.c +F: Documentation/devicetree/bindings/display/panel/boe,himax8279d.txt + DRM DRIVER FOR FARADAY TVE200 TV ENCODER M: Linus Walleij T: git git://anongit.freedesktop.org/drm/drm-misc @@ -5404,7 +5429,6 @@ F: include/linux/vga* DRM DRIVERS AND MISC GPU PATCHES M: Maarten Lankhorst M: Maxime Ripard -M: Sean Paul W: https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html S: Maintained T: git git://anongit.freedesktop.org/drm/drm-misc @@ -12393,7 +12417,7 @@ L: linux-unionfs@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git S: Supported F: fs/overlayfs/ -F: Documentation/filesystems/overlayfs.txt +F: Documentation/filesystems/overlayfs.rst P54 WIRELESS DRIVER M: Christian Lamparter @@ -16314,12 +16338,10 @@ F: drivers/media/radio/radio-raremono.c THERMAL M: Zhang Rui -M: Eduardo Valentin -R: Daniel Lezcano +M: Daniel Lezcano R: Amit Kucheria L: linux-pm@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git -T: git git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git Q: https://patchwork.kernel.org/project/linux-pm/list/ S: Supported F: drivers/thermal/ diff --git a/Makefile b/Makefile index 73e3c280292770ccd4b5bb1be95c2fca391bfba8..f900c23b82914f9ff8717550a4687716f4241d8a 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ VERSION = 5 PATCHLEVEL = 5 SUBLEVEL = 0 -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2 NAME = Kleptomaniac Octopus # *DOCUMENTATION* diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c index dc05a63516f5b5a3c695578cd864b2f3886910ba..27ea64b1fa3321c3d86f2c25b419e1fd1882b269 100644 --- a/arch/arc/kernel/unwind.c +++ b/arch/arc/kernel/unwind.c @@ -42,10 +42,10 @@ do { \ #define EXTRA_INFO(f) { \ BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) \ - % FIELD_SIZEOF(struct unwind_frame_info, f)) \ + % sizeof_field(struct unwind_frame_info, f)) \ + offsetof(struct unwind_frame_info, f) \ - / FIELD_SIZEOF(struct unwind_frame_info, f), \ - FIELD_SIZEOF(struct unwind_frame_info, f) \ + / sizeof_field(struct unwind_frame_info, f), \ + sizeof_field(struct unwind_frame_info, f) \ } #define PTREGS_INFO(f) EXTRA_INFO(regs.f) diff --git a/arch/arm/crypto/curve25519-glue.c b/arch/arm/crypto/curve25519-glue.c index f3f42cf3b8937e3e28fd01a6e2ab4890335f0dd3..776ae07e04697527754a463647e34ed882faa1ee 100644 --- a/arch/arm/crypto/curve25519-glue.c +++ b/arch/arm/crypto/curve25519-glue.c @@ -38,6 +38,13 @@ void curve25519_arch(u8 out[CURVE25519_KEY_SIZE], } EXPORT_SYMBOL(curve25519_arch); +void curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE], + const u8 secret[CURVE25519_KEY_SIZE]) +{ + return curve25519_arch(pub, secret, curve25519_base_point); +} +EXPORT_SYMBOL(curve25519_base_arch); + static int curve25519_set_secret(struct crypto_kpp *tfm, const void *buf, unsigned int len) { diff --git a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c index ba8f82a29a816a0bc7b5a6793403ccfa09f5c7d9..e794b2d53adfcf9d9c0a94d93f7e3109c725ae40 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c +++ b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c @@ -44,13 +44,6 @@ static struct cvmx_bootmem_desc *cvmx_bootmem_desc; /* See header file for descriptions of functions */ -/** - * This macro returns the size of a member of a structure. - * Logically it is the same as "sizeof(s::field)" in C++, but - * C lacks the "::" operator. - */ -#define SIZEOF_FIELD(s, field) sizeof(((s *)NULL)->field) - /** * This macro returns a member of the * cvmx_bootmem_named_block_desc_t structure. These members can't @@ -65,7 +58,7 @@ static struct cvmx_bootmem_desc *cvmx_bootmem_desc; #define CVMX_BOOTMEM_NAMED_GET_FIELD(addr, field) \ __cvmx_bootmem_desc_get(addr, \ offsetof(struct cvmx_bootmem_named_block_desc, field), \ - SIZEOF_FIELD(struct cvmx_bootmem_named_block_desc, field)) + sizeof_field(struct cvmx_bootmem_named_block_desc, field)) /** * This function is the implementation of the get macros defined diff --git a/arch/nios2/mm/ioremap.c b/arch/nios2/mm/ioremap.c index b56af759dcdfcc2b8c3d19ff7bfed99bda0ddde2..819bdfcc2e714d64ba1657de319dcc1ba6b6a5da 100644 --- a/arch/nios2/mm/ioremap.c +++ b/arch/nios2/mm/ioremap.c @@ -138,6 +138,14 @@ void __iomem *ioremap(unsigned long phys_addr, unsigned long size) return NULL; } + /* + * Map uncached objects in the low part of address space to + * CONFIG_NIOS2_IO_REGION_BASE + */ + if (IS_MAPPABLE_UNCACHEABLE(phys_addr) && + IS_MAPPABLE_UNCACHEABLE(last_addr)) + return (void __iomem *)(CONFIG_NIOS2_IO_REGION_BASE + phys_addr); + /* Mappings have to be page-aligned */ offset = phys_addr & ~PAGE_MASK; phys_addr &= PAGE_MASK; diff --git a/arch/powerpc/net/bpf_jit32.h b/arch/powerpc/net/bpf_jit32.h index 6e5a2a4faeab0d9fe4b49851ecee60d6e7baada4..4ec2a9f14f845cebe96449faeb32914abcf55eae 100644 --- a/arch/powerpc/net/bpf_jit32.h +++ b/arch/powerpc/net/bpf_jit32.h @@ -97,12 +97,12 @@ DECLARE_LOAD_FUNC(sk_load_byte_msh); #ifdef CONFIG_SMP #ifdef CONFIG_PPC64 #define PPC_BPF_LOAD_CPU(r) \ - do { BUILD_BUG_ON(FIELD_SIZEOF(struct paca_struct, paca_index) != 2); \ + do { BUILD_BUG_ON(sizeof_field(struct paca_struct, paca_index) != 2); \ PPC_LHZ_OFFS(r, 13, offsetof(struct paca_struct, paca_index)); \ } while (0) #else #define PPC_BPF_LOAD_CPU(r) \ - do { BUILD_BUG_ON(FIELD_SIZEOF(struct task_struct, cpu) != 4); \ + do { BUILD_BUG_ON(sizeof_field(struct task_struct, cpu) != 4); \ PPC_LHZ_OFFS(r, 2, offsetof(struct task_struct, cpu)); \ } while(0) #endif diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c index d57b46e0dd6044d1a918e8a518f4fead29ad5c0e..0acc9d5fb19e9a638c8bdc4f6f699d5b62689e7d 100644 --- a/arch/powerpc/net/bpf_jit_comp.c +++ b/arch/powerpc/net/bpf_jit_comp.c @@ -321,7 +321,7 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, ctx->seen |= SEEN_XREG | SEEN_MEM | (1<<(K & 0xf)); break; case BPF_LD | BPF_W | BPF_LEN: /* A = skb->len; */ - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4); + BUILD_BUG_ON(sizeof_field(struct sk_buff, len) != 4); PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff, len)); break; case BPF_LDX | BPF_W | BPF_ABS: /* A = *((u32 *)(seccomp_data + K)); */ @@ -333,16 +333,16 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, /*** Ancillary info loads ***/ case BPF_ANC | SKF_AD_PROTOCOL: /* A = ntohs(skb->protocol); */ - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, + BUILD_BUG_ON(sizeof_field(struct sk_buff, protocol) != 2); PPC_NTOHS_OFFS(r_A, r_skb, offsetof(struct sk_buff, protocol)); break; case BPF_ANC | SKF_AD_IFINDEX: case BPF_ANC | SKF_AD_HATYPE: - BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, + BUILD_BUG_ON(sizeof_field(struct net_device, ifindex) != 4); - BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, + BUILD_BUG_ON(sizeof_field(struct net_device, type) != 2); PPC_LL_OFFS(r_scratch1, r_skb, offsetof(struct sk_buff, dev)); @@ -365,17 +365,17 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, break; case BPF_ANC | SKF_AD_MARK: - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4); + BUILD_BUG_ON(sizeof_field(struct sk_buff, mark) != 4); PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff, mark)); break; case BPF_ANC | SKF_AD_RXHASH: - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4); + BUILD_BUG_ON(sizeof_field(struct sk_buff, hash) != 4); PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff, hash)); break; case BPF_ANC | SKF_AD_VLAN_TAG: - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_tci) != 2); + BUILD_BUG_ON(sizeof_field(struct sk_buff, vlan_tci) != 2); PPC_LHZ_OFFS(r_A, r_skb, offsetof(struct sk_buff, vlan_tci)); @@ -388,7 +388,7 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, PPC_ANDI(r_A, r_A, 1); break; case BPF_ANC | SKF_AD_QUEUE: - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, + BUILD_BUG_ON(sizeof_field(struct sk_buff, queue_mapping) != 2); PPC_LHZ_OFFS(r_A, r_skb, offsetof(struct sk_buff, queue_mapping)); diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs index 634759ac8c717a8d0c2b5774ceb9ec9ce53da86b..d325b67d00dfcf70c4f3cf89e68e3964eec62a06 100644 --- a/arch/riscv/Kconfig.socs +++ b/arch/riscv/Kconfig.socs @@ -2,8 +2,8 @@ menu "SoC selection" config SOC_SIFIVE bool "SiFive SoCs" - select SERIAL_SIFIVE - select SERIAL_SIFIVE_CONSOLE + select SERIAL_SIFIVE if TTY + select SERIAL_SIFIVE_CONSOLE if TTY select CLK_SIFIVE select CLK_SIFIVE_FU540_PRCI select SIFIVE_PLIC diff --git a/arch/riscv/boot/Makefile b/arch/riscv/boot/Makefile index a474f98ce4fae8d49e65dec1f8da26d72c70745b..36db8145f9f46013c2b1b31e3c7e9f75e4dce349 100644 --- a/arch/riscv/boot/Makefile +++ b/arch/riscv/boot/Makefile @@ -24,7 +24,7 @@ $(obj)/Image: vmlinux FORCE $(obj)/Image.gz: $(obj)/Image FORCE $(call if_changed,gzip) -loader.o: $(src)/loader.S $(obj)/Image +$(obj)/loader.o: $(src)/loader.S $(obj)/Image $(obj)/loader: $(obj)/loader.o $(obj)/Image $(obj)/loader.lds FORCE $(Q)$(LD) -T $(obj)/loader.lds -o $@ $(obj)/loader.o diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index d4051e88e6250ddbb621b18c0dc6f8356411ffd8..bc88841d335d20816596d354060341d2377c4df8 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -124,6 +124,7 @@ config S390 select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL_RELATIVE select HAVE_ARCH_KASAN + select HAVE_ARCH_KASAN_VMALLOC select CPU_NO_EFFICIENT_FFS if !HAVE_MARCH_Z9_109_FEATURES select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_SOFT_DIRTY diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 6dc6c4fbc8e2b1a59796afb96bff120d4c0f8a21..69289e99cabdcee175a4a176881a128f49e3a574 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -27,7 +27,6 @@ #define MACHINE_FLAG_DIAG9C BIT(3) #define MACHINE_FLAG_ESOP BIT(4) #define MACHINE_FLAG_IDTE BIT(5) -#define MACHINE_FLAG_DIAG44 BIT(6) #define MACHINE_FLAG_EDAT1 BIT(7) #define MACHINE_FLAG_EDAT2 BIT(8) #define MACHINE_FLAG_TOPOLOGY BIT(10) @@ -94,7 +93,6 @@ extern unsigned long __swsusp_reset_dma; #define MACHINE_HAS_DIAG9C (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG9C) #define MACHINE_HAS_ESOP (S390_lowcore.machine_flags & MACHINE_FLAG_ESOP) #define MACHINE_HAS_IDTE (S390_lowcore.machine_flags & MACHINE_FLAG_IDTE) -#define MACHINE_HAS_DIAG44 (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG44) #define MACHINE_HAS_EDAT1 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT1) #define MACHINE_HAS_EDAT2 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT2) #define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY) diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h index ef3c00b049ab45b4cd050d97a30e8210b63f7676..4093a2856929a0a420b82c819116fc6d4da6e90b 100644 --- a/arch/s390/include/asm/uv.h +++ b/arch/s390/include/asm/uv.h @@ -86,7 +86,7 @@ static inline int share(unsigned long addr, u16 cmd) }; if (!is_prot_virt_guest()) - return -ENOTSUPP; + return -EOPNOTSUPP; /* * Sharing is page wise, if we encounter addresses that are * not page aligned, we assume something went wrong. If diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index db32a55daaec605a7b0042f7c4eb126996c9ccba..cd241ee66eff4feb6d39842ac9972136394e23c1 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -204,21 +204,6 @@ static __init void detect_diag9c(void) S390_lowcore.machine_flags |= MACHINE_FLAG_DIAG9C; } -static __init void detect_diag44(void) -{ - int rc; - - diag_stat_inc(DIAG_STAT_X044); - asm volatile( - " diag 0,0,0x44\n" - "0: la %0,0\n" - "1:\n" - EX_TABLE(0b,1b) - : "=d" (rc) : "0" (-EOPNOTSUPP) : "cc"); - if (!rc) - S390_lowcore.machine_flags |= MACHINE_FLAG_DIAG44; -} - static __init void detect_machine_facilities(void) { if (test_facility(8)) { @@ -331,7 +316,6 @@ void __init startup_init(void) setup_arch_string(); setup_boot_command_line(); detect_diag9c(); - detect_diag44(); detect_machine_facilities(); save_vector_registers(); setup_topology(); diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index c07fdcd737266de36e821eae1d0fcc0bb41abf27..77d93c534284d0bba7b1a02f99e743d9d5ff8292 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c @@ -1303,18 +1303,28 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all) */ if (flush_all && done) break; - - /* If an event overflow happened, discard samples by - * processing any remaining sample-data-blocks. - */ - if (event_overflow) - flush_all = 1; } /* Account sample overflows in the event hardware structure */ if (sampl_overflow) OVERFLOW_REG(hwc) = DIV_ROUND_UP(OVERFLOW_REG(hwc) + sampl_overflow, 1 + num_sdb); + + /* Perf_event_overflow() and perf_event_account_interrupt() limit + * the interrupt rate to an upper limit. Roughly 1000 samples per + * task tick. + * Hitting this limit results in a large number + * of throttled REF_REPORT_THROTTLE entries and the samples + * are dropped. + * Slightly increase the interval to avoid hitting this limit. + */ + if (event_overflow) { + SAMPL_RATE(hwc) += DIV_ROUND_UP(SAMPL_RATE(hwc), 10); + debug_sprintf_event(sfdbg, 1, "%s: rate adjustment %ld\n", + __func__, + DIV_ROUND_UP(SAMPL_RATE(hwc), 10)); + } + if (sampl_overflow || event_overflow) debug_sprintf_event(sfdbg, 4, "%s: " "overflows: sample %llu event %llu" diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 2794cad9312e37cda034425386edf7356f2e6d97..a08bd2522dd95a08a27de50850e60546fedb31e5 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -413,14 +413,11 @@ EXPORT_SYMBOL(arch_vcpu_is_preempted); void smp_yield_cpu(int cpu) { - if (MACHINE_HAS_DIAG9C) { - diag_stat_inc_norecursion(DIAG_STAT_X09C); - asm volatile("diag %0,0,0x9c" - : : "d" (pcpu_devices[cpu].address)); - } else if (MACHINE_HAS_DIAG44 && !smp_cpu_mtid) { - diag_stat_inc_norecursion(DIAG_STAT_X044); - asm volatile("diag 0,0,0x44"); - } + if (!MACHINE_HAS_DIAG9C) + return; + diag_stat_inc_norecursion(DIAG_STAT_X09C); + asm volatile("diag %0,0,0x9c" + : : "d" (pcpu_devices[cpu].address)); } /* diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c index ce1e4bbe53aaf2d447f4aa82a4ba1c55ffdc13e6..9b2dab5a69f995055c9067f37a5688d65f1b4642 100644 --- a/arch/s390/lib/spinlock.c +++ b/arch/s390/lib/spinlock.c @@ -242,7 +242,6 @@ static inline void arch_spin_lock_classic(arch_spinlock_t *lp) void arch_spin_lock_wait(arch_spinlock_t *lp) { - /* Use classic spinlocks + niai if the steal time is >= 10% */ if (test_cpu_flag(CIF_DEDICATED_CPU)) arch_spin_lock_queued(lp); else diff --git a/arch/s390/lib/test_unwind.c b/arch/s390/lib/test_unwind.c index bda7ac0ddd29710d62bb23911408cc4e64adc329..32b7a30b2485d53f9dede2756ddfb7ce105bc4da 100644 --- a/arch/s390/lib/test_unwind.c +++ b/arch/s390/lib/test_unwind.c @@ -238,7 +238,7 @@ static int test_unwind_irq(struct unwindme *u) { preempt_disable(); if (register_external_irq(EXT_IRQ_CLK_COMP, unwindme_irq_handler)) { - pr_info("Couldn't reqister external interrupt handler"); + pr_info("Couldn't register external interrupt handler"); return -1; } u->task = current; diff --git a/arch/s390/mm/kasan_init.c b/arch/s390/mm/kasan_init.c index 460f2557294021f0f7bd49e1f31bcfbaed007f31..06345616a6466a921c9476ca6ecf6a0710a3638a 100644 --- a/arch/s390/mm/kasan_init.c +++ b/arch/s390/mm/kasan_init.c @@ -82,7 +82,8 @@ static pte_t * __init kasan_early_pte_alloc(void) enum populate_mode { POPULATE_ONE2ONE, POPULATE_MAP, - POPULATE_ZERO_SHADOW + POPULATE_ZERO_SHADOW, + POPULATE_SHALLOW }; static void __init kasan_early_vmemmap_populate(unsigned long address, unsigned long end, @@ -116,6 +117,12 @@ static void __init kasan_early_vmemmap_populate(unsigned long address, pgd_populate(&init_mm, pg_dir, p4_dir); } + if (IS_ENABLED(CONFIG_KASAN_S390_4_LEVEL_PAGING) && + mode == POPULATE_SHALLOW) { + address = (address + P4D_SIZE) & P4D_MASK; + continue; + } + p4_dir = p4d_offset(pg_dir, address); if (p4d_none(*p4_dir)) { if (mode == POPULATE_ZERO_SHADOW && @@ -130,6 +137,12 @@ static void __init kasan_early_vmemmap_populate(unsigned long address, p4d_populate(&init_mm, p4_dir, pu_dir); } + if (!IS_ENABLED(CONFIG_KASAN_S390_4_LEVEL_PAGING) && + mode == POPULATE_SHALLOW) { + address = (address + PUD_SIZE) & PUD_MASK; + continue; + } + pu_dir = pud_offset(p4_dir, address); if (pud_none(*pu_dir)) { if (mode == POPULATE_ZERO_SHADOW && @@ -195,6 +208,9 @@ static void __init kasan_early_vmemmap_populate(unsigned long address, page = kasan_early_shadow_page; pte_val(*pt_dir) = __pa(page) | pgt_prot_zero; break; + case POPULATE_SHALLOW: + /* should never happen */ + break; } } address += PAGE_SIZE; @@ -313,22 +329,50 @@ void __init kasan_early_init(void) init_mm.pgd = early_pg_dir; /* * Current memory layout: - * +- 0 -------------+ +- shadow start -+ - * | 1:1 ram mapping | /| 1/8 ram | - * +- end of ram ----+ / +----------------+ - * | ... gap ... |/ | kasan | - * +- shadow start --+ | zero | - * | 1/8 addr space | | page | - * +- shadow end -+ | mapping | - * | ... gap ... |\ | (untracked) | - * +- modules vaddr -+ \ +----------------+ - * | 2Gb | \| unmapped | allocated per module - * +-----------------+ +- shadow end ---+ + * +- 0 -------------+ +- shadow start -+ + * | 1:1 ram mapping | /| 1/8 ram | + * | | / | | + * +- end of ram ----+ / +----------------+ + * | ... gap ... | / | | + * | |/ | kasan | + * +- shadow start --+ | zero | + * | 1/8 addr space | | page | + * +- shadow end -+ | mapping | + * | ... gap ... |\ | (untracked) | + * +- vmalloc area -+ \ | | + * | vmalloc_size | \ | | + * +- modules vaddr -+ \ +----------------+ + * | 2Gb | \| unmapped | allocated per module + * +-----------------+ +- shadow end ---+ + * + * Current memory layout (KASAN_VMALLOC): + * +- 0 -------------+ +- shadow start -+ + * | 1:1 ram mapping | /| 1/8 ram | + * | | / | | + * +- end of ram ----+ / +----------------+ + * | ... gap ... | / | kasan | + * | |/ | zero | + * +- shadow start --+ | page | + * | 1/8 addr space | | mapping | + * +- shadow end -+ | (untracked) | + * | ... gap ... |\ | | + * +- vmalloc area -+ \ +- vmalloc area -+ + * | vmalloc_size | \ |shallow populate| + * +- modules vaddr -+ \ +- modules area -+ + * | 2Gb | \|shallow populate| + * +-----------------+ +- shadow end ---+ */ /* populate kasan shadow (for identity mapping and zero page mapping) */ kasan_early_vmemmap_populate(__sha(0), __sha(memsize), POPULATE_MAP); if (IS_ENABLED(CONFIG_MODULES)) untracked_mem_end = vmax - MODULES_LEN; + if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) { + untracked_mem_end = vmax - vmalloc_size - MODULES_LEN; + /* shallowly populate kasan shadow for vmalloc and modules */ + kasan_early_vmemmap_populate(__sha(untracked_mem_end), + __sha(vmax), POPULATE_SHALLOW); + } + /* populate kasan shadow for untracked memory */ kasan_early_vmemmap_populate(__sha(max_physmem_end), __sha(untracked_mem_end), POPULATE_ZERO_SHADOW); diff --git a/arch/sh/drivers/platform_early.c b/arch/sh/drivers/platform_early.c index f6d148451dfc724eb8f2fa5bf4916d8d459136d8..f3dc3f25b3ff08c2af8bd2a1db845fd2c6308ded 100644 --- a/arch/sh/drivers/platform_early.c +++ b/arch/sh/drivers/platform_early.c @@ -325,9 +325,9 @@ int __init sh_early_platform_driver_probe(char *class_str, } /** - * sh_early_platform_cleanup - clean up early platform code + * early_platform_cleanup - clean up early platform code */ -static int __init sh_early_platform_cleanup(void) +void __init early_platform_cleanup(void) { struct platform_device *pd, *pd2; @@ -337,11 +337,4 @@ static int __init sh_early_platform_cleanup(void) list_del(&pd->dev.devres_head); memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head)); } - - return 0; } -/* - * This must happen once after all early devices are probed but before probing - * real platform devices. - */ -subsys_initcall(sh_early_platform_cleanup); diff --git a/arch/sh/kernel/kgdb.c b/arch/sh/kernel/kgdb.c index 6d61f8cf4c131dac3b48b33acc4635f85814a32e..0d5f3c9d52f30edbcbf51141b8de16a294236903 100644 --- a/arch/sh/kernel/kgdb.c +++ b/arch/sh/kernel/kgdb.c @@ -266,6 +266,7 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, ptr = &remcomInBuffer[1]; if (kgdb_hex2long(&ptr, &addr)) linux_regs->pc = addr; + /* fallthrough */ case 'D': case 'k': atomic_set(&kgdb_cpu_doing_single_step, -1); diff --git a/arch/sparc/net/bpf_jit_comp_32.c b/arch/sparc/net/bpf_jit_comp_32.c index 84cc8f7f83e9934e1aae5b4d38d3ce099c38e32a..c8eabb973b8688648dff42f70bd6f05b43a35103 100644 --- a/arch/sparc/net/bpf_jit_comp_32.c +++ b/arch/sparc/net/bpf_jit_comp_32.c @@ -180,19 +180,19 @@ do { \ #define emit_loadptr(BASE, STRUCT, FIELD, DEST) \ do { unsigned int _off = offsetof(STRUCT, FIELD); \ - BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(void *)); \ + BUILD_BUG_ON(sizeof_field(STRUCT, FIELD) != sizeof(void *)); \ *prog++ = LDPTRI | RS1(BASE) | S13(_off) | RD(DEST); \ } while (0) #define emit_load32(BASE, STRUCT, FIELD, DEST) \ do { unsigned int _off = offsetof(STRUCT, FIELD); \ - BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u32)); \ + BUILD_BUG_ON(sizeof_field(STRUCT, FIELD) != sizeof(u32)); \ *prog++ = LD32I | RS1(BASE) | S13(_off) | RD(DEST); \ } while (0) #define emit_load16(BASE, STRUCT, FIELD, DEST) \ do { unsigned int _off = offsetof(STRUCT, FIELD); \ - BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u16)); \ + BUILD_BUG_ON(sizeof_field(STRUCT, FIELD) != sizeof(u16)); \ *prog++ = LD16I | RS1(BASE) | S13(_off) | RD(DEST); \ } while (0) @@ -202,7 +202,7 @@ do { unsigned int _off = offsetof(STRUCT, FIELD); \ } while (0) #define emit_load8(BASE, STRUCT, FIELD, DEST) \ -do { BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u8)); \ +do { BUILD_BUG_ON(sizeof_field(STRUCT, FIELD) != sizeof(u8)); \ __emit_load8(BASE, STRUCT, FIELD, DEST); \ } while (0) diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 319be936c348ef1f0c09ed99d243e4d04efb8005..fa31470bbf24aa72582b37d56879f16081fe6eaa 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -259,7 +259,7 @@ static void __init setup_xstate_features(void) xmm_space); xstate_offsets[XFEATURE_SSE] = xstate_sizes[XFEATURE_FP]; - xstate_sizes[XFEATURE_SSE] = FIELD_SIZEOF(struct fxregs_state, + xstate_sizes[XFEATURE_SSE] = sizeof_field(struct fxregs_state, xmm_space); for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) { diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 060a361d9d11b09303d901cbfa7dff896d5af1d2..024c3053dbbab673d4d23f7e78726022b03620b5 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -1042,20 +1042,6 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent, if (unlikely(atomic_read(¤t->tracing_graph_pause))) return; - /* - * If the return location is actually pointing directly to - * the start of a direct trampoline (if we trace the trampoline - * it will still be offset by MCOUNT_INSN_SIZE), then the - * return address is actually off by one word, and we - * need to adjust for that. - */ - if (ftrace_direct_func_count) { - if (ftrace_find_direct_func(self_addr + MCOUNT_INSN_SIZE)) { - self_addr = *parent; - parent++; - } - } - /* * Protect against fault, even if it shouldn't * happen. This tool is too much intrusive to diff --git a/arch/x86/platform/intel-mid/device_libs/platform_tc35876x.c b/arch/x86/platform/intel-mid/device_libs/platform_tc35876x.c index 44d1f884c3d3df4f7eadbbfa687b8873a103f17e..139738bbdd36e50ef660ae247aceb2c7a897b904 100644 --- a/arch/x86/platform/intel-mid/device_libs/platform_tc35876x.c +++ b/arch/x86/platform/intel-mid/device_libs/platform_tc35876x.c @@ -6,21 +6,31 @@ * Author: Sathyanarayanan Kuppuswamy */ -#include -#include +#include #include +static struct gpiod_lookup_table tc35876x_gpio_table = { + .dev_id = "i2c_disp_brig", + .table = { + GPIO_LOOKUP("0000:00:0c.0", -1, "bridge-reset", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("0000:00:0c.0", -1, "bl-en", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("0000:00:0c.0", -1, "vadd", GPIO_ACTIVE_HIGH), + { }, + }, +}; + /*tc35876x DSI_LVDS bridge chip and panel platform data*/ static void *tc35876x_platform_data(void *data) { - static struct tc35876x_platform_data pdata; + struct gpiod_lookup_table *table = &tc35876x_gpio_table; + struct gpiod_lookup *lookup = table->table; - /* gpio pins set to -1 will not be used by the driver */ - pdata.gpio_bridge_reset = get_gpio_by_name("LCMB_RXEN"); - pdata.gpio_panel_bl_en = get_gpio_by_name("6S6P_BL_EN"); - pdata.gpio_panel_vadd = get_gpio_by_name("EN_VREG_LCD_V3P3"); + lookup[0].chip_hwnum = get_gpio_by_name("LCMB_RXEN"); + lookup[1].chip_hwnum = get_gpio_by_name("6S6P_BL_EN"); + lookup[2].chip_hwnum = get_gpio_by_name("EN_VREG_LCD_V3P3"); + gpiod_add_lookup_table(table); - return &pdata; + return NULL; } static const struct devs_id tc35876x_dev_id __initconst = { diff --git a/block/bio.c b/block/bio.c index 9d54aa37ce6c7074be56e99a14bc60d0bc058edd..a5d75f6bf4c7eedc96454bade72dbc9fe88af74d 100644 --- a/block/bio.c +++ b/block/bio.c @@ -754,10 +754,12 @@ bool __bio_try_merge_page(struct bio *bio, struct page *page, if (WARN_ON_ONCE(bio_flagged(bio, BIO_CLONED))) return false; - if (bio->bi_vcnt > 0 && !bio_full(bio, len)) { + if (bio->bi_vcnt > 0) { struct bio_vec *bv = &bio->bi_io_vec[bio->bi_vcnt - 1]; if (page_is_mergeable(bv, page, len, off, same_page)) { + if (bio->bi_iter.bi_size > UINT_MAX - len) + return false; bv->bv_len += len; bio->bi_iter.bi_size += len; return true; diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 708dea92dac8c6037dd1716e3d1bccadf346abac..a229b94d53908aa35ff3f2d8d1fa3532df4c2899 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -1061,26 +1061,6 @@ err_unlock: return PTR_ERR(blkg); } -/** - * blkcg_drain_queue - drain blkcg part of request_queue - * @q: request_queue to drain - * - * Called from blk_drain_queue(). Responsible for draining blkcg part. - */ -void blkcg_drain_queue(struct request_queue *q) -{ - lockdep_assert_held(&q->queue_lock); - - /* - * @q could be exiting and already have destroyed all blkgs as - * indicated by NULL root_blkg. If so, don't confuse policies. - */ - if (!q->root_blkg) - return; - - blk_throtl_drain(q); -} - /** * blkcg_exit_queue - exit and release blkcg part of request_queue * @q: request_queue being released diff --git a/block/blk-core.c b/block/blk-core.c index a1e228752083f411f114cd990fa4cad546e3ca45..e0a094fddee5f3e16b660c8cab189987663cb7f7 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1310,7 +1310,7 @@ EXPORT_SYMBOL_GPL(blk_rq_err_bytes); void blk_account_io_completion(struct request *req, unsigned int bytes) { - if (blk_do_io_stat(req)) { + if (req->part && blk_do_io_stat(req)) { const int sgrp = op_stat_group(req_op(req)); struct hd_struct *part; @@ -1328,7 +1328,8 @@ void blk_account_io_done(struct request *req, u64 now) * normal IO on queueing nor completion. Accounting the * containing request is enough. */ - if (blk_do_io_stat(req) && !(req->rq_flags & RQF_FLUSH_SEQ)) { + if (req->part && blk_do_io_stat(req) && + !(req->rq_flags & RQF_FLUSH_SEQ)) { const int sgrp = op_stat_group(req_op(req)); struct hd_struct *part; @@ -1792,9 +1793,9 @@ int __init blk_dev_init(void) { BUILD_BUG_ON(REQ_OP_LAST >= (1 << REQ_OP_BITS)); BUILD_BUG_ON(REQ_OP_BITS + REQ_FLAG_BITS > 8 * - FIELD_SIZEOF(struct request, cmd_flags)); + sizeof_field(struct request, cmd_flags)); BUILD_BUG_ON(REQ_OP_BITS + REQ_FLAG_BITS > 8 * - FIELD_SIZEOF(struct bio, bi_opf)); + sizeof_field(struct bio, bi_opf)); /* used for unplugging and affects IO latency/throughput - HIGHPRI */ kblockd_workqueue = alloc_workqueue("kblockd", diff --git a/crypto/adiantum.c b/crypto/adiantum.c index aded260922684061047a2bceac0aaedc0d5ee8d8..9dc53cf9b1f17fb8fbefe6cb647f8b57f76d4c44 100644 --- a/crypto/adiantum.c +++ b/crypto/adiantum.c @@ -436,10 +436,10 @@ static int adiantum_init_tfm(struct crypto_skcipher *tfm) BUILD_BUG_ON(offsetofend(struct adiantum_request_ctx, u) != sizeof(struct adiantum_request_ctx)); - subreq_size = max(FIELD_SIZEOF(struct adiantum_request_ctx, + subreq_size = max(sizeof_field(struct adiantum_request_ctx, u.hash_desc) + crypto_shash_descsize(hash), - FIELD_SIZEOF(struct adiantum_request_ctx, + sizeof_field(struct adiantum_request_ctx, u.streamcipher_req) + crypto_skcipher_reqsize(streamcipher)); diff --git a/crypto/essiv.c b/crypto/essiv.c index 808f2b3621068f6db28e7c3083f3176aeb111c09..495a2d1e1460eaaa3bc0e8c45be9660ba8cebd6f 100644 --- a/crypto/essiv.c +++ b/crypto/essiv.c @@ -347,7 +347,7 @@ static int essiv_aead_init_tfm(struct crypto_aead *tfm) if (IS_ERR(aead)) return PTR_ERR(aead); - subreq_size = FIELD_SIZEOF(struct essiv_aead_request_ctx, aead_req) + + subreq_size = sizeof_field(struct essiv_aead_request_ctx, aead_req) + crypto_aead_reqsize(aead); tctx->ivoffset = offsetof(struct essiv_aead_request_ctx, aead_req) + diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 08bb9f2f2d2310367c9fde629aaa62e8955bf0e9..5e4a8860a9c0c57e5cdcf64b523ec6d9d40baaf7 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -1314,9 +1314,19 @@ static void acpi_dev_pm_detach(struct device *dev, bool power_off) */ int acpi_dev_pm_attach(struct device *dev, bool power_on) { + /* + * Skip devices whose ACPI companions match the device IDs below, + * because they require special power management handling incompatible + * with the generic ACPI PM domain. + */ + static const struct acpi_device_id special_pm_ids[] = { + {"PNP0C0B", }, /* Generic ACPI fan */ + {"INT3404", }, /* Fan */ + {} + }; struct acpi_device *adev = ACPI_COMPANION(dev); - if (!adev) + if (!adev || !acpi_match_device_ids(adev, special_pm_ids)) return 0; /* diff --git a/drivers/android/binder.c b/drivers/android/binder.c index e9bc9fcc7ea5cb8213fdf73bc855b86f2c947341..b2dad43dbf82962b76c47c0a87d44bd15541e1de 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3310,7 +3310,7 @@ static void binder_transaction(struct binder_proc *proc, binder_size_t parent_offset; struct binder_fd_array_object *fda = to_binder_fd_array_object(hdr); - size_t num_valid = (buffer_offset - off_start_offset) * + size_t num_valid = (buffer_offset - off_start_offset) / sizeof(binder_size_t); struct binder_buffer_object *parent = binder_validate_ptr(target_proc, t->buffer, @@ -3384,7 +3384,7 @@ static void binder_transaction(struct binder_proc *proc, t->buffer->user_data + sg_buf_offset; sg_buf_offset += ALIGN(bp->length, sizeof(u64)); - num_valid = (buffer_offset - off_start_offset) * + num_valid = (buffer_offset - off_start_offset) / sizeof(binder_size_t); ret = binder_fixup_parent(t, thread, bp, off_start_offset, diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c index 4074886b7bc85b9dc9ab438081b82bba134e953c..2002291ab338829ceafe909b3c72cd46bb37ce18 100644 --- a/drivers/auxdisplay/cfag12864bfb.c +++ b/drivers/auxdisplay/cfag12864bfb.c @@ -57,7 +57,7 @@ static int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma) return vm_map_pages_zero(vma, &pages, 1); } -static struct fb_ops cfag12864bfb_ops = { +static const struct fb_ops cfag12864bfb_ops = { .owner = THIS_MODULE, .fb_read = fb_sys_read, .fb_write = fb_sys_write, diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c index a2fcde582e2a1614d21f0edf21faee4870668b5a..d951d54b26f5239b47d36f2ec6b95a71e54310d7 100644 --- a/drivers/auxdisplay/ht16k33.c +++ b/drivers/auxdisplay/ht16k33.c @@ -228,7 +228,7 @@ static int ht16k33_mmap(struct fb_info *info, struct vm_area_struct *vma) return vm_map_pages_zero(vma, &pages, 1); } -static struct fb_ops ht16k33_fb_ops = { +static const struct fb_ops ht16k33_fb_ops = { .owner = THIS_MODULE, .fb_read = fb_sys_read, .fb_write = fb_sys_write, diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index 30d0523014e0d49e0ac6e16880a7bb08ecfbef27..6cdbf15312387f93455bafb2b816e691def1cb94 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -359,7 +359,7 @@ static int handle_remove(const char *nodename, struct device *dev) * If configured, or requested by the commandline, devtmpfs will be * auto-mounted after the kernel mounted the root filesystem. */ -int devtmpfs_mount(const char *mntdir) +int devtmpfs_mount(void) { int err; @@ -369,7 +369,7 @@ int devtmpfs_mount(const char *mntdir) if (!thread) return 0; - err = ksys_mount("devtmpfs", mntdir, "devtmpfs", MS_SILENT, NULL); + err = do_mount("devtmpfs", "dev", "devtmpfs", MS_SILENT, NULL); if (err) printk(KERN_INFO "devtmpfs: error mounting %i\n", err); else @@ -394,7 +394,7 @@ static int devtmpfsd(void *p) *err = ksys_unshare(CLONE_NEWNS); if (*err) goto out; - *err = ksys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, NULL); + *err = do_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, NULL); if (*err) goto out; ksys_chdir("/.."); /* will traverse into overmounted root */ diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 7c532548b0a62d8d0ac99d8d052de4a8d045ef18..cf6b6b722e5c91612b93a52e59b27e06a4aa8877 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -1325,10 +1325,14 @@ struct device *platform_find_device_by_driver(struct device *start, } EXPORT_SYMBOL_GPL(platform_find_device_by_driver); +void __weak __init early_platform_cleanup(void) { } + int __init platform_bus_init(void) { int error; + early_platform_cleanup(); + error = device_register(&platform_bus); if (error) { put_device(&platform_bus); diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index e8c5c54e1d2657a1394dde3bdee52b443d32b2e3..d6a6adfd5159d5c6f2587fa10fce6f9d9a5e1a0b 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -171,6 +171,15 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid) blkif->domid = domid; atomic_set(&blkif->refcnt, 1); init_completion(&blkif->drain_complete); + + /* + * Because freeing back to the cache may be deferred, it is not + * safe to unload the module (and hence destroy the cache) until + * this has completed. To prevent premature unloading, take an + * extra module reference here and release only when the object + * has been freed back to the cache. + */ + __module_get(THIS_MODULE); INIT_WORK(&blkif->free_work, xen_blkif_deferred_free); return blkif; @@ -320,6 +329,7 @@ static void xen_blkif_free(struct xen_blkif *blkif) /* Make sure everything is drained before shutting down */ kmem_cache_free(xen_blkif_cachep, blkif); + module_put(THIS_MODULE); } int __init xen_blkif_interface_init(void) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 0005be5ea2b45f560a2a378a3c66b89354b3fb42..33d19c8eb02723646d48ad1eb9a864fd0bc13d81 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -381,7 +381,8 @@ u64 cpuidle_poll_time(struct cpuidle_driver *drv, if (dev->states_usage[i].disable) continue; - limit_ns = (u64)drv->states[i].target_residency_ns; + limit_ns = drv->states[i].target_residency_ns; + break; } dev->poll_limit_ns = limit_ns; diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index c76423aaef4d7ebe1098ec63507752ecf0eb194a..ce6a5f80fb8384c810d8c0890e1a003d216cbed4 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -403,6 +403,13 @@ void cpuidle_driver_state_disabled(struct cpuidle_driver *drv, int idx, mutex_lock(&cpuidle_lock); + spin_lock(&cpuidle_driver_lock); + + if (!drv->cpumask) { + drv->states[idx].flags |= CPUIDLE_FLAG_UNUSABLE; + goto unlock; + } + for_each_cpu(cpu, drv->cpumask) { struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu); @@ -415,5 +422,8 @@ void cpuidle_driver_state_disabled(struct cpuidle_driver *drv, int idx, dev->states_usage[idx].disable &= ~CPUIDLE_STATE_DISABLED_BY_DRIVER; } +unlock: + spin_unlock(&cpuidle_driver_lock); + mutex_unlock(&cpuidle_lock); } diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 425149e8bab0799753cc1db9a82104fb7bb6600d..57f6944d65a6d21f4b5c87e3d1b8e4c43152bfdf 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -24,11 +24,14 @@ #include #include #include +#include #include "governor.h" #define CREATE_TRACE_POINTS #include +#define HZ_PER_KHZ 1000 + static struct class *devfreq_class; /* @@ -98,6 +101,54 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq) return max_freq; } +/** + * get_freq_range() - Get the current freq range + * @devfreq: the devfreq instance + * @min_freq: the min frequency + * @max_freq: the max frequency + * + * This takes into consideration all constraints. + */ +static void get_freq_range(struct devfreq *devfreq, + unsigned long *min_freq, + unsigned long *max_freq) +{ + unsigned long *freq_table = devfreq->profile->freq_table; + s32 qos_min_freq, qos_max_freq; + + lockdep_assert_held(&devfreq->lock); + + /* + * Initialize minimum/maximum frequency from freq table. + * The devfreq drivers can initialize this in either ascending or + * descending order and devfreq core supports both. + */ + if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) { + *min_freq = freq_table[0]; + *max_freq = freq_table[devfreq->profile->max_state - 1]; + } else { + *min_freq = freq_table[devfreq->profile->max_state - 1]; + *max_freq = freq_table[0]; + } + + /* Apply constraints from PM QoS */ + qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent, + DEV_PM_QOS_MIN_FREQUENCY); + qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent, + DEV_PM_QOS_MAX_FREQUENCY); + *min_freq = max(*min_freq, (unsigned long)HZ_PER_KHZ * qos_min_freq); + if (qos_max_freq != PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE) + *max_freq = min(*max_freq, + (unsigned long)HZ_PER_KHZ * qos_max_freq); + + /* Apply constraints from OPP interface */ + *min_freq = max(*min_freq, devfreq->scaling_min_freq); + *max_freq = min(*max_freq, devfreq->scaling_max_freq); + + if (*min_freq > *max_freq) + *min_freq = *max_freq; +} + /** * devfreq_get_freq_level() - Lookup freq_table for the frequency * @devfreq: the devfreq instance @@ -351,16 +402,7 @@ int update_devfreq(struct devfreq *devfreq) err = devfreq->governor->get_target_freq(devfreq, &freq); if (err) return err; - - /* - * Adjust the frequency with user freq, QoS and available freq. - * - * List from the highest priority - * max_freq - * min_freq - */ - max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq); - min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq); + get_freq_range(devfreq, &min_freq, &max_freq); if (freq < min_freq) { freq = min_freq; @@ -568,26 +610,69 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type, void *devp) { struct devfreq *devfreq = container_of(nb, struct devfreq, nb); - int ret; + int err = -EINVAL; mutex_lock(&devfreq->lock); devfreq->scaling_min_freq = find_available_min_freq(devfreq); - if (!devfreq->scaling_min_freq) { - mutex_unlock(&devfreq->lock); - return -EINVAL; - } + if (!devfreq->scaling_min_freq) + goto out; devfreq->scaling_max_freq = find_available_max_freq(devfreq); if (!devfreq->scaling_max_freq) { - mutex_unlock(&devfreq->lock); - return -EINVAL; + devfreq->scaling_max_freq = ULONG_MAX; + goto out; } - ret = update_devfreq(devfreq); + err = update_devfreq(devfreq); + +out: mutex_unlock(&devfreq->lock); + if (err) + dev_err(devfreq->dev.parent, + "failed to update frequency from OPP notifier (%d)\n", + err); - return ret; + return NOTIFY_OK; +} + +/** + * qos_notifier_call() - Common handler for QoS constraints. + * @devfreq: the devfreq instance. + */ +static int qos_notifier_call(struct devfreq *devfreq) +{ + int err; + + mutex_lock(&devfreq->lock); + err = update_devfreq(devfreq); + mutex_unlock(&devfreq->lock); + if (err) + dev_err(devfreq->dev.parent, + "failed to update frequency from PM QoS (%d)\n", + err); + + return NOTIFY_OK; +} + +/** + * qos_min_notifier_call() - Callback for QoS min_freq changes. + * @nb: Should be devfreq->nb_min + */ +static int qos_min_notifier_call(struct notifier_block *nb, + unsigned long val, void *ptr) +{ + return qos_notifier_call(container_of(nb, struct devfreq, nb_min)); +} + +/** + * qos_max_notifier_call() - Callback for QoS max_freq changes. + * @nb: Should be devfreq->nb_max + */ +static int qos_max_notifier_call(struct notifier_block *nb, + unsigned long val, void *ptr) +{ + return qos_notifier_call(container_of(nb, struct devfreq, nb_max)); } /** @@ -599,16 +684,36 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type, static void devfreq_dev_release(struct device *dev) { struct devfreq *devfreq = to_devfreq(dev); + int err; mutex_lock(&devfreq_list_lock); - if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) { - mutex_unlock(&devfreq_list_lock); - dev_warn(&devfreq->dev, "releasing devfreq which doesn't exist\n"); - return; - } list_del(&devfreq->node); mutex_unlock(&devfreq_list_lock); + err = dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max, + DEV_PM_QOS_MAX_FREQUENCY); + if (err && err != -ENOENT) + dev_warn(dev->parent, + "Failed to remove max_freq notifier: %d\n", err); + err = dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min, + DEV_PM_QOS_MIN_FREQUENCY); + if (err && err != -ENOENT) + dev_warn(dev->parent, + "Failed to remove min_freq notifier: %d\n", err); + + if (dev_pm_qos_request_active(&devfreq->user_max_freq_req)) { + err = dev_pm_qos_remove_request(&devfreq->user_max_freq_req); + if (err) + dev_warn(dev->parent, + "Failed to remove max_freq request: %d\n", err); + } + if (dev_pm_qos_request_active(&devfreq->user_min_freq_req)) { + err = dev_pm_qos_remove_request(&devfreq->user_min_freq_req); + if (err) + dev_warn(dev->parent, + "Failed to remove min_freq request: %d\n", err); + } + if (devfreq->profile->exit) devfreq->profile->exit(devfreq->dev.parent); @@ -660,6 +765,7 @@ struct devfreq *devfreq_add_device(struct device *dev, devfreq->dev.parent = dev; devfreq->dev.class = devfreq_class; devfreq->dev.release = devfreq_dev_release; + INIT_LIST_HEAD(&devfreq->node); devfreq->profile = profile; strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN); devfreq->previous_freq = profile->initial_freq; @@ -681,7 +787,6 @@ struct devfreq *devfreq_add_device(struct device *dev, err = -EINVAL; goto err_dev; } - devfreq->min_freq = devfreq->scaling_min_freq; devfreq->scaling_max_freq = find_available_max_freq(devfreq); if (!devfreq->scaling_max_freq) { @@ -689,7 +794,6 @@ struct devfreq *devfreq_add_device(struct device *dev, err = -EINVAL; goto err_dev; } - devfreq->max_freq = devfreq->scaling_max_freq; devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev); atomic_set(&devfreq->suspend_count, 0); @@ -730,6 +834,28 @@ struct devfreq *devfreq_add_device(struct device *dev, mutex_unlock(&devfreq->lock); + err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req, + DEV_PM_QOS_MIN_FREQUENCY, 0); + if (err < 0) + goto err_devfreq; + err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req, + DEV_PM_QOS_MAX_FREQUENCY, + PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE); + if (err < 0) + goto err_devfreq; + + devfreq->nb_min.notifier_call = qos_min_notifier_call; + err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min, + DEV_PM_QOS_MIN_FREQUENCY); + if (err) + goto err_devfreq; + + devfreq->nb_max.notifier_call = qos_max_notifier_call; + err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max, + DEV_PM_QOS_MAX_FREQUENCY); + if (err) + goto err_devfreq; + mutex_lock(&devfreq_list_lock); governor = try_then_request_governor(devfreq->governor_name); @@ -1303,41 +1429,37 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr, unsigned long value; int ret; + /* + * Protect against theoretical sysfs writes between + * device_add and dev_pm_qos_add_request + */ + if (!dev_pm_qos_request_active(&df->user_min_freq_req)) + return -EAGAIN; + ret = sscanf(buf, "%lu", &value); if (ret != 1) return -EINVAL; - mutex_lock(&df->lock); - - if (value) { - if (value > df->max_freq) { - ret = -EINVAL; - goto unlock; - } - } else { - unsigned long *freq_table = df->profile->freq_table; - - /* Get minimum frequency according to sorting order */ - if (freq_table[0] < freq_table[df->profile->max_state - 1]) - value = freq_table[0]; - else - value = freq_table[df->profile->max_state - 1]; - } + /* Round down to kHz for PM QoS */ + ret = dev_pm_qos_update_request(&df->user_min_freq_req, + value / HZ_PER_KHZ); + if (ret < 0) + return ret; - df->min_freq = value; - update_devfreq(df); - ret = count; -unlock: - mutex_unlock(&df->lock); - return ret; + return count; } static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr, char *buf) { struct devfreq *df = to_devfreq(dev); + unsigned long min_freq, max_freq; - return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq)); + mutex_lock(&df->lock); + get_freq_range(df, &min_freq, &max_freq); + mutex_unlock(&df->lock); + + return sprintf(buf, "%lu\n", min_freq); } static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, @@ -1347,33 +1469,37 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, unsigned long value; int ret; + /* + * Protect against theoretical sysfs writes between + * device_add and dev_pm_qos_add_request + */ + if (!dev_pm_qos_request_active(&df->user_max_freq_req)) + return -EINVAL; + ret = sscanf(buf, "%lu", &value); if (ret != 1) return -EINVAL; - mutex_lock(&df->lock); - - if (value) { - if (value < df->min_freq) { - ret = -EINVAL; - goto unlock; - } - } else { - unsigned long *freq_table = df->profile->freq_table; + /* + * PM QoS frequencies are in kHz so we need to convert. Convert by + * rounding upwards so that the acceptable interval never shrinks. + * + * For example if the user writes "666666666" to sysfs this value will + * be converted to 666667 kHz and back to 666667000 Hz before an OPP + * lookup, this ensures that an OPP of 666666666Hz is still accepted. + * + * A value of zero means "no limit". + */ + if (value) + value = DIV_ROUND_UP(value, HZ_PER_KHZ); + else + value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE; - /* Get maximum frequency according to sorting order */ - if (freq_table[0] < freq_table[df->profile->max_state - 1]) - value = freq_table[df->profile->max_state - 1]; - else - value = freq_table[0]; - } + ret = dev_pm_qos_update_request(&df->user_max_freq_req, value); + if (ret < 0) + return ret; - df->max_freq = value; - update_devfreq(df); - ret = count; -unlock: - mutex_unlock(&df->lock); - return ret; + return count; } static DEVICE_ATTR_RW(min_freq); @@ -1381,8 +1507,13 @@ static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr, char *buf) { struct devfreq *df = to_devfreq(dev); + unsigned long min_freq, max_freq; + + mutex_lock(&df->lock); + get_freq_range(df, &min_freq, &max_freq); + mutex_unlock(&df->lock); - return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq)); + return sprintf(buf, "%lu\n", max_freq); } static DEVICE_ATTR_RW(max_freq); diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig index a23b6752d11ac08d403bd88ce31c9a554482fc85..0613bb7770f52db969da6d8d65644d9002d62760 100644 --- a/drivers/dma-buf/Kconfig +++ b/drivers/dma-buf/Kconfig @@ -44,4 +44,15 @@ config DMABUF_SELFTESTS default n depends on DMA_SHARED_BUFFER +menuconfig DMABUF_HEAPS + bool "DMA-BUF Userland Memory Heaps" + select DMA_SHARED_BUFFER + help + Choose this option to enable the DMA-BUF userland memory heaps. + This options creates per heap chardevs in /dev/dma_heap/ which + allows userspace to allocate dma-bufs that can be shared + between drivers. + +source "drivers/dma-buf/heaps/Kconfig" + endmenu diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index 03479da0642223a26684e02ec62f2a6fef9f94d2..9c190026bfab1f9b34169206a6034a5b63384603 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ dma-resv.o seqno-fence.o +obj-$(CONFIG_DMABUF_HEAPS) += dma-heap.o +obj-$(CONFIG_DMABUF_HEAPS) += heaps/ obj-$(CONFIG_SYNC_FILE) += sync_file.o obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o obj-$(CONFIG_UDMABUF) += udmabuf.o diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index ce41cd9b758ac8fbaf22bc5c145ad9d93aac58f4..d4097856c86b8b4a93242e09095f6006fbb0c2ea 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -878,29 +878,9 @@ EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment); * with calls to dma_buf_begin_cpu_access() and dma_buf_end_cpu_access() * access. * - * To support dma_buf objects residing in highmem cpu access is page-based - * using an api similar to kmap. Accessing a dma_buf is done in aligned chunks - * of PAGE_SIZE size. Before accessing a chunk it needs to be mapped, which - * returns a pointer in kernel virtual address space. Afterwards the chunk - * needs to be unmapped again. There is no limit on how often a given chunk - * can be mapped and unmapped, i.e. the importer does not need to call - * begin_cpu_access again before mapping the same chunk again. - * - * Interfaces:: - * void \*dma_buf_kmap(struct dma_buf \*, unsigned long); - * void dma_buf_kunmap(struct dma_buf \*, unsigned long, void \*); - * - * Implementing the functions is optional for exporters and for importers all - * the restrictions of using kmap apply. - * - * dma_buf kmap calls outside of the range specified in begin_cpu_access are - * undefined. If the range is not PAGE_SIZE aligned, kmap needs to succeed on - * the partial chunks at the beginning and end but may return stale or bogus - * data outside of the range (in these partial chunks). - * - * For some cases the overhead of kmap can be too high, a vmap interface - * is introduced. This interface should be used very carefully, as vmalloc - * space is a limited resources on many architectures. + * Since for most kernel internal dma-buf accesses need the entire buffer, a + * vmap interface is introduced. Note that on very old 32-bit architectures + * vmalloc space might be limited and result in vmap calls failing. * * Interfaces:: * void \*dma_buf_vmap(struct dma_buf \*dmabuf) @@ -1050,43 +1030,6 @@ int dma_buf_end_cpu_access(struct dma_buf *dmabuf, } EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access); -/** - * dma_buf_kmap - Map a page of the buffer object into kernel address space. The - * same restrictions as for kmap and friends apply. - * @dmabuf: [in] buffer to map page from. - * @page_num: [in] page in PAGE_SIZE units to map. - * - * This call must always succeed, any necessary preparations that might fail - * need to be done in begin_cpu_access. - */ -void *dma_buf_kmap(struct dma_buf *dmabuf, unsigned long page_num) -{ - WARN_ON(!dmabuf); - - if (!dmabuf->ops->map) - return NULL; - return dmabuf->ops->map(dmabuf, page_num); -} -EXPORT_SYMBOL_GPL(dma_buf_kmap); - -/** - * dma_buf_kunmap - Unmap a page obtained by dma_buf_kmap. - * @dmabuf: [in] buffer to unmap page from. - * @page_num: [in] page in PAGE_SIZE units to unmap. - * @vaddr: [in] kernel space pointer obtained from dma_buf_kmap. - * - * This call must always succeed. - */ -void dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long page_num, - void *vaddr) -{ - WARN_ON(!dmabuf); - - if (dmabuf->ops->unmap) - dmabuf->ops->unmap(dmabuf, page_num, vaddr); -} -EXPORT_SYMBOL_GPL(dma_buf_kunmap); - /** * dma_buf_mmap - Setup up a userspace mmap with the given vma diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c new file mode 100644 index 0000000000000000000000000000000000000000..afd22c9dbdcfa16864f07e2fdab2e1ed8f5992fb --- /dev/null +++ b/drivers/dma-buf/dma-heap.c @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Framework for userspace DMA-BUF allocations + * + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2019 Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVNAME "dma_heap" + +#define NUM_HEAP_MINORS 128 + +/** + * struct dma_heap - represents a dmabuf heap in the system + * @name: used for debugging/device-node name + * @ops: ops struct for this heap + * @heap_devt heap device node + * @list list head connecting to list of heaps + * @heap_cdev heap char device + * + * Represents a heap of memory from which buffers can be made. + */ +struct dma_heap { + const char *name; + const struct dma_heap_ops *ops; + void *priv; + dev_t heap_devt; + struct list_head list; + struct cdev heap_cdev; +}; + +static LIST_HEAD(heap_list); +static DEFINE_MUTEX(heap_list_lock); +static dev_t dma_heap_devt; +static struct class *dma_heap_class; +static DEFINE_XARRAY_ALLOC(dma_heap_minors); + +static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len, + unsigned int fd_flags, + unsigned int heap_flags) +{ + /* + * Allocations from all heaps have to begin + * and end on page boundaries. + */ + len = PAGE_ALIGN(len); + if (!len) + return -EINVAL; + + return heap->ops->allocate(heap, len, fd_flags, heap_flags); +} + +static int dma_heap_open(struct inode *inode, struct file *file) +{ + struct dma_heap *heap; + + heap = xa_load(&dma_heap_minors, iminor(inode)); + if (!heap) { + pr_err("dma_heap: minor %d unknown.\n", iminor(inode)); + return -ENODEV; + } + + /* instance data as context */ + file->private_data = heap; + nonseekable_open(inode, file); + + return 0; +} + +static long dma_heap_ioctl_allocate(struct file *file, void *data) +{ + struct dma_heap_allocation_data *heap_allocation = data; + struct dma_heap *heap = file->private_data; + int fd; + + if (heap_allocation->fd) + return -EINVAL; + + if (heap_allocation->fd_flags & ~DMA_HEAP_VALID_FD_FLAGS) + return -EINVAL; + + if (heap_allocation->heap_flags & ~DMA_HEAP_VALID_HEAP_FLAGS) + return -EINVAL; + + fd = dma_heap_buffer_alloc(heap, heap_allocation->len, + heap_allocation->fd_flags, + heap_allocation->heap_flags); + if (fd < 0) + return fd; + + heap_allocation->fd = fd; + + return 0; +} + +static unsigned int dma_heap_ioctl_cmds[] = { + DMA_HEAP_IOCTL_ALLOC, +}; + +static long dma_heap_ioctl(struct file *file, unsigned int ucmd, + unsigned long arg) +{ + char stack_kdata[128]; + char *kdata = stack_kdata; + unsigned int kcmd; + unsigned int in_size, out_size, drv_size, ksize; + int nr = _IOC_NR(ucmd); + int ret = 0; + + if (nr >= ARRAY_SIZE(dma_heap_ioctl_cmds)) + return -EINVAL; + + /* Get the kernel ioctl cmd that matches */ + kcmd = dma_heap_ioctl_cmds[nr]; + + /* Figure out the delta between user cmd size and kernel cmd size */ + drv_size = _IOC_SIZE(kcmd); + out_size = _IOC_SIZE(ucmd); + in_size = out_size; + if ((ucmd & kcmd & IOC_IN) == 0) + in_size = 0; + if ((ucmd & kcmd & IOC_OUT) == 0) + out_size = 0; + ksize = max(max(in_size, out_size), drv_size); + + /* If necessary, allocate buffer for ioctl argument */ + if (ksize > sizeof(stack_kdata)) { + kdata = kmalloc(ksize, GFP_KERNEL); + if (!kdata) + return -ENOMEM; + } + + if (copy_from_user(kdata, (void __user *)arg, in_size) != 0) { + ret = -EFAULT; + goto err; + } + + /* zero out any difference between the kernel/user structure size */ + if (ksize > in_size) + memset(kdata + in_size, 0, ksize - in_size); + + switch (kcmd) { + case DMA_HEAP_IOCTL_ALLOC: + ret = dma_heap_ioctl_allocate(file, kdata); + break; + default: + ret = -ENOTTY; + goto err; + } + + if (copy_to_user((void __user *)arg, kdata, out_size) != 0) + ret = -EFAULT; +err: + if (kdata != stack_kdata) + kfree(kdata); + return ret; +} + +static const struct file_operations dma_heap_fops = { + .owner = THIS_MODULE, + .open = dma_heap_open, + .unlocked_ioctl = dma_heap_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = dma_heap_ioctl, +#endif +}; + +/** + * dma_heap_get_drvdata() - get per-subdriver data for the heap + * @heap: DMA-Heap to retrieve private data for + * + * Returns: + * The per-subdriver data for the heap. + */ +void *dma_heap_get_drvdata(struct dma_heap *heap) +{ + return heap->priv; +} + +struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info) +{ + struct dma_heap *heap, *h, *err_ret; + struct device *dev_ret; + unsigned int minor; + int ret; + + if (!exp_info->name || !strcmp(exp_info->name, "")) { + pr_err("dma_heap: Cannot add heap without a name\n"); + return ERR_PTR(-EINVAL); + } + + if (!exp_info->ops || !exp_info->ops->allocate) { + pr_err("dma_heap: Cannot add heap with invalid ops struct\n"); + return ERR_PTR(-EINVAL); + } + + /* check the name is unique */ + mutex_lock(&heap_list_lock); + list_for_each_entry(h, &heap_list, list) { + if (!strcmp(h->name, exp_info->name)) { + mutex_unlock(&heap_list_lock); + pr_err("dma_heap: Already registered heap named %s\n", + exp_info->name); + return ERR_PTR(-EINVAL); + } + } + mutex_unlock(&heap_list_lock); + + heap = kzalloc(sizeof(*heap), GFP_KERNEL); + if (!heap) + return ERR_PTR(-ENOMEM); + + heap->name = exp_info->name; + heap->ops = exp_info->ops; + heap->priv = exp_info->priv; + + /* Find unused minor number */ + ret = xa_alloc(&dma_heap_minors, &minor, heap, + XA_LIMIT(0, NUM_HEAP_MINORS - 1), GFP_KERNEL); + if (ret < 0) { + pr_err("dma_heap: Unable to get minor number for heap\n"); + err_ret = ERR_PTR(ret); + goto err0; + } + + /* Create device */ + heap->heap_devt = MKDEV(MAJOR(dma_heap_devt), minor); + + cdev_init(&heap->heap_cdev, &dma_heap_fops); + ret = cdev_add(&heap->heap_cdev, heap->heap_devt, 1); + if (ret < 0) { + pr_err("dma_heap: Unable to add char device\n"); + err_ret = ERR_PTR(ret); + goto err1; + } + + dev_ret = device_create(dma_heap_class, + NULL, + heap->heap_devt, + NULL, + heap->name); + if (IS_ERR(dev_ret)) { + pr_err("dma_heap: Unable to create device\n"); + err_ret = ERR_CAST(dev_ret); + goto err2; + } + /* Add heap to the list */ + mutex_lock(&heap_list_lock); + list_add(&heap->list, &heap_list); + mutex_unlock(&heap_list_lock); + + return heap; + +err2: + cdev_del(&heap->heap_cdev); +err1: + xa_erase(&dma_heap_minors, minor); +err0: + kfree(heap); + return err_ret; +} + +static char *dma_heap_devnode(struct device *dev, umode_t *mode) +{ + return kasprintf(GFP_KERNEL, "dma_heap/%s", dev_name(dev)); +} + +static int dma_heap_init(void) +{ + int ret; + + ret = alloc_chrdev_region(&dma_heap_devt, 0, NUM_HEAP_MINORS, DEVNAME); + if (ret) + return ret; + + dma_heap_class = class_create(THIS_MODULE, DEVNAME); + if (IS_ERR(dma_heap_class)) { + unregister_chrdev_region(dma_heap_devt, NUM_HEAP_MINORS); + return PTR_ERR(dma_heap_class); + } + dma_heap_class->devnode = dma_heap_devnode; + + return 0; +} +subsys_initcall(dma_heap_init); diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index 709002515550cd2e6ff989a4c2bdd11b5b0cdf9c..4264e64788c4639ea260d949038d9e85d5b8467d 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -34,6 +34,7 @@ #include #include +#include /** * DOC: Reservation Object Overview @@ -95,6 +96,37 @@ static void dma_resv_list_free(struct dma_resv_list *list) kfree_rcu(list, rcu); } +#if IS_ENABLED(CONFIG_LOCKDEP) +static int __init dma_resv_lockdep(void) +{ + struct mm_struct *mm = mm_alloc(); + struct ww_acquire_ctx ctx; + struct dma_resv obj; + int ret; + + if (!mm) + return -ENOMEM; + + dma_resv_init(&obj); + + down_read(&mm->mmap_sem); + ww_acquire_init(&ctx, &reservation_ww_class); + ret = dma_resv_lock(&obj, &ctx); + if (ret == -EDEADLK) + dma_resv_lock_slow(&obj, &ctx); + fs_reclaim_acquire(GFP_KERNEL); + fs_reclaim_release(GFP_KERNEL); + ww_mutex_unlock(&obj.lock); + ww_acquire_fini(&ctx); + up_read(&mm->mmap_sem); + + mmput(mm); + + return 0; +} +subsys_initcall(dma_resv_lockdep); +#endif + /** * dma_resv_init - initialize a reservation object * @obj: the reservation object diff --git a/drivers/dma-buf/heaps/Kconfig b/drivers/dma-buf/heaps/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..a5eef06c422644e8aadaf5aff2bd9a33c49c1ba3 --- /dev/null +++ b/drivers/dma-buf/heaps/Kconfig @@ -0,0 +1,14 @@ +config DMABUF_HEAPS_SYSTEM + bool "DMA-BUF System Heap" + depends on DMABUF_HEAPS + help + Choose this option to enable the system dmabuf heap. The system heap + is backed by pages from the buddy allocator. If in doubt, say Y. + +config DMABUF_HEAPS_CMA + bool "DMA-BUF CMA Heap" + depends on DMABUF_HEAPS && DMA_CMA + help + Choose this option to enable dma-buf CMA heap. This heap is backed + by the Contiguous Memory Allocator (CMA). If your system has these + regions, you should say Y here. diff --git a/drivers/dma-buf/heaps/Makefile b/drivers/dma-buf/heaps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6e54cdec3da02bbc4b5d7e10ebb881855ab2ac0e --- /dev/null +++ b/drivers/dma-buf/heaps/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-y += heap-helpers.o +obj-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o +obj-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c new file mode 100644 index 0000000000000000000000000000000000000000..626cf7fd033afdc63e6d13fffa4adb85f13698fa --- /dev/null +++ b/drivers/dma-buf/heaps/cma_heap.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DMABUF CMA heap exporter + * + * Copyright (C) 2012, 2019 Linaro Ltd. + * Author: for ST-Ericsson. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "heap-helpers.h" + +struct cma_heap { + struct dma_heap *heap; + struct cma *cma; +}; + +static void cma_heap_free(struct heap_helper_buffer *buffer) +{ + struct cma_heap *cma_heap = dma_heap_get_drvdata(buffer->heap); + unsigned long nr_pages = buffer->pagecount; + struct page *cma_pages = buffer->priv_virt; + + /* free page list */ + kfree(buffer->pages); + /* release memory */ + cma_release(cma_heap->cma, cma_pages, nr_pages); + kfree(buffer); +} + +/* dmabuf heap CMA operations functions */ +static int cma_heap_allocate(struct dma_heap *heap, + unsigned long len, + unsigned long fd_flags, + unsigned long heap_flags) +{ + struct cma_heap *cma_heap = dma_heap_get_drvdata(heap); + struct heap_helper_buffer *helper_buffer; + struct page *cma_pages; + size_t size = PAGE_ALIGN(len); + unsigned long nr_pages = size >> PAGE_SHIFT; + unsigned long align = get_order(size); + struct dma_buf *dmabuf; + int ret = -ENOMEM; + pgoff_t pg; + + if (align > CONFIG_CMA_ALIGNMENT) + align = CONFIG_CMA_ALIGNMENT; + + helper_buffer = kzalloc(sizeof(*helper_buffer), GFP_KERNEL); + if (!helper_buffer) + return -ENOMEM; + + init_heap_helper_buffer(helper_buffer, cma_heap_free); + helper_buffer->heap = heap; + helper_buffer->size = len; + + cma_pages = cma_alloc(cma_heap->cma, nr_pages, align, false); + if (!cma_pages) + goto free_buf; + + if (PageHighMem(cma_pages)) { + unsigned long nr_clear_pages = nr_pages; + struct page *page = cma_pages; + + while (nr_clear_pages > 0) { + void *vaddr = kmap_atomic(page); + + memset(vaddr, 0, PAGE_SIZE); + kunmap_atomic(vaddr); + /* + * Avoid wasting time zeroing memory if the process + * has been killed by by SIGKILL + */ + if (fatal_signal_pending(current)) + goto free_cma; + + page++; + nr_clear_pages--; + } + } else { + memset(page_address(cma_pages), 0, size); + } + + helper_buffer->pagecount = nr_pages; + helper_buffer->pages = kmalloc_array(helper_buffer->pagecount, + sizeof(*helper_buffer->pages), + GFP_KERNEL); + if (!helper_buffer->pages) { + ret = -ENOMEM; + goto free_cma; + } + + for (pg = 0; pg < helper_buffer->pagecount; pg++) + helper_buffer->pages[pg] = &cma_pages[pg]; + + /* create the dmabuf */ + dmabuf = heap_helper_export_dmabuf(helper_buffer, fd_flags); + if (IS_ERR(dmabuf)) { + ret = PTR_ERR(dmabuf); + goto free_pages; + } + + helper_buffer->dmabuf = dmabuf; + helper_buffer->priv_virt = cma_pages; + + ret = dma_buf_fd(dmabuf, fd_flags); + if (ret < 0) { + dma_buf_put(dmabuf); + /* just return, as put will call release and that will free */ + return ret; + } + + return ret; + +free_pages: + kfree(helper_buffer->pages); +free_cma: + cma_release(cma_heap->cma, cma_pages, nr_pages); +free_buf: + kfree(helper_buffer); + return ret; +} + +static const struct dma_heap_ops cma_heap_ops = { + .allocate = cma_heap_allocate, +}; + +static int __add_cma_heap(struct cma *cma, void *data) +{ + struct cma_heap *cma_heap; + struct dma_heap_export_info exp_info; + + cma_heap = kzalloc(sizeof(*cma_heap), GFP_KERNEL); + if (!cma_heap) + return -ENOMEM; + cma_heap->cma = cma; + + exp_info.name = cma_get_name(cma); + exp_info.ops = &cma_heap_ops; + exp_info.priv = cma_heap; + + cma_heap->heap = dma_heap_add(&exp_info); + if (IS_ERR(cma_heap->heap)) { + int ret = PTR_ERR(cma_heap->heap); + + kfree(cma_heap); + return ret; + } + + return 0; +} + +static int add_default_cma_heap(void) +{ + struct cma *default_cma = dev_get_cma_area(NULL); + int ret = 0; + + if (default_cma) + ret = __add_cma_heap(default_cma, NULL); + + return ret; +} +module_init(add_default_cma_heap); +MODULE_DESCRIPTION("DMA-BUF CMA Heap"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma-buf/heaps/heap-helpers.c b/drivers/dma-buf/heaps/heap-helpers.c new file mode 100644 index 0000000000000000000000000000000000000000..9f964ca3f59ceafa54f4c9c0522c518aa547e9b4 --- /dev/null +++ b/drivers/dma-buf/heaps/heap-helpers.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "heap-helpers.h" + +void init_heap_helper_buffer(struct heap_helper_buffer *buffer, + void (*free)(struct heap_helper_buffer *)) +{ + buffer->priv_virt = NULL; + mutex_init(&buffer->lock); + buffer->vmap_cnt = 0; + buffer->vaddr = NULL; + buffer->pagecount = 0; + buffer->pages = NULL; + INIT_LIST_HEAD(&buffer->attachments); + buffer->free = free; +} + +struct dma_buf *heap_helper_export_dmabuf(struct heap_helper_buffer *buffer, + int fd_flags) +{ + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &heap_helper_ops; + exp_info.size = buffer->size; + exp_info.flags = fd_flags; + exp_info.priv = buffer; + + return dma_buf_export(&exp_info); +} + +static void *dma_heap_map_kernel(struct heap_helper_buffer *buffer) +{ + void *vaddr; + + vaddr = vmap(buffer->pages, buffer->pagecount, VM_MAP, PAGE_KERNEL); + if (!vaddr) + return ERR_PTR(-ENOMEM); + + return vaddr; +} + +static void dma_heap_buffer_destroy(struct heap_helper_buffer *buffer) +{ + if (buffer->vmap_cnt > 0) { + WARN(1, "%s: buffer still mapped in the kernel\n", __func__); + vunmap(buffer->vaddr); + } + + buffer->free(buffer); +} + +static void *dma_heap_buffer_vmap_get(struct heap_helper_buffer *buffer) +{ + void *vaddr; + + if (buffer->vmap_cnt) { + buffer->vmap_cnt++; + return buffer->vaddr; + } + vaddr = dma_heap_map_kernel(buffer); + if (IS_ERR(vaddr)) + return vaddr; + buffer->vaddr = vaddr; + buffer->vmap_cnt++; + return vaddr; +} + +static void dma_heap_buffer_vmap_put(struct heap_helper_buffer *buffer) +{ + if (!--buffer->vmap_cnt) { + vunmap(buffer->vaddr); + buffer->vaddr = NULL; + } +} + +struct dma_heaps_attachment { + struct device *dev; + struct sg_table table; + struct list_head list; +}; + +static int dma_heap_attach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attachment) +{ + struct dma_heaps_attachment *a; + struct heap_helper_buffer *buffer = dmabuf->priv; + int ret; + + a = kzalloc(sizeof(*a), GFP_KERNEL); + if (!a) + return -ENOMEM; + + ret = sg_alloc_table_from_pages(&a->table, buffer->pages, + buffer->pagecount, 0, + buffer->pagecount << PAGE_SHIFT, + GFP_KERNEL); + if (ret) { + kfree(a); + return ret; + } + + a->dev = attachment->dev; + INIT_LIST_HEAD(&a->list); + + attachment->priv = a; + + mutex_lock(&buffer->lock); + list_add(&a->list, &buffer->attachments); + mutex_unlock(&buffer->lock); + + return 0; +} + +static void dma_heap_detach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attachment) +{ + struct dma_heaps_attachment *a = attachment->priv; + struct heap_helper_buffer *buffer = dmabuf->priv; + + mutex_lock(&buffer->lock); + list_del(&a->list); + mutex_unlock(&buffer->lock); + + sg_free_table(&a->table); + kfree(a); +} + +static +struct sg_table *dma_heap_map_dma_buf(struct dma_buf_attachment *attachment, + enum dma_data_direction direction) +{ + struct dma_heaps_attachment *a = attachment->priv; + struct sg_table *table; + + table = &a->table; + + if (!dma_map_sg(attachment->dev, table->sgl, table->nents, + direction)) + table = ERR_PTR(-ENOMEM); + return table; +} + +static void dma_heap_unmap_dma_buf(struct dma_buf_attachment *attachment, + struct sg_table *table, + enum dma_data_direction direction) +{ + dma_unmap_sg(attachment->dev, table->sgl, table->nents, direction); +} + +static vm_fault_t dma_heap_vm_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + struct heap_helper_buffer *buffer = vma->vm_private_data; + + if (vmf->pgoff > buffer->pagecount) + return VM_FAULT_SIGBUS; + + vmf->page = buffer->pages[vmf->pgoff]; + get_page(vmf->page); + + return 0; +} + +static const struct vm_operations_struct dma_heap_vm_ops = { + .fault = dma_heap_vm_fault, +}; + +static int dma_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) +{ + struct heap_helper_buffer *buffer = dmabuf->priv; + + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) + return -EINVAL; + + vma->vm_ops = &dma_heap_vm_ops; + vma->vm_private_data = buffer; + + return 0; +} + +static void dma_heap_dma_buf_release(struct dma_buf *dmabuf) +{ + struct heap_helper_buffer *buffer = dmabuf->priv; + + dma_heap_buffer_destroy(buffer); +} + +static int dma_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) +{ + struct heap_helper_buffer *buffer = dmabuf->priv; + struct dma_heaps_attachment *a; + int ret = 0; + + mutex_lock(&buffer->lock); + + if (buffer->vmap_cnt) + invalidate_kernel_vmap_range(buffer->vaddr, buffer->size); + + list_for_each_entry(a, &buffer->attachments, list) { + dma_sync_sg_for_cpu(a->dev, a->table.sgl, a->table.nents, + direction); + } + mutex_unlock(&buffer->lock); + + return ret; +} + +static int dma_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) +{ + struct heap_helper_buffer *buffer = dmabuf->priv; + struct dma_heaps_attachment *a; + + mutex_lock(&buffer->lock); + + if (buffer->vmap_cnt) + flush_kernel_vmap_range(buffer->vaddr, buffer->size); + + list_for_each_entry(a, &buffer->attachments, list) { + dma_sync_sg_for_device(a->dev, a->table.sgl, a->table.nents, + direction); + } + mutex_unlock(&buffer->lock); + + return 0; +} + +static void *dma_heap_dma_buf_vmap(struct dma_buf *dmabuf) +{ + struct heap_helper_buffer *buffer = dmabuf->priv; + void *vaddr; + + mutex_lock(&buffer->lock); + vaddr = dma_heap_buffer_vmap_get(buffer); + mutex_unlock(&buffer->lock); + + return vaddr; +} + +static void dma_heap_dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr) +{ + struct heap_helper_buffer *buffer = dmabuf->priv; + + mutex_lock(&buffer->lock); + dma_heap_buffer_vmap_put(buffer); + mutex_unlock(&buffer->lock); +} + +const struct dma_buf_ops heap_helper_ops = { + .map_dma_buf = dma_heap_map_dma_buf, + .unmap_dma_buf = dma_heap_unmap_dma_buf, + .mmap = dma_heap_mmap, + .release = dma_heap_dma_buf_release, + .attach = dma_heap_attach, + .detach = dma_heap_detach, + .begin_cpu_access = dma_heap_dma_buf_begin_cpu_access, + .end_cpu_access = dma_heap_dma_buf_end_cpu_access, + .vmap = dma_heap_dma_buf_vmap, + .vunmap = dma_heap_dma_buf_vunmap, +}; diff --git a/drivers/dma-buf/heaps/heap-helpers.h b/drivers/dma-buf/heaps/heap-helpers.h new file mode 100644 index 0000000000000000000000000000000000000000..805d2df88024ffcf84f4a2abcea25a2967aeb119 --- /dev/null +++ b/drivers/dma-buf/heaps/heap-helpers.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * DMABUF Heaps helper code + * + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2019 Linaro Ltd. + */ + +#ifndef _HEAP_HELPERS_H +#define _HEAP_HELPERS_H + +#include +#include + +/** + * struct heap_helper_buffer - helper buffer metadata + * @heap: back pointer to the heap the buffer came from + * @dmabuf: backing dma-buf for this buffer + * @size: size of the buffer + * @priv_virt pointer to heap specific private value + * @lock mutext to protect the data in this structure + * @vmap_cnt count of vmap references on the buffer + * @vaddr vmap'ed virtual address + * @pagecount number of pages in the buffer + * @pages list of page pointers + * @attachments list of device attachments + * + * @free heap callback to free the buffer + */ +struct heap_helper_buffer { + struct dma_heap *heap; + struct dma_buf *dmabuf; + size_t size; + + void *priv_virt; + struct mutex lock; + int vmap_cnt; + void *vaddr; + pgoff_t pagecount; + struct page **pages; + struct list_head attachments; + + void (*free)(struct heap_helper_buffer *buffer); +}; + +void init_heap_helper_buffer(struct heap_helper_buffer *buffer, + void (*free)(struct heap_helper_buffer *)); + +struct dma_buf *heap_helper_export_dmabuf(struct heap_helper_buffer *buffer, + int fd_flags); + +extern const struct dma_buf_ops heap_helper_ops; +#endif /* _HEAP_HELPERS_H */ diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c new file mode 100644 index 0000000000000000000000000000000000000000..0bf688e3c023aef6e79680b43b17925caecb84d2 --- /dev/null +++ b/drivers/dma-buf/heaps/system_heap.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DMABUF System heap exporter + * + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2019 Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "heap-helpers.h" + +struct dma_heap *sys_heap; + +static void system_heap_free(struct heap_helper_buffer *buffer) +{ + pgoff_t pg; + + for (pg = 0; pg < buffer->pagecount; pg++) + __free_page(buffer->pages[pg]); + kfree(buffer->pages); + kfree(buffer); +} + +static int system_heap_allocate(struct dma_heap *heap, + unsigned long len, + unsigned long fd_flags, + unsigned long heap_flags) +{ + struct heap_helper_buffer *helper_buffer; + struct dma_buf *dmabuf; + int ret = -ENOMEM; + pgoff_t pg; + + helper_buffer = kzalloc(sizeof(*helper_buffer), GFP_KERNEL); + if (!helper_buffer) + return -ENOMEM; + + init_heap_helper_buffer(helper_buffer, system_heap_free); + helper_buffer->heap = heap; + helper_buffer->size = len; + + helper_buffer->pagecount = len / PAGE_SIZE; + helper_buffer->pages = kmalloc_array(helper_buffer->pagecount, + sizeof(*helper_buffer->pages), + GFP_KERNEL); + if (!helper_buffer->pages) { + ret = -ENOMEM; + goto err0; + } + + for (pg = 0; pg < helper_buffer->pagecount; pg++) { + /* + * Avoid trying to allocate memory if the process + * has been killed by by SIGKILL + */ + if (fatal_signal_pending(current)) + goto err1; + + helper_buffer->pages[pg] = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!helper_buffer->pages[pg]) + goto err1; + } + + /* create the dmabuf */ + dmabuf = heap_helper_export_dmabuf(helper_buffer, fd_flags); + if (IS_ERR(dmabuf)) { + ret = PTR_ERR(dmabuf); + goto err1; + } + + helper_buffer->dmabuf = dmabuf; + + ret = dma_buf_fd(dmabuf, fd_flags); + if (ret < 0) { + dma_buf_put(dmabuf); + /* just return, as put will call release and that will free */ + return ret; + } + + return ret; + +err1: + while (pg > 0) + __free_page(helper_buffer->pages[--pg]); + kfree(helper_buffer->pages); +err0: + kfree(helper_buffer); + + return ret; +} + +static const struct dma_heap_ops system_heap_ops = { + .allocate = system_heap_allocate, +}; + +static int system_heap_create(void) +{ + struct dma_heap_export_info exp_info; + int ret = 0; + + exp_info.name = "system"; + exp_info.ops = &system_heap_ops; + exp_info.priv = NULL; + + sys_heap = dma_heap_add(&exp_info); + if (IS_ERR(sys_heap)) + ret = PTR_ERR(sys_heap); + + return ret; +} +module_init(system_heap_create); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index 76fb072c22dc403ef5bb34c37472bd3fc1533415..5a5a1da01a00f3fbc8ca6e2e51a8dea69003342a 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c @@ -221,7 +221,7 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a, a_fences = get_fences(a, &a_num_fences); b_fences = get_fences(b, &b_num_fences); if (a_num_fences > INT_MAX - b_num_fences) - return NULL; + goto err; num_fences = a_num_fences + b_num_fences; diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c index 9635897458a09e660a07ef29064b6a1fb6995bbc..acb26c627d27bbc43f766802205866e168ab0c8b 100644 --- a/drivers/dma-buf/udmabuf.c +++ b/drivers/dma-buf/udmabuf.c @@ -18,6 +18,8 @@ static const size_t size_limit_mb = 64; /* total dmabuf size, in megabytes */ struct udmabuf { pgoff_t pagecount; struct page **pages; + struct sg_table *sg; + struct miscdevice *device; }; static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf) @@ -46,10 +48,10 @@ static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) return 0; } -static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, - enum dma_data_direction direction) +static struct sg_table *get_sg_table(struct device *dev, struct dma_buf *buf, + enum dma_data_direction direction) { - struct udmabuf *ubuf = at->dmabuf->priv; + struct udmabuf *ubuf = buf->priv; struct sg_table *sg; int ret; @@ -61,7 +63,7 @@ static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, GFP_KERNEL); if (ret < 0) goto err; - if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction)) { + if (!dma_map_sg(dev, sg->sgl, sg->nents, direction)) { ret = -EINVAL; goto err; } @@ -73,54 +75,89 @@ err: return ERR_PTR(ret); } +static void put_sg_table(struct device *dev, struct sg_table *sg, + enum dma_data_direction direction) +{ + dma_unmap_sg(dev, sg->sgl, sg->nents, direction); + sg_free_table(sg); + kfree(sg); +} + +static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, + enum dma_data_direction direction) +{ + return get_sg_table(at->dev, at->dmabuf, direction); +} + static void unmap_udmabuf(struct dma_buf_attachment *at, struct sg_table *sg, enum dma_data_direction direction) { - dma_unmap_sg(at->dev, sg->sgl, sg->nents, direction); - sg_free_table(sg); - kfree(sg); + return put_sg_table(at->dev, sg, direction); } static void release_udmabuf(struct dma_buf *buf) { struct udmabuf *ubuf = buf->priv; + struct device *dev = ubuf->device->this_device; pgoff_t pg; + if (ubuf->sg) + put_sg_table(dev, ubuf->sg, DMA_BIDIRECTIONAL); + for (pg = 0; pg < ubuf->pagecount; pg++) put_page(ubuf->pages[pg]); kfree(ubuf->pages); kfree(ubuf); } -static void *kmap_udmabuf(struct dma_buf *buf, unsigned long page_num) +static int begin_cpu_udmabuf(struct dma_buf *buf, + enum dma_data_direction direction) { struct udmabuf *ubuf = buf->priv; - struct page *page = ubuf->pages[page_num]; + struct device *dev = ubuf->device->this_device; + + if (!ubuf->sg) { + ubuf->sg = get_sg_table(dev, buf, direction); + if (IS_ERR(ubuf->sg)) + return PTR_ERR(ubuf->sg); + } else { + dma_sync_sg_for_cpu(dev, ubuf->sg->sgl, ubuf->sg->nents, + direction); + } - return kmap(page); + return 0; } -static void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, - void *vaddr) +static int end_cpu_udmabuf(struct dma_buf *buf, + enum dma_data_direction direction) { - kunmap(vaddr); + struct udmabuf *ubuf = buf->priv; + struct device *dev = ubuf->device->this_device; + + if (!ubuf->sg) + return -EINVAL; + + dma_sync_sg_for_device(dev, ubuf->sg->sgl, ubuf->sg->nents, direction); + return 0; } static const struct dma_buf_ops udmabuf_ops = { - .map_dma_buf = map_udmabuf, - .unmap_dma_buf = unmap_udmabuf, - .release = release_udmabuf, - .map = kmap_udmabuf, - .unmap = kunmap_udmabuf, - .mmap = mmap_udmabuf, + .cache_sgt_mapping = true, + .map_dma_buf = map_udmabuf, + .unmap_dma_buf = unmap_udmabuf, + .release = release_udmabuf, + .mmap = mmap_udmabuf, + .begin_cpu_access = begin_cpu_udmabuf, + .end_cpu_access = end_cpu_udmabuf, }; #define SEALS_WANTED (F_SEAL_SHRINK) #define SEALS_DENIED (F_SEAL_WRITE) -static long udmabuf_create(const struct udmabuf_create_list *head, - const struct udmabuf_create_item *list) +static long udmabuf_create(struct miscdevice *device, + struct udmabuf_create_list *head, + struct udmabuf_create_item *list) { DEFINE_DMA_BUF_EXPORT_INFO(exp_info); struct file *memfd = NULL; @@ -187,6 +224,7 @@ static long udmabuf_create(const struct udmabuf_create_list *head, exp_info.priv = ubuf; exp_info.flags = O_RDWR; + ubuf->device = device; buf = dma_buf_export(&exp_info); if (IS_ERR(buf)) { ret = PTR_ERR(buf); @@ -224,7 +262,7 @@ static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) list.offset = create.offset; list.size = create.size; - return udmabuf_create(&head, &list); + return udmabuf_create(filp->private_data, &head, &list); } static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) @@ -243,7 +281,7 @@ static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) if (IS_ERR(list)) return PTR_ERR(list); - ret = udmabuf_create(&head, list); + ret = udmabuf_create(filp->private_data, &head, list); kfree(list); return ret; } diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index d101f072c8f8ac85db7605966a979a05f06abcae..407816da9fcb46509feb3914cce58d4cda41e5ce 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -681,7 +681,7 @@ device_initcall(efi_load_efivars); { name }, \ { prop }, \ offsetof(struct efi_fdt_params, field), \ - FIELD_SIZEOF(struct efi_fdt_params, field) \ + sizeof_field(struct efi_fdt_params, field) \ } struct params { diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index c87262997dcbe035f759b13f72382ddf0687c829..7041323a7bff36c18d49538cefc0b479b41f1ba7 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -298,9 +298,6 @@ config DRM_VKMS If M is selected the module will be called vkms. -config DRM_ATI_PCIGART - bool - source "drivers/gpu/drm/exynos/Kconfig" source "drivers/gpu/drm/rockchip/Kconfig" @@ -397,7 +394,6 @@ menuconfig DRM_LEGACY bool "Enable legacy drivers (DANGEROUS)" depends on DRM && MMU select DRM_VM - select DRM_ATI_PCIGART if PCI help Enable legacy DRI1 drivers. Those drivers expose unsafe and dangerous APIs to user-space, which can be used to circumvent access diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 9f1c7c486f88b500e0eae0f28e31f83d1bba7f3b..6493088a0fdd3f9b98f6d34e7145049005859380 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -5,7 +5,7 @@ drm-y := drm_auth.o drm_cache.o \ drm_file.o drm_gem.o drm_ioctl.o drm_irq.o \ - drm_memory.o drm_drv.o drm_pci.o \ + drm_memory.o drm_drv.o \ drm_sysfs.o drm_hashtab.o drm_mm.o \ drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o \ drm_encoder_slave.o \ @@ -25,10 +25,10 @@ drm-$(CONFIG_DRM_VM) += drm_vm.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o drm-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_gem_shmem_helper.o -drm-$(CONFIG_DRM_ATI_PCIGART) += ati_pcigart.o drm-$(CONFIG_DRM_PANEL) += drm_panel.o drm-$(CONFIG_OF) += drm_of.o drm-$(CONFIG_AGP) += drm_agpsupport.o +drm-$(CONFIG_PCI) += drm_pci.o drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o diff --git a/drivers/gpu/drm/amd/acp/Kconfig b/drivers/gpu/drm/amd/acp/Kconfig index d968c24714125288693c7754e587f9f5f5116dfe..13340f353ea817e36d79bb1213070e7266beb40f 100644 --- a/drivers/gpu/drm/amd/acp/Kconfig +++ b/drivers/gpu/drm/amd/acp/Kconfig @@ -1,12 +1,12 @@ -# SPDX-License-Identifier: GPL-2.0-only +# SPDX-License-Identifier: MIT menu "ACP (Audio CoProcessor) Configuration" config DRM_AMD_ACP - bool "Enable AMD Audio CoProcessor IP support" - depends on DRM_AMDGPU - select MFD_CORE - select PM_GENERIC_DOMAINS if PM - help + bool "Enable AMD Audio CoProcessor IP support" + depends on DRM_AMDGPU + select MFD_CORE + select PM_GENERIC_DOMAINS if PM + help Choose this option to enable ACP IP support for AMD SOCs. This adds the ACP (Audio CoProcessor) IP driver and wires it up into the amdgpu driver. The ACP block provides the DMA diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig b/drivers/gpu/drm/amd/amdgpu/Kconfig index 2e98c016cb47dbcf947ccaae97cb11fc8fde98a6..9375e7f1242057274c70eec0f24678bdee6f0965 100644 --- a/drivers/gpu/drm/amd/amdgpu/Kconfig +++ b/drivers/gpu/drm/amd/amdgpu/Kconfig @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-only +# SPDX-License-Identifier: MIT config DRM_AMDGPU_SI bool "Enable amdgpu support for SI parts" depends on DRM_AMDGPU diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index ca0e435559d5c446e5a77730703e1462c01ab9b2..7ae3b22c5628bdcee07db8ddc49b839e6f29c385 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -147,12 +147,16 @@ amdgpu-y += \ vce_v3_0.o \ vce_v4_0.o -# add VCN block +# add VCN and JPEG block amdgpu-y += \ amdgpu_vcn.o \ vcn_v1_0.o \ vcn_v2_0.o \ - vcn_v2_5.o + vcn_v2_5.o \ + amdgpu_jpeg.o \ + jpeg_v1_0.o \ + jpeg_v2_0.o \ + jpeg_v2_5.o # add ATHUB block amdgpu-y += \ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 0c229a92a24b008d65e0a53b9df76bd9bf11781e..81a531b652aaca3eca6fea7115362971d8865e6f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -69,6 +69,7 @@ #include "amdgpu_uvd.h" #include "amdgpu_vce.h" #include "amdgpu_vcn.h" +#include "amdgpu_jpeg.h" #include "amdgpu_mn.h" #include "amdgpu_gmc.h" #include "amdgpu_gfx.h" @@ -588,6 +589,8 @@ struct amdgpu_asic_funcs { bool (*need_reset_on_init)(struct amdgpu_device *adev); /* PCIe replay counter */ uint64_t (*get_pcie_replay_count)(struct amdgpu_device *adev); + /* device supports BACO */ + bool (*supports_baco)(struct amdgpu_device *adev); }; /* @@ -704,6 +707,7 @@ enum amd_hw_ip_block_type { MP1_HWIP, UVD_HWIP, VCN_HWIP = UVD_HWIP, + JPEG_HWIP = VCN_HWIP, VCE_HWIP, DF_HWIP, DCE_HWIP, @@ -899,6 +903,9 @@ struct amdgpu_device { /* vcn */ struct amdgpu_vcn vcn; + /* jpeg */ + struct amdgpu_jpeg jpeg; + /* firmwares */ struct amdgpu_firmware firmware; @@ -982,6 +989,13 @@ struct amdgpu_device { /* device pstate */ int pstate; + /* enable runtime pm on the device */ + bool runpm; + + bool pm_sysfs_en; + bool ucode_sysfs_en; + + bool in_baco; }; static inline struct amdgpu_device *amdgpu_ttm_adev(struct ttm_bo_device *bdev) @@ -1117,6 +1131,8 @@ int emu_soc_asic_init(struct amdgpu_device *adev); #define amdgpu_asic_get_pcie_usage(adev, cnt0, cnt1) ((adev)->asic_funcs->get_pcie_usage((adev), (cnt0), (cnt1))) #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_inc_vram_lost(adev) atomic_inc(&((adev)->vram_lost_counter)); /* Common functions */ @@ -1133,9 +1149,12 @@ void amdgpu_device_program_register_sequence(struct amdgpu_device *adev, const u32 *registers, const u32 array_size); -bool amdgpu_device_is_px(struct drm_device *dev); +bool amdgpu_device_supports_boco(struct drm_device *dev); +bool amdgpu_device_supports_baco(struct drm_device *dev); bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev, struct amdgpu_device *peer_adev); +int amdgpu_device_baco_enter(struct drm_device *dev); +int amdgpu_device_baco_exit(struct drm_device *dev); /* atpx handler */ #if defined(CONFIG_VGA_SWITCHEROO) @@ -1173,8 +1192,8 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv); void amdgpu_driver_postclose_kms(struct drm_device *dev, struct drm_file *file_priv); int amdgpu_device_ip_suspend(struct amdgpu_device *adev); -int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon); -int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon); +int amdgpu_device_suspend(struct drm_device *dev, bool fbcon); +int amdgpu_device_resume(struct drm_device *dev, bool fbcon); u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe); int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe); void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe); 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 47c853ef1051944c477f1ccc6d90b30b6ef734cd..6f1a4676dddee3aba12ea2a58ac417292372fda3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c @@ -40,7 +40,7 @@ #include "soc15d.h" #include "mmhub_v1_0.h" #include "gfxhub_v1_0.h" -#include "gmc_v9_0.h" +#include "mmhub_v9_4.h" enum hqd_dequeue_request_type { @@ -774,9 +774,7 @@ void kgd_gfx_v9_set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmi * on GFX8 and older. */ if (adev->asic_type == CHIP_ARCTURUS) { - /* Two MMHUBs */ - mmhub_v9_4_setup_vm_pt_regs(adev, 0, vmid, page_table_base); - mmhub_v9_4_setup_vm_pt_regs(adev, 1, vmid, page_table_base); + mmhub_v9_4_setup_vm_pt_regs(adev, vmid, page_table_base); } else mmhub_v1_0_setup_vm_pt_regs(adev, vmid, 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 888209eb8cecd5b27b7ca68331f38364cd18d2f1..b2487f4f271b1d87d23596b6a884abcab62e56c1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -85,7 +85,7 @@ static bool check_if_add_bo_to_vm(struct amdgpu_vm *avm, } /* Set memory usage limits. Current, limits are - * System (TTM + userptr) memory - 3/4th System RAM + * System (TTM + userptr) memory - 15/16th System RAM * TTM memory - 3/8th System RAM */ void amdgpu_amdkfd_gpuvm_init_mem_limits(void) @@ -98,7 +98,7 @@ void amdgpu_amdkfd_gpuvm_init_mem_limits(void) mem *= si.mem_unit; spin_lock_init(&kfd_mem_limit.mem_limit_lock); - kfd_mem_limit.max_system_mem_limit = (mem >> 1) + (mem >> 2); + kfd_mem_limit.max_system_mem_limit = mem - (mem >> 4); kfd_mem_limit.max_ttm_mem_limit = (mem >> 1) - (mem >> 3); pr_debug("Kernel memory limit %lluM, TTM limit %lluM\n", (kfd_mem_limit.max_system_mem_limit >> 20), @@ -358,7 +358,7 @@ static int vm_update_pds(struct amdgpu_vm *vm, struct amdgpu_sync *sync) if (ret) return ret; - return amdgpu_sync_fence(NULL, sync, vm->last_update, false); + return amdgpu_sync_fence(sync, vm->last_update, false); } static uint64_t get_pte_flags(struct amdgpu_device *adev, struct kgd_mem *mem) @@ -750,7 +750,7 @@ static int unmap_bo_from_gpuvm(struct amdgpu_device *adev, amdgpu_vm_clear_freed(adev, vm, &bo_va->last_pt_update); - amdgpu_sync_fence(NULL, sync, bo_va->last_pt_update, false); + amdgpu_sync_fence(sync, bo_va->last_pt_update, false); return 0; } @@ -769,7 +769,7 @@ static int update_gpuvm_pte(struct amdgpu_device *adev, return ret; } - return amdgpu_sync_fence(NULL, sync, bo_va->last_pt_update, false); + return amdgpu_sync_fence(sync, bo_va->last_pt_update, false); } static int map_bo_to_gpuvm(struct amdgpu_device *adev, @@ -1674,10 +1674,10 @@ int amdgpu_amdkfd_evict_userptr(struct kgd_mem *mem, struct mm_struct *mm) { struct amdkfd_process_info *process_info = mem->process_info; - int invalid, evicted_bos; + int evicted_bos; int r = 0; - invalid = atomic_inc_return(&mem->invalid); + atomic_inc(&mem->invalid); evicted_bos = atomic_inc_return(&process_info->evicted_bos); if (evicted_bos == 1) { /* First eviction, stop the queues */ @@ -2048,7 +2048,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef) pr_debug("Memory eviction: Validate BOs failed. Try again\n"); goto validate_map_fail; } - ret = amdgpu_sync_fence(NULL, &sync_obj, bo->tbo.moving, false); + ret = amdgpu_sync_fence(&sync_obj, bo->tbo.moving, false); if (ret) { pr_debug("Memory eviction: Sync BO fence failed. Try again\n"); goto validate_map_fail; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c index 72232fccf61a75d5a90d9e56542395d7ede99f50..9ba80d828876e511544ab551c33c548f4520d758 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c @@ -338,17 +338,9 @@ bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device * path_size += le16_to_cpu(path->usSize); if (device_support & le16_to_cpu(path->usDeviceTag)) { - uint8_t con_obj_id, con_obj_num, con_obj_type; - - con_obj_id = + uint8_t con_obj_id = (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; - con_obj_num = - (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK) - >> ENUM_ID_SHIFT; - con_obj_type = - (le16_to_cpu(path->usConnObjectId) & - OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; /* Skip TV/CV support */ if ((le16_to_cpu(path->usDeviceTag) == @@ -373,15 +365,7 @@ bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device * router.ddc_valid = false; router.cd_valid = false; for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) { - uint8_t grph_obj_id, grph_obj_num, grph_obj_type; - - grph_obj_id = - (le16_to_cpu(path->usGraphicObjIds[j]) & - OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; - grph_obj_num = - (le16_to_cpu(path->usGraphicObjIds[j]) & - ENUM_ID_MASK) >> ENUM_ID_SHIFT; - grph_obj_type = + uint8_t grph_obj_type = (le16_to_cpu(path->usGraphicObjIds[j]) & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 5ca905b4a0fb8a885c07ee1164aba7136baabd60..5b330f69194b4e7b243008191082bb8d5b8ea540 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -795,29 +795,23 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) if (r) return r; - r = amdgpu_sync_fence(adev, &p->job->sync, - fpriv->prt_va->last_pt_update, false); + r = amdgpu_sync_vm_fence(&p->job->sync, fpriv->prt_va->last_pt_update); if (r) return r; if (amdgpu_mcbp || amdgpu_sriov_vf(adev)) { - struct dma_fence *f; - bo_va = fpriv->csa_va; BUG_ON(!bo_va); r = amdgpu_vm_bo_update(adev, bo_va, false); if (r) return r; - f = bo_va->last_pt_update; - r = amdgpu_sync_fence(adev, &p->job->sync, f, false); + r = amdgpu_sync_vm_fence(&p->job->sync, bo_va->last_pt_update); if (r) return r; } amdgpu_bo_list_for_each_entry(e, p->bo_list) { - struct dma_fence *f; - /* ignore duplicates */ bo = ttm_to_amdgpu_bo(e->tv.bo); if (!bo) @@ -831,8 +825,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) if (r) return r; - f = bo_va->last_pt_update; - r = amdgpu_sync_fence(adev, &p->job->sync, f, false); + r = amdgpu_sync_vm_fence(&p->job->sync, bo_va->last_pt_update); if (r) return r; } @@ -845,7 +838,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) if (r) return r; - r = amdgpu_sync_fence(adev, &p->job->sync, vm->last_update, false); + r = amdgpu_sync_vm_fence(&p->job->sync, vm->last_update); if (r) return r; @@ -987,7 +980,7 @@ static int amdgpu_cs_process_fence_dep(struct amdgpu_cs_parser *p, dma_fence_put(old); } - r = amdgpu_sync_fence(p->adev, &p->job->sync, fence, true); + r = amdgpu_sync_fence(&p->job->sync, fence, true); dma_fence_put(fence); if (r) return r; @@ -1009,7 +1002,7 @@ static int amdgpu_syncobj_lookup_and_add_to_sync(struct amdgpu_cs_parser *p, return r; } - r = amdgpu_sync_fence(p->adev, &p->job->sync, fence, true); + r = amdgpu_sync_fence(&p->job->sync, fence, true); dma_fence_put(fence); return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index 2cdaf3b2a72170c5a638530dce89007e850735a8..1d2bbf10614e5faa308b1fcc063345bc0836738f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -169,10 +169,10 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev, } break; case AMDGPU_HW_IP_VCN_JPEG: - for (j = 0; j < adev->vcn.num_vcn_inst; ++j) { - if (adev->vcn.harvest_config & (1 << j)) + for (j = 0; j < adev->jpeg.num_jpeg_inst; ++j) { + if (adev->jpeg.harvest_config & (1 << j)) continue; - rings[num_rings++] = &adev->vcn.inst[j].ring_jpeg; + rings[num_rings++] = &adev->jpeg.inst[j].ring_dec; } break; } @@ -604,11 +604,8 @@ void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) continue; } - for (i = 0; i < num_entities; i++) { - mutex_lock(&ctx->adev->lock_reset); + for (i = 0; i < num_entities; i++) drm_sched_entity_fini(&ctx->entities[0][i].entity); - mutex_unlock(&ctx->adev->lock_reset); - } } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index c17505fba98849b2d632fe7afb0240dbbef58c8c..a979468780248bb4794da4ad469e96c901318eea 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -137,14 +137,14 @@ static DEVICE_ATTR(pcie_replay_count, S_IRUGO, static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev); /** - * amdgpu_device_is_px - Is the device is a dGPU with HG/PX power control + * amdgpu_device_supports_boco - Is the device a dGPU with HG/PX power control * * @dev: drm_device pointer * * Returns true if the device is a dGPU with HG/PX power control, * otherwise return false. */ -bool amdgpu_device_is_px(struct drm_device *dev) +bool amdgpu_device_supports_boco(struct drm_device *dev) { struct amdgpu_device *adev = dev->dev_private; @@ -153,6 +153,21 @@ bool amdgpu_device_is_px(struct drm_device *dev) return false; } +/** + * amdgpu_device_supports_baco - Does the device support BACO + * + * @dev: drm_device pointer + * + * Returns true if the device supporte BACO, + * otherwise return false. + */ +bool amdgpu_device_supports_baco(struct drm_device *dev) +{ + struct amdgpu_device *adev = dev->dev_private; + + return amdgpu_asic_supports_baco(adev); +} + /** * VRAM access helper functions. * @@ -1072,8 +1087,9 @@ static int amdgpu_device_check_arguments(struct amdgpu_device *adev) 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; - if (amdgpu_device_is_px(dev) && state == VGA_SWITCHEROO_OFF) + if (amdgpu_device_supports_boco(dev) && state == VGA_SWITCHEROO_OFF) return; if (state == VGA_SWITCHEROO_ON) { @@ -1081,7 +1097,12 @@ static void amdgpu_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero /* don't suspend or resume card normally */ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; - amdgpu_device_resume(dev, true, true); + pci_set_power_state(dev->pdev, PCI_D0); + pci_restore_state(dev->pdev); + r = pci_enable_device(dev->pdev); + if (r) + DRM_WARN("pci_enable_device failed (%d)\n", r); + amdgpu_device_resume(dev, true); dev->switch_power_state = DRM_SWITCH_POWER_ON; drm_kms_helper_poll_enable(dev); @@ -1089,7 +1110,11 @@ static void amdgpu_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero pr_info("amdgpu: switched off\n"); drm_kms_helper_poll_disable(dev); dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; - amdgpu_device_suspend(dev, true, true); + amdgpu_device_suspend(dev, true); + pci_save_state(dev->pdev); + /* Shut down the device */ + pci_disable_device(dev->pdev); + pci_set_power_state(dev->pdev, PCI_D3cold); dev->switch_power_state = DRM_SWITCH_POWER_OFF; } } @@ -1527,7 +1552,6 @@ static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev) } parse_soc_bounding_box: -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 /* * soc bounding box info is not integrated in disocovery table, * we always need to parse it from gpu info firmware. @@ -1538,7 +1562,6 @@ parse_soc_bounding_box: le32_to_cpu(hdr->header.ucode_array_offset_bytes)); adev->dm.soc_bounding_box = &gpu_info_fw->soc_bounding_box; } -#endif break; } default: @@ -1854,6 +1877,9 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) } } + if (amdgpu_sriov_vf(adev)) + amdgpu_virt_init_data_exchange(adev); + r = amdgpu_ib_pool_init(adev); if (r) { dev_err(adev->dev, "IB initialization failed (%d).\n", r); @@ -1895,11 +1921,8 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) amdgpu_amdkfd_device_init(adev); init_failed: - if (amdgpu_sriov_vf(adev)) { - if (!r) - amdgpu_virt_init_data_exchange(adev); + if (amdgpu_sriov_vf(adev)) amdgpu_virt_release_full_gpu(adev, true); - } return r; } @@ -1938,6 +1961,7 @@ static bool amdgpu_device_check_vram_lost(struct amdgpu_device *adev) * amdgpu_device_set_cg_state - set clockgating for amdgpu device * * @adev: amdgpu_device pointer + * @state: clockgating state (gate or ungate) * * The list of all the hardware IPs that make up the asic is walked and the * set_clockgating_state callbacks are run. @@ -1962,6 +1986,7 @@ static int amdgpu_device_set_cg_state(struct amdgpu_device *adev, if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD && adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE && adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCN && + adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_JPEG && adev->ip_blocks[i].version->funcs->set_clockgating_state) { /* enable clockgating to save power */ r = adev->ip_blocks[i].version->funcs->set_clockgating_state((void *)adev, @@ -1992,6 +2017,7 @@ static int amdgpu_device_set_pg_state(struct amdgpu_device *adev, enum amd_power if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD && adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE && adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCN && + adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_JPEG && adev->ip_blocks[i].version->funcs->set_powergating_state) { /* enable powergating to save power */ r = adev->ip_blocks[i].version->funcs->set_powergating_state((void *)adev, @@ -2600,20 +2626,19 @@ bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type) case CHIP_VEGA10: case CHIP_VEGA12: case CHIP_VEGA20: -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) case CHIP_RAVEN: -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) case CHIP_NAVI10: case CHIP_NAVI14: case CHIP_NAVI12: -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) case CHIP_RENOIR: #endif return amdgpu_dc != 0; #endif default: + if (amdgpu_dc > 0) + DRM_INFO("Display Core has been requested via kernel parameter " + "but isn't supported by ASIC, ignoring\n"); return false; } } @@ -2639,7 +2664,13 @@ static void amdgpu_device_xgmi_reset_func(struct work_struct *__work) struct amdgpu_device *adev = container_of(__work, struct amdgpu_device, xgmi_reset_work); - adev->asic_reset_res = amdgpu_asic_reset(adev); + if (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO) + adev->asic_reset_res = (adev->in_baco == false) ? + amdgpu_device_baco_enter(adev->ddev) : + amdgpu_device_baco_exit(adev->ddev); + else + adev->asic_reset_res = amdgpu_asic_reset(adev); + if (adev->asic_reset_res) DRM_WARN("ASIC reset failed with error, %d for drm dev, %s", adev->asic_reset_res, adev->ddev->unique); @@ -2731,7 +2762,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, uint32_t flags) { int r, i; - bool runtime = false; + bool boco = false; u32 max_MBps; adev->shutdown = false; @@ -2794,8 +2825,6 @@ int amdgpu_device_init(struct amdgpu_device *adev, mutex_init(&adev->virt.vf_errors.lock); hash_init(adev->mn_hash); mutex_init(&adev->lock_reset); - mutex_init(&adev->notifier_lock); - mutex_init(&adev->virt.dpm_mutex); mutex_init(&adev->psp.mutex); r = amdgpu_device_check_arguments(adev); @@ -2902,12 +2931,15 @@ int amdgpu_device_init(struct amdgpu_device *adev, * ignore it */ vga_client_register(adev->pdev, adev, NULL, amdgpu_device_vga_set_decode); - if (amdgpu_device_is_px(ddev)) - runtime = true; - if (!pci_is_thunderbolt_attached(adev->pdev)) + if (amdgpu_device_supports_boco(ddev)) + boco = true; + if (amdgpu_has_atpx() && + (amdgpu_is_atpx_hybrid() || + amdgpu_has_atpx_dgpu_power_cntl()) && + !pci_is_thunderbolt_attached(adev->pdev)) vga_switcheroo_register_client(adev->pdev, - &amdgpu_switcheroo_ops, runtime); - if (runtime) + &amdgpu_switcheroo_ops, boco); + if (boco) vga_switcheroo_init_domain_pm_ops(adev->dev, &adev->vga_pm_domain); if (amdgpu_emu_mode == 1) { @@ -2994,8 +3026,6 @@ fence_driver_init: } dev_err(adev->dev, "amdgpu_device_ip_init failed\n"); amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_AMDGPU_INIT_FAIL, 0, 0); - if (amdgpu_virt_request_full_gpu(adev, false)) - amdgpu_virt_release_full_gpu(adev, false); goto failed; } @@ -3013,16 +3043,19 @@ fence_driver_init: amdgpu_fbdev_init(adev); - if (amdgpu_sriov_vf(adev) && amdgim_is_hwperf(adev)) - amdgpu_pm_virt_sysfs_init(adev); - r = amdgpu_pm_sysfs_init(adev); - if (r) + if (r) { + adev->pm_sysfs_en = false; DRM_ERROR("registering pm debugfs failed (%d).\n", r); + } else + adev->pm_sysfs_en = true; r = amdgpu_ucode_sysfs_init(adev); - if (r) + if (r) { + adev->ucode_sysfs_en = false; DRM_ERROR("Creating firmware sysfs failed (%d).\n", r); + } else + adev->ucode_sysfs_en = true; r = amdgpu_debugfs_gem_init(adev); if (r) @@ -3091,7 +3124,7 @@ fence_driver_init: failed: amdgpu_vf_error_trans_all(adev); - if (runtime) + if (boco) vga_switcheroo_fini_domain_pm_ops(adev->dev); return r; @@ -3122,7 +3155,8 @@ void amdgpu_device_fini(struct amdgpu_device *adev) drm_atomic_helper_shutdown(adev->ddev); } amdgpu_fence_driver_fini(adev); - amdgpu_pm_sysfs_fini(adev); + if (adev->pm_sysfs_en) + amdgpu_pm_sysfs_fini(adev); amdgpu_fbdev_fini(adev); r = amdgpu_device_ip_fini(adev); if (adev->firmware.gpu_info_fw) { @@ -3139,9 +3173,12 @@ void amdgpu_device_fini(struct amdgpu_device *adev) kfree(adev->bios); adev->bios = NULL; - if (!pci_is_thunderbolt_attached(adev->pdev)) + if (amdgpu_has_atpx() && + (amdgpu_is_atpx_hybrid() || + amdgpu_has_atpx_dgpu_power_cntl()) && + !pci_is_thunderbolt_attached(adev->pdev)) vga_switcheroo_unregister_client(adev->pdev); - if (adev->flags & AMD_IS_PX) + if (amdgpu_device_supports_boco(adev->ddev)) vga_switcheroo_fini_domain_pm_ops(adev->dev); vga_client_register(adev->pdev, NULL, NULL, NULL); if (adev->rio_mem) @@ -3150,12 +3187,11 @@ void amdgpu_device_fini(struct amdgpu_device *adev) iounmap(adev->rmmio); adev->rmmio = NULL; amdgpu_device_doorbell_fini(adev); - if (amdgpu_sriov_vf(adev) && amdgim_is_hwperf(adev)) - amdgpu_pm_virt_sysfs_fini(adev); amdgpu_debugfs_regs_cleanup(adev); device_remove_file(adev->dev, &dev_attr_pcie_replay_count); - amdgpu_ucode_sysfs_fini(adev); + if (adev->ucode_sysfs_en) + amdgpu_ucode_sysfs_fini(adev); if (IS_ENABLED(CONFIG_PERF_EVENTS)) amdgpu_pmu_fini(adev); amdgpu_debugfs_preempt_cleanup(adev); @@ -3178,7 +3214,7 @@ void amdgpu_device_fini(struct amdgpu_device *adev) * Returns 0 for success or an error on failure. * Called at driver suspend. */ -int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon) +int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) { struct amdgpu_device *adev; struct drm_crtc *crtc; @@ -3261,13 +3297,6 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon) */ amdgpu_bo_evict_vram(adev); - if (suspend) { - pci_save_state(dev->pdev); - /* Shut down the device */ - pci_disable_device(dev->pdev); - pci_set_power_state(dev->pdev, PCI_D3hot); - } - return 0; } @@ -3282,7 +3311,7 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon) * Returns 0 for success or an error on failure. * Called at driver resume. */ -int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon) +int amdgpu_device_resume(struct drm_device *dev, bool fbcon) { struct drm_connector *connector; struct drm_connector_list_iter iter; @@ -3293,14 +3322,6 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon) if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; - if (resume) { - pci_set_power_state(dev->pdev, PCI_D0); - pci_restore_state(dev->pdev); - r = pci_enable_device(dev->pdev); - if (r) - return r; - } - /* post card */ if (amdgpu_device_need_post(adev)) { r = amdgpu_atom_asic_init(adev->mode_info.atom_context); @@ -3646,6 +3667,7 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev, if (r) goto error; + 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]); @@ -3663,7 +3685,6 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev, amdgpu_amdkfd_post_reset(adev); error: - amdgpu_virt_init_data_exchange(adev); amdgpu_virt_release_full_gpu(adev, true); if (!r && adev->virt.gim_feature & AMDGIM_FEATURE_GIM_FLR_VRAMLOST) { amdgpu_inc_vram_lost(adev); @@ -3769,13 +3790,18 @@ static int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, return r; } -static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, +static int amdgpu_do_asic_reset(struct amdgpu_device *adev, + struct amdgpu_hive_info *hive, struct list_head *device_list_handle, bool *need_full_reset_arg) { struct amdgpu_device *tmp_adev = NULL; bool need_full_reset = *need_full_reset_arg, vram_lost = false; int r = 0; + int cpu = smp_processor_id(); + bool use_baco = + (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO) ? + true : false; /* * ASIC reset has to be done on all HGMI hive nodes ASAP @@ -3783,21 +3809,24 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, */ if (need_full_reset) { list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { - /* For XGMI run all resets in parallel to speed up the process */ + /* + * For XGMI run all resets in parallel to speed up the + * process by scheduling the highpri wq on different + * cpus. For XGMI with baco reset, all nodes must enter + * baco within close proximity before anyone exit. + */ if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) { - if (!queue_work(system_highpri_wq, &tmp_adev->xgmi_reset_work)) + if (!queue_work_on(cpu, system_highpri_wq, + &tmp_adev->xgmi_reset_work)) r = -EALREADY; + cpu = cpumask_next(cpu, cpu_online_mask); } else 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); + if (r) break; - } } - /* For XGMI wait for all PSP resets to complete before proceed */ + /* For XGMI wait for all work to complete before proceed */ if (!r) { list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { @@ -3806,11 +3835,57 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, r = tmp_adev->asic_reset_res; if (r) break; + if (use_baco) + tmp_adev->in_baco = true; + } + } + } + + /* + * For XGMI with baco reset, need exit baco phase by scheduling + * xgmi_reset_work one more time. PSP reset and sGPU skips this + * phase. Not assume the situation that PSP reset and baco reset + * coexist within an XGMI hive. + */ + + if (!r && use_baco) { + cpu = smp_processor_id(); + list_for_each_entry(tmp_adev, device_list_handle, + gmc.xgmi.head) { + if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) { + if (!queue_work_on(cpu, + system_highpri_wq, + &tmp_adev->xgmi_reset_work)) + r = -EALREADY; + if (r) + break; + cpu = cpumask_next(cpu, cpu_online_mask); + } + } + } + + if (!r && use_baco) { + list_for_each_entry(tmp_adev, device_list_handle, + gmc.xgmi.head) { + if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) { + flush_work(&tmp_adev->xgmi_reset_work); + r = tmp_adev->asic_reset_res; + if (r) + break; + tmp_adev->in_baco = false; } } } + + if (r) { + DRM_ERROR("ASIC reset failed with error, %d for drm dev, %s", + r, tmp_adev->ddev->unique); + goto end; + } } + if (!r && amdgpu_ras_intr_triggered()) + amdgpu_ras_intr_cleared(); list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { if (need_full_reset) { @@ -3943,12 +4018,15 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, struct amdgpu_device *tmp_adev = NULL; int i, r = 0; bool in_ras_intr = amdgpu_ras_intr_triggered(); + bool use_baco = + (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO) ? + true : false; /* * Flush RAM to disk so that after reboot * the user can read log and see why the system rebooted. */ - if (in_ras_intr && amdgpu_ras_get_context(adev)->reboot) { + if (in_ras_intr && !use_baco && amdgpu_ras_get_context(adev)->reboot) { DRM_WARN("Emergency reboot."); @@ -3959,7 +4037,8 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, need_full_reset = job_signaled = false; INIT_LIST_HEAD(&device_list); - dev_info(adev->dev, "GPU %s begin!\n", in_ras_intr ? "jobs stop":"reset"); + dev_info(adev->dev, "GPU %s begin!\n", + (in_ras_intr && !use_baco) ? "jobs stop":"reset"); cancel_delayed_work_sync(&adev->delayed_init_work); @@ -4026,7 +4105,8 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, amdgpu_unregister_gpu_instance(tmp_adev); /* disable ras on ALL IPs */ - if (!in_ras_intr && amdgpu_device_ip_need_full_reset(tmp_adev)) + if (!(in_ras_intr && !use_baco) && + amdgpu_device_ip_need_full_reset(tmp_adev)) amdgpu_ras_suspend(tmp_adev); for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { @@ -4037,13 +4117,13 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, drm_sched_stop(&ring->sched, job ? &job->base : NULL); - if (in_ras_intr) + if (in_ras_intr && !use_baco) amdgpu_job_stop_all_jobs_on_sched(&ring->sched); } } - if (in_ras_intr) + if (in_ras_intr && !use_baco) goto skip_sched_resume; /* @@ -4095,7 +4175,8 @@ retry: /* Rest of adevs pre asic reset from XGMI hive. */ if (r) adev->asic_reset_res = r; } else { - r = amdgpu_do_asic_reset(hive, device_list_handle, &need_full_reset); + r = amdgpu_do_asic_reset(adev, hive, device_list_handle, + &need_full_reset); if (r && r == -EAGAIN) goto retry; } @@ -4136,7 +4217,7 @@ skip_hw_reset: skip_sched_resume: list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { /*unlock kfd: SRIOV would do it separately */ - if (!in_ras_intr && !amdgpu_sriov_vf(tmp_adev)) + if (!(in_ras_intr && !use_baco) && !amdgpu_sriov_vf(tmp_adev)) amdgpu_amdkfd_post_reset(tmp_adev); amdgpu_device_unlock_adev(tmp_adev); } @@ -4285,3 +4366,69 @@ 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_ras *ras = amdgpu_ras_get_context(adev); + + if (!amdgpu_device_supports_baco(adev->ddev)) + return -ENOTSUPP; + + if (ras && ras->supported) + adev->nbio.funcs->enable_doorbell_interrupt(adev, false); + + if (is_support_sw_smu(adev)) { + struct smu_context *smu = &adev->smu; + int ret; + + ret = smu_baco_enter(smu); + if (ret) + return ret; + } else { + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs ||!pp_funcs->get_asic_baco_state ||!pp_funcs->set_asic_baco_state) + return -ENOENT; + + /* enter BACO state */ + if (pp_funcs->set_asic_baco_state(pp_handle, 1)) + return -EIO; + } + + return 0; +} + +int amdgpu_device_baco_exit(struct drm_device *dev) +{ + struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); + + if (!amdgpu_device_supports_baco(adev->ddev)) + return -ENOTSUPP; + + if (is_support_sw_smu(adev)) { + struct smu_context *smu = &adev->smu; + int ret; + + ret = smu_baco_exit(smu); + if (ret) + return ret; + + } else { + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs ||!pp_funcs->get_asic_baco_state ||!pp_funcs->set_asic_baco_state) + return -ENOENT; + + /* exit BACO state */ + if (pp_funcs->set_asic_baco_state(pp_handle, 0)) + return -EIO; + } + + if (ras && ras->supported) + adev->nbio.funcs->enable_doorbell_interrupt(adev, true); + + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 3cadb0b76f221c026611a89c605944afeb6205cb..4e699071d1443deefe71aaf3841ac6f6b7bd0788 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -690,7 +690,6 @@ bool amdgpu_display_crtc_scaling_mode_fixup(struct drm_crtc *crtc, struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct amdgpu_encoder *amdgpu_encoder; struct drm_connector *connector; - struct amdgpu_connector *amdgpu_connector; u32 src_v = 1, dst_v = 1; u32 src_h = 1, dst_h = 1; @@ -702,7 +701,6 @@ bool amdgpu_display_crtc_scaling_mode_fixup(struct drm_crtc *crtc, continue; amdgpu_encoder = to_amdgpu_encoder(encoder); connector = amdgpu_get_connector_for_encoder(encoder); - amdgpu_connector = to_amdgpu_connector(connector); /* set scaling */ if (amdgpu_encoder->rmx_type == RMX_OFF) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index e2eec7b6633407916513249f7826d10e2a4eba65..a59cd47aa6c1e0f4ee162fe940361361bdb37004 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -360,10 +360,8 @@ struct dma_buf *amdgpu_gem_prime_export(struct drm_gem_object *gobj, return ERR_PTR(-EPERM); buf = drm_gem_prime_export(gobj, flags); - if (!IS_ERR(buf)) { - buf->file->f_mapping = gobj->dev->anon_inode->i_mapping; + if (!IS_ERR(buf)) buf->ops = &amdgpu_dmabuf_ops; - } return buf; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 0ffc9447b573a3f532d1fb37337d240052bdaa18..3f6f14ce1511a9bc1ff2741226690c64c1206d4b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -1147,7 +1147,7 @@ static int amdgpu_pmops_suspend(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); - return amdgpu_device_suspend(drm_dev, true, true); + return amdgpu_device_suspend(drm_dev, true); } static int amdgpu_pmops_resume(struct device *dev) @@ -1155,13 +1155,14 @@ static int amdgpu_pmops_resume(struct device *dev) struct drm_device *drm_dev = dev_get_drvdata(dev); /* GPU comes up enabled by the bios on resume */ - if (amdgpu_device_is_px(drm_dev)) { + if (amdgpu_device_supports_boco(drm_dev) || + amdgpu_device_supports_baco(drm_dev)) { pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); } - return amdgpu_device_resume(drm_dev, true, true); + return amdgpu_device_resume(drm_dev, true); } static int amdgpu_pmops_freeze(struct device *dev) @@ -1170,7 +1171,7 @@ static int amdgpu_pmops_freeze(struct device *dev) struct amdgpu_device *adev = drm_dev->dev_private; int r; - r = amdgpu_device_suspend(drm_dev, false, true); + r = amdgpu_device_suspend(drm_dev, true); if (r) return r; return amdgpu_asic_reset(adev); @@ -1180,46 +1181,56 @@ static int amdgpu_pmops_thaw(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); - return amdgpu_device_resume(drm_dev, false, true); + return amdgpu_device_resume(drm_dev, true); } static int amdgpu_pmops_poweroff(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); - return amdgpu_device_suspend(drm_dev, true, true); + return amdgpu_device_suspend(drm_dev, true); } static int amdgpu_pmops_restore(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); - return amdgpu_device_resume(drm_dev, false, true); + return amdgpu_device_resume(drm_dev, true); } 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; int ret; - if (!amdgpu_device_is_px(drm_dev)) { + if (!adev->runpm) { pm_runtime_forbid(dev); return -EBUSY; } - drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; + if (amdgpu_device_supports_boco(drm_dev)) + drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; drm_kms_helper_poll_disable(drm_dev); - ret = amdgpu_device_suspend(drm_dev, false, false); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_ignore_hotplug(pdev); - if (amdgpu_is_atpx_hybrid()) - pci_set_power_state(pdev, PCI_D3cold); - else if (!amdgpu_has_atpx_dgpu_power_cntl()) - pci_set_power_state(pdev, PCI_D3hot); - drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; + ret = amdgpu_device_suspend(drm_dev, false); + if (amdgpu_device_supports_boco(drm_dev)) { + /* Only need to handle PCI state in the driver for ATPX + * PCI core handles it for _PR3. + */ + if (amdgpu_is_atpx_hybrid()) { + pci_ignore_hotplug(pdev); + } else { + pci_save_state(pdev); + pci_disable_device(pdev); + pci_ignore_hotplug(pdev); + pci_set_power_state(pdev, PCI_D3cold); + } + drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; + } else if (amdgpu_device_supports_baco(drm_dev)) { + amdgpu_device_baco_enter(drm_dev); + } return 0; } @@ -1228,34 +1239,45 @@ 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; int ret; - if (!amdgpu_device_is_px(drm_dev)) + if (!adev->runpm) return -EINVAL; - drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; - - if (amdgpu_is_atpx_hybrid() || - !amdgpu_has_atpx_dgpu_power_cntl()) - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - ret = pci_enable_device(pdev); - if (ret) - return ret; - pci_set_master(pdev); - - ret = amdgpu_device_resume(drm_dev, false, false); + if (amdgpu_device_supports_boco(drm_dev)) { + drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; + + /* Only need to handle PCI state in the driver for ATPX + * PCI core handles it for _PR3. + */ + if (amdgpu_is_atpx_hybrid()) { + pci_set_master(pdev); + } else { + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + ret = pci_enable_device(pdev); + if (ret) + return ret; + pci_set_master(pdev); + } + } else if (amdgpu_device_supports_baco(drm_dev)) { + amdgpu_device_baco_exit(drm_dev); + } + ret = amdgpu_device_resume(drm_dev, false); drm_kms_helper_poll_enable(drm_dev); - drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; + if (amdgpu_device_supports_boco(drm_dev)) + drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; return 0; } 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 drm_crtc *crtc; - if (!amdgpu_device_is_px(drm_dev)) { + if (!adev->runpm) { pm_runtime_forbid(dev); return -EBUSY; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index 143753d237e7c697d51259724259177fe293a2cf..2672dc64a3101a220e4e8b2cf4d1f6dbf3901b95 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -69,7 +69,7 @@ amdgpufb_release(struct fb_info *info, int user) return 0; } -static struct fb_ops amdgpufb_ops = { +static const struct fb_ops amdgpufb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, .fb_open = amdgpufb_open, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index 19705e399905b5dacd1a8abeb64276f213d91054..e01e681d2a600ca9e7a3c9405ef931a90a6fb8b6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -302,6 +302,7 @@ int amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset, * @pages: number of pages to bind * @pagelist: pages to bind * @dma_addr: DMA addresses of pages + * @flags: page table entry flags * * Binds the requested pages to the gart page table * (all asics). diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index 6f9289735e31a368b852af71c9ec6f3af280f6a6..3a67f6c046d4d4579cfb63bcfd20f4f4e35027db 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -206,7 +206,7 @@ static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm, int r; if (ring->vmid_wait && !dma_fence_is_signaled(ring->vmid_wait)) - return amdgpu_sync_fence(adev, sync, ring->vmid_wait, false); + return amdgpu_sync_fence(sync, ring->vmid_wait, false); fences = kmalloc_array(sizeof(void *), id_mgr->num_ids, GFP_KERNEL); if (!fences) @@ -241,7 +241,7 @@ static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm, return -ENOMEM; } - r = amdgpu_sync_fence(adev, sync, &array->base, false); + r = amdgpu_sync_fence(sync, &array->base, false); dma_fence_put(ring->vmid_wait); ring->vmid_wait = &array->base; return r; @@ -294,7 +294,7 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm, tmp = amdgpu_sync_peek_fence(&(*id)->active, ring); if (tmp) { *id = NULL; - r = amdgpu_sync_fence(adev, sync, tmp, false); + r = amdgpu_sync_fence(sync, tmp, false); return r; } needs_flush = true; @@ -303,7 +303,7 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm, /* Good we can use this VMID. Remember this submission as * user of the VMID. */ - r = amdgpu_sync_fence(ring->adev, &(*id)->active, fence, false); + r = amdgpu_sync_fence(&(*id)->active, fence, false); if (r) return r; @@ -375,7 +375,7 @@ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm, /* Good, we can use this VMID. Remember this submission as * user of the VMID. */ - r = amdgpu_sync_fence(ring->adev, &(*id)->active, fence, false); + r = amdgpu_sync_fence(&(*id)->active, fence, false); if (r) return r; @@ -435,8 +435,7 @@ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring, id = idle; /* Remember this submission as user of the VMID */ - r = amdgpu_sync_fence(ring->adev, &id->active, - fence, false); + r = amdgpu_sync_fence(&id->active, fence, false); if (r) goto error; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c index 6d8f05511ababb761d8bd97cf3cbb72a00720fd1..111a301ce878b2a619e7b4849fcd5f787497a631 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c @@ -66,7 +66,6 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih, if (ih->ring == NULL) return -ENOMEM; - memset((void *)ih->ring, 0, ih->ring_size + 8); ih->gpu_addr = dma_addr; ih->wptr_addr = dma_addr + ih->ring_size; ih->wptr_cpu = &ih->ring[ih->ring_size / 4]; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c index 30d540d23b778a0ac01a2224988730cd7b38f042..5ed4227f304bd49050139505622cdf2673878e8a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c @@ -55,6 +55,7 @@ #include "amdgpu_connectors.h" #include "amdgpu_trace.h" #include "amdgpu_amdkfd.h" +#include "amdgpu_ras.h" #include @@ -162,13 +163,15 @@ irqreturn_t amdgpu_irq_handler(int irq, void *arg) * register to check whether the interrupt is triggered or not, and properly * ack the interrupt if it is there */ - if (adev->nbio.funcs && - adev->nbio.funcs->handle_ras_controller_intr_no_bifring) - adev->nbio.funcs->handle_ras_controller_intr_no_bifring(adev); - - if (adev->nbio.funcs && - adev->nbio.funcs->handle_ras_err_event_athub_intr_no_bifring) - adev->nbio.funcs->handle_ras_err_event_athub_intr_no_bifring(adev); + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__PCIE_BIF)) { + if (adev->nbio.funcs && + adev->nbio.funcs->handle_ras_controller_intr_no_bifring) + adev->nbio.funcs->handle_ras_controller_intr_no_bifring(adev); + + if (adev->nbio.funcs && + adev->nbio.funcs->handle_ras_err_event_athub_intr_no_bifring) + adev->nbio.funcs->handle_ras_err_event_athub_intr_no_bifring(adev); + } return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 4fb20e870e635bb45e635ed2a0e66d1284a59aab..73328d0c741da6f146aac152c86a8d6acd5bb167 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -193,8 +193,7 @@ static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job, fence = amdgpu_sync_get_fence(&job->sync, &explicit); if (fence && explicit) { if (drm_sched_dependency_optimized(fence, s_entity)) { - r = amdgpu_sync_fence(ring->adev, &job->sched_sync, - fence, false); + r = amdgpu_sync_fence(&job->sched_sync, fence, false); if (r) DRM_ERROR("Error adding fence (%d)\n", r); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c new file mode 100644 index 0000000000000000000000000000000000000000..5727f00afc8e6503647256cb171473eb0670aeda --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c @@ -0,0 +1,211 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + */ + +#include "amdgpu.h" +#include "amdgpu_jpeg.h" +#include "amdgpu_pm.h" +#include "soc15d.h" +#include "soc15_common.h" + +#define JPEG_IDLE_TIMEOUT msecs_to_jiffies(1000) + +static void amdgpu_jpeg_idle_work_handler(struct work_struct *work); + +int amdgpu_jpeg_sw_init(struct amdgpu_device *adev) +{ + INIT_DELAYED_WORK(&adev->jpeg.idle_work, amdgpu_jpeg_idle_work_handler); + + return 0; +} + +int amdgpu_jpeg_sw_fini(struct amdgpu_device *adev) +{ + int i; + + cancel_delayed_work_sync(&adev->jpeg.idle_work); + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + if (adev->jpeg.harvest_config & (1 << i)) + continue; + + amdgpu_ring_fini(&adev->jpeg.inst[i].ring_dec); + } + + return 0; +} + +int amdgpu_jpeg_suspend(struct amdgpu_device *adev) +{ + cancel_delayed_work_sync(&adev->jpeg.idle_work); + + return 0; +} + +int amdgpu_jpeg_resume(struct amdgpu_device *adev) +{ + return 0; +} + +static void amdgpu_jpeg_idle_work_handler(struct work_struct *work) +{ + struct amdgpu_device *adev = + container_of(work, struct amdgpu_device, jpeg.idle_work.work); + unsigned int fences = 0; + unsigned int i; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + if (adev->jpeg.harvest_config & (1 << i)) + continue; + + fences += amdgpu_fence_count_emitted(&adev->jpeg.inst[i].ring_dec); + } + + if (fences == 0) + amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_JPEG, + AMD_PG_STATE_GATE); + else + schedule_delayed_work(&adev->jpeg.idle_work, JPEG_IDLE_TIMEOUT); +} + +void amdgpu_jpeg_ring_begin_use(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + bool set_clocks = !cancel_delayed_work_sync(&adev->jpeg.idle_work); + + if (set_clocks) + amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_JPEG, + AMD_PG_STATE_UNGATE); +} + +void amdgpu_jpeg_ring_end_use(struct amdgpu_ring *ring) +{ + schedule_delayed_work(&ring->adev->jpeg.idle_work, JPEG_IDLE_TIMEOUT); +} + +int amdgpu_jpeg_dec_ring_test_ring(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + uint32_t tmp = 0; + unsigned i; + int r; + + WREG32(adev->jpeg.inst[ring->me].external.jpeg_pitch, 0xCAFEDEAD); + r = amdgpu_ring_alloc(ring, 3); + if (r) + return r; + + amdgpu_ring_write(ring, PACKET0(adev->jpeg.internal.jpeg_pitch, 0)); + amdgpu_ring_write(ring, 0xDEADBEEF); + amdgpu_ring_commit(ring); + + for (i = 0; i < adev->usec_timeout; i++) { + tmp = RREG32(adev->jpeg.inst[ring->me].external.jpeg_pitch); + if (tmp == 0xDEADBEEF) + break; + udelay(1); + } + + if (i >= adev->usec_timeout) + r = -ETIMEDOUT; + + return r; +} + +static int amdgpu_jpeg_dec_set_reg(struct amdgpu_ring *ring, uint32_t handle, + struct dma_fence **fence) +{ + struct amdgpu_device *adev = ring->adev; + struct amdgpu_job *job; + struct amdgpu_ib *ib; + struct dma_fence *f = NULL; + const unsigned ib_size_dw = 16; + int i, r; + + r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, &job); + if (r) + return r; + + ib = &job->ibs[0]; + + ib->ptr[0] = PACKETJ(adev->jpeg.internal.jpeg_pitch, 0, 0, PACKETJ_TYPE0); + ib->ptr[1] = 0xDEADBEEF; + for (i = 2; i < 16; i += 2) { + ib->ptr[i] = PACKETJ(0, 0, 0, PACKETJ_TYPE6); + ib->ptr[i+1] = 0; + } + ib->length_dw = 16; + + r = amdgpu_job_submit_direct(job, ring, &f); + if (r) + goto err; + + if (fence) + *fence = dma_fence_get(f); + dma_fence_put(f); + + return 0; + +err: + amdgpu_job_free(job); + return r; +} + +int amdgpu_jpeg_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout) +{ + struct amdgpu_device *adev = ring->adev; + uint32_t tmp = 0; + unsigned i; + struct dma_fence *fence = NULL; + long r = 0; + + r = amdgpu_jpeg_dec_set_reg(ring, 1, &fence); + if (r) + goto error; + + r = dma_fence_wait_timeout(fence, false, timeout); + if (r == 0) { + r = -ETIMEDOUT; + goto error; + } else if (r < 0) { + goto error; + } else { + r = 0; + } + + for (i = 0; i < adev->usec_timeout; i++) { + tmp = RREG32(adev->jpeg.inst[ring->me].external.jpeg_pitch); + if (tmp == 0xDEADBEEF) + break; + udelay(1); + } + + if (i >= adev->usec_timeout) + r = -ETIMEDOUT; + + dma_fence_put(fence); +error: + return r; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h new file mode 100644 index 0000000000000000000000000000000000000000..5131a0a1bc8aa90c8c9dde5482ff466ee0ce8977 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h @@ -0,0 +1,62 @@ +/* + * Copyright 2019 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_JPEG_H__ +#define __AMDGPU_JPEG_H__ + +#define AMDGPU_MAX_JPEG_INSTANCES 2 + +#define AMDGPU_JPEG_HARVEST_JPEG0 (1 << 0) +#define AMDGPU_JPEG_HARVEST_JPEG1 (1 << 1) + +struct amdgpu_jpeg_reg{ + unsigned jpeg_pitch; +}; + +struct amdgpu_jpeg_inst { + struct amdgpu_ring ring_dec; + struct amdgpu_irq_src irq; + struct amdgpu_jpeg_reg external; +}; + +struct amdgpu_jpeg { + uint8_t num_jpeg_inst; + struct amdgpu_jpeg_inst inst[AMDGPU_MAX_JPEG_INSTANCES]; + struct amdgpu_jpeg_reg internal; + unsigned harvest_config; + struct delayed_work idle_work; + enum amd_powergating_state cur_state; +}; + +int amdgpu_jpeg_sw_init(struct amdgpu_device *adev); +int amdgpu_jpeg_sw_fini(struct amdgpu_device *adev); +int amdgpu_jpeg_suspend(struct amdgpu_device *adev); +int amdgpu_jpeg_resume(struct amdgpu_device *adev); + +void amdgpu_jpeg_ring_begin_use(struct amdgpu_ring *ring); +void amdgpu_jpeg_ring_end_use(struct amdgpu_ring *ring); + +int amdgpu_jpeg_dec_ring_test_ring(struct amdgpu_ring *ring); +int amdgpu_jpeg_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout); + +#endif /*__AMDGPU_JPEG_H__*/ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index b6db28a570c2cf4bb70a567dcbdee3526db64d91..60591dbc2097ecbbb8611e791b950cdd82b3596a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -91,7 +91,7 @@ void amdgpu_driver_unload_kms(struct drm_device *dev) if (amdgpu_sriov_vf(adev)) amdgpu_virt_request_full_gpu(adev, false); - if (amdgpu_device_is_px(dev)) { + if (adev->runpm) { pm_runtime_get_sync(dev->dev); pm_runtime_forbid(dev->dev); } @@ -150,8 +150,7 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) } dev->dev_private = (void *)adev; - if ((amdgpu_runtime_pm != 0) && - amdgpu_has_atpx() && + if (amdgpu_has_atpx() && (amdgpu_is_atpx_hybrid() || amdgpu_has_atpx_dgpu_power_cntl()) && ((flags & AMD_IS_APU) == 0) && @@ -170,6 +169,13 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) goto out; } + if (amdgpu_device_supports_boco(dev) && + (amdgpu_runtime_pm != 0)) /* enable runpm by default */ + adev->runpm = true; + else if (amdgpu_device_supports_baco(dev) && + (amdgpu_runtime_pm > 0)) /* enable runpm if runpm=1 */ + adev->runpm = true; + /* Call ACPI methods: require modeset init * but failure is not fatal */ @@ -180,7 +186,7 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) "Error during ACPI methods call\n"); } - if (amdgpu_device_is_px(dev)) { + if (adev->runpm) { dev_pm_set_driver_flags(dev->dev, DPM_FLAG_NEVER_SKIP); pm_runtime_use_autosuspend(dev->dev); pm_runtime_set_autosuspend_delay(dev->dev, 5000); @@ -193,7 +199,7 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) out: if (r) { /* balance pm_runtime_get_sync in amdgpu_driver_unload_kms */ - if (adev->rmmio && amdgpu_device_is_px(dev)) + if (adev->rmmio && adev->runpm) pm_runtime_put_noidle(dev->dev); amdgpu_driver_unload_kms(dev); } @@ -293,6 +299,10 @@ static int amdgpu_firmware_info(struct drm_amdgpu_info_firmware *fw_info, fw_info->ver = adev->dm.dmcu_fw_version; fw_info->feature = 0; break; + case AMDGPU_INFO_FW_DMCUB: + fw_info->ver = adev->dm.dmcub_fw_version; + fw_info->feature = 0; + break; default: return -EINVAL; } @@ -396,12 +406,14 @@ static int amdgpu_hw_ip_info(struct amdgpu_device *adev, ib_size_alignment = 1; break; case AMDGPU_HW_IP_VCN_JPEG: - type = AMD_IP_BLOCK_TYPE_VCN; - for (i = 0; i < adev->vcn.num_vcn_inst; i++) { - if (adev->uvd.harvest_config & (1 << i)) + type = (amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_JPEG)) ? + AMD_IP_BLOCK_TYPE_JPEG : AMD_IP_BLOCK_TYPE_VCN; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; i++) { + if (adev->jpeg.harvest_config & (1 << i)) continue; - if (adev->vcn.inst[i].ring_jpeg.sched.ready) + if (adev->jpeg.inst[i].ring_dec.sched.ready) ++num_rings; } ib_start_alignment = 16; @@ -517,9 +529,12 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file break; case AMDGPU_HW_IP_VCN_DEC: case AMDGPU_HW_IP_VCN_ENC: - case AMDGPU_HW_IP_VCN_JPEG: type = AMD_IP_BLOCK_TYPE_VCN; break; + case AMDGPU_HW_IP_VCN_JPEG: + type = (amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_JPEG)) ? + AMD_IP_BLOCK_TYPE_JPEG : AMD_IP_BLOCK_TYPE_VCN; + break; default: return -EINVAL; } @@ -688,10 +703,6 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file if (adev->pm.dpm_enabled) { dev_info.max_engine_clock = amdgpu_dpm_get_sclk(adev, false) * 10; dev_info.max_memory_clock = amdgpu_dpm_get_mclk(adev, false) * 10; - } else if (amdgpu_sriov_vf(adev) && amdgim_is_hwperf(adev) && - adev->virt.ops->get_pp_clk) { - dev_info.max_engine_clock = amdgpu_virt_get_sclk(adev, false) * 10; - dev_info.max_memory_clock = amdgpu_virt_get_mclk(adev, false) * 10; } else { dev_info.max_engine_clock = adev->clock.default_sclk * 10; dev_info.max_memory_clock = adev->clock.default_mclk * 10; @@ -1394,6 +1405,14 @@ static int amdgpu_debugfs_firmware_info(struct seq_file *m, void *data) seq_printf(m, "DMCU feature version: %u, firmware version: 0x%08x\n", fw_info.feature, fw_info.ver); + /* DMCUB */ + query_fw.fw_type = AMDGPU_INFO_FW_DMCUB; + ret = amdgpu_firmware_info(&fw_info, &query_fw, adev); + if (ret) + return ret; + seq_printf(m, "DMCUB feature version: %u, firmware version: 0x%08x\n", + fw_info.feature, fw_info.ver); + seq_printf(m, "VBIOS version: %s\n", ctx->vbios_version); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index f205f56e3358399f846a4a400643119d5fd82ac1..b32adda70bbc64dd3f92dccbf9f8ab3f56de27c0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -159,6 +159,9 @@ static ssize_t amdgpu_get_dpm_state(struct device *dev, struct amdgpu_device *adev = ddev->dev_private; enum amd_pm_state_type pm; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + if (is_support_sw_smu(adev)) { if (adev->smu.ppt_funcs->get_current_power_state) pm = smu_get_current_power_state(&adev->smu); @@ -184,6 +187,9 @@ static ssize_t amdgpu_set_dpm_state(struct device *dev, struct amdgpu_device *adev = ddev->dev_private; enum amd_pm_state_type state; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return -EINVAL; + if (strncmp("battery", buf, strlen("battery")) == 0) state = POWER_STATE_TYPE_BATTERY; else if (strncmp("balanced", buf, strlen("balanced")) == 0) @@ -283,7 +289,7 @@ static ssize_t amdgpu_get_dpm_forced_performance_level(struct device *dev, struct amdgpu_device *adev = ddev->dev_private; enum amd_dpm_forced_level level = 0xff; - if (amdgpu_sriov_vf(adev)) + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) return 0; if ((adev->flags & AMD_IS_PX) && @@ -320,6 +326,9 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev, enum amd_dpm_forced_level current_level = 0xff; int ret = 0; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return -EINVAL; + /* Can't force performance level when the card is off */ if ((adev->flags & AMD_IS_PX) && (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) @@ -348,19 +357,6 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev, goto fail; } - /* handle sriov case here */ - if (amdgpu_sriov_vf(adev)) { - if (amdgim_is_hwperf(adev) && - adev->virt.ops->force_dpm_level) { - mutex_lock(&adev->pm.mutex); - adev->virt.ops->force_dpm_level(adev, level); - mutex_unlock(&adev->pm.mutex); - return count; - } else { - return -EINVAL; - } - } - if (is_support_sw_smu(adev)) current_level = smu_get_performance_level(&adev->smu); else if (adev->powerplay.pp_funcs->get_performance_level) @@ -440,6 +436,9 @@ static ssize_t amdgpu_get_pp_cur_state(struct device *dev, enum amd_pm_state_type pm = 0; int i = 0, ret = 0; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + if (is_support_sw_smu(adev)) { pm = smu_get_current_power_state(smu); ret = smu_get_power_num_states(smu, &data); @@ -469,6 +468,9 @@ static ssize_t amdgpu_get_pp_force_state(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + if (adev->pp_force_state_enabled) return amdgpu_get_pp_cur_state(dev, attr, buf); else @@ -486,6 +488,9 @@ static ssize_t amdgpu_set_pp_force_state(struct device *dev, unsigned long idx; int ret; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return -EINVAL; + if (strlen(buf) == 1) adev->pp_force_state_enabled = false; else if (is_support_sw_smu(adev)) @@ -535,6 +540,9 @@ static ssize_t amdgpu_get_pp_table(struct device *dev, char *table = NULL; int size; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + if (is_support_sw_smu(adev)) { size = smu_sys_get_pp_table(&adev->smu, (void **)&table); if (size < 0) @@ -562,6 +570,9 @@ static ssize_t amdgpu_set_pp_table(struct device *dev, struct amdgpu_device *adev = ddev->dev_private; int ret = 0; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return -EINVAL; + if (is_support_sw_smu(adev)) { ret = smu_sys_set_pp_table(&adev->smu, (void *)buf, count); if (ret) @@ -654,6 +665,9 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, const char delimiter[3] = {' ', '\n', '\0'}; uint32_t type; + if (amdgpu_sriov_vf(adev)) + return -EINVAL; + if (count > 127) return -EINVAL; @@ -726,6 +740,9 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev, struct amdgpu_device *adev = ddev->dev_private; uint32_t size = 0; + if (amdgpu_sriov_vf(adev)) + return 0; + if (is_support_sw_smu(adev)) { size = smu_print_clk_levels(&adev->smu, SMU_OD_SCLK, buf); size += smu_print_clk_levels(&adev->smu, SMU_OD_MCLK, buf+size); @@ -770,6 +787,9 @@ static ssize_t amdgpu_set_pp_feature_status(struct device *dev, uint64_t featuremask; int ret; + if (amdgpu_sriov_vf(adev)) + return -EINVAL; + ret = kstrtou64(buf, 0, &featuremask); if (ret) return -EINVAL; @@ -796,6 +816,9 @@ static ssize_t amdgpu_get_pp_feature_status(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; + if (amdgpu_sriov_vf(adev)) + return 0; + if (is_support_sw_smu(adev)) { return smu_sys_get_pp_feature_mask(&adev->smu, buf); } else if (adev->powerplay.pp_funcs->get_ppfeature_status) @@ -841,9 +864,8 @@ static ssize_t amdgpu_get_pp_dpm_sclk(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; - if (amdgpu_sriov_vf(adev) && amdgim_is_hwperf(adev) && - adev->virt.ops->get_pp_clk) - return adev->virt.ops->get_pp_clk(adev, PP_SCLK, buf); + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; if (is_support_sw_smu(adev)) return smu_print_clk_levels(&adev->smu, SMU_SCLK, buf); @@ -899,8 +921,8 @@ static ssize_t amdgpu_set_pp_dpm_sclk(struct device *dev, int ret; uint32_t mask = 0; - if (amdgpu_sriov_vf(adev)) - return 0; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return -EINVAL; ret = amdgpu_read_mask(buf, count, &mask); if (ret) @@ -924,9 +946,8 @@ static ssize_t amdgpu_get_pp_dpm_mclk(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; - if (amdgpu_sriov_vf(adev) && amdgim_is_hwperf(adev) && - adev->virt.ops->get_pp_clk) - return adev->virt.ops->get_pp_clk(adev, PP_MCLK, buf); + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; if (is_support_sw_smu(adev)) return smu_print_clk_levels(&adev->smu, SMU_MCLK, buf); @@ -946,8 +967,8 @@ static ssize_t amdgpu_set_pp_dpm_mclk(struct device *dev, int ret; uint32_t mask = 0; - if (amdgpu_sriov_vf(adev)) - return 0; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return -EINVAL; ret = amdgpu_read_mask(buf, count, &mask); if (ret) @@ -971,6 +992,9 @@ static ssize_t amdgpu_get_pp_dpm_socclk(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + if (is_support_sw_smu(adev)) return smu_print_clk_levels(&adev->smu, SMU_SOCCLK, buf); else if (adev->powerplay.pp_funcs->print_clock_levels) @@ -989,6 +1013,9 @@ static ssize_t amdgpu_set_pp_dpm_socclk(struct device *dev, int ret; uint32_t mask = 0; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return -EINVAL; + ret = amdgpu_read_mask(buf, count, &mask); if (ret) return ret; @@ -1011,6 +1038,9 @@ static ssize_t amdgpu_get_pp_dpm_fclk(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + if (is_support_sw_smu(adev)) return smu_print_clk_levels(&adev->smu, SMU_FCLK, buf); else if (adev->powerplay.pp_funcs->print_clock_levels) @@ -1029,6 +1059,9 @@ static ssize_t amdgpu_set_pp_dpm_fclk(struct device *dev, int ret; uint32_t mask = 0; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return -EINVAL; + ret = amdgpu_read_mask(buf, count, &mask); if (ret) return ret; @@ -1051,6 +1084,9 @@ static ssize_t amdgpu_get_pp_dpm_dcefclk(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; + if (amdgpu_sriov_vf(adev)) + return 0; + if (is_support_sw_smu(adev)) return smu_print_clk_levels(&adev->smu, SMU_DCEFCLK, buf); else if (adev->powerplay.pp_funcs->print_clock_levels) @@ -1069,6 +1105,9 @@ static ssize_t amdgpu_set_pp_dpm_dcefclk(struct device *dev, int ret; uint32_t mask = 0; + if (amdgpu_sriov_vf(adev)) + return -EINVAL; + ret = amdgpu_read_mask(buf, count, &mask); if (ret) return ret; @@ -1091,6 +1130,9 @@ static ssize_t amdgpu_get_pp_dpm_pcie(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + if (is_support_sw_smu(adev)) return smu_print_clk_levels(&adev->smu, SMU_PCIE, buf); else if (adev->powerplay.pp_funcs->print_clock_levels) @@ -1109,6 +1151,9 @@ static ssize_t amdgpu_set_pp_dpm_pcie(struct device *dev, int ret; uint32_t mask = 0; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return -EINVAL; + ret = amdgpu_read_mask(buf, count, &mask); if (ret) return ret; @@ -1132,6 +1177,9 @@ static ssize_t amdgpu_get_pp_sclk_od(struct device *dev, struct amdgpu_device *adev = ddev->dev_private; uint32_t value = 0; + if (amdgpu_sriov_vf(adev)) + return 0; + if (is_support_sw_smu(adev)) value = smu_get_od_percentage(&(adev->smu), SMU_OD_SCLK); else if (adev->powerplay.pp_funcs->get_sclk_od) @@ -1150,6 +1198,9 @@ static ssize_t amdgpu_set_pp_sclk_od(struct device *dev, int ret; long int value; + if (amdgpu_sriov_vf(adev)) + return -EINVAL; + ret = kstrtol(buf, 0, &value); if (ret) { @@ -1183,6 +1234,9 @@ static ssize_t amdgpu_get_pp_mclk_od(struct device *dev, struct amdgpu_device *adev = ddev->dev_private; uint32_t value = 0; + if (amdgpu_sriov_vf(adev)) + return 0; + if (is_support_sw_smu(adev)) value = smu_get_od_percentage(&(adev->smu), SMU_OD_MCLK); else if (adev->powerplay.pp_funcs->get_mclk_od) @@ -1201,6 +1255,9 @@ static ssize_t amdgpu_set_pp_mclk_od(struct device *dev, int ret; long int value; + if (amdgpu_sriov_vf(adev)) + return 0; + ret = kstrtol(buf, 0, &value); if (ret) { @@ -1253,6 +1310,9 @@ static ssize_t amdgpu_get_pp_power_profile_mode(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + if (is_support_sw_smu(adev)) return smu_get_power_profile_mode(&adev->smu, buf); else if (adev->powerplay.pp_funcs->get_power_profile_mode) @@ -1285,6 +1345,9 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev, if (ret) goto fail; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return -EINVAL; + if (profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { if (count < 2 || count > 127) return -EINVAL; @@ -1331,6 +1394,9 @@ static ssize_t amdgpu_get_busy_percent(struct device *dev, struct amdgpu_device *adev = ddev->dev_private; int r, value, size = sizeof(value); + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + /* read the IP busy sensor */ r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_LOAD, (void *)&value, &size); @@ -1357,6 +1423,9 @@ static ssize_t amdgpu_get_memory_busy_percent(struct device *dev, struct amdgpu_device *adev = ddev->dev_private; int r, value, size = sizeof(value); + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + /* read the IP busy sensor */ r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_MEM_LOAD, (void *)&value, &size); @@ -1387,6 +1456,9 @@ static ssize_t amdgpu_get_pcie_bw(struct device *dev, struct amdgpu_device *adev = ddev->dev_private; uint64_t count0, count1; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + amdgpu_asic_get_pcie_usage(adev, &count0, &count1); return snprintf(buf, PAGE_SIZE, "%llu %llu %i\n", count0, count1, pcie_get_mps(adev->pdev)); @@ -1409,6 +1481,9 @@ static ssize_t amdgpu_get_unique_id(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + if (adev->unique_id) return snprintf(buf, PAGE_SIZE, "%016llx\n", adev->unique_id); @@ -1603,6 +1678,7 @@ static ssize_t amdgpu_hwmon_get_pwm1_enable(struct device *dev, { struct amdgpu_device *adev = dev_get_drvdata(dev); u32 pwm_mode = 0; + if (is_support_sw_smu(adev)) { pwm_mode = smu_get_fan_control_mode(&adev->smu); } else { @@ -2053,6 +2129,9 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev, int err; u32 value; + if (amdgpu_sriov_vf(adev)) + return -EINVAL; + err = kstrtou32(buf, 10, &value); if (err) return err; @@ -2299,6 +2378,23 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, struct amdgpu_device *adev = dev_get_drvdata(dev); umode_t effective_mode = attr->mode; + /* under multi-vf mode, the hwmon attributes are all not supported */ + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + + /* there is no fan under pp one vf mode */ + if (amdgpu_sriov_is_pp_one_vf(adev) && + (attr == &sensor_dev_attr_pwm1.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_max.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_min.dev_attr.attr || + attr == &sensor_dev_attr_fan1_input.dev_attr.attr || + attr == &sensor_dev_attr_fan1_min.dev_attr.attr || + attr == &sensor_dev_attr_fan1_max.dev_attr.attr || + attr == &sensor_dev_attr_fan1_target.dev_attr.attr || + attr == &sensor_dev_attr_fan1_enable.dev_attr.attr)) + return 0; + /* Skip fan attributes if fan is not present */ if (adev->pm.no_fan && (attr == &sensor_dev_attr_pwm1.dev_attr.attr || attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr || @@ -2718,42 +2814,16 @@ void amdgpu_pm_print_power_states(struct amdgpu_device *adev) } -int amdgpu_pm_virt_sysfs_init(struct amdgpu_device *adev) +void amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable) { int ret = 0; - if (!(amdgpu_sriov_vf(adev) && amdgim_is_hwperf(adev))) - return ret; - - ret = device_create_file(adev->dev, &dev_attr_pp_dpm_sclk); - if (ret) { - DRM_ERROR("failed to create device file pp_dpm_sclk\n"); - return ret; - } - - ret = device_create_file(adev->dev, &dev_attr_pp_dpm_mclk); - if (ret) { - DRM_ERROR("failed to create device file pp_dpm_mclk\n"); - return ret; - } - - ret = device_create_file(adev->dev, &dev_attr_power_dpm_force_performance_level); - if (ret) { - DRM_ERROR("failed to create device file for dpm state\n"); - return ret; + if (is_support_sw_smu(adev)) { + ret = smu_dpm_set_power_gate(&adev->smu, AMD_IP_BLOCK_TYPE_JPEG, enable); + if (ret) + DRM_ERROR("[SW SMU]: dpm enable jpeg failed, state = %s, ret = %d. \n", + enable ? "true" : "false", ret); } - - return ret; -} - -void amdgpu_pm_virt_sysfs_fini(struct amdgpu_device *adev) -{ - if (!(amdgpu_sriov_vf(adev) && amdgim_is_hwperf(adev))) - return; - - device_remove_file(adev->dev, &dev_attr_power_dpm_force_performance_level); - device_remove_file(adev->dev, &dev_attr_pp_dpm_sclk); - device_remove_file(adev->dev, &dev_attr_pp_dpm_mclk); } int amdgpu_pm_load_smu_firmware(struct amdgpu_device *adev, uint32_t *smu_version) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.h index ef31448ee8d88eb366ac832036c1e726afa1b89f..3da1da277805f333a67dcaa8fa2f61a6b13918a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.h @@ -41,5 +41,6 @@ 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); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 44be3a45b25eaf2453a649d244365f2f5a727eb5..c14f2ccd0677768fadb69dec721058d83dd789bc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -158,7 +158,7 @@ psp_cmd_submit_buf(struct psp_context *psp, memcpy(psp->cmd_buf_mem, cmd, sizeof(struct psp_gfx_cmd_resp)); index = atomic_inc_return(&psp->fence_value); - ret = psp_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr, index); + ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr, index); if (ret) { atomic_dec(&psp->fence_value); mutex_unlock(&psp->mutex); @@ -318,35 +318,17 @@ static int psp_tmr_load(struct psp_context *psp) return ret; } -static void psp_prep_asd_cmd_buf(struct psp_gfx_cmd_resp *cmd, - uint64_t asd_mc, uint64_t asd_mc_shared, - uint32_t size, uint32_t shared_size) +static void psp_prep_asd_load_cmd_buf(struct psp_gfx_cmd_resp *cmd, + uint64_t asd_mc, uint32_t size) { cmd->cmd_id = GFX_CMD_ID_LOAD_ASD; cmd->cmd.cmd_load_ta.app_phy_addr_lo = lower_32_bits(asd_mc); cmd->cmd.cmd_load_ta.app_phy_addr_hi = upper_32_bits(asd_mc); cmd->cmd.cmd_load_ta.app_len = size; - cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo = lower_32_bits(asd_mc_shared); - cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi = upper_32_bits(asd_mc_shared); - cmd->cmd.cmd_load_ta.cmd_buf_len = shared_size; -} - -static int psp_asd_init(struct psp_context *psp) -{ - int ret; - - /* - * Allocate 16k memory aligned to 4k from Frame Buffer (local - * physical) for shared ASD <-> Driver - */ - ret = amdgpu_bo_create_kernel(psp->adev, PSP_ASD_SHARED_MEM_SIZE, - PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, - &psp->asd_shared_bo, - &psp->asd_shared_mc_addr, - &psp->asd_shared_buf); - - return ret; + cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo = 0; + cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi = 0; + cmd->cmd.cmd_load_ta.cmd_buf_len = 0; } static int psp_asd_load(struct psp_context *psp) @@ -368,11 +350,49 @@ static int psp_asd_load(struct psp_context *psp) memset(psp->fw_pri_buf, 0, PSP_1_MEG); memcpy(psp->fw_pri_buf, psp->asd_start_addr, psp->asd_ucode_size); - psp_prep_asd_cmd_buf(cmd, psp->fw_pri_mc_addr, psp->asd_shared_mc_addr, - psp->asd_ucode_size, PSP_ASD_SHARED_MEM_SIZE); + psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr, + psp->asd_ucode_size); + + ret = psp_cmd_submit_buf(psp, NULL, cmd, + psp->fence_buf_mc_addr); + if (!ret) { + psp->asd_context.asd_initialized = true; + psp->asd_context.session_id = cmd->resp.session_id; + } + + kfree(cmd); + + return ret; +} + +static void psp_prep_asd_unload_cmd_buf(struct psp_gfx_cmd_resp *cmd, + uint32_t asd_session_id) +{ + cmd->cmd_id = GFX_CMD_ID_UNLOAD_TA; + cmd->cmd.cmd_unload_ta.session_id = asd_session_id; +} + +static int psp_asd_unload(struct psp_context *psp) +{ + int ret; + struct psp_gfx_cmd_resp *cmd; + + if (amdgpu_sriov_vf(psp->adev)) + return 0; + + if (!psp->asd_context.asd_initialized) + return 0; + + cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + psp_prep_asd_unload_cmd_buf(cmd, psp->asd_context.session_id); ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); + if (!ret) + psp->asd_context.asd_initialized = false; kfree(cmd); @@ -1211,45 +1231,6 @@ static int psp_hw_start(struct psp_context *psp) return ret; } - ret = psp_asd_init(psp); - if (ret) { - DRM_ERROR("PSP asd init failed!\n"); - return ret; - } - - ret = psp_asd_load(psp); - if (ret) { - DRM_ERROR("PSP load asd failed!\n"); - return ret; - } - - if (adev->gmc.xgmi.num_physical_nodes > 1) { - ret = psp_xgmi_initialize(psp); - /* Warning the XGMI seesion initialize failure - * Instead of stop driver initialization - */ - if (ret) - dev_err(psp->adev->dev, - "XGMI: Failed to initialize XGMI session\n"); - } - - if (psp->adev->psp.ta_fw) { - ret = psp_ras_initialize(psp); - if (ret) - dev_err(psp->adev->dev, - "RAS: Failed to initialize RAS\n"); - - ret = psp_hdcp_initialize(psp); - if (ret) - dev_err(psp->adev->dev, - "HDCP: Failed to initialize HDCP\n"); - - ret = psp_dtm_initialize(psp); - if (ret) - dev_err(psp->adev->dev, - "DTM: Failed to initialize DTM\n"); - } - return 0; } @@ -1341,6 +1322,9 @@ static int psp_get_fw_type(struct amdgpu_firmware_info *ucode, case AMDGPU_UCODE_ID_VCN1_RAM: *type = GFX_FW_TYPE_VCN1_RAM; break; + case AMDGPU_UCODE_ID_DMCUB: + *type = GFX_FW_TYPE_DMUB; + break; case AMDGPU_UCODE_ID_MAXIMUM: default: return -EINVAL; @@ -1562,6 +1546,39 @@ skip_memalloc: if (ret) goto failed; + ret = psp_asd_load(psp); + if (ret) { + DRM_ERROR("PSP load asd failed!\n"); + return ret; + } + + if (adev->gmc.xgmi.num_physical_nodes > 1) { + ret = psp_xgmi_initialize(psp); + /* Warning the XGMI seesion initialize failure + * Instead of stop driver initialization + */ + if (ret) + dev_err(psp->adev->dev, + "XGMI: Failed to initialize XGMI session\n"); + } + + if (psp->adev->psp.ta_fw) { + ret = psp_ras_initialize(psp); + if (ret) + dev_err(psp->adev->dev, + "RAS: Failed to initialize RAS\n"); + + ret = psp_hdcp_initialize(psp); + if (ret) + dev_err(psp->adev->dev, + "HDCP: Failed to initialize HDCP\n"); + + ret = psp_dtm_initialize(psp); + if (ret) + dev_err(psp->adev->dev, + "DTM: Failed to initialize DTM\n"); + } + return 0; failed: @@ -1619,6 +1636,8 @@ static int psp_hw_fini(void *handle) psp_hdcp_terminate(psp); } + psp_asd_unload(psp); + psp_ring_destroy(psp, PSP_RING_TYPE__KM); pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL; @@ -1627,8 +1646,6 @@ static int psp_hw_fini(void *handle) &psp->fw_pri_mc_addr, &psp->fw_pri_buf); amdgpu_bo_free_kernel(&psp->fence_buf_bo, &psp->fence_buf_mc_addr, &psp->fence_buf); - amdgpu_bo_free_kernel(&psp->asd_shared_bo, &psp->asd_shared_mc_addr, - &psp->asd_shared_buf); amdgpu_bo_free_kernel(&psp->cmd_buf_bo, &psp->cmd_buf_mc_addr, (void **)&psp->cmd_buf_mem); @@ -1704,6 +1721,39 @@ static int psp_resume(void *handle) if (ret) goto failed; + ret = psp_asd_load(psp); + if (ret) { + DRM_ERROR("PSP load asd failed!\n"); + goto failed; + } + + if (adev->gmc.xgmi.num_physical_nodes > 1) { + ret = psp_xgmi_initialize(psp); + /* Warning the XGMI seesion initialize failure + * Instead of stop driver initialization + */ + if (ret) + dev_err(psp->adev->dev, + "XGMI: Failed to initialize XGMI session\n"); + } + + if (psp->adev->psp.ta_fw) { + ret = psp_ras_initialize(psp); + if (ret) + dev_err(psp->adev->dev, + "RAS: Failed to initialize RAS\n"); + + ret = psp_hdcp_initialize(psp); + if (ret) + dev_err(psp->adev->dev, + "HDCP: Failed to initialize HDCP\n"); + + ret = psp_dtm_initialize(psp); + if (ret) + dev_err(psp->adev->dev, + "DTM: Failed to initialize DTM\n"); + } + mutex_unlock(&adev->firmware.mutex); return 0; @@ -1758,6 +1808,56 @@ int psp_update_vcn_sram(struct amdgpu_device *adev, int inst_idx, return psp_execute_np_fw_load(&adev->psp, &ucode); } +int psp_ring_cmd_submit(struct psp_context *psp, + uint64_t cmd_buf_mc_addr, + uint64_t fence_mc_addr, + int index) +{ + unsigned int psp_write_ptr_reg = 0; + struct psp_gfx_rb_frame *write_frame; + struct psp_ring *ring = &psp->km_ring; + struct psp_gfx_rb_frame *ring_buffer_start = ring->ring_mem; + struct psp_gfx_rb_frame *ring_buffer_end = ring_buffer_start + + ring->ring_size / sizeof(struct psp_gfx_rb_frame) - 1; + struct amdgpu_device *adev = psp->adev; + uint32_t ring_size_dw = ring->ring_size / 4; + uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4; + + /* KM (GPCOM) prepare write pointer */ + psp_write_ptr_reg = psp_ring_get_wptr(psp); + + /* Update KM RB frame pointer to new frame */ + /* write_frame ptr increments by size of rb_frame in bytes */ + /* psp_write_ptr_reg increments by size of rb_frame in DWORDs */ + if ((psp_write_ptr_reg % ring_size_dw) == 0) + write_frame = ring_buffer_start; + else + write_frame = ring_buffer_start + (psp_write_ptr_reg / rb_frame_size_dw); + /* Check invalid write_frame ptr address */ + if ((write_frame < ring_buffer_start) || (ring_buffer_end < write_frame)) { + DRM_ERROR("ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n", + ring_buffer_start, ring_buffer_end, write_frame); + DRM_ERROR("write_frame is pointing to address out of bounds\n"); + return -EINVAL; + } + + /* Initialize KM RB frame */ + memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame)); + + /* Update KM RB frame */ + write_frame->cmd_buf_addr_hi = upper_32_bits(cmd_buf_mc_addr); + write_frame->cmd_buf_addr_lo = lower_32_bits(cmd_buf_mc_addr); + write_frame->fence_addr_hi = upper_32_bits(fence_mc_addr); + write_frame->fence_addr_lo = lower_32_bits(fence_mc_addr); + write_frame->fence_value = index; + amdgpu_asic_flush_hdp(adev, NULL); + + /* Update the write Pointer in DWORDs */ + psp_write_ptr_reg = (psp_write_ptr_reg + rb_frame_size_dw) % ring_size_dw; + psp_ring_set_wptr(psp, psp_write_ptr_reg); + return 0; +} + static bool psp_check_fw_loading_status(struct amdgpu_device *adev, enum AMDGPU_UCODE_ID ucode_type) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index 09c5474ebcc348b7b4461395832c9511092aed31..5f8fd3e3535bcf6481cf7cc12fac1645e5eb10b8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -32,7 +32,6 @@ #define PSP_FENCE_BUFFER_SIZE 0x1000 #define PSP_CMD_BUFFER_SIZE 0x1000 -#define PSP_ASD_SHARED_MEM_SIZE 0x4000 #define PSP_XGMI_SHARED_MEM_SIZE 0x4000 #define PSP_RAS_SHARED_MEM_SIZE 0x4000 #define PSP_1_MEG 0x100000 @@ -94,9 +93,6 @@ struct psp_funcs enum psp_ring_type ring_type); int (*ring_destroy)(struct psp_context *psp, enum psp_ring_type ring_type); - int (*cmd_submit)(struct psp_context *psp, - uint64_t cmd_buf_mc_addr, uint64_t fence_mc_addr, - int index); bool (*compare_sram_data)(struct psp_context *psp, struct amdgpu_firmware_info *ucode, enum AMDGPU_UCODE_ID ucode_type); @@ -116,6 +112,8 @@ struct psp_funcs int (*mem_training_init)(struct psp_context *psp); void (*mem_training_fini)(struct psp_context *psp); int (*mem_training)(struct psp_context *psp, uint32_t ops); + uint32_t (*ring_get_wptr)(struct psp_context *psp); + void (*ring_set_wptr)(struct psp_context *psp, uint32_t value); }; #define AMDGPU_XGMI_MAX_CONNECTED_NODES 64 @@ -131,6 +129,11 @@ struct psp_xgmi_topology_info { struct psp_xgmi_node_info nodes[AMDGPU_XGMI_MAX_CONNECTED_NODES]; }; +struct psp_asd_context { + bool asd_initialized; + uint32_t session_id; +}; + struct psp_xgmi_context { uint8_t initialized; uint32_t session_id; @@ -239,15 +242,12 @@ struct psp_context struct amdgpu_bo *tmr_bo; uint64_t tmr_mc_addr; - /* asd firmware and buffer */ + /* asd firmware */ const struct firmware *asd_fw; uint32_t asd_fw_version; uint32_t asd_feature_version; uint32_t asd_ucode_size; uint8_t *asd_start_addr; - struct amdgpu_bo *asd_shared_bo; - uint64_t asd_shared_mc_addr; - void *asd_shared_buf; /* fence buffer */ struct amdgpu_bo *fence_buf_bo; @@ -282,6 +282,7 @@ struct psp_context uint32_t ta_dtm_ucode_size; uint8_t *ta_dtm_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; @@ -300,8 +301,6 @@ struct amdgpu_psp_funcs { #define psp_ring_create(psp, type) (psp)->funcs->ring_create((psp), (type)) #define psp_ring_stop(psp, type) (psp)->funcs->ring_stop((psp), (type)) #define psp_ring_destroy(psp, type) ((psp)->funcs->ring_destroy((psp), (type))) -#define psp_cmd_submit(psp, cmd_mc, fence_mc, index) \ - (psp)->funcs->cmd_submit((psp), (cmd_mc), (fence_mc), (index)) #define psp_compare_sram_data(psp, ucode, type) \ (psp)->funcs->compare_sram_data((psp), (ucode), (type)) #define psp_init_microcode(psp) \ @@ -346,6 +345,9 @@ struct amdgpu_psp_funcs { ((psp)->funcs->ras_cure_posion ? \ (psp)->funcs->ras_cure_posion(psp, (addr)) : -EINVAL) +#define psp_ring_get_wptr(psp) (psp)->funcs->ring_get_wptr((psp)) +#define psp_ring_set_wptr(psp, value) (psp)->funcs->ring_set_wptr((psp), (value)) + extern const struct amd_ip_funcs psp_ip_funcs; extern const struct amdgpu_ip_block_version psp_v3_1_ip_block; @@ -372,4 +374,8 @@ int psp_rlc_autoload_start(struct psp_context *psp); extern const struct amdgpu_ip_block_version psp_v11_0_ip_block; int psp_reg_program(struct psp_context *psp, enum psp_reg_prog_id reg, uint32_t value); +int psp_ring_cmd_submit(struct psp_context *psp, + uint64_t cmd_buf_mc_addr, + uint64_t fence_mc_addr, + int index); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 404483437bd3aa1a4b8d353196d4f27a6256b096..04394c45aa031211da38f4688d42a1666d6bc64a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -198,9 +198,6 @@ static int amdgpu_ras_debugfs_ctrl_parse_data(struct file *f, return 0; } -static struct ras_manager *amdgpu_ras_find_obj(struct amdgpu_device *adev, - struct ras_common_if *head); - /** * DOC: AMDGPU RAS debugfs control interface * @@ -445,7 +442,7 @@ static struct ras_manager *amdgpu_ras_create_obj(struct amdgpu_device *adev, } /* return an obj equal to head, or the first when head is NULL */ -static struct ras_manager *amdgpu_ras_find_obj(struct amdgpu_device *adev, +struct ras_manager *amdgpu_ras_find_obj(struct amdgpu_device *adev, struct ras_common_if *head) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); @@ -1687,7 +1684,8 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev, *supported = 0; if (amdgpu_sriov_vf(adev) || - adev->asic_type != CHIP_VEGA20) + (adev->asic_type != CHIP_VEGA20 && + adev->asic_type != CHIP_ARCTURUS)) return; if (adev->is_atom_fw && diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h index f80fd3428c98ea449e8b907a8eec40366dd66fbd..d4ade47392455e5810688198e9a6d35711c1f622 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h @@ -611,6 +611,9 @@ int amdgpu_ras_interrupt_remove_handler(struct amdgpu_device *adev, int amdgpu_ras_interrupt_dispatch(struct amdgpu_device *adev, struct ras_dispatch_if *info); +struct ras_manager *amdgpu_ras_find_obj(struct amdgpu_device *adev, + struct ras_common_if *head); + extern atomic_t amdgpu_ras_in_intr; static inline bool amdgpu_ras_intr_triggered(void) @@ -618,6 +621,11 @@ static inline bool amdgpu_ras_intr_triggered(void) return !!atomic_read(&amdgpu_ras_in_intr); } +static inline void amdgpu_ras_intr_cleared(void) +{ + atomic_set(&amdgpu_ras_in_intr, 0); +} + void amdgpu_ras_global_ras_isr(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index 95e5e93edd18c27ca00ae3bc82c531a87afb1741..a09b6b9c27d11bab2c7c5e0f449f035f500851d2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -129,7 +129,8 @@ static void amdgpu_sync_keep_later(struct dma_fence **keep, * Tries to add the fence to an existing hash entry. Returns true when an entry * was found, false otherwise. */ -static bool amdgpu_sync_add_later(struct amdgpu_sync *sync, struct dma_fence *f, bool explicit) +static bool amdgpu_sync_add_later(struct amdgpu_sync *sync, struct dma_fence *f, + bool explicit) { struct amdgpu_sync_entry *e; @@ -151,19 +152,18 @@ static bool amdgpu_sync_add_later(struct amdgpu_sync *sync, struct dma_fence *f, * amdgpu_sync_fence - remember to sync to this fence * * @sync: sync object to add fence to - * @fence: fence to sync to + * @f: fence to sync to + * @explicit: if this is an explicit dependency * + * Add the fence to the sync object. */ -int amdgpu_sync_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync, - struct dma_fence *f, bool explicit) +int amdgpu_sync_fence(struct amdgpu_sync *sync, struct dma_fence *f, + bool explicit) { struct amdgpu_sync_entry *e; if (!f) return 0; - if (amdgpu_sync_same_dev(adev, f) && - amdgpu_sync_get_owner(f) == AMDGPU_FENCE_OWNER_VM) - amdgpu_sync_keep_later(&sync->last_vm_update, f); if (amdgpu_sync_add_later(sync, f, explicit)) return 0; @@ -179,6 +179,24 @@ int amdgpu_sync_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync, return 0; } +/** + * amdgpu_sync_vm_fence - remember to sync to this VM fence + * + * @adev: amdgpu device + * @sync: sync object to add fence to + * @fence: the VM fence to add + * + * Add the fence to the sync object and remember it as VM update. + */ +int amdgpu_sync_vm_fence(struct amdgpu_sync *sync, struct dma_fence *fence) +{ + if (!fence) + return 0; + + amdgpu_sync_keep_later(&sync->last_vm_update, fence); + return amdgpu_sync_fence(sync, fence, false); +} + /** * amdgpu_sync_resv - sync to a reservation object * @@ -204,7 +222,7 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, /* always sync to the exclusive fence */ f = dma_resv_get_excl(resv); - r = amdgpu_sync_fence(adev, sync, f, false); + r = amdgpu_sync_fence(sync, f, false); flist = dma_resv_get_list(resv); if (!flist || r) @@ -222,13 +240,11 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, continue; if (amdgpu_sync_same_dev(adev, f)) { - /* VM updates are only interesting - * for other VM updates and moves. + /* VM updates only sync with moves but not with user + * command submissions or KFD evictions fences */ - if ((owner != AMDGPU_FENCE_OWNER_UNDEFINED) && - (fence_owner != AMDGPU_FENCE_OWNER_UNDEFINED) && - ((owner == AMDGPU_FENCE_OWNER_VM) != - (fence_owner == AMDGPU_FENCE_OWNER_VM))) + if (owner == AMDGPU_FENCE_OWNER_VM && + fence_owner != AMDGPU_FENCE_OWNER_UNDEFINED) continue; /* Ignore fence from the same owner and explicit one as @@ -239,7 +255,7 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, continue; } - r = amdgpu_sync_fence(adev, sync, f, false); + r = amdgpu_sync_fence(sync, f, false); if (r) break; } @@ -340,7 +356,7 @@ int amdgpu_sync_clone(struct amdgpu_sync *source, struct amdgpu_sync *clone) hash_for_each_safe(source->fences, i, tmp, e, node) { f = e->fence; if (!dma_fence_is_signaled(f)) { - r = amdgpu_sync_fence(NULL, clone, f, e->explicit); + r = amdgpu_sync_fence(clone, f, e->explicit); if (r) return r; } else { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h index b5f1778a2319bc91906aab6bc189e94674b99cf5..d62c2b81d92bf0489d8f2e684bbd4a01a0c97af4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h @@ -40,8 +40,9 @@ struct amdgpu_sync { }; void amdgpu_sync_create(struct amdgpu_sync *sync); -int amdgpu_sync_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync, - struct dma_fence *f, bool explicit); +int amdgpu_sync_fence(struct amdgpu_sync *sync, struct dma_fence *f, + bool explicit); +int amdgpu_sync_vm_fence(struct amdgpu_sync *sync, struct dma_fence *fence); int amdgpu_sync_resv(struct amdgpu_device *adev, struct amdgpu_sync *sync, struct dma_resv *resv, @@ -49,7 +50,8 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, bool explicit_sync); struct dma_fence *amdgpu_sync_peek_fence(struct amdgpu_sync *sync, struct amdgpu_ring *ring); -struct dma_fence *amdgpu_sync_get_fence(struct amdgpu_sync *sync, bool *explicit); +struct dma_fence *amdgpu_sync_get_fence(struct amdgpu_sync *sync, + bool *explicit); int amdgpu_sync_clone(struct amdgpu_sync *source, struct amdgpu_sync *clone); int amdgpu_sync_wait(struct amdgpu_sync *sync, bool intr); void amdgpu_sync_free(struct amdgpu_sync *sync); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 2616e2eafdebe95b9c0d9d6f4b2b49a826f35ee0..445de594c214bfd53afe59fef3c5fdf9c65580b1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1522,11 +1522,8 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo, struct dma_fence *f; int i; - /* Don't evict VM page tables while they are busy, otherwise we can't - * cleanly handle page faults. - */ if (bo->type == ttm_bo_type_kernel && - !dma_resv_test_signaled_rcu(bo->base.resv, true)) + !amdgpu_vm_evictable(ttm_to_amdgpu_bo(bo))) return false; /* If bo is a KFD BO, check if the bo belongs to the current process. diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c index 833fc4b68940bfb5e69b130aae24b0e5a4586c41..9ef3124282318f37dffcf20c2ebf98ebf6561372 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c @@ -447,6 +447,7 @@ static int amdgpu_ucode_init_single_fw(struct amdgpu_device *adev, const struct common_firmware_header *header = NULL; const struct gfx_firmware_header_v1_0 *cp_hdr = NULL; const struct dmcu_firmware_header_v1_0 *dmcu_hdr = NULL; + const struct dmcub_firmware_header_v1_0 *dmcub_hdr = NULL; if (NULL == ucode->fw) return 0; @@ -460,6 +461,7 @@ static int amdgpu_ucode_init_single_fw(struct amdgpu_device *adev, header = (const struct common_firmware_header *)ucode->fw->data; cp_hdr = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data; dmcu_hdr = (const struct dmcu_firmware_header_v1_0 *)ucode->fw->data; + dmcub_hdr = (const struct dmcub_firmware_header_v1_0 *)ucode->fw->data; if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP || (ucode->ucode_id != AMDGPU_UCODE_ID_CP_MEC1 && @@ -470,7 +472,8 @@ static int amdgpu_ucode_init_single_fw(struct amdgpu_device *adev, ucode->ucode_id != AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM && ucode->ucode_id != AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM && ucode->ucode_id != AMDGPU_UCODE_ID_DMCU_ERAM && - ucode->ucode_id != AMDGPU_UCODE_ID_DMCU_INTV)) { + ucode->ucode_id != AMDGPU_UCODE_ID_DMCU_INTV && + ucode->ucode_id != AMDGPU_UCODE_ID_DMCUB)) { ucode->ucode_size = le32_to_cpu(header->ucode_size_bytes); memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data + @@ -506,6 +509,12 @@ static int amdgpu_ucode_init_single_fw(struct amdgpu_device *adev, le32_to_cpu(header->ucode_array_offset_bytes) + le32_to_cpu(dmcu_hdr->intv_offset_bytes)), ucode->ucode_size); + } else if (ucode->ucode_id == AMDGPU_UCODE_ID_DMCUB) { + ucode->ucode_size = le32_to_cpu(dmcub_hdr->inst_const_bytes); + memcpy(ucode->kaddr, + (void *)((uint8_t *)ucode->fw->data + + le32_to_cpu(header->ucode_array_offset_bytes)), + ucode->ucode_size); } else if (ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL) { ucode->ucode_size = adev->gfx.rlc.save_restore_list_cntl_size_bytes; memcpy(ucode->kaddr, adev->gfx.rlc.save_restore_list_cntl, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h index 410587b950f3c8490c881c982281e1e45aae2b20..eaf2d5b9c92fea2b9d5c802e2a404792acaf37d3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h @@ -251,6 +251,13 @@ struct dmcu_firmware_header_v1_0 { uint32_t intv_size_bytes; /* size of interrupt vectors, in bytes */ }; +/* version_major=1, version_minor=0 */ +struct dmcub_firmware_header_v1_0 { + struct common_firmware_header header; + uint32_t inst_const_bytes; /* size of instruction region, in bytes */ + uint32_t bss_data_bytes; /* size of bss/data region, in bytes */ +}; + /* header is fixed size */ union amdgpu_firmware_header { struct common_firmware_header common; @@ -268,6 +275,7 @@ union amdgpu_firmware_header { struct sdma_firmware_header_v1_1 sdma_v1_1; struct gpu_info_firmware_header_v1_0 gpu_info; struct dmcu_firmware_header_v1_0 dmcu; + struct dmcub_firmware_header_v1_0 dmcub; uint8_t raw[0x100]; }; @@ -307,6 +315,7 @@ enum AMDGPU_UCODE_ID { AMDGPU_UCODE_ID_DMCU_INTV, AMDGPU_UCODE_ID_VCN0_RAM, AMDGPU_UCODE_ID_VCN1_RAM, + AMDGPU_UCODE_ID_DMCUB, AMDGPU_UCODE_ID_MAXIMUM, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index e324bfe6c58f2f025ac8f724b8aee5d9f8ec2b2f..d587ffe2af8eec6ed491da08e19a9c1d0a8645b2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -349,6 +349,7 @@ int amdgpu_uvd_suspend(struct amdgpu_device *adev) unsigned size; void *ptr; int i, j; + bool in_ras_intr = amdgpu_ras_intr_triggered(); cancel_delayed_work_sync(&adev->uvd.idle_work); @@ -376,13 +377,15 @@ int amdgpu_uvd_suspend(struct amdgpu_device *adev) return -ENOMEM; /* re-write 0 since err_event_athub will corrupt VCPU buffer */ - if (amdgpu_ras_intr_triggered()) { - DRM_WARN("UVD VCPU state may lost due to RAS ERREVENT_ATHUB_INTERRUPT\n"); + if (in_ras_intr) memset(adev->uvd.inst[j].saved_bo, 0, size); - } else { + else memcpy_fromio(adev->uvd.inst[j].saved_bo, ptr, size); - } } + + if (in_ras_intr) + DRM_WARN("UVD VCPU state may lost due to RAS ERREVENT_ATHUB_INTERRUPT\n"); + return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 9d870444d7d6af0b1767edec94498722c0440c8b..428cfd58b37de78bb33f64be235778723b0e72a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -214,8 +214,6 @@ int amdgpu_vcn_sw_fini(struct amdgpu_device *adev) for (i = 0; i < adev->vcn.num_enc_rings; ++i) amdgpu_ring_fini(&adev->vcn.inst[j].ring_enc[i]); - - amdgpu_ring_fini(&adev->vcn.inst[j].ring_jpeg); } release_firmware(adev->vcn.fw); @@ -308,7 +306,7 @@ static void amdgpu_vcn_idle_work_handler(struct work_struct *work) else new_state.fw_based = VCN_DPG_STATE__UNPAUSE; - if (amdgpu_fence_count_emitted(&adev->vcn.inst[j].ring_jpeg)) + if (amdgpu_fence_count_emitted(&adev->jpeg.inst[j].ring_dec)) new_state.jpeg = VCN_DPG_STATE__PAUSE; else new_state.jpeg = VCN_DPG_STATE__UNPAUSE; @@ -316,7 +314,7 @@ static void amdgpu_vcn_idle_work_handler(struct work_struct *work) adev->vcn.pause_dpg_mode(adev, &new_state); } - fence[j] += amdgpu_fence_count_emitted(&adev->vcn.inst[j].ring_jpeg); + fence[j] += amdgpu_fence_count_emitted(&adev->jpeg.inst[j].ring_dec); fence[j] += amdgpu_fence_count_emitted(&adev->vcn.inst[j].ring_dec); fences += fence[j]; } @@ -360,7 +358,7 @@ void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring) else new_state.fw_based = VCN_DPG_STATE__UNPAUSE; - if (amdgpu_fence_count_emitted(&adev->vcn.inst[ring->me].ring_jpeg)) + if (amdgpu_fence_count_emitted(&adev->jpeg.inst[ring->me].ring_dec)) new_state.jpeg = VCN_DPG_STATE__PAUSE; else new_state.jpeg = VCN_DPG_STATE__UNPAUSE; @@ -708,108 +706,3 @@ error: amdgpu_bo_unref(&bo); return r; } - -int amdgpu_vcn_jpeg_ring_test_ring(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - uint32_t tmp = 0; - unsigned i; - int r; - - WREG32(adev->vcn.inst[ring->me].external.jpeg_pitch, 0xCAFEDEAD); - r = amdgpu_ring_alloc(ring, 3); - if (r) - return r; - - amdgpu_ring_write(ring, PACKET0(adev->vcn.internal.jpeg_pitch, 0)); - amdgpu_ring_write(ring, 0xDEADBEEF); - amdgpu_ring_commit(ring); - - for (i = 0; i < adev->usec_timeout; i++) { - tmp = RREG32(adev->vcn.inst[ring->me].external.jpeg_pitch); - if (tmp == 0xDEADBEEF) - break; - udelay(1); - } - - if (i >= adev->usec_timeout) - r = -ETIMEDOUT; - - return r; -} - -static int amdgpu_vcn_jpeg_set_reg(struct amdgpu_ring *ring, uint32_t handle, - struct dma_fence **fence) -{ - struct amdgpu_device *adev = ring->adev; - struct amdgpu_job *job; - struct amdgpu_ib *ib; - struct dma_fence *f = NULL; - const unsigned ib_size_dw = 16; - int i, r; - - r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, &job); - if (r) - return r; - - ib = &job->ibs[0]; - - ib->ptr[0] = PACKETJ(adev->vcn.internal.jpeg_pitch, 0, 0, PACKETJ_TYPE0); - ib->ptr[1] = 0xDEADBEEF; - for (i = 2; i < 16; i += 2) { - ib->ptr[i] = PACKETJ(0, 0, 0, PACKETJ_TYPE6); - ib->ptr[i+1] = 0; - } - ib->length_dw = 16; - - r = amdgpu_job_submit_direct(job, ring, &f); - if (r) - goto err; - - if (fence) - *fence = dma_fence_get(f); - dma_fence_put(f); - - return 0; - -err: - amdgpu_job_free(job); - return r; -} - -int amdgpu_vcn_jpeg_ring_test_ib(struct amdgpu_ring *ring, long timeout) -{ - struct amdgpu_device *adev = ring->adev; - uint32_t tmp = 0; - unsigned i; - struct dma_fence *fence = NULL; - long r = 0; - - r = amdgpu_vcn_jpeg_set_reg(ring, 1, &fence); - if (r) - goto error; - - r = dma_fence_wait_timeout(fence, false, timeout); - if (r == 0) { - r = -ETIMEDOUT; - goto error; - } else if (r < 0) { - goto error; - } else { - r = 0; - } - - for (i = 0; i < adev->usec_timeout; i++) { - tmp = RREG32(adev->vcn.inst[ring->me].external.jpeg_pitch); - if (tmp == 0xDEADBEEF) - break; - udelay(1); - } - - if (i >= adev->usec_timeout) - r = -ETIMEDOUT; - - dma_fence_put(fence); -error: - return r; -} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h index dface275c81a39990af847a5294b3b2a498ef754..402a5046b98581529b878e4a54d91625dbc184cb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h @@ -158,7 +158,6 @@ struct amdgpu_vcn_reg{ unsigned ib_size; unsigned gp_scratch8; unsigned scratch9; - unsigned jpeg_pitch; }; struct amdgpu_vcn_inst { @@ -168,7 +167,6 @@ struct amdgpu_vcn_inst { void *saved_bo; struct amdgpu_ring ring_dec; struct amdgpu_ring ring_enc[AMDGPU_VCN_MAX_ENC_RINGS]; - struct amdgpu_ring ring_jpeg; struct amdgpu_irq_src irq; struct amdgpu_vcn_reg external; }; @@ -209,7 +207,4 @@ int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout); int amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring *ring); int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout); -int amdgpu_vcn_jpeg_ring_test_ring(struct amdgpu_ring *ring); -int amdgpu_vcn_jpeg_ring_test_ib(struct amdgpu_ring *ring, long timeout); - #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index e32ae906d79732521a1b3a8020d6faa5b5e5639b..103033f96f133c27c77b320485eb01d028e89718 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -379,54 +379,3 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev) } } } - -static uint32_t parse_clk(char *buf, bool min) -{ - char *ptr = buf; - uint32_t clk = 0; - - do { - ptr = strchr(ptr, ':'); - if (!ptr) - break; - ptr+=2; - if (kstrtou32(ptr, 10, &clk)) - return 0; - } while (!min); - - return clk * 100; -} - -uint32_t amdgpu_virt_get_sclk(struct amdgpu_device *adev, bool lowest) -{ - char *buf = NULL; - uint32_t clk = 0; - - buf = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - adev->virt.ops->get_pp_clk(adev, PP_SCLK, buf); - clk = parse_clk(buf, lowest); - - kfree(buf); - - return clk; -} - -uint32_t amdgpu_virt_get_mclk(struct amdgpu_device *adev, bool lowest) -{ - char *buf = NULL; - uint32_t clk = 0; - - buf = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - adev->virt.ops->get_pp_clk(adev, PP_MCLK, buf); - clk = parse_clk(buf, lowest); - - kfree(buf); - - return clk; -} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h index b0b2bdc750df924df393dbabd99b0977cdda3749..4d1ac7612967e3a52255bd9f79b2db8a9b3b9241 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h @@ -57,8 +57,6 @@ struct amdgpu_virt_ops { int (*reset_gpu)(struct amdgpu_device *adev); int (*wait_reset)(struct amdgpu_device *adev); void (*trans_msg)(struct amdgpu_device *adev, u32 req, u32 data1, u32 data2, u32 data3); - int (*get_pp_clk)(struct amdgpu_device *adev, u32 type, char *buf); - int (*force_dpm_level)(struct amdgpu_device *adev, u32 level); }; /* @@ -85,8 +83,8 @@ enum AMDGIM_FEATURE_FLAG { AMDGIM_FEATURE_GIM_LOAD_UCODES = 0x2, /* VRAM LOST by GIM */ AMDGIM_FEATURE_GIM_FLR_VRAMLOST = 0x4, - /* HW PERF SIM in GIM */ - AMDGIM_FEATURE_HW_PERF_SIMULATION = (1 << 3), + /* PP ONE VF MODE in GIM */ + AMDGIM_FEATURE_PP_ONE_VF = (1 << 4), }; struct amd_sriov_msg_pf2vf_info_header { @@ -257,8 +255,6 @@ struct amdgpu_virt { struct amdgpu_vf_error_buffer vf_errors; struct amdgpu_virt_fw_reserve fw_reserve; uint32_t gim_feature; - /* protect DPM events to GIM */ - struct mutex dpm_mutex; uint32_t reg_access_mode; }; @@ -286,8 +282,8 @@ static inline bool is_virtual_machine(void) #endif } -#define amdgim_is_hwperf(adev) \ - ((adev)->virt.gim_feature & AMDGIM_FEATURE_HW_PERF_SIMULATION) +#define amdgpu_sriov_is_pp_one_vf(adev) \ + ((adev)->virt.gim_feature & AMDGIM_FEATURE_PP_ONE_VF) bool amdgpu_virt_mmio_blocked(struct amdgpu_device *adev); void amdgpu_virt_init_setting(struct amdgpu_device *adev); @@ -306,6 +302,4 @@ int amdgpu_virt_fw_reserve_get_checksum(void *obj, unsigned long obj_size, unsigned int key, unsigned int chksum); void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev); -uint32_t amdgpu_virt_get_sclk(struct amdgpu_device *adev, bool lowest); -uint32_t amdgpu_virt_get_mclk(struct amdgpu_device *adev, bool lowest); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 598c24505c73b0161abf83928d8d4bc77c17ef55..8f26504a59a7a5cdf9738f636d3312cae259c89a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -562,8 +562,8 @@ void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm, { entry->priority = 0; entry->tv.bo = &vm->root.base.bo->tbo; - /* One for the VM updates, one for TTM and one for the CS job */ - entry->tv.num_shared = 3; + /* One for TTM and one for the CS job */ + entry->tv.num_shared = 2; entry->user_pages = NULL; list_add(&entry->tv.head, validated); } @@ -656,7 +656,7 @@ int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm, void *param) { struct amdgpu_vm_bo_base *bo_base, *tmp; - int r = 0; + int r; vm->bulk_moveable &= list_empty(&vm->evicted); @@ -665,7 +665,7 @@ int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm, r = validate(param, bo); if (r) - break; + return r; if (bo->tbo.type != ttm_bo_type_kernel) { amdgpu_vm_bo_moved(bo_base); @@ -678,7 +678,11 @@ int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm, } } - return r; + mutex_lock(&vm->eviction_lock); + vm->evicting = false; + mutex_unlock(&vm->eviction_lock); + + return 0; } /** @@ -1555,15 +1559,25 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev, if (!(flags & AMDGPU_PTE_VALID)) owner = AMDGPU_FENCE_OWNER_KFD; + mutex_lock(&vm->eviction_lock); + if (vm->evicting) { + r = -EBUSY; + goto error_unlock; + } + r = vm->update_funcs->prepare(¶ms, owner, exclusive); if (r) - return r; + goto error_unlock; r = amdgpu_vm_update_ptes(¶ms, start, last + 1, addr, flags); if (r) - return r; + goto error_unlock; + + r = vm->update_funcs->commit(¶ms, fence); - return vm->update_funcs->commit(¶ms, fence); +error_unlock: + mutex_unlock(&vm->eviction_lock); + return r; } /** @@ -2499,6 +2513,41 @@ void amdgpu_vm_bo_rmv(struct amdgpu_device *adev, kfree(bo_va); } +/** + * amdgpu_vm_evictable - check if we can evict a VM + * + * @bo: A page table of the VM. + * + * Check if it is possible to evict a VM. + */ +bool amdgpu_vm_evictable(struct amdgpu_bo *bo) +{ + struct amdgpu_vm_bo_base *bo_base = bo->vm_bo; + + /* Page tables of a destroyed VM can go away immediately */ + if (!bo_base || !bo_base->vm) + return true; + + /* Don't evict VM page tables while they are busy */ + if (!dma_resv_test_signaled_rcu(bo->tbo.base.resv, true)) + return false; + + /* Try to block ongoing updates */ + if (!mutex_trylock(&bo_base->vm->eviction_lock)) + return false; + + /* Don't evict VM page tables while they are updated */ + if (!dma_fence_is_signaled(bo_base->vm->last_direct) || + !dma_fence_is_signaled(bo_base->vm->last_delayed)) { + mutex_unlock(&bo_base->vm->eviction_lock); + return false; + } + + bo_base->vm->evicting = true; + mutex_unlock(&bo_base->vm->eviction_lock); + return true; +} + /** * amdgpu_vm_bo_invalidate - mark the bo as invalid * @@ -2661,8 +2710,16 @@ void amdgpu_vm_adjust_size(struct amdgpu_device *adev, uint32_t min_vm_size, */ long amdgpu_vm_wait_idle(struct amdgpu_vm *vm, long timeout) { - return dma_resv_wait_timeout_rcu(vm->root.base.bo->tbo.base.resv, - true, true, timeout); + timeout = dma_resv_wait_timeout_rcu(vm->root.base.bo->tbo.base.resv, + true, true, timeout); + if (timeout <= 0) + return timeout; + + timeout = dma_fence_wait_timeout(vm->last_direct, true, timeout); + if (timeout <= 0) + return timeout; + + return dma_fence_wait_timeout(vm->last_delayed, true, timeout); } /** @@ -2708,6 +2765,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, goto error_free_direct; vm->pte_support_ats = false; + vm->is_compute_context = false; if (vm_context == AMDGPU_VM_CONTEXT_COMPUTE) { vm->use_cpu_for_update = !!(adev->vm_manager.vm_update_mode & @@ -2730,6 +2788,11 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, else vm->update_funcs = &amdgpu_vm_sdma_funcs; vm->last_update = NULL; + vm->last_direct = dma_fence_get_stub(); + vm->last_delayed = dma_fence_get_stub(); + + mutex_init(&vm->eviction_lock); + vm->evicting = false; amdgpu_vm_bo_param(adev, vm, adev->vm_manager.root_level, false, &bp); if (vm_context == AMDGPU_VM_CONTEXT_COMPUTE) @@ -2780,6 +2843,8 @@ error_free_root: vm->root.base.bo = NULL; error_free_delayed: + dma_fence_put(vm->last_direct); + dma_fence_put(vm->last_delayed); drm_sched_entity_destroy(&vm->delayed); error_free_direct: @@ -2893,6 +2958,7 @@ int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm, vm->update_funcs = &amdgpu_vm_sdma_funcs; dma_fence_put(vm->last_update); vm->last_update = NULL; + vm->is_compute_context = true; if (vm->pasid) { unsigned long flags; @@ -2947,6 +3013,7 @@ void amdgpu_vm_release_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm) spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags); } vm->pasid = 0; + vm->is_compute_context = false; } /** @@ -2978,6 +3045,11 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) vm->pasid = 0; } + dma_fence_wait(vm->last_direct, false); + dma_fence_put(vm->last_direct); + dma_fence_wait(vm->last_delayed, false); + dma_fence_put(vm->last_delayed); + list_for_each_entry_safe(mapping, tmp, &vm->freed, list) { if (mapping->flags & AMDGPU_PTE_PRT && prt_fini_needed) { amdgpu_vm_prt_fini(adev, vm); @@ -3194,11 +3266,20 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, unsigned int pasid, flags = AMDGPU_PTE_VALID | AMDGPU_PTE_SNOOPED | AMDGPU_PTE_SYSTEM; - if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_NEVER) { + if (vm->is_compute_context) { + /* Intentionally setting invalid PTE flag + * combination to force a no-retry-fault + */ + flags = AMDGPU_PTE_EXECUTABLE | AMDGPU_PDE_PTE | + AMDGPU_PTE_TF; + value = 0; + + } else if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_NEVER) { /* Redirect the access to the dummy page */ value = adev->dummy_page_addr; flags |= AMDGPU_PTE_EXECUTABLE | AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE; + } else { /* Let the hw retry silently on the PTE */ value = 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 4dbbe1b6b413604e33ae7be5abfffc36dcdd45f4..7e0eb36da27deaae5e36d7810f0277d60e184c43 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -239,6 +239,10 @@ struct amdgpu_vm { /* tree of virtual addresses mapped */ struct rb_root_cached va; + /* Lock to prevent eviction while we are updating page tables */ + struct mutex eviction_lock; + bool evicting; + /* BOs who needs a validation */ struct list_head evicted; @@ -266,6 +270,10 @@ struct amdgpu_vm { struct drm_sched_entity direct; struct drm_sched_entity delayed; + /* Last submission to the scheduler entities */ + struct dma_fence *last_direct; + struct dma_fence *last_delayed; + unsigned int pasid; /* dedicated to vm */ struct amdgpu_vmid *reserved_vmid[AMDGPU_MAX_VMHUBS]; @@ -298,6 +306,8 @@ struct amdgpu_vm { struct ttm_lru_bulk_move lru_bulk_move; /* mark whether can do the bulk move */ bool bulk_moveable; + /* Flag to indicate if VM is used for compute */ + bool is_compute_context; }; struct amdgpu_vm_manager { @@ -376,6 +386,7 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev, int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, bool clear); +bool amdgpu_vm_evictable(struct amdgpu_bo *bo); void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev, struct amdgpu_bo *bo, bool evicted); uint64_t amdgpu_vm_map_gart(const dma_addr_t *pages_addr, uint64_t addr); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c index 832db59f441ecc8c1b79106307f5bd69ab7ca1ca..19b7f80758f12eb0e37379f9d35799d6bc448c57 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm_sdma.c @@ -71,7 +71,7 @@ static int amdgpu_vm_sdma_prepare(struct amdgpu_vm_update_params *p, p->num_dw_left = ndw; /* Wait for moves to be completed */ - r = amdgpu_sync_fence(p->adev, &p->job->sync, exclusive, false); + r = amdgpu_sync_fence(&p->job->sync, exclusive, false); if (r) return r; @@ -95,11 +95,10 @@ static int amdgpu_vm_sdma_prepare(struct amdgpu_vm_update_params *p, static int amdgpu_vm_sdma_commit(struct amdgpu_vm_update_params *p, struct dma_fence **fence) { - struct amdgpu_bo *root = p->vm->root.base.bo; struct amdgpu_ib *ib = p->job->ibs; struct drm_sched_entity *entity; + struct dma_fence *f, *tmp; struct amdgpu_ring *ring; - struct dma_fence *f; int r; entity = p->direct ? &p->vm->direct : &p->vm->delayed; @@ -112,7 +111,13 @@ static int amdgpu_vm_sdma_commit(struct amdgpu_vm_update_params *p, if (r) goto error; - amdgpu_bo_fence(root, f, true); + tmp = dma_fence_get(f); + if (p->direct) + swap(p->vm->last_direct, tmp); + else + swap(p->vm->last_delayed, tmp); + dma_fence_put(tmp); + if (fence && !p->direct) swap(*fence, f); dma_fence_put(f); diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c index 6858cde9fc5d34cd9424f26b2b59ab3fa4474838..ea702a64f80740abdd31ca31b9fae4d63ce3b807 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c @@ -361,7 +361,6 @@ int amdgpu_atombios_dp_get_panel_mode(struct drm_encoder *encoder, struct drm_connector *connector) { struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); - struct amdgpu_connector_atom_dig *dig_connector; int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; u16 dp_bridge = amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector); u8 tmp; @@ -369,8 +368,6 @@ int amdgpu_atombios_dp_get_panel_mode(struct drm_encoder *encoder, if (!amdgpu_connector->con_priv) return panel_mode; - dig_connector = amdgpu_connector->con_priv; - if (dp_bridge != ENCODER_OBJECT_ID_NONE) { /* DP bridge chips */ if (drm_dp_dpcd_readb(&amdgpu_connector->ddc_bus->aux, @@ -713,7 +710,6 @@ void amdgpu_atombios_dp_link_train(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct amdgpu_device *adev = dev->dev_private; struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); - struct amdgpu_encoder_atom_dig *dig; struct amdgpu_connector *amdgpu_connector; struct amdgpu_connector_atom_dig *dig_connector; struct amdgpu_atombios_dp_link_train_info dp_info; @@ -721,7 +717,6 @@ void amdgpu_atombios_dp_link_train(struct drm_encoder *encoder, if (!amdgpu_encoder->enc_priv) return; - dig = amdgpu_encoder->enc_priv; amdgpu_connector = to_amdgpu_connector(connector); if (!amdgpu_connector->con_priv) diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c b/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c index 980c363b1a0aebece2da26162f9bc48b027e71d6..b4cc7c55fa16f6137d27f641cc2594eecdb70ecf 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c @@ -76,11 +76,6 @@ static int amdgpu_atombios_i2c_process_i2c_ch(struct amdgpu_i2c_chan *chan, } args.lpI2CDataOut = cpu_to_le16(out); } else { - if (num > ATOM_MAX_HW_I2C_READ) { - DRM_ERROR("hw i2c: tried to read too many bytes (%d vs 255)\n", num); - r = -EINVAL; - goto done; - } args.ucRegIndex = 0; args.lpI2CDataOut = 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 1befdee9f0f1d9fd5647e08538520a6f009f8dc0..e9822ea8bb19957ea09142b1ae733a2302d5f3fe 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -1310,6 +1310,23 @@ static int cik_asic_pci_config_reset(struct amdgpu_device *adev) return r; } +static bool cik_asic_supports_baco(struct amdgpu_device *adev) +{ + bool baco_support; + + switch (adev->asic_type) { + case CHIP_BONAIRE: + case CHIP_HAWAII: + smu7_asic_get_baco_capability(adev, &baco_support); + break; + default: + baco_support = false; + break; + } + + return baco_support; +} + static enum amd_reset_method cik_asic_reset_method(struct amdgpu_device *adev) { @@ -1927,6 +1944,7 @@ static const struct amdgpu_asic_funcs cik_asic_funcs = .get_pcie_usage = &cik_get_pcie_usage, .need_reset_on_init = &cik_need_reset_on_init, .get_pcie_replay_count = &cik_get_pcie_replay_count, + .supports_baco = &cik_asic_supports_baco, }; static int cik_common_early_init(void *handle) diff --git a/drivers/gpu/drm/amd/amdgpu/df_v3_6.c b/drivers/gpu/drm/amd/amdgpu/df_v3_6.c index 16fbd2bc8ad1ea00d3f1c7a6c9e8df996970571e..4043ebcea5de6e1efca0a89dad8356e5c5de385e 100644 --- a/drivers/gpu/drm/amd/amdgpu/df_v3_6.c +++ b/drivers/gpu/drm/amd/amdgpu/df_v3_6.c @@ -268,23 +268,29 @@ static void df_v3_6_update_medium_grain_clock_gating(struct amdgpu_device *adev, { u32 tmp; - /* Put DF on broadcast mode */ - adev->df_funcs->enable_broadcast_mode(adev, true); - - if (enable && (adev->cg_flags & AMD_CG_SUPPORT_DF_MGCG)) { - tmp = RREG32_SOC15(DF, 0, mmDF_PIE_AON0_DfGlobalClkGater); - tmp &= ~DF_PIE_AON0_DfGlobalClkGater__MGCGMode_MASK; - tmp |= DF_V3_6_MGCG_ENABLE_15_CYCLE_DELAY; - WREG32_SOC15(DF, 0, mmDF_PIE_AON0_DfGlobalClkGater, tmp); - } else { - tmp = RREG32_SOC15(DF, 0, mmDF_PIE_AON0_DfGlobalClkGater); - tmp &= ~DF_PIE_AON0_DfGlobalClkGater__MGCGMode_MASK; - tmp |= DF_V3_6_MGCG_DISABLE; - WREG32_SOC15(DF, 0, mmDF_PIE_AON0_DfGlobalClkGater, tmp); - } + if (adev->cg_flags & AMD_CG_SUPPORT_DF_MGCG) { + /* Put DF on broadcast mode */ + adev->df_funcs->enable_broadcast_mode(adev, true); + + if (enable) { + tmp = RREG32_SOC15(DF, 0, + mmDF_PIE_AON0_DfGlobalClkGater); + tmp &= ~DF_PIE_AON0_DfGlobalClkGater__MGCGMode_MASK; + tmp |= DF_V3_6_MGCG_ENABLE_15_CYCLE_DELAY; + WREG32_SOC15(DF, 0, + mmDF_PIE_AON0_DfGlobalClkGater, tmp); + } else { + tmp = RREG32_SOC15(DF, 0, + mmDF_PIE_AON0_DfGlobalClkGater); + tmp &= ~DF_PIE_AON0_DfGlobalClkGater__MGCGMode_MASK; + tmp |= DF_V3_6_MGCG_DISABLE; + WREG32_SOC15(DF, 0, + mmDF_PIE_AON0_DfGlobalClkGater, tmp); + } - /* Exit broadcast mode */ - adev->df_funcs->enable_broadcast_mode(adev, false); + /* Exit broadcast mode */ + adev->df_funcs->enable_broadcast_mode(adev, false); + } } static void df_v3_6_get_clockgating_state(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index f2c1b026397b9520f6f6c4ccc26d6800ec3a3374..98db25215d0da8875a7454e4151a6c6c35f54040 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -50,9 +50,6 @@ * Navi10 has two graphic rings to share each graphic pipe. * 1. Primary ring * 2. Async ring - * - * In bring-up phase, it just used primary ring so set gfx ring number as 1 at - * first. */ #define GFX10_NUM_GFX_RINGS 2 #define GFX10_MEC_HPD_SIZE 2048 @@ -117,10 +114,13 @@ static const struct soc15_reg_golden golden_settings_gc_10_1[] = SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2C_CGTT_SCLK_CTRL, 0x10000000, 0x10000100), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2C_CTRL2, 0xffffffff, 0x1402002f), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2C_CTRL3, 0xffff9fff, 0x00001188), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmPA_SC_BINNER_TIMEOUT_COUNTER, 0xffffffff, 0x00000800), SOC15_REG_GOLDEN_VALUE(GC, 0, mmPA_SC_ENHANCE, 0x3fffffff, 0x08000009), SOC15_REG_GOLDEN_VALUE(GC, 0, mmPA_SC_ENHANCE_1, 0x00400000, 0x04440000), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmPA_SC_ENHANCE_2, 0x00000800, 0x00000820), SOC15_REG_GOLDEN_VALUE(GC, 0, mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000), SOC15_REG_GOLDEN_VALUE(GC, 0, mmRMI_SPARE, 0xffffffff, 0xffff3101), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmSPI_CONFIG_CNTL, 0x001f0000, 0x00070104), SOC15_REG_GOLDEN_VALUE(GC, 0, mmSQ_ALU_CLK_CTRL, 0xffffffff, 0xffffffff), SOC15_REG_GOLDEN_VALUE(GC, 0, mmSQ_ARB_CONFIG, 0x00000100, 0x00000130), SOC15_REG_GOLDEN_VALUE(GC, 0, mmSQ_LDS_CLK_CTRL, 0xffffffff, 0xffffffff), @@ -162,10 +162,13 @@ static const struct soc15_reg_golden golden_settings_gc_10_1_1[] = SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2C_CGTT_SCLK_CTRL, 0xffff0fff, 0x10000100), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2C_CTRL2, 0xffffffff, 0x1402002f), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2C_CTRL3, 0xffffbfff, 0x00000188), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmPA_SC_BINNER_TIMEOUT_COUNTER, 0xffffffff, 0x00000800), SOC15_REG_GOLDEN_VALUE(GC, 0, mmPA_SC_ENHANCE, 0x3fffffff, 0x08000009), SOC15_REG_GOLDEN_VALUE(GC, 0, mmPA_SC_ENHANCE_1, 0x00400000, 0x04440000), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmPA_SC_ENHANCE_2, 0x00000800, 0x00000820), SOC15_REG_GOLDEN_VALUE(GC, 0, mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000), SOC15_REG_GOLDEN_VALUE(GC, 0, mmRMI_SPARE, 0xffffffff, 0xffff3101), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmSPI_CONFIG_CNTL, 0x001f0000, 0x00070105), SOC15_REG_GOLDEN_VALUE(GC, 0, mmSQ_ALU_CLK_CTRL, 0xffffffff, 0xffffffff), SOC15_REG_GOLDEN_VALUE(GC, 0, mmSQ_ARB_CONFIG, 0x00000133, 0x00000130), SOC15_REG_GOLDEN_VALUE(GC, 0, mmSQ_LDS_CLK_CTRL, 0xffffffff, 0xffffffff), @@ -611,11 +614,29 @@ static void gfx_v10_0_init_rlc_ext_microcode(struct amdgpu_device *adev) le32_to_cpu(rlc_hdr->reg_list_format_direct_reg_list_length); } +static bool gfx_v10_0_navi10_gfxoff_should_enable(struct amdgpu_device *adev) +{ + bool ret = false; + + switch (adev->pdev->revision) { + case 0xc2: + case 0xc3: + ret = true; + break; + default: + ret = false; + break; + } + + return ret ; +} + static void gfx_v10_0_check_gfxoff_flag(struct amdgpu_device *adev) { switch (adev->asic_type) { case CHIP_NAVI10: - adev->pm.pp_feature &= ~PP_GFXOFF_MASK; + if (!gfx_v10_0_navi10_gfxoff_should_enable(adev)) + adev->pm.pp_feature &= ~PP_GFXOFF_MASK; break; default: break; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c index 7f0a63628c43a72956fb2efd24cd077917690419..31f44d05e606d1e367da11ff176b4279c81dc2a4 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c @@ -1576,7 +1576,7 @@ static void gfx_v6_0_config_init(struct amdgpu_device *adev) static void gfx_v6_0_constants_init(struct amdgpu_device *adev) { u32 gb_addr_config = 0; - u32 mc_shared_chmap, mc_arb_ramcfg; + u32 mc_arb_ramcfg; u32 sx_debug_1; u32 hdp_host_path_cntl; u32 tmp; @@ -1678,7 +1678,6 @@ static void gfx_v6_0_constants_init(struct amdgpu_device *adev) WREG32(mmBIF_FB_EN, BIF_FB_EN__FB_READ_EN_MASK | BIF_FB_EN__FB_WRITE_EN_MASK); - mc_shared_chmap = RREG32(mmMC_SHARED_CHMAP); adev->gfx.config.mc_arb_ramcfg = RREG32(mmMC_ARB_RAMCFG); mc_arb_ramcfg = adev->gfx.config.mc_arb_ramcfg; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index d92e92e5d50b703a3ccae4b61595e819fccfdc2b..8f20a5dd44fe71a77f374894c61b99073d248505 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -4258,7 +4258,7 @@ static int gfx_v7_0_late_init(void *handle) static void gfx_v7_0_gpu_early_init(struct amdgpu_device *adev) { u32 gb_addr_config; - u32 mc_shared_chmap, mc_arb_ramcfg; + u32 mc_arb_ramcfg; u32 dimm00_addr_map, dimm01_addr_map, dimm10_addr_map, dimm11_addr_map; u32 tmp; @@ -4335,7 +4335,6 @@ static void gfx_v7_0_gpu_early_init(struct amdgpu_device *adev) break; } - mc_shared_chmap = RREG32(mmMC_SHARED_CHMAP); adev->gfx.config.mc_arb_ramcfg = RREG32(mmMC_ARB_RAMCFG); mc_arb_ramcfg = adev->gfx.config.mc_arb_ramcfg; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 983db77999e7a6d27800c7d42f2cd03028f5d194..cfc1403fc855a2d1b1f7871e36a047f1ba03b558 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -1677,7 +1677,7 @@ fail: static int gfx_v8_0_gpu_early_init(struct amdgpu_device *adev) { u32 gb_addr_config; - u32 mc_shared_chmap, mc_arb_ramcfg; + u32 mc_arb_ramcfg; u32 dimm00_addr_map, dimm01_addr_map, dimm10_addr_map, dimm11_addr_map; u32 tmp; int ret; @@ -1817,7 +1817,6 @@ static int gfx_v8_0_gpu_early_init(struct amdgpu_device *adev) break; } - mc_shared_chmap = RREG32(mmMC_SHARED_CHMAP); adev->gfx.config.mc_arb_ramcfg = RREG32(mmMC_ARB_RAMCFG); mc_arb_ramcfg = adev->gfx.config.mc_arb_ramcfg; @@ -6146,7 +6145,23 @@ static void gfx_v8_0_ring_emit_fence_gfx(struct amdgpu_ring *ring, u64 addr, bool write64bit = flags & AMDGPU_FENCE_FLAG_64BIT; bool int_sel = flags & AMDGPU_FENCE_FLAG_INT; - /* EVENT_WRITE_EOP - flush caches, send int */ + /* Workaround for cache flush problems. First send a dummy EOP + * event down the pipe with seq one below. + */ + amdgpu_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4)); + amdgpu_ring_write(ring, (EOP_TCL1_ACTION_EN | + EOP_TC_ACTION_EN | + EOP_TC_WB_ACTION_EN | + EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) | + EVENT_INDEX(5))); + amdgpu_ring_write(ring, addr & 0xfffffffc); + amdgpu_ring_write(ring, (upper_32_bits(addr) & 0xffff) | + DATA_SEL(1) | INT_SEL(0)); + amdgpu_ring_write(ring, lower_32_bits(seq - 1)); + amdgpu_ring_write(ring, upper_32_bits(seq - 1)); + + /* Then send the real EOP event down the pipe: + * EVENT_WRITE_EOP - flush caches, send int */ amdgpu_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4)); amdgpu_ring_write(ring, (EOP_TCL1_ACTION_EN | EOP_TC_ACTION_EN | @@ -6888,7 +6903,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = { 5 + /* COND_EXEC */ 7 + /* PIPELINE_SYNC */ VI_FLUSH_GPU_TLB_NUM_WREG * 5 + 9 + /* VM_FLUSH */ - 8 + /* FENCE for VM_FLUSH */ + 12 + /* FENCE for VM_FLUSH */ 20 + /* GDS switch */ 4 + /* double SWITCH_BUFFER, the first COND_EXEC jump to the place just @@ -6900,7 +6915,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = { 31 + /* DE_META */ 3 + /* CNTX_CTRL */ 5 + /* HDP_INVL */ - 8 + 8 + /* FENCE x2 */ + 12 + 12 + /* FENCE x2 */ 2, /* SWITCH_BUFFER */ .emit_ib_size = 4, /* gfx_v8_0_ring_emit_ib_gfx */ .emit_ib = gfx_v8_0_ring_emit_ib_gfx, diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 66328ffa395af240cb6f069206a4a0217de69aeb..2616f1b59bbd08d49f360ed0831e1eeb010a567e 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -48,6 +48,8 @@ #include "amdgpu_ras.h" +#include "sdma0/sdma0_4_0_offset.h" +#include "sdma1/sdma1_4_0_offset.h" #define GFX9_NUM_GFX_RINGS 1 #define GFX9_MEC_HPD_SIZE 4096 #define RLCG_UCODE_LOADING_START_ADDRESS 0x00002000L @@ -131,18 +133,6 @@ MODULE_FIRMWARE("amdgpu/renoir_rlc.bin"); #define mmTCP_CHAN_STEER_5_ARCT 0x0b0c #define mmTCP_CHAN_STEER_5_ARCT_BASE_IDX 0 -struct ras_gfx_subblock_reg { - const char *name; - uint32_t hwip; - uint32_t inst; - uint32_t seg; - uint32_t reg_offset; - uint32_t sec_count_mask; - uint32_t sec_count_shift; - uint32_t ded_count_mask; - uint32_t ded_count_shift; -}; - enum ta_ras_gfx_subblock { /*CPC*/ TA_RAS_BLOCK__GFX_CPC_INDEX_START = 0, @@ -3948,24 +3938,37 @@ static const struct soc15_reg_entry vgpr_init_regs[] = { { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_STATIC_THREAD_MGMT_SE1), 0xffffffff }, { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_STATIC_THREAD_MGMT_SE2), 0xffffffff }, { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_STATIC_THREAD_MGMT_SE3), 0xffffffff }, - { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_RESOURCE_LIMITS), 0x1000000 }, /* CU_GROUP_COUNT=1 */ - { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_NUM_THREAD_X), 256*2 }, - { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_NUM_THREAD_Y), 1 }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_RESOURCE_LIMITS), 0x0000000 }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_NUM_THREAD_X), 0x40 }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_NUM_THREAD_Y), 4 }, { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_NUM_THREAD_Z), 1 }, - { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_PGM_RSRC1), 0x100007f }, /* VGPRS=15 (256 logical VGPRs, SGPRS=1 (16 SGPRs, BULKY=1 */ + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_PGM_RSRC1), 0x3f }, { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_PGM_RSRC2), 0x400000 }, /* 64KB LDS */ }; -static const struct soc15_reg_entry sgpr_init_regs[] = { - { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_STATIC_THREAD_MGMT_SE0), 0xffffffff }, - { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_STATIC_THREAD_MGMT_SE1), 0xffffffff }, - { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_STATIC_THREAD_MGMT_SE2), 0xffffffff }, - { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_STATIC_THREAD_MGMT_SE3), 0xffffffff }, - { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_RESOURCE_LIMITS), 0x1000000 }, /* CU_GROUP_COUNT=1 */ - { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_NUM_THREAD_X), 256*2 }, - { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_NUM_THREAD_Y), 1 }, +static const struct soc15_reg_entry sgpr1_init_regs[] = { + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_STATIC_THREAD_MGMT_SE0), 0x000000ff }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_STATIC_THREAD_MGMT_SE1), 0x000000ff }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_STATIC_THREAD_MGMT_SE2), 0x000000ff }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_STATIC_THREAD_MGMT_SE3), 0x000000ff }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_RESOURCE_LIMITS), 0x0000000 }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_NUM_THREAD_X), 0x40 }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_NUM_THREAD_Y), 8 }, { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_NUM_THREAD_Z), 1 }, - { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_PGM_RSRC1), 0x340 }, /* SGPRS=13 (112 GPRS) */ + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_PGM_RSRC1), 0x240 }, /* (80 GPRS) */ + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_PGM_RSRC2), 0x0 }, +}; + +static const struct soc15_reg_entry sgpr2_init_regs[] = { + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_STATIC_THREAD_MGMT_SE0), 0x0000ff00 }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_STATIC_THREAD_MGMT_SE1), 0x0000ff00 }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_STATIC_THREAD_MGMT_SE2), 0x0000ff00 }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_STATIC_THREAD_MGMT_SE3), 0x0000ff00 }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_RESOURCE_LIMITS), 0x0000000 }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_NUM_THREAD_X), 0x40 }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_NUM_THREAD_Y), 8 }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_NUM_THREAD_Z), 1 }, + { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_PGM_RSRC1), 0x240 }, /* (80 GPRS) */ { SOC15_REG_ENTRY(GC, 0, mmCOMPUTE_PGM_RSRC2), 0x0 }, }; @@ -4003,6 +4006,9 @@ static const struct soc15_reg_entry sec_ded_counter_registers[] = { { SOC15_REG_ENTRY(GC, 0, mmTCC_EDC_CNT2), 0, 1, 16}, { SOC15_REG_ENTRY(GC, 0, mmTCA_EDC_CNT), 0, 1, 2}, { SOC15_REG_ENTRY(GC, 0, mmSQC_EDC_CNT3), 0, 4, 6}, + { SOC15_REG_ENTRY(SDMA0, 0, mmSDMA0_EDC_COUNTER), 0, 1, 1}, + { SOC15_REG_ENTRY(SDMA1, 0, mmSDMA1_EDC_COUNTER), 0, 1, 1}, + { SOC15_REG_ENTRY(HDP, 0, mmHDP_EDC_CNT), 0, 1, 1}, }; static int gfx_v9_0_do_edc_gds_workarounds(struct amdgpu_device *adev) @@ -4072,7 +4078,9 @@ static int gfx_v9_0_do_edc_gpr_workarounds(struct amdgpu_device *adev) total_size = ((ARRAY_SIZE(vgpr_init_regs) * 3) + 4 + 5 + 2) * 4; total_size += - ((ARRAY_SIZE(sgpr_init_regs) * 3) + 4 + 5 + 2) * 4; + ((ARRAY_SIZE(sgpr1_init_regs) * 3) + 4 + 5 + 2) * 4; + total_size += + ((ARRAY_SIZE(sgpr2_init_regs) * 3) + 4 + 5 + 2) * 4; total_size = ALIGN(total_size, 256); vgpr_offset = total_size; total_size += ALIGN(sizeof(vgpr_init_compute_shader), 256); @@ -4115,7 +4123,35 @@ static int gfx_v9_0_do_edc_gpr_workarounds(struct amdgpu_device *adev) /* write dispatch packet */ ib.ptr[ib.length_dw++] = PACKET3(PACKET3_DISPATCH_DIRECT, 3); - ib.ptr[ib.length_dw++] = 128; /* x */ + ib.ptr[ib.length_dw++] = 0x40*2; /* x */ + ib.ptr[ib.length_dw++] = 1; /* y */ + ib.ptr[ib.length_dw++] = 1; /* z */ + ib.ptr[ib.length_dw++] = + REG_SET_FIELD(0, COMPUTE_DISPATCH_INITIATOR, COMPUTE_SHADER_EN, 1); + + /* write CS partial flush packet */ + ib.ptr[ib.length_dw++] = PACKET3(PACKET3_EVENT_WRITE, 0); + ib.ptr[ib.length_dw++] = EVENT_TYPE(7) | EVENT_INDEX(4); + + /* SGPR1 */ + /* write the register state for the compute dispatch */ + for (i = 0; i < ARRAY_SIZE(sgpr1_init_regs); i++) { + ib.ptr[ib.length_dw++] = PACKET3(PACKET3_SET_SH_REG, 1); + ib.ptr[ib.length_dw++] = SOC15_REG_ENTRY_OFFSET(sgpr1_init_regs[i]) + - PACKET3_SET_SH_REG_START; + ib.ptr[ib.length_dw++] = sgpr1_init_regs[i].reg_value; + } + /* write the shader start address: mmCOMPUTE_PGM_LO, mmCOMPUTE_PGM_HI */ + gpu_addr = (ib.gpu_addr + (u64)sgpr_offset) >> 8; + ib.ptr[ib.length_dw++] = PACKET3(PACKET3_SET_SH_REG, 2); + ib.ptr[ib.length_dw++] = SOC15_REG_OFFSET(GC, 0, mmCOMPUTE_PGM_LO) + - PACKET3_SET_SH_REG_START; + ib.ptr[ib.length_dw++] = lower_32_bits(gpu_addr); + ib.ptr[ib.length_dw++] = upper_32_bits(gpu_addr); + + /* write dispatch packet */ + ib.ptr[ib.length_dw++] = PACKET3(PACKET3_DISPATCH_DIRECT, 3); + ib.ptr[ib.length_dw++] = 0xA0*2; /* x */ ib.ptr[ib.length_dw++] = 1; /* y */ ib.ptr[ib.length_dw++] = 1; /* z */ ib.ptr[ib.length_dw++] = @@ -4125,13 +4161,13 @@ static int gfx_v9_0_do_edc_gpr_workarounds(struct amdgpu_device *adev) ib.ptr[ib.length_dw++] = PACKET3(PACKET3_EVENT_WRITE, 0); ib.ptr[ib.length_dw++] = EVENT_TYPE(7) | EVENT_INDEX(4); - /* SGPR */ + /* SGPR2 */ /* write the register state for the compute dispatch */ - for (i = 0; i < ARRAY_SIZE(sgpr_init_regs); i++) { + for (i = 0; i < ARRAY_SIZE(sgpr2_init_regs); i++) { ib.ptr[ib.length_dw++] = PACKET3(PACKET3_SET_SH_REG, 1); - ib.ptr[ib.length_dw++] = SOC15_REG_ENTRY_OFFSET(sgpr_init_regs[i]) + ib.ptr[ib.length_dw++] = SOC15_REG_ENTRY_OFFSET(sgpr2_init_regs[i]) - PACKET3_SET_SH_REG_START; - ib.ptr[ib.length_dw++] = sgpr_init_regs[i].reg_value; + ib.ptr[ib.length_dw++] = sgpr2_init_regs[i].reg_value; } /* write the shader start address: mmCOMPUTE_PGM_LO, mmCOMPUTE_PGM_HI */ gpu_addr = (ib.gpu_addr + (u64)sgpr_offset) >> 8; @@ -4143,7 +4179,7 @@ static int gfx_v9_0_do_edc_gpr_workarounds(struct amdgpu_device *adev) /* write dispatch packet */ ib.ptr[ib.length_dw++] = PACKET3(PACKET3_DISPATCH_DIRECT, 3); - ib.ptr[ib.length_dw++] = 128; /* x */ + ib.ptr[ib.length_dw++] = 0xA0*2; /* x */ ib.ptr[ib.length_dw++] = 1; /* y */ ib.ptr[ib.length_dw++] = 1; /* z */ ib.ptr[ib.length_dw++] = @@ -4209,10 +4245,6 @@ static int gfx_v9_0_ecc_late_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = amdgpu_gfx_ras_late_init(adev); - if (r) - return r; - r = gfx_v9_0_do_edc_gds_workarounds(adev); if (r) return r; @@ -4222,6 +4254,10 @@ static int gfx_v9_0_ecc_late_init(void *handle) if (r) return r; + r = amdgpu_gfx_ras_late_init(adev); + if (r) + return r; + return 0; } @@ -5447,7 +5483,7 @@ static int gfx_v9_0_priv_inst_irq(struct amdgpu_device *adev, } -static const struct ras_gfx_subblock_reg ras_subblock_regs[] = { +static const struct soc15_ras_field_entry gc_ras_fields_vg20[] = { { "CPC_SCRATCH", SOC15_REG_ENTRY(GC, 0, mmCPC_EDC_SCRATCH_CNT), SOC15_REG_FIELD(CPC_EDC_SCRATCH_CNT, SEC_COUNT), SOC15_REG_FIELD(CPC_EDC_SCRATCH_CNT, DED_COUNT) @@ -6106,29 +6142,29 @@ static int __get_ras_error_count(const struct soc15_reg_entry *reg, uint32_t i; uint32_t sec_cnt, ded_cnt; - for (i = 0; i < ARRAY_SIZE(ras_subblock_regs); i++) { - if(ras_subblock_regs[i].reg_offset != reg->reg_offset || - ras_subblock_regs[i].seg != reg->seg || - ras_subblock_regs[i].inst != reg->inst) + for (i = 0; i < ARRAY_SIZE(gc_ras_fields_vg20); i++) { + if(gc_ras_fields_vg20[i].reg_offset != reg->reg_offset || + gc_ras_fields_vg20[i].seg != reg->seg || + gc_ras_fields_vg20[i].inst != reg->inst) continue; sec_cnt = (value & - ras_subblock_regs[i].sec_count_mask) >> - ras_subblock_regs[i].sec_count_shift; + gc_ras_fields_vg20[i].sec_count_mask) >> + gc_ras_fields_vg20[i].sec_count_shift; if (sec_cnt) { DRM_INFO("GFX SubBlock %s, Instance[%d][%d], SEC %d\n", - ras_subblock_regs[i].name, + gc_ras_fields_vg20[i].name, se_id, inst_id, sec_cnt); *sec_count += sec_cnt; } ded_cnt = (value & - ras_subblock_regs[i].ded_count_mask) >> - ras_subblock_regs[i].ded_count_shift; + gc_ras_fields_vg20[i].ded_count_mask) >> + gc_ras_fields_vg20[i].ded_count_shift; if (ded_cnt) { DRM_INFO("GFX SubBlock %s, Instance[%d][%d], DED %d\n", - ras_subblock_regs[i].name, + gc_ras_fields_vg20[i].name, se_id, inst_id, ded_cnt); *ded_count += ded_cnt; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index 2324695074463a9bd3fe16054fc057bb1ef7927c..f5725336a5f26dbc3082bd52a90bc260c557a026 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -219,6 +219,21 @@ static uint32_t gmc_v10_0_get_invalidate_req(unsigned int vmid, return req; } +/** + * gmc_v10_0_use_invalidate_semaphore - judge whether to use semaphore + * + * @adev: amdgpu_device pointer + * @vmhub: vmhub type + * + */ +static bool gmc_v10_0_use_invalidate_semaphore(struct amdgpu_device *adev, + uint32_t vmhub) +{ + return ((vmhub == AMDGPU_MMHUB_0 || + vmhub == AMDGPU_MMHUB_1) && + (!amdgpu_sriov_vf(adev))); +} + /* * GART * VMID 0 is the physical GPU addresses as used by the kernel. @@ -229,6 +244,7 @@ static uint32_t gmc_v10_0_get_invalidate_req(unsigned int vmid, static void gmc_v10_0_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid, unsigned int vmhub, uint32_t flush_type) { + bool use_semaphore = gmc_v10_0_use_invalidate_semaphore(adev, vmhub); struct amdgpu_vmhub *hub = &adev->vmhub[vmhub]; u32 tmp = gmc_v10_0_get_invalidate_req(vmid, flush_type); /* Use register 17 for GART */ @@ -244,8 +260,7 @@ static void gmc_v10_0_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid, */ /* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */ - if (vmhub == AMDGPU_MMHUB_0 || - vmhub == AMDGPU_MMHUB_1) { + if (use_semaphore) { for (i = 0; i < adev->usec_timeout; i++) { /* a read return value of 1 means semaphore acuqire */ tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_sem + eng); @@ -278,8 +293,7 @@ static void gmc_v10_0_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid, } /* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */ - if (vmhub == AMDGPU_MMHUB_0 || - vmhub == AMDGPU_MMHUB_1) + if (use_semaphore) /* * add semaphore release after invalidation, * write with 0 means semaphore release @@ -369,6 +383,7 @@ error_alloc: static uint64_t gmc_v10_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { + 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); unsigned eng = ring->vm_inv_eng; @@ -381,8 +396,7 @@ static uint64_t gmc_v10_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring, */ /* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */ - if (ring->funcs->vmhub == AMDGPU_MMHUB_0 || - ring->funcs->vmhub == AMDGPU_MMHUB_1) + if (use_semaphore) /* a read return value of 1 means semaphore acuqire */ amdgpu_ring_emit_reg_wait(ring, hub->vm_inv_eng0_sem + eng, 0x1, 0x1); @@ -398,8 +412,7 @@ static uint64_t gmc_v10_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring, req, 1 << vmid); /* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */ - if (ring->funcs->vmhub == AMDGPU_MMHUB_0 || - ring->funcs->vmhub == AMDGPU_MMHUB_1) + if (use_semaphore) /* * add semaphore release after invalidation, * write with 0 means semaphore release diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 3c355fb5d2b47227621c220115ebc1957841399a..fa025ceeea0fa1e68ee9e7e6e71631e7f61e0250 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -416,6 +416,24 @@ static uint32_t gmc_v9_0_get_invalidate_req(unsigned int vmid, return req; } +/** + * gmc_v9_0_use_invalidate_semaphore - judge whether to use semaphore + * + * @adev: amdgpu_device pointer + * @vmhub: vmhub type + * + */ +static bool gmc_v9_0_use_invalidate_semaphore(struct amdgpu_device *adev, + uint32_t vmhub) +{ + return ((vmhub == AMDGPU_MMHUB_0 || + vmhub == AMDGPU_MMHUB_1) && + (!amdgpu_sriov_vf(adev)) && + (!(adev->asic_type == CHIP_RAVEN && + adev->rev_id < 0x8 && + adev->pdev->device == 0x15d8))); +} + /* * GART * VMID 0 is the physical GPU addresses as used by the kernel. @@ -435,6 +453,7 @@ static uint32_t gmc_v9_0_get_invalidate_req(unsigned int vmid, static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, uint32_t vmhub, uint32_t flush_type) { + bool use_semaphore = gmc_v9_0_use_invalidate_semaphore(adev, vmhub); const unsigned eng = 17; u32 j, tmp; struct amdgpu_vmhub *hub; @@ -468,8 +487,7 @@ static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, */ /* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */ - if (vmhub == AMDGPU_MMHUB_0 || - vmhub == AMDGPU_MMHUB_1) { + if (use_semaphore) { for (j = 0; j < adev->usec_timeout; j++) { /* a read return value of 1 means semaphore acuqire */ tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_sem + eng); @@ -499,8 +517,7 @@ static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, } /* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */ - if (vmhub == AMDGPU_MMHUB_0 || - vmhub == AMDGPU_MMHUB_1) + if (use_semaphore) /* * add semaphore release after invalidation, * write with 0 means semaphore release @@ -518,6 +535,7 @@ static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, static uint64_t gmc_v9_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { + bool use_semaphore = gmc_v9_0_use_invalidate_semaphore(ring->adev, ring->funcs->vmhub); struct amdgpu_device *adev = ring->adev; struct amdgpu_vmhub *hub = &adev->vmhub[ring->funcs->vmhub]; uint32_t req = gmc_v9_0_get_invalidate_req(vmid, 0); @@ -531,8 +549,7 @@ static uint64_t gmc_v9_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring, */ /* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */ - if (ring->funcs->vmhub == AMDGPU_MMHUB_0 || - ring->funcs->vmhub == AMDGPU_MMHUB_1) + if (use_semaphore) /* a read return value of 1 means semaphore acuqire */ amdgpu_ring_emit_reg_wait(ring, hub->vm_inv_eng0_sem + eng, 0x1, 0x1); @@ -548,8 +565,7 @@ static uint64_t gmc_v9_0_emit_flush_gpu_tlb(struct amdgpu_ring *ring, req, 1 << vmid); /* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */ - if (ring->funcs->vmhub == AMDGPU_MMHUB_0 || - ring->funcs->vmhub == AMDGPU_MMHUB_1) + if (use_semaphore) /* * add semaphore release after invalidation, * write with 0 means semaphore release @@ -699,7 +715,15 @@ static void gmc_v9_0_set_umc_funcs(struct amdgpu_device *adev) adev->umc.max_ras_err_cnt_per_query = UMC_V6_1_TOTAL_CHANNEL_NUM; adev->umc.channel_inst_num = UMC_V6_1_CHANNEL_INSTANCE_NUM; adev->umc.umc_inst_num = UMC_V6_1_UMC_INSTANCE_NUM; - adev->umc.channel_offs = UMC_V6_1_PER_CHANNEL_OFFSET; + adev->umc.channel_offs = UMC_V6_1_PER_CHANNEL_OFFSET_VG20; + adev->umc.channel_idx_tbl = &umc_v6_1_channel_idx_tbl[0][0]; + adev->umc.funcs = &umc_v6_1_funcs; + break; + case CHIP_ARCTURUS: + adev->umc.max_ras_err_cnt_per_query = UMC_V6_1_TOTAL_CHANNEL_NUM; + adev->umc.channel_inst_num = UMC_V6_1_CHANNEL_INSTANCE_NUM; + adev->umc.umc_inst_num = UMC_V6_1_UMC_INSTANCE_NUM; + adev->umc.channel_offs = UMC_V6_1_PER_CHANNEL_OFFSET_ARCT; adev->umc.channel_idx_tbl = &umc_v6_1_channel_idx_tbl[0][0]; adev->umc.funcs = &umc_v6_1_funcs; break; @@ -714,6 +738,9 @@ static void gmc_v9_0_set_mmhub_funcs(struct amdgpu_device *adev) case CHIP_VEGA20: adev->mmhub.funcs = &mmhub_v1_0_funcs; break; + case CHIP_ARCTURUS: + adev->mmhub.funcs = &mmhub_v9_4_funcs; + break; default: break; } @@ -809,6 +836,7 @@ static int gmc_v9_0_late_init(void *handle) switch (adev->asic_type) { case CHIP_VEGA10: case CHIP_VEGA20: + case CHIP_ARCTURUS: r = amdgpu_atomfirmware_mem_ecc_supported(adev); if (!r) { DRM_INFO("ECC is not present.\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.h b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.h index 971c0840358f51dac88b08ee36c7c5f8c8d656e5..49e8be761214bdecbc10e9927ffdda6dfd8fd1ad 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.h +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.h @@ -36,12 +36,4 @@ extern const struct amd_ip_funcs gmc_v9_0_ip_funcs; extern const struct amdgpu_ip_block_version gmc_v9_0_ip_block; - -/* amdgpu_amdkfd*.c */ -void gfxhub_v1_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid, - uint64_t value); -void mmhub_v1_0_setup_vm_pt_regs(struct amdgpu_device *adev, uint32_t vmid, - uint64_t value); -void mmhub_v9_4_setup_vm_pt_regs(struct amdgpu_device *adev, int hubid, - uint32_t vmid, uint64_t value); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c new file mode 100644 index 0000000000000000000000000000000000000000..a141408dfb23d2381c9d94b240cf7adebe8129a2 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c @@ -0,0 +1,585 @@ +/* + * Copyright 2019 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 "amdgpu.h" +#include "amdgpu_jpeg.h" +#include "soc15.h" +#include "soc15d.h" + +#include "vcn/vcn_1_0_offset.h" +#include "vcn/vcn_1_0_sh_mask.h" + +static void jpeg_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev); +static void jpeg_v1_0_set_irq_funcs(struct amdgpu_device *adev); + +static void jpeg_v1_0_decode_ring_patch_wreg(struct amdgpu_ring *ring, uint32_t *ptr, uint32_t reg_offset, uint32_t val) +{ + struct amdgpu_device *adev = ring->adev; + ring->ring[(*ptr)++] = PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0); + if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) || + ((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) { + ring->ring[(*ptr)++] = 0; + ring->ring[(*ptr)++] = PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE0); + } else { + ring->ring[(*ptr)++] = reg_offset; + ring->ring[(*ptr)++] = PACKETJ(0, 0, 0, PACKETJ_TYPE0); + } + ring->ring[(*ptr)++] = val; +} + +static void jpeg_v1_0_decode_ring_set_patch_ring(struct amdgpu_ring *ring, uint32_t ptr) +{ + struct amdgpu_device *adev = ring->adev; + + uint32_t reg, reg_offset, val, mask, i; + + // 1st: program mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW + reg = SOC15_REG_OFFSET(JPEG, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW); + reg_offset = (reg << 2); + val = lower_32_bits(ring->gpu_addr); + jpeg_v1_0_decode_ring_patch_wreg(ring, &ptr, reg_offset, val); + + // 2nd: program mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH + reg = SOC15_REG_OFFSET(JPEG, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH); + reg_offset = (reg << 2); + val = upper_32_bits(ring->gpu_addr); + jpeg_v1_0_decode_ring_patch_wreg(ring, &ptr, reg_offset, val); + + // 3rd to 5th: issue MEM_READ commands + for (i = 0; i <= 2; i++) { + ring->ring[ptr++] = PACKETJ(0, 0, 0, PACKETJ_TYPE2); + ring->ring[ptr++] = 0; + } + + // 6th: program mmUVD_JRBC_RB_CNTL register to enable NO_FETCH and RPTR write ability + reg = SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_RB_CNTL); + reg_offset = (reg << 2); + val = 0x13; + jpeg_v1_0_decode_ring_patch_wreg(ring, &ptr, reg_offset, val); + + // 7th: program mmUVD_JRBC_RB_REF_DATA + reg = SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_RB_REF_DATA); + reg_offset = (reg << 2); + val = 0x1; + jpeg_v1_0_decode_ring_patch_wreg(ring, &ptr, reg_offset, val); + + // 8th: issue conditional register read mmUVD_JRBC_RB_CNTL + reg = SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_RB_CNTL); + reg_offset = (reg << 2); + val = 0x1; + mask = 0x1; + + ring->ring[ptr++] = PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0); + ring->ring[ptr++] = 0x01400200; + ring->ring[ptr++] = PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0); + ring->ring[ptr++] = val; + ring->ring[ptr++] = PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0); + if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) || + ((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) { + ring->ring[ptr++] = 0; + ring->ring[ptr++] = PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE3); + } else { + ring->ring[ptr++] = reg_offset; + ring->ring[ptr++] = PACKETJ(0, 0, 0, PACKETJ_TYPE3); + } + ring->ring[ptr++] = mask; + + //9th to 21st: insert no-op + for (i = 0; i <= 12; i++) { + ring->ring[ptr++] = PACKETJ(0, 0, 0, PACKETJ_TYPE6); + ring->ring[ptr++] = 0; + } + + //22nd: reset mmUVD_JRBC_RB_RPTR + reg = SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_RB_RPTR); + reg_offset = (reg << 2); + val = 0; + jpeg_v1_0_decode_ring_patch_wreg(ring, &ptr, reg_offset, val); + + //23rd: program mmUVD_JRBC_RB_CNTL to disable no_fetch + reg = SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_RB_CNTL); + reg_offset = (reg << 2); + val = 0x12; + jpeg_v1_0_decode_ring_patch_wreg(ring, &ptr, reg_offset, val); +} + +/** + * jpeg_v1_0_decode_ring_get_rptr - get read pointer + * + * @ring: amdgpu_ring pointer + * + * Returns the current hardware read pointer + */ +static uint64_t jpeg_v1_0_decode_ring_get_rptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + return RREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_RPTR); +} + +/** + * jpeg_v1_0_decode_ring_get_wptr - get write pointer + * + * @ring: amdgpu_ring pointer + * + * Returns the current hardware write pointer + */ +static uint64_t jpeg_v1_0_decode_ring_get_wptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + return RREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_WPTR); +} + +/** + * jpeg_v1_0_decode_ring_set_wptr - set write pointer + * + * @ring: amdgpu_ring pointer + * + * Commits the write pointer to the hardware + */ +static void jpeg_v1_0_decode_ring_set_wptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_WPTR, lower_32_bits(ring->wptr)); +} + +/** + * jpeg_v1_0_decode_ring_insert_start - insert a start command + * + * @ring: amdgpu_ring pointer + * + * Write a start command to the ring. + */ +static void jpeg_v1_0_decode_ring_insert_start(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x68e04); + + amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x80010000); +} + +/** + * jpeg_v1_0_decode_ring_insert_end - insert a end command + * + * @ring: amdgpu_ring pointer + * + * Write a end command to the ring. + */ +static void jpeg_v1_0_decode_ring_insert_end(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x68e04); + + amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x00010000); +} + +/** + * jpeg_v1_0_decode_ring_emit_fence - emit an fence & trap command + * + * @ring: amdgpu_ring pointer + * @fence: fence to emit + * + * Write a fence and a trap command to the ring. + */ +static void jpeg_v1_0_decode_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq, + unsigned flags) +{ + struct amdgpu_device *adev = ring->adev; + + WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JPEG_GPCOM_DATA0), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, seq); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JPEG_GPCOM_DATA1), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, seq); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, lower_32_bits(addr)); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JPEG_GPCOM_CMD), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x8); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JPEG_GPCOM_CMD), 0, PACKETJ_CONDITION_CHECK0, PACKETJ_TYPE4)); + amdgpu_ring_write(ring, 0); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x01400200); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, seq); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, lower_32_bits(addr)); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + + amdgpu_ring_write(ring, + PACKETJ(0, 0, PACKETJ_CONDITION_CHECK3, PACKETJ_TYPE2)); + amdgpu_ring_write(ring, 0xffffffff); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x3fbc); + + amdgpu_ring_write(ring, + PACKETJ(0, 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x1); + + /* emit trap */ + amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE7)); + amdgpu_ring_write(ring, 0); +} + +/** + * jpeg_v1_0_decode_ring_emit_ib - execute indirect buffer + * + * @ring: amdgpu_ring pointer + * @ib: indirect buffer to execute + * + * Write ring commands to execute the indirect buffer. + */ +static void jpeg_v1_0_decode_ring_emit_ib(struct amdgpu_ring *ring, + struct amdgpu_job *job, + struct amdgpu_ib *ib, + uint32_t flags) +{ + struct amdgpu_device *adev = ring->adev; + unsigned vmid = AMDGPU_JOB_GET_VMID(job); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_LMI_JRBC_IB_VMID), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, (vmid | (vmid << 4))); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_LMI_JPEG_VMID), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, (vmid | (vmid << 4))); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_LMI_JRBC_IB_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr)); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_LMI_JRBC_IB_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr)); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_IB_SIZE), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, ib->length_dw); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, lower_32_bits(ring->gpu_addr)); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, upper_32_bits(ring->gpu_addr)); + + amdgpu_ring_write(ring, + PACKETJ(0, 0, PACKETJ_CONDITION_CHECK0, PACKETJ_TYPE2)); + amdgpu_ring_write(ring, 0); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x01400200); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x2); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_STATUS), 0, PACKETJ_CONDITION_CHECK3, PACKETJ_TYPE3)); + amdgpu_ring_write(ring, 0x2); +} + +static void jpeg_v1_0_decode_ring_emit_reg_wait(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val, + uint32_t mask) +{ + struct amdgpu_device *adev = ring->adev; + uint32_t reg_offset = (reg << 2); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x01400200); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, val); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0)); + if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) || + ((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) { + amdgpu_ring_write(ring, 0); + amdgpu_ring_write(ring, + PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE3)); + } else { + amdgpu_ring_write(ring, reg_offset); + amdgpu_ring_write(ring, + PACKETJ(0, 0, 0, PACKETJ_TYPE3)); + } + amdgpu_ring_write(ring, mask); +} + +static void jpeg_v1_0_decode_ring_emit_vm_flush(struct amdgpu_ring *ring, + unsigned vmid, uint64_t pd_addr) +{ + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; + uint32_t data0, data1, mask; + + pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); + + /* wait for register write */ + data0 = hub->ctx0_ptb_addr_lo32 + vmid * 2; + data1 = lower_32_bits(pd_addr); + mask = 0xffffffff; + jpeg_v1_0_decode_ring_emit_reg_wait(ring, data0, data1, mask); +} + +static void jpeg_v1_0_decode_ring_emit_wreg(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val) +{ + struct amdgpu_device *adev = ring->adev; + uint32_t reg_offset = (reg << 2); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0)); + if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) || + ((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) { + amdgpu_ring_write(ring, 0); + amdgpu_ring_write(ring, + PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE0)); + } else { + amdgpu_ring_write(ring, reg_offset); + amdgpu_ring_write(ring, + PACKETJ(0, 0, 0, PACKETJ_TYPE0)); + } + amdgpu_ring_write(ring, val); +} + +static void jpeg_v1_0_decode_ring_nop(struct amdgpu_ring *ring, uint32_t count) +{ + int i; + + WARN_ON(ring->wptr % 2 || count % 2); + + for (i = 0; i < count / 2; i++) { + amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE6)); + amdgpu_ring_write(ring, 0); + } +} + +static int jpeg_v1_0_set_interrupt_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned type, + enum amdgpu_interrupt_state state) +{ + return 0; +} + +static int jpeg_v1_0_process_interrupt(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + DRM_DEBUG("IH: JPEG decode TRAP\n"); + + switch (entry->src_id) { + case 126: + amdgpu_fence_process(&adev->jpeg.inst->ring_dec); + break; + default: + DRM_ERROR("Unhandled interrupt: %d %d\n", + entry->src_id, entry->src_data[0]); + break; + } + + return 0; +} + +/** + * jpeg_v1_0_early_init - set function pointers + * + * @handle: amdgpu_device pointer + * + * Set ring and irq function pointers + */ +int jpeg_v1_0_early_init(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + adev->jpeg.num_jpeg_inst = 1; + + jpeg_v1_0_set_dec_ring_funcs(adev); + jpeg_v1_0_set_irq_funcs(adev); + + return 0; +} + +/** + * jpeg_v1_0_sw_init - sw init for JPEG block + * + * @handle: amdgpu_device pointer + * + */ +int jpeg_v1_0_sw_init(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_ring *ring; + int r; + + /* JPEG TRAP */ + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, 126, &adev->jpeg.inst->irq); + if (r) + return r; + + ring = &adev->jpeg.inst->ring_dec; + sprintf(ring->name, "jpeg_dec"); + r = amdgpu_ring_init(adev, ring, 512, &adev->jpeg.inst->irq, 0); + if (r) + return r; + + adev->jpeg.internal.jpeg_pitch = adev->jpeg.inst->external.jpeg_pitch = + SOC15_REG_OFFSET(JPEG, 0, mmUVD_JPEG_PITCH); + + return 0; +} + +/** + * jpeg_v1_0_sw_fini - sw fini for JPEG block + * + * @handle: amdgpu_device pointer + * + * JPEG free up sw allocation + */ +void jpeg_v1_0_sw_fini(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + amdgpu_ring_fini(&adev->jpeg.inst[0].ring_dec); +} + +/** + * jpeg_v1_0_start - start JPEG block + * + * @adev: amdgpu_device pointer + * + * Setup and start the JPEG block + */ +void jpeg_v1_0_start(struct amdgpu_device *adev, int mode) +{ + struct amdgpu_ring *ring = &adev->jpeg.inst->ring_dec; + + if (mode == 0) { + WREG32_SOC15(JPEG, 0, mmUVD_LMI_JRBC_RB_VMID, 0); + WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_CNTL, UVD_JRBC_RB_CNTL__RB_NO_FETCH_MASK | + UVD_JRBC_RB_CNTL__RB_RPTR_WR_EN_MASK); + WREG32_SOC15(JPEG, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_LOW, lower_32_bits(ring->gpu_addr)); + WREG32_SOC15(JPEG, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_HIGH, upper_32_bits(ring->gpu_addr)); + WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_RPTR, 0); + WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_WPTR, 0); + WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_CNTL, UVD_JRBC_RB_CNTL__RB_RPTR_WR_EN_MASK); + } + + /* initialize wptr */ + ring->wptr = RREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_WPTR); + + /* copy patch commands to the jpeg ring */ + jpeg_v1_0_decode_ring_set_patch_ring(ring, + (ring->wptr + ring->max_dw * amdgpu_sched_hw_submission)); +} + +static const struct amdgpu_ring_funcs jpeg_v1_0_decode_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, + .nop = PACKET0(0x81ff, 0), + .support_64bit_ptrs = false, + .no_user_fence = true, + .vmhub = AMDGPU_MMHUB_0, + .extra_dw = 64, + .get_rptr = jpeg_v1_0_decode_ring_get_rptr, + .get_wptr = jpeg_v1_0_decode_ring_get_wptr, + .set_wptr = jpeg_v1_0_decode_ring_set_wptr, + .emit_frame_size = + 6 + 6 + /* hdp invalidate / flush */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 + + 8 + /* jpeg_v1_0_decode_ring_emit_vm_flush */ + 26 + 26 + /* jpeg_v1_0_decode_ring_emit_fence x2 vm fence */ + 6, + .emit_ib_size = 22, /* jpeg_v1_0_decode_ring_emit_ib */ + .emit_ib = jpeg_v1_0_decode_ring_emit_ib, + .emit_fence = jpeg_v1_0_decode_ring_emit_fence, + .emit_vm_flush = jpeg_v1_0_decode_ring_emit_vm_flush, + .test_ring = amdgpu_jpeg_dec_ring_test_ring, + .test_ib = amdgpu_jpeg_dec_ring_test_ib, + .insert_nop = jpeg_v1_0_decode_ring_nop, + .insert_start = jpeg_v1_0_decode_ring_insert_start, + .insert_end = jpeg_v1_0_decode_ring_insert_end, + .pad_ib = amdgpu_ring_generic_pad_ib, + .begin_use = amdgpu_vcn_ring_begin_use, + .end_use = amdgpu_vcn_ring_end_use, + .emit_wreg = jpeg_v1_0_decode_ring_emit_wreg, + .emit_reg_wait = jpeg_v1_0_decode_ring_emit_reg_wait, + .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, +}; + +static void jpeg_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev) +{ + adev->jpeg.inst->ring_dec.funcs = &jpeg_v1_0_decode_ring_vm_funcs; + DRM_INFO("JPEG decode is enabled in VM mode\n"); +} + +static const struct amdgpu_irq_src_funcs jpeg_v1_0_irq_funcs = { + .set = jpeg_v1_0_set_interrupt_state, + .process = jpeg_v1_0_process_interrupt, +}; + +static void jpeg_v1_0_set_irq_funcs(struct amdgpu_device *adev) +{ + adev->jpeg.inst->irq.funcs = &jpeg_v1_0_irq_funcs; +} diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h new file mode 100644 index 0000000000000000000000000000000000000000..bbf33a6a397298be9c2bd40f2c61de4235f235f5 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h @@ -0,0 +1,32 @@ +/* + * Copyright 2019 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 __JPEG_V1_0_H__ +#define __JPEG_V1_0_H__ + +int jpeg_v1_0_early_init(void *handle); +int jpeg_v1_0_sw_init(void *handle); +void jpeg_v1_0_sw_fini(void *handle); +void jpeg_v1_0_start(struct amdgpu_device *adev, int mode); + +#endif /*__JPEG_V1_0_H__*/ diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c new file mode 100644 index 0000000000000000000000000000000000000000..a78292d84854dca5298618ef43a3f246ae1151db --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c @@ -0,0 +1,827 @@ +/* + * Copyright 2019 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 "amdgpu.h" +#include "amdgpu_jpeg.h" +#include "amdgpu_pm.h" +#include "soc15.h" +#include "soc15d.h" + +#include "vcn/vcn_2_0_0_offset.h" +#include "vcn/vcn_2_0_0_sh_mask.h" +#include "ivsrcid/vcn/irqsrcs_vcn_2_0.h" + +#define mmUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET 0x1bfff +#define mmUVD_JPEG_GPCOM_CMD_INTERNAL_OFFSET 0x4029 +#define mmUVD_JPEG_GPCOM_DATA0_INTERNAL_OFFSET 0x402a +#define mmUVD_JPEG_GPCOM_DATA1_INTERNAL_OFFSET 0x402b +#define mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_LOW_INTERNAL_OFFSET 0x40ea +#define mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_HIGH_INTERNAL_OFFSET 0x40eb +#define mmUVD_LMI_JRBC_IB_VMID_INTERNAL_OFFSET 0x40cf +#define mmUVD_LMI_JPEG_VMID_INTERNAL_OFFSET 0x40d1 +#define mmUVD_LMI_JRBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET 0x40e8 +#define mmUVD_LMI_JRBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET 0x40e9 +#define mmUVD_JRBC_IB_SIZE_INTERNAL_OFFSET 0x4082 +#define mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW_INTERNAL_OFFSET 0x40ec +#define mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH_INTERNAL_OFFSET 0x40ed +#define mmUVD_JRBC_RB_COND_RD_TIMER_INTERNAL_OFFSET 0x4085 +#define mmUVD_JRBC_RB_REF_DATA_INTERNAL_OFFSET 0x4084 +#define mmUVD_JRBC_STATUS_INTERNAL_OFFSET 0x4089 +#define mmUVD_JPEG_PITCH_INTERNAL_OFFSET 0x401f + +#define JRBC_DEC_EXTERNAL_REG_WRITE_ADDR 0x18000 + +static void jpeg_v2_0_set_dec_ring_funcs(struct amdgpu_device *adev); +static void jpeg_v2_0_set_irq_funcs(struct amdgpu_device *adev); +static int jpeg_v2_0_set_powergating_state(void *handle, + enum amd_powergating_state state); + +/** + * jpeg_v2_0_early_init - set function pointers + * + * @handle: amdgpu_device pointer + * + * Set ring and irq function pointers + */ +static int jpeg_v2_0_early_init(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + adev->jpeg.num_jpeg_inst = 1; + + jpeg_v2_0_set_dec_ring_funcs(adev); + jpeg_v2_0_set_irq_funcs(adev); + + return 0; +} + +/** + * jpeg_v2_0_sw_init - sw init for JPEG block + * + * @handle: amdgpu_device pointer + * + * Load firmware and sw initialization + */ +static int jpeg_v2_0_sw_init(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_ring *ring; + int r; + + /* JPEG TRAP */ + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, + VCN_2_0__SRCID__JPEG_DECODE, &adev->jpeg.inst->irq); + if (r) + return r; + + r = amdgpu_jpeg_sw_init(adev); + if (r) + return r; + + r = amdgpu_jpeg_resume(adev); + if (r) + return r; + + ring = &adev->jpeg.inst->ring_dec; + ring->use_doorbell = true; + ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 1; + sprintf(ring->name, "jpeg_dec"); + r = amdgpu_ring_init(adev, ring, 512, &adev->jpeg.inst->irq, 0); + if (r) + return r; + + adev->jpeg.internal.jpeg_pitch = mmUVD_JPEG_PITCH_INTERNAL_OFFSET; + adev->jpeg.inst->external.jpeg_pitch = SOC15_REG_OFFSET(JPEG, 0, mmUVD_JPEG_PITCH); + + return 0; +} + +/** + * jpeg_v2_0_sw_fini - sw fini for JPEG block + * + * @handle: amdgpu_device pointer + * + * JPEG suspend and free up sw allocation + */ +static int jpeg_v2_0_sw_fini(void *handle) +{ + int r; + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + r = amdgpu_jpeg_suspend(adev); + if (r) + return r; + + r = amdgpu_jpeg_sw_fini(adev); + + return r; +} + +/** + * jpeg_v2_0_hw_init - start and test JPEG block + * + * @handle: amdgpu_device pointer + * + */ +static int jpeg_v2_0_hw_init(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_ring *ring = &adev->jpeg.inst->ring_dec; + int r; + + adev->nbio.funcs->vcn_doorbell_range(adev, ring->use_doorbell, + (adev->doorbell_index.vcn.vcn_ring0_1 << 1), 0); + + r = amdgpu_ring_test_helper(ring); + if (!r) + DRM_INFO("JPEG decode initialized successfully.\n"); + + return r; +} + +/** + * jpeg_v2_0_hw_fini - stop the hardware block + * + * @handle: amdgpu_device pointer + * + * Stop the JPEG block, mark ring as not ready any more + */ +static int jpeg_v2_0_hw_fini(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_ring *ring = &adev->jpeg.inst->ring_dec; + + if (adev->jpeg.cur_state != AMD_PG_STATE_GATE && + RREG32_SOC15(JPEG, 0, mmUVD_JRBC_STATUS)) + jpeg_v2_0_set_powergating_state(adev, AMD_PG_STATE_GATE); + + ring->sched.ready = false; + + return 0; +} + +/** + * jpeg_v2_0_suspend - suspend JPEG block + * + * @handle: amdgpu_device pointer + * + * HW fini and suspend JPEG block + */ +static int jpeg_v2_0_suspend(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int r; + + r = jpeg_v2_0_hw_fini(adev); + if (r) + return r; + + r = amdgpu_jpeg_suspend(adev); + + return r; +} + +/** + * jpeg_v2_0_resume - resume JPEG block + * + * @handle: amdgpu_device pointer + * + * Resume firmware and hw init JPEG block + */ +static int jpeg_v2_0_resume(void *handle) +{ + int r; + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + r = amdgpu_jpeg_resume(adev); + if (r) + return r; + + r = jpeg_v2_0_hw_init(adev); + + return r; +} + +static int jpeg_v2_0_disable_power_gating(struct amdgpu_device *adev) +{ + uint32_t data; + int r = 0; + + if (adev->pg_flags & AMD_PG_SUPPORT_JPEG) { + data = 1 << UVD_PGFSM_CONFIG__UVDJ_PWR_CONFIG__SHIFT; + WREG32(SOC15_REG_OFFSET(JPEG, 0, mmUVD_PGFSM_CONFIG), data); + + SOC15_WAIT_ON_RREG(JPEG, 0, + mmUVD_PGFSM_STATUS, UVD_PGFSM_STATUS_UVDJ_PWR_ON, + UVD_PGFSM_STATUS__UVDJ_PWR_STATUS_MASK, r); + + if (r) { + DRM_ERROR("amdgpu: JPEG disable power gating failed\n"); + return r; + } + } + + /* Removing the anti hang mechanism to indicate the UVDJ tile is ON */ + data = RREG32(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JPEG_POWER_STATUS)) & ~0x1; + WREG32(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JPEG_POWER_STATUS), data); + + return 0; +} + +static int jpeg_v2_0_enable_power_gating(struct amdgpu_device* adev) +{ + if (adev->pg_flags & AMD_PG_SUPPORT_JPEG) { + uint32_t data; + int r = 0; + + data = RREG32(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JPEG_POWER_STATUS)); + data &= ~UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_MASK; + data |= 0x1; //UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_TILES_OFF; + WREG32(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JPEG_POWER_STATUS), data); + + data = 2 << UVD_PGFSM_CONFIG__UVDJ_PWR_CONFIG__SHIFT; + WREG32(SOC15_REG_OFFSET(JPEG, 0, mmUVD_PGFSM_CONFIG), data); + + SOC15_WAIT_ON_RREG(JPEG, 0, mmUVD_PGFSM_STATUS, + (2 << UVD_PGFSM_STATUS__UVDJ_PWR_STATUS__SHIFT), + UVD_PGFSM_STATUS__UVDJ_PWR_STATUS_MASK, r); + + if (r) { + DRM_ERROR("amdgpu: JPEG enable power gating failed\n"); + return r; + } + } + + return 0; +} + +static void jpeg_v2_0_disable_clock_gating(struct amdgpu_device* adev) +{ + uint32_t data; + + data = RREG32_SOC15(JPEG, 0, mmJPEG_CGC_CTRL); + if (adev->cg_flags & AMD_CG_SUPPORT_JPEG_MGCG) + data |= 1 << JPEG_CGC_CTRL__DYN_CLOCK_MODE__SHIFT; + else + data &= ~JPEG_CGC_CTRL__DYN_CLOCK_MODE__SHIFT; + + data |= 1 << JPEG_CGC_CTRL__CLK_GATE_DLY_TIMER__SHIFT; + data |= 4 << JPEG_CGC_CTRL__CLK_OFF_DELAY__SHIFT; + WREG32_SOC15(JPEG, 0, mmJPEG_CGC_CTRL, data); + + data = RREG32_SOC15(JPEG, 0, mmJPEG_CGC_GATE); + data &= ~(JPEG_CGC_GATE__JPEG_DEC_MASK + | JPEG_CGC_GATE__JPEG2_DEC_MASK + | JPEG_CGC_GATE__JPEG_ENC_MASK + | JPEG_CGC_GATE__JMCIF_MASK + | JPEG_CGC_GATE__JRBBM_MASK); + WREG32_SOC15(JPEG, 0, mmJPEG_CGC_GATE, data); +} + +static void jpeg_v2_0_enable_clock_gating(struct amdgpu_device* adev) +{ + uint32_t data; + + data = RREG32_SOC15(JPEG, 0, mmJPEG_CGC_CTRL); + if (adev->cg_flags & AMD_CG_SUPPORT_JPEG_MGCG) + data |= 1 << JPEG_CGC_CTRL__DYN_CLOCK_MODE__SHIFT; + else + data |= 0 << JPEG_CGC_CTRL__DYN_CLOCK_MODE__SHIFT; + + data |= 1 << JPEG_CGC_CTRL__CLK_GATE_DLY_TIMER__SHIFT; + data |= 4 << JPEG_CGC_CTRL__CLK_OFF_DELAY__SHIFT; + WREG32_SOC15(JPEG, 0, mmJPEG_CGC_CTRL, data); + + data = RREG32_SOC15(JPEG, 0, mmJPEG_CGC_GATE); + data |= (JPEG_CGC_GATE__JPEG_DEC_MASK + |JPEG_CGC_GATE__JPEG2_DEC_MASK + |JPEG_CGC_GATE__JPEG_ENC_MASK + |JPEG_CGC_GATE__JMCIF_MASK + |JPEG_CGC_GATE__JRBBM_MASK); + WREG32_SOC15(JPEG, 0, mmJPEG_CGC_GATE, data); +} + +/** + * jpeg_v2_0_start - start JPEG block + * + * @adev: amdgpu_device pointer + * + * Setup and start the JPEG block + */ +static int jpeg_v2_0_start(struct amdgpu_device *adev) +{ + struct amdgpu_ring *ring = &adev->jpeg.inst->ring_dec; + int r; + + if (adev->pm.dpm_enabled) + amdgpu_dpm_enable_jpeg(adev, true); + + /* disable power gating */ + r = jpeg_v2_0_disable_power_gating(adev); + if (r) + return r; + + /* JPEG disable CGC */ + jpeg_v2_0_disable_clock_gating(adev); + + WREG32_SOC15(JPEG, 0, mmJPEG_DEC_GFX10_ADDR_CONFIG, adev->gfx.config.gb_addr_config); + + /* enable JMI channel */ + WREG32_P(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JMI_CNTL), 0, + ~UVD_JMI_CNTL__SOFT_RESET_MASK); + + /* enable System Interrupt for JRBC */ + WREG32_P(SOC15_REG_OFFSET(JPEG, 0, mmJPEG_SYS_INT_EN), + JPEG_SYS_INT_EN__DJRBC_MASK, + ~JPEG_SYS_INT_EN__DJRBC_MASK); + + WREG32_SOC15(JPEG, 0, mmUVD_LMI_JRBC_RB_VMID, 0); + WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_CNTL, (0x00000001L | 0x00000002L)); + WREG32_SOC15(JPEG, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_LOW, + lower_32_bits(ring->gpu_addr)); + WREG32_SOC15(JPEG, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_HIGH, + upper_32_bits(ring->gpu_addr)); + WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_RPTR, 0); + WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_WPTR, 0); + WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_CNTL, 0x00000002L); + WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_SIZE, ring->ring_size / 4); + ring->wptr = RREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_WPTR); + + return 0; +} + +/** + * jpeg_v2_0_stop - stop JPEG block + * + * @adev: amdgpu_device pointer + * + * stop the JPEG block + */ +static int jpeg_v2_0_stop(struct amdgpu_device *adev) +{ + int r; + + /* reset JMI */ + WREG32_P(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JMI_CNTL), + UVD_JMI_CNTL__SOFT_RESET_MASK, + ~UVD_JMI_CNTL__SOFT_RESET_MASK); + + /* enable JPEG CGC */ + jpeg_v2_0_enable_clock_gating(adev); + + /* enable power gating */ + r = jpeg_v2_0_enable_power_gating(adev); + if (r) + return r; + + if (adev->pm.dpm_enabled) + amdgpu_dpm_enable_jpeg(adev, false); + + return 0; +} + +/** + * jpeg_v2_0_dec_ring_get_rptr - get read pointer + * + * @ring: amdgpu_ring pointer + * + * Returns the current hardware read pointer + */ +static uint64_t jpeg_v2_0_dec_ring_get_rptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + return RREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_RPTR); +} + +/** + * jpeg_v2_0_dec_ring_get_wptr - get write pointer + * + * @ring: amdgpu_ring pointer + * + * Returns the current hardware write pointer + */ +static uint64_t jpeg_v2_0_dec_ring_get_wptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + if (ring->use_doorbell) + return adev->wb.wb[ring->wptr_offs]; + else + return RREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_WPTR); +} + +/** + * jpeg_v2_0_dec_ring_set_wptr - set write pointer + * + * @ring: amdgpu_ring pointer + * + * Commits the write pointer to the hardware + */ +static void jpeg_v2_0_dec_ring_set_wptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + if (ring->use_doorbell) { + adev->wb.wb[ring->wptr_offs] = lower_32_bits(ring->wptr); + WDOORBELL32(ring->doorbell_index, lower_32_bits(ring->wptr)); + } else { + WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_WPTR, lower_32_bits(ring->wptr)); + } +} + +/** + * jpeg_v2_0_dec_ring_insert_start - insert a start command + * + * @ring: amdgpu_ring pointer + * + * Write a start command to the ring. + */ +void jpeg_v2_0_dec_ring_insert_start(struct amdgpu_ring *ring) +{ + amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x68e04); + + amdgpu_ring_write(ring, PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x80010000); +} + +/** + * jpeg_v2_0_dec_ring_insert_end - insert a end command + * + * @ring: amdgpu_ring pointer + * + * Write a end command to the ring. + */ +void jpeg_v2_0_dec_ring_insert_end(struct amdgpu_ring *ring) +{ + amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x68e04); + + amdgpu_ring_write(ring, PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x00010000); +} + +/** + * jpeg_v2_0_dec_ring_emit_fence - emit an fence & trap command + * + * @ring: amdgpu_ring pointer + * @fence: fence to emit + * + * Write a fence and a trap command to the ring. + */ +void jpeg_v2_0_dec_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq, + unsigned flags) +{ + WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_JPEG_GPCOM_DATA0_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, seq); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_JPEG_GPCOM_DATA1_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, seq); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_LOW_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, lower_32_bits(addr)); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_HIGH_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_JPEG_GPCOM_CMD_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x8); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_JPEG_GPCOM_CMD_INTERNAL_OFFSET, + 0, PACKETJ_CONDITION_CHECK0, PACKETJ_TYPE4)); + amdgpu_ring_write(ring, 0); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x3fbc); + + amdgpu_ring_write(ring, PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x1); + + amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE7)); + amdgpu_ring_write(ring, 0); +} + +/** + * jpeg_v2_0_dec_ring_emit_ib - execute indirect buffer + * + * @ring: amdgpu_ring pointer + * @ib: indirect buffer to execute + * + * Write ring commands to execute the indirect buffer. + */ +void jpeg_v2_0_dec_ring_emit_ib(struct amdgpu_ring *ring, + struct amdgpu_job *job, + struct amdgpu_ib *ib, + uint32_t flags) +{ + unsigned vmid = AMDGPU_JOB_GET_VMID(job); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_IB_VMID_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, (vmid | (vmid << 4))); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JPEG_VMID_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, (vmid | (vmid << 4))); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr)); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr)); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_IB_SIZE_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, ib->length_dw); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, lower_32_bits(ring->gpu_addr)); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, upper_32_bits(ring->gpu_addr)); + + amdgpu_ring_write(ring, PACKETJ(0, 0, PACKETJ_CONDITION_CHECK0, PACKETJ_TYPE2)); + amdgpu_ring_write(ring, 0); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_RB_COND_RD_TIMER_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x01400200); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_RB_REF_DATA_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x2); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_STATUS_INTERNAL_OFFSET, + 0, PACKETJ_CONDITION_CHECK3, PACKETJ_TYPE3)); + amdgpu_ring_write(ring, 0x2); +} + +void jpeg_v2_0_dec_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, + uint32_t val, uint32_t mask) +{ + uint32_t reg_offset = (reg << 2); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_RB_COND_RD_TIMER_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x01400200); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_RB_REF_DATA_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, val); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + if (reg_offset >= 0x10000 && reg_offset <= 0x105ff) { + amdgpu_ring_write(ring, 0); + amdgpu_ring_write(ring, + PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE3)); + } else { + amdgpu_ring_write(ring, reg_offset); + amdgpu_ring_write(ring, PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, + 0, 0, PACKETJ_TYPE3)); + } + amdgpu_ring_write(ring, mask); +} + +void jpeg_v2_0_dec_ring_emit_vm_flush(struct amdgpu_ring *ring, + unsigned vmid, uint64_t pd_addr) +{ + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; + uint32_t data0, data1, mask; + + pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); + + /* wait for register write */ + data0 = hub->ctx0_ptb_addr_lo32 + vmid * 2; + data1 = lower_32_bits(pd_addr); + mask = 0xffffffff; + jpeg_v2_0_dec_ring_emit_reg_wait(ring, data0, data1, mask); +} + +void jpeg_v2_0_dec_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg, uint32_t val) +{ + uint32_t reg_offset = (reg << 2); + + amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET, + 0, 0, PACKETJ_TYPE0)); + if (reg_offset >= 0x10000 && reg_offset <= 0x105ff) { + amdgpu_ring_write(ring, 0); + amdgpu_ring_write(ring, + PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE0)); + } else { + amdgpu_ring_write(ring, reg_offset); + amdgpu_ring_write(ring, PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, + 0, 0, PACKETJ_TYPE0)); + } + amdgpu_ring_write(ring, val); +} + +void jpeg_v2_0_dec_ring_nop(struct amdgpu_ring *ring, uint32_t count) +{ + int i; + + WARN_ON(ring->wptr % 2 || count % 2); + + for (i = 0; i < count / 2; i++) { + amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE6)); + amdgpu_ring_write(ring, 0); + } +} + +static bool jpeg_v2_0_is_idle(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + return ((RREG32_SOC15(JPEG, 0, mmUVD_JRBC_STATUS) & + UVD_JRBC_STATUS__RB_JOB_DONE_MASK) == + UVD_JRBC_STATUS__RB_JOB_DONE_MASK); +} + +static int jpeg_v2_0_wait_for_idle(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int ret = 0; + + SOC15_WAIT_ON_RREG(JPEG, 0, mmUVD_JRBC_STATUS, UVD_JRBC_STATUS__RB_JOB_DONE_MASK, + UVD_JRBC_STATUS__RB_JOB_DONE_MASK, ret); + + return ret; +} + +static int jpeg_v2_0_set_clockgating_state(void *handle, + enum amd_clockgating_state state) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + bool enable = (state == AMD_CG_STATE_GATE) ? true : false; + + if (enable) { + if (jpeg_v2_0_is_idle(handle)) + return -EBUSY; + jpeg_v2_0_enable_clock_gating(adev); + } else { + jpeg_v2_0_disable_clock_gating(adev); + } + + return 0; +} + +static int jpeg_v2_0_set_powergating_state(void *handle, + enum amd_powergating_state state) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int ret; + + if (state == adev->jpeg.cur_state) + return 0; + + if (state == AMD_PG_STATE_GATE) + ret = jpeg_v2_0_stop(adev); + else + ret = jpeg_v2_0_start(adev); + + if (!ret) + adev->jpeg.cur_state = state; + + return ret; +} + +static int jpeg_v2_0_set_interrupt_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned type, + enum amdgpu_interrupt_state state) +{ + return 0; +} + +static int jpeg_v2_0_process_interrupt(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + DRM_DEBUG("IH: JPEG TRAP\n"); + + switch (entry->src_id) { + case VCN_2_0__SRCID__JPEG_DECODE: + amdgpu_fence_process(&adev->jpeg.inst->ring_dec); + break; + default: + DRM_ERROR("Unhandled interrupt: %d %d\n", + entry->src_id, entry->src_data[0]); + break; + } + + return 0; +} + +static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = { + .name = "jpeg_v2_0", + .early_init = jpeg_v2_0_early_init, + .late_init = NULL, + .sw_init = jpeg_v2_0_sw_init, + .sw_fini = jpeg_v2_0_sw_fini, + .hw_init = jpeg_v2_0_hw_init, + .hw_fini = jpeg_v2_0_hw_fini, + .suspend = jpeg_v2_0_suspend, + .resume = jpeg_v2_0_resume, + .is_idle = jpeg_v2_0_is_idle, + .wait_for_idle = jpeg_v2_0_wait_for_idle, + .check_soft_reset = NULL, + .pre_soft_reset = NULL, + .soft_reset = NULL, + .post_soft_reset = NULL, + .set_clockgating_state = jpeg_v2_0_set_clockgating_state, + .set_powergating_state = jpeg_v2_0_set_powergating_state, +}; + +static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, + .vmhub = AMDGPU_MMHUB_0, + .get_rptr = jpeg_v2_0_dec_ring_get_rptr, + .get_wptr = jpeg_v2_0_dec_ring_get_wptr, + .set_wptr = jpeg_v2_0_dec_ring_set_wptr, + .emit_frame_size = + SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 + + 8 + /* jpeg_v2_0_dec_ring_emit_vm_flush */ + 18 + 18 + /* jpeg_v2_0_dec_ring_emit_fence x2 vm fence */ + 8 + 16, + .emit_ib_size = 22, /* jpeg_v2_0_dec_ring_emit_ib */ + .emit_ib = jpeg_v2_0_dec_ring_emit_ib, + .emit_fence = jpeg_v2_0_dec_ring_emit_fence, + .emit_vm_flush = jpeg_v2_0_dec_ring_emit_vm_flush, + .test_ring = amdgpu_jpeg_dec_ring_test_ring, + .test_ib = amdgpu_jpeg_dec_ring_test_ib, + .insert_nop = jpeg_v2_0_dec_ring_nop, + .insert_start = jpeg_v2_0_dec_ring_insert_start, + .insert_end = jpeg_v2_0_dec_ring_insert_end, + .pad_ib = amdgpu_ring_generic_pad_ib, + .begin_use = amdgpu_jpeg_ring_begin_use, + .end_use = amdgpu_jpeg_ring_end_use, + .emit_wreg = jpeg_v2_0_dec_ring_emit_wreg, + .emit_reg_wait = jpeg_v2_0_dec_ring_emit_reg_wait, + .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, +}; + +static void jpeg_v2_0_set_dec_ring_funcs(struct amdgpu_device *adev) +{ + adev->jpeg.inst->ring_dec.funcs = &jpeg_v2_0_dec_ring_vm_funcs; + DRM_INFO("JPEG decode is enabled in VM mode\n"); +} + +static const struct amdgpu_irq_src_funcs jpeg_v2_0_irq_funcs = { + .set = jpeg_v2_0_set_interrupt_state, + .process = jpeg_v2_0_process_interrupt, +}; + +static void jpeg_v2_0_set_irq_funcs(struct amdgpu_device *adev) +{ + adev->jpeg.inst->irq.num_types = 1; + adev->jpeg.inst->irq.funcs = &jpeg_v2_0_irq_funcs; +} + +const struct amdgpu_ip_block_version jpeg_v2_0_ip_block = +{ + .type = AMD_IP_BLOCK_TYPE_JPEG, + .major = 2, + .minor = 0, + .rev = 0, + .funcs = &jpeg_v2_0_ip_funcs, +}; diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.h b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.h new file mode 100644 index 0000000000000000000000000000000000000000..15a344ed340fc894db51fb4d6318e051b71fc6a5 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.h @@ -0,0 +1,42 @@ +/* + * Copyright 2019 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 __JPEG_V2_0_H__ +#define __JPEG_V2_0_H__ + +void jpeg_v2_0_dec_ring_insert_start(struct amdgpu_ring *ring); +void jpeg_v2_0_dec_ring_insert_end(struct amdgpu_ring *ring); +void jpeg_v2_0_dec_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq, + unsigned flags); +void jpeg_v2_0_dec_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_job *job, + struct amdgpu_ib *ib, uint32_t flags); +void jpeg_v2_0_dec_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, + uint32_t val, uint32_t mask); +void jpeg_v2_0_dec_ring_emit_vm_flush(struct amdgpu_ring *ring, + unsigned vmid, uint64_t pd_addr); +void jpeg_v2_0_dec_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg, uint32_t val); +void jpeg_v2_0_dec_ring_nop(struct amdgpu_ring *ring, uint32_t count); + +extern const struct amdgpu_ip_block_version jpeg_v2_0_ip_block; + +#endif /* __JPEG_V2_0_H__ */ diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c new file mode 100644 index 0000000000000000000000000000000000000000..2c58939e6ad03508dddfc75b2e75e63ec0634066 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c @@ -0,0 +1,641 @@ +/* + * Copyright 2019 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 "amdgpu.h" +#include "amdgpu_jpeg.h" +#include "soc15.h" +#include "soc15d.h" +#include "jpeg_v2_0.h" + +#include "vcn/vcn_2_5_offset.h" +#include "vcn/vcn_2_5_sh_mask.h" +#include "ivsrcid/vcn/irqsrcs_vcn_2_0.h" + +#define mmUVD_JPEG_PITCH_INTERNAL_OFFSET 0x401f + +#define JPEG25_MAX_HW_INSTANCES_ARCTURUS 2 + +static void jpeg_v2_5_set_dec_ring_funcs(struct amdgpu_device *adev); +static void jpeg_v2_5_set_irq_funcs(struct amdgpu_device *adev); +static int jpeg_v2_5_set_powergating_state(void *handle, + enum amd_powergating_state state); + +static int amdgpu_ih_clientid_jpeg[] = { + SOC15_IH_CLIENTID_VCN, + SOC15_IH_CLIENTID_VCN1 +}; + +/** + * jpeg_v2_5_early_init - set function pointers + * + * @handle: amdgpu_device pointer + * + * Set ring and irq function pointers + */ +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; + } + + if (adev->jpeg.harvest_config == (AMDGPU_JPEG_HARVEST_JPEG0 | + AMDGPU_JPEG_HARVEST_JPEG1)) + return -ENOENT; + } else + adev->jpeg.num_jpeg_inst = 1; + + jpeg_v2_5_set_dec_ring_funcs(adev); + jpeg_v2_5_set_irq_funcs(adev); + + return 0; +} + +/** + * jpeg_v2_5_sw_init - sw init for JPEG block + * + * @handle: amdgpu_device pointer + * + * Load firmware and sw initialization + */ +static int jpeg_v2_5_sw_init(void *handle) +{ + struct amdgpu_ring *ring; + int i, r; + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + if (adev->jpeg.harvest_config & (1 << i)) + continue; + + /* JPEG TRAP */ + r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_jpeg[i], + VCN_2_0__SRCID__JPEG_DECODE, &adev->jpeg.inst[i].irq); + if (r) + return r; + } + + r = amdgpu_jpeg_sw_init(adev); + if (r) + return r; + + r = amdgpu_jpeg_resume(adev); + if (r) + return r; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + if (adev->jpeg.harvest_config & (1 << i)) + continue; + + ring = &adev->jpeg.inst[i].ring_dec; + ring->use_doorbell = true; + ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 1 + 8 * i; + sprintf(ring->name, "jpeg_dec_%d", i); + r = amdgpu_ring_init(adev, ring, 512, &adev->jpeg.inst[i].irq, 0); + if (r) + return r; + + adev->jpeg.internal.jpeg_pitch = mmUVD_JPEG_PITCH_INTERNAL_OFFSET; + adev->jpeg.inst[i].external.jpeg_pitch = SOC15_REG_OFFSET(JPEG, i, mmUVD_JPEG_PITCH); + } + + return 0; +} + +/** + * jpeg_v2_5_sw_fini - sw fini for JPEG block + * + * @handle: amdgpu_device pointer + * + * JPEG suspend and free up sw allocation + */ +static int jpeg_v2_5_sw_fini(void *handle) +{ + int r; + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + r = amdgpu_jpeg_suspend(adev); + if (r) + return r; + + r = amdgpu_jpeg_sw_fini(adev); + + return r; +} + +/** + * jpeg_v2_5_hw_init - start and test JPEG block + * + * @handle: amdgpu_device pointer + * + */ +static int jpeg_v2_5_hw_init(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_ring *ring; + int i, r; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + if (adev->jpeg.harvest_config & (1 << i)) + continue; + + ring = &adev->jpeg.inst[i].ring_dec; + adev->nbio.funcs->vcn_doorbell_range(adev, ring->use_doorbell, + (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 8 * i, i); + + r = amdgpu_ring_test_helper(ring); + if (r) + return r; + } + + DRM_INFO("JPEG decode initialized successfully.\n"); + + return 0; +} + +/** + * jpeg_v2_5_hw_fini - stop the hardware block + * + * @handle: amdgpu_device pointer + * + * Stop the JPEG block, mark ring as not ready any more + */ +static int jpeg_v2_5_hw_fini(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_ring *ring; + int i; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + if (adev->jpeg.harvest_config & (1 << i)) + continue; + + ring = &adev->jpeg.inst[i].ring_dec; + if (adev->jpeg.cur_state != AMD_PG_STATE_GATE && + RREG32_SOC15(JPEG, i, mmUVD_JRBC_STATUS)) + jpeg_v2_5_set_powergating_state(adev, AMD_PG_STATE_GATE); + + ring->sched.ready = false; + } + + return 0; +} + +/** + * jpeg_v2_5_suspend - suspend JPEG block + * + * @handle: amdgpu_device pointer + * + * HW fini and suspend JPEG block + */ +static int jpeg_v2_5_suspend(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int r; + + r = jpeg_v2_5_hw_fini(adev); + if (r) + return r; + + r = amdgpu_jpeg_suspend(adev); + + return r; +} + +/** + * jpeg_v2_5_resume - resume JPEG block + * + * @handle: amdgpu_device pointer + * + * Resume firmware and hw init JPEG block + */ +static int jpeg_v2_5_resume(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int r; + + r = amdgpu_jpeg_resume(adev); + if (r) + return r; + + r = jpeg_v2_5_hw_init(adev); + + return r; +} + +static void jpeg_v2_5_disable_clock_gating(struct amdgpu_device* adev, int inst) +{ + uint32_t data; + + data = RREG32_SOC15(JPEG, inst, mmJPEG_CGC_CTRL); + if (adev->cg_flags & AMD_CG_SUPPORT_JPEG_MGCG) + data |= 1 << JPEG_CGC_CTRL__DYN_CLOCK_MODE__SHIFT; + else + data &= ~JPEG_CGC_CTRL__DYN_CLOCK_MODE__SHIFT; + + data |= 1 << JPEG_CGC_CTRL__CLK_GATE_DLY_TIMER__SHIFT; + data |= 4 << JPEG_CGC_CTRL__CLK_OFF_DELAY__SHIFT; + WREG32_SOC15(JPEG, inst, mmJPEG_CGC_CTRL, data); + + data = RREG32_SOC15(JPEG, inst, mmJPEG_CGC_GATE); + data &= ~(JPEG_CGC_GATE__JPEG_DEC_MASK + | JPEG_CGC_GATE__JPEG2_DEC_MASK + | JPEG_CGC_GATE__JPEG_ENC_MASK + | JPEG_CGC_GATE__JMCIF_MASK + | JPEG_CGC_GATE__JRBBM_MASK); + WREG32_SOC15(JPEG, inst, mmJPEG_CGC_GATE, data); + + data = RREG32_SOC15(JPEG, inst, mmJPEG_CGC_CTRL); + data &= ~(JPEG_CGC_CTRL__JPEG_DEC_MODE_MASK + | JPEG_CGC_CTRL__JPEG2_DEC_MODE_MASK + | JPEG_CGC_CTRL__JMCIF_MODE_MASK + | JPEG_CGC_CTRL__JRBBM_MODE_MASK); + WREG32_SOC15(JPEG, inst, mmJPEG_CGC_CTRL, data); +} + +static void jpeg_v2_5_enable_clock_gating(struct amdgpu_device* adev, int inst) +{ + uint32_t data; + + data = RREG32_SOC15(JPEG, inst, mmJPEG_CGC_GATE); + data |= (JPEG_CGC_GATE__JPEG_DEC_MASK + |JPEG_CGC_GATE__JPEG2_DEC_MASK + |JPEG_CGC_GATE__JPEG_ENC_MASK + |JPEG_CGC_GATE__JMCIF_MASK + |JPEG_CGC_GATE__JRBBM_MASK); + WREG32_SOC15(JPEG, inst, mmJPEG_CGC_GATE, data); +} + +/** + * jpeg_v2_5_start - start JPEG block + * + * @adev: amdgpu_device pointer + * + * Setup and start the JPEG block + */ +static int jpeg_v2_5_start(struct amdgpu_device *adev) +{ + struct amdgpu_ring *ring; + int i; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + if (adev->jpeg.harvest_config & (1 << i)) + continue; + + ring = &adev->jpeg.inst[i].ring_dec; + /* disable anti hang mechanism */ + WREG32_P(SOC15_REG_OFFSET(JPEG, i, mmUVD_JPEG_POWER_STATUS), 0, + ~UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_MASK); + + /* JPEG disable CGC */ + jpeg_v2_5_disable_clock_gating(adev, i); + + /* MJPEG global tiling registers */ + WREG32_SOC15(JPEG, i, mmJPEG_DEC_GFX8_ADDR_CONFIG, + adev->gfx.config.gb_addr_config); + WREG32_SOC15(JPEG, i, mmJPEG_DEC_GFX10_ADDR_CONFIG, + adev->gfx.config.gb_addr_config); + + /* enable JMI channel */ + WREG32_P(SOC15_REG_OFFSET(JPEG, i, mmUVD_JMI_CNTL), 0, + ~UVD_JMI_CNTL__SOFT_RESET_MASK); + + /* enable System Interrupt for JRBC */ + WREG32_P(SOC15_REG_OFFSET(JPEG, i, mmJPEG_SYS_INT_EN), + JPEG_SYS_INT_EN__DJRBC_MASK, + ~JPEG_SYS_INT_EN__DJRBC_MASK); + + WREG32_SOC15(JPEG, i, mmUVD_LMI_JRBC_RB_VMID, 0); + WREG32_SOC15(JPEG, i, mmUVD_JRBC_RB_CNTL, (0x00000001L | 0x00000002L)); + WREG32_SOC15(JPEG, i, mmUVD_LMI_JRBC_RB_64BIT_BAR_LOW, + lower_32_bits(ring->gpu_addr)); + WREG32_SOC15(JPEG, i, mmUVD_LMI_JRBC_RB_64BIT_BAR_HIGH, + upper_32_bits(ring->gpu_addr)); + WREG32_SOC15(JPEG, i, mmUVD_JRBC_RB_RPTR, 0); + WREG32_SOC15(JPEG, i, mmUVD_JRBC_RB_WPTR, 0); + WREG32_SOC15(JPEG, i, mmUVD_JRBC_RB_CNTL, 0x00000002L); + WREG32_SOC15(JPEG, i, mmUVD_JRBC_RB_SIZE, ring->ring_size / 4); + ring->wptr = RREG32_SOC15(JPEG, i, mmUVD_JRBC_RB_WPTR); + } + + return 0; +} + +/** + * jpeg_v2_5_stop - stop JPEG block + * + * @adev: amdgpu_device pointer + * + * stop the JPEG block + */ +static int jpeg_v2_5_stop(struct amdgpu_device *adev) +{ + int i; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + if (adev->jpeg.harvest_config & (1 << i)) + continue; + + /* reset JMI */ + WREG32_P(SOC15_REG_OFFSET(JPEG, i, mmUVD_JMI_CNTL), + UVD_JMI_CNTL__SOFT_RESET_MASK, + ~UVD_JMI_CNTL__SOFT_RESET_MASK); + + jpeg_v2_5_enable_clock_gating(adev, i); + + /* enable anti hang mechanism */ + WREG32_P(SOC15_REG_OFFSET(JPEG, i, mmUVD_JPEG_POWER_STATUS), + UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_MASK, + ~UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_MASK); + } + + return 0; +} + +/** + * jpeg_v2_5_dec_ring_get_rptr - get read pointer + * + * @ring: amdgpu_ring pointer + * + * Returns the current hardware read pointer + */ +static uint64_t jpeg_v2_5_dec_ring_get_rptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + return RREG32_SOC15(JPEG, ring->me, mmUVD_JRBC_RB_RPTR); +} + +/** + * jpeg_v2_5_dec_ring_get_wptr - get write pointer + * + * @ring: amdgpu_ring pointer + * + * Returns the current hardware write pointer + */ +static uint64_t jpeg_v2_5_dec_ring_get_wptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + if (ring->use_doorbell) + return adev->wb.wb[ring->wptr_offs]; + else + return RREG32_SOC15(JPEG, ring->me, mmUVD_JRBC_RB_WPTR); +} + +/** + * jpeg_v2_5_dec_ring_set_wptr - set write pointer + * + * @ring: amdgpu_ring pointer + * + * Commits the write pointer to the hardware + */ +static void jpeg_v2_5_dec_ring_set_wptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + if (ring->use_doorbell) { + adev->wb.wb[ring->wptr_offs] = lower_32_bits(ring->wptr); + WDOORBELL32(ring->doorbell_index, lower_32_bits(ring->wptr)); + } else { + WREG32_SOC15(JPEG, ring->me, mmUVD_JRBC_RB_WPTR, lower_32_bits(ring->wptr)); + } +} + +static bool jpeg_v2_5_is_idle(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int i, ret = 1; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + if (adev->jpeg.harvest_config & (1 << i)) + continue; + + ret &= (((RREG32_SOC15(JPEG, i, mmUVD_JRBC_STATUS) & + UVD_JRBC_STATUS__RB_JOB_DONE_MASK) == + UVD_JRBC_STATUS__RB_JOB_DONE_MASK)); + } + + return ret; +} + +static int jpeg_v2_5_wait_for_idle(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int i, ret = 0; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + if (adev->jpeg.harvest_config & (1 << i)) + continue; + + SOC15_WAIT_ON_RREG(JPEG, i, mmUVD_JRBC_STATUS, + UVD_JRBC_STATUS__RB_JOB_DONE_MASK, + UVD_JRBC_STATUS__RB_JOB_DONE_MASK, ret); + if (ret) + return ret; + } + + return ret; +} + +static int jpeg_v2_5_set_clockgating_state(void *handle, + enum amd_clockgating_state state) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + bool enable = (state == AMD_CG_STATE_GATE) ? true : false; + int i; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + if (adev->jpeg.harvest_config & (1 << i)) + continue; + + if (enable) { + if (jpeg_v2_5_is_idle(handle)) + return -EBUSY; + jpeg_v2_5_enable_clock_gating(adev, i); + } else { + jpeg_v2_5_disable_clock_gating(adev, i); + } + } + + return 0; +} + +static int jpeg_v2_5_set_powergating_state(void *handle, + enum amd_powergating_state state) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int ret; + + if(state == adev->jpeg.cur_state) + return 0; + + if (state == AMD_PG_STATE_GATE) + ret = jpeg_v2_5_stop(adev); + else + ret = jpeg_v2_5_start(adev); + + if(!ret) + adev->jpeg.cur_state = state; + + return ret; +} + +static int jpeg_v2_5_set_interrupt_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned type, + enum amdgpu_interrupt_state state) +{ + return 0; +} + +static int jpeg_v2_5_process_interrupt(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + uint32_t ip_instance; + + switch (entry->client_id) { + case SOC15_IH_CLIENTID_VCN: + ip_instance = 0; + break; + case SOC15_IH_CLIENTID_VCN1: + ip_instance = 1; + break; + default: + DRM_ERROR("Unhandled client id: %d\n", entry->client_id); + return 0; + } + + DRM_DEBUG("IH: JPEG TRAP\n"); + + switch (entry->src_id) { + case VCN_2_0__SRCID__JPEG_DECODE: + amdgpu_fence_process(&adev->jpeg.inst[ip_instance].ring_dec); + break; + default: + DRM_ERROR("Unhandled interrupt: %d %d\n", + entry->src_id, entry->src_data[0]); + break; + } + + return 0; +} + +static const struct amd_ip_funcs jpeg_v2_5_ip_funcs = { + .name = "jpeg_v2_5", + .early_init = jpeg_v2_5_early_init, + .late_init = NULL, + .sw_init = jpeg_v2_5_sw_init, + .sw_fini = jpeg_v2_5_sw_fini, + .hw_init = jpeg_v2_5_hw_init, + .hw_fini = jpeg_v2_5_hw_fini, + .suspend = jpeg_v2_5_suspend, + .resume = jpeg_v2_5_resume, + .is_idle = jpeg_v2_5_is_idle, + .wait_for_idle = jpeg_v2_5_wait_for_idle, + .check_soft_reset = NULL, + .pre_soft_reset = NULL, + .soft_reset = NULL, + .post_soft_reset = NULL, + .set_clockgating_state = jpeg_v2_5_set_clockgating_state, + .set_powergating_state = jpeg_v2_5_set_powergating_state, +}; + +static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, + .vmhub = AMDGPU_MMHUB_1, + .get_rptr = jpeg_v2_5_dec_ring_get_rptr, + .get_wptr = jpeg_v2_5_dec_ring_get_wptr, + .set_wptr = jpeg_v2_5_dec_ring_set_wptr, + .emit_frame_size = + SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 + + 8 + /* jpeg_v2_5_dec_ring_emit_vm_flush */ + 18 + 18 + /* jpeg_v2_5_dec_ring_emit_fence x2 vm fence */ + 8 + 16, + .emit_ib_size = 22, /* jpeg_v2_5_dec_ring_emit_ib */ + .emit_ib = jpeg_v2_0_dec_ring_emit_ib, + .emit_fence = jpeg_v2_0_dec_ring_emit_fence, + .emit_vm_flush = jpeg_v2_0_dec_ring_emit_vm_flush, + .test_ring = amdgpu_jpeg_dec_ring_test_ring, + .test_ib = amdgpu_jpeg_dec_ring_test_ib, + .insert_nop = jpeg_v2_0_dec_ring_nop, + .insert_start = jpeg_v2_0_dec_ring_insert_start, + .insert_end = jpeg_v2_0_dec_ring_insert_end, + .pad_ib = amdgpu_ring_generic_pad_ib, + .begin_use = amdgpu_jpeg_ring_begin_use, + .end_use = amdgpu_jpeg_ring_end_use, + .emit_wreg = jpeg_v2_0_dec_ring_emit_wreg, + .emit_reg_wait = jpeg_v2_0_dec_ring_emit_reg_wait, + .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, +}; + +static void jpeg_v2_5_set_dec_ring_funcs(struct amdgpu_device *adev) +{ + int i; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + if (adev->jpeg.harvest_config & (1 << i)) + continue; + + adev->jpeg.inst[i].ring_dec.funcs = &jpeg_v2_5_dec_ring_vm_funcs; + adev->jpeg.inst[i].ring_dec.me = i; + DRM_INFO("JPEG(%d) JPEG decode is enabled in VM mode\n", i); + } +} + +static const struct amdgpu_irq_src_funcs jpeg_v2_5_irq_funcs = { + .set = jpeg_v2_5_set_interrupt_state, + .process = jpeg_v2_5_process_interrupt, +}; + +static void jpeg_v2_5_set_irq_funcs(struct amdgpu_device *adev) +{ + int i; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + if (adev->jpeg.harvest_config & (1 << i)) + continue; + + adev->jpeg.inst[i].irq.num_types = 1; + adev->jpeg.inst[i].irq.funcs = &jpeg_v2_5_irq_funcs; + } +} + +const struct amdgpu_ip_block_version jpeg_v2_5_ip_block = +{ + .type = AMD_IP_BLOCK_TYPE_JPEG, + .major = 2, + .minor = 5, + .rev = 0, + .funcs = &jpeg_v2_5_ip_funcs, +}; diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.h b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.h new file mode 100644 index 0000000000000000000000000000000000000000..2b4087c026204a7e877ff61fb6c2ec6376143191 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.h @@ -0,0 +1,29 @@ +/* + * Copyright 2019 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 __JPEG_V2_5_H__ +#define __JPEG_V2_5_H__ + +extern const struct amdgpu_ip_block_version jpeg_v2_5_ip_block; + +#endif /* __JPEG_V2_5_H__ */ diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c index 28105e4af507e3b7472d3d7a2f84c504dfadfe43..adfd8a6171eb83b2951e7eda2074d0b863e1d432 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c @@ -27,17 +27,13 @@ #include "mmhub/mmhub_1_0_offset.h" #include "mmhub/mmhub_1_0_sh_mask.h" #include "mmhub/mmhub_1_0_default.h" -#include "mmhub/mmhub_9_4_0_offset.h" #include "vega10_enum.h" - +#include "soc15.h" #include "soc15_common.h" #define mmDAGB0_CNTL_MISC2_RV 0x008f #define mmDAGB0_CNTL_MISC2_RV_BASE_IDX 0 -#define EA_EDC_CNT_MASK 0x3 -#define EA_EDC_CNT_SHIFT 0x2 - u64 mmhub_v1_0_get_fb_location(struct amdgpu_device *adev) { u64 base = RREG32_SOC15(MMHUB, 0, mmMC_VM_FB_LOCATION_BASE); @@ -564,59 +560,191 @@ void mmhub_v1_0_get_clockgating(struct amdgpu_device *adev, u32 *flags) *flags |= AMD_CG_SUPPORT_MC_LS; } +static const struct soc15_ras_field_entry mmhub_v1_0_ras_fields[] = { + { "MMEA0_DRAMRD_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA0_EDC_CNT_VG20, DRAMRD_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT_VG20, DRAMRD_CMDMEM_DED_COUNT), + }, + { "MMEA0_DRAMWR_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA0_EDC_CNT_VG20, DRAMWR_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT_VG20, DRAMWR_CMDMEM_DED_COUNT), + }, + { "MMEA0_DRAMWR_DATAMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA0_EDC_CNT_VG20, DRAMWR_DATAMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT_VG20, DRAMWR_DATAMEM_DED_COUNT), + }, + { "MMEA0_RRET_TAGMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA0_EDC_CNT_VG20, RRET_TAGMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT_VG20, RRET_TAGMEM_DED_COUNT), + }, + { "MMEA0_WRET_TAGMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA0_EDC_CNT_VG20, WRET_TAGMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT_VG20, WRET_TAGMEM_DED_COUNT), + }, + { "MMEA0_DRAMRD_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA0_EDC_CNT_VG20, DRAMRD_PAGEMEM_SED_COUNT), + 0, 0, + }, + { "MMEA0_DRAMWR_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA0_EDC_CNT_VG20, DRAMWR_PAGEMEM_SED_COUNT), + 0, 0, + }, + { "MMEA0_IORD_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA0_EDC_CNT_VG20, IORD_CMDMEM_SED_COUNT), + 0, 0, + }, + { "MMEA0_IOWR_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA0_EDC_CNT_VG20, IOWR_CMDMEM_SED_COUNT), + 0, 0, + }, + { "MMEA0_IOWR_DATAMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA0_EDC_CNT_VG20, IOWR_DATAMEM_SED_COUNT), + 0, 0, + }, + { "MMEA0_GMIRD_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT2_VG20), + SOC15_REG_FIELD(MMEA0_EDC_CNT2_VG20, GMIRD_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT2_VG20, GMIRD_CMDMEM_DED_COUNT), + }, + { "MMEA0_GMIWR_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT2_VG20), + SOC15_REG_FIELD(MMEA0_EDC_CNT2_VG20, GMIWR_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT2_VG20, GMIWR_CMDMEM_DED_COUNT), + }, + { "MMEA0_GMIWR_DATAMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT2_VG20), + SOC15_REG_FIELD(MMEA0_EDC_CNT2_VG20, GMIWR_DATAMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT2_VG20, GMIWR_DATAMEM_DED_COUNT), + }, + { "MMEA0_GMIRD_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT2_VG20), + SOC15_REG_FIELD(MMEA0_EDC_CNT2_VG20, GMIRD_PAGEMEM_SED_COUNT), + 0, 0, + }, + { "MMEA0_GMIWR_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT2_VG20), + SOC15_REG_FIELD(MMEA0_EDC_CNT2_VG20, GMIWR_PAGEMEM_SED_COUNT), + 0, 0, + }, + { "MMEA1_DRAMRD_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA1_EDC_CNT_VG20, DRAMRD_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT_VG20, DRAMRD_CMDMEM_DED_COUNT), + }, + { "MMEA1_DRAMWR_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA1_EDC_CNT_VG20, DRAMWR_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT_VG20, DRAMWR_CMDMEM_DED_COUNT), + }, + { "MMEA1_DRAMWR_DATAMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA1_EDC_CNT_VG20, DRAMWR_DATAMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT_VG20, DRAMWR_DATAMEM_DED_COUNT), + }, + { "MMEA1_RRET_TAGMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA1_EDC_CNT_VG20, RRET_TAGMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT_VG20, RRET_TAGMEM_DED_COUNT), + }, + { "MMEA1_WRET_TAGMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA1_EDC_CNT_VG20, WRET_TAGMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT_VG20, WRET_TAGMEM_DED_COUNT), + }, + { "MMEA1_DRAMRD_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA1_EDC_CNT_VG20, DRAMRD_PAGEMEM_SED_COUNT), + 0, 0, + }, + { "MMEA1_DRAMWR_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA1_EDC_CNT_VG20, DRAMWR_PAGEMEM_SED_COUNT), + 0, 0, + }, + { "MMEA1_IORD_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA1_EDC_CNT_VG20, IORD_CMDMEM_SED_COUNT), + 0, 0, + }, + { "MMEA1_IOWR_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA1_EDC_CNT_VG20, IOWR_CMDMEM_SED_COUNT), + 0, 0, + }, + { "MMEA1_IOWR_DATAMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT_VG20), + SOC15_REG_FIELD(MMEA1_EDC_CNT_VG20, IOWR_DATAMEM_SED_COUNT), + 0, 0, + }, + { "MMEA1_GMIRD_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT2_VG20), + SOC15_REG_FIELD(MMEA1_EDC_CNT2_VG20, GMIRD_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT2_VG20, GMIRD_CMDMEM_DED_COUNT), + }, + { "MMEA1_GMIWR_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT2_VG20), + SOC15_REG_FIELD(MMEA1_EDC_CNT2_VG20, GMIWR_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT2_VG20, GMIWR_CMDMEM_DED_COUNT), + }, + { "MMEA1_GMIWR_DATAMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT2_VG20), + SOC15_REG_FIELD(MMEA1_EDC_CNT2_VG20, GMIWR_DATAMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT2_VG20, GMIWR_DATAMEM_DED_COUNT), + }, + { "MMEA1_GMIRD_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT2_VG20), + SOC15_REG_FIELD(MMEA1_EDC_CNT2_VG20, GMIRD_PAGEMEM_SED_COUNT), + 0, 0, + }, + { "MMEA1_GMIWR_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT2_VG20), + SOC15_REG_FIELD(MMEA1_EDC_CNT2_VG20, GMIWR_PAGEMEM_SED_COUNT), + 0, 0, + } +}; + +static const struct soc15_reg_entry mmhub_v1_0_edc_cnt_regs[] = { + { SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT_VG20), 0, 0, 0}, + { SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT2_VG20), 0, 0, 0}, + { SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT_VG20), 0, 0, 0}, + { SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT2_VG20), 0, 0, 0}, +}; + +static int mmhub_v1_0_get_ras_error_count(const struct soc15_reg_entry *reg, + uint32_t value, uint32_t *sec_count, uint32_t *ded_count) +{ + uint32_t i; + uint32_t sec_cnt, ded_cnt; + + for (i = 0; i < ARRAY_SIZE(mmhub_v1_0_ras_fields); i++) { + if(mmhub_v1_0_ras_fields[i].reg_offset != reg->reg_offset) + continue; + + sec_cnt = (value & + mmhub_v1_0_ras_fields[i].sec_count_mask) >> + mmhub_v1_0_ras_fields[i].sec_count_shift; + if (sec_cnt) { + DRM_INFO("MMHUB SubBlock %s, SEC %d\n", + mmhub_v1_0_ras_fields[i].name, + sec_cnt); + *sec_count += sec_cnt; + } + + ded_cnt = (value & + mmhub_v1_0_ras_fields[i].ded_count_mask) >> + mmhub_v1_0_ras_fields[i].ded_count_shift; + if (ded_cnt) { + DRM_INFO("MMHUB SubBlock %s, DED %d\n", + mmhub_v1_0_ras_fields[i].name, + ded_cnt); + *ded_count += ded_cnt; + } + } + + return 0; +} + static void mmhub_v1_0_query_ras_error_count(struct amdgpu_device *adev, void *ras_error_status) { - int i; - uint32_t ea0_edc_cnt, ea0_edc_cnt2; - uint32_t ea1_edc_cnt, ea1_edc_cnt2; struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; - - /* EDC CNT will be cleared automatically after read */ - ea0_edc_cnt = RREG32_SOC15(MMHUB, 0, mmMMEA0_EDC_CNT_VG20); - ea0_edc_cnt2 = RREG32_SOC15(MMHUB, 0, mmMMEA0_EDC_CNT2_VG20); - ea1_edc_cnt = RREG32_SOC15(MMHUB, 0, mmMMEA1_EDC_CNT_VG20); - ea1_edc_cnt2 = RREG32_SOC15(MMHUB, 0, mmMMEA1_EDC_CNT2_VG20); - - /* error count of each error type is recorded by 2 bits, - * ce and ue count in EDC_CNT - */ - for (i = 0; i < 5; i++) { - err_data->ce_count += (ea0_edc_cnt & EA_EDC_CNT_MASK); - err_data->ce_count += (ea1_edc_cnt & EA_EDC_CNT_MASK); - ea0_edc_cnt >>= EA_EDC_CNT_SHIFT; - ea1_edc_cnt >>= EA_EDC_CNT_SHIFT; - err_data->ue_count += (ea0_edc_cnt & EA_EDC_CNT_MASK); - err_data->ue_count += (ea1_edc_cnt & EA_EDC_CNT_MASK); - ea0_edc_cnt >>= EA_EDC_CNT_SHIFT; - ea1_edc_cnt >>= EA_EDC_CNT_SHIFT; - } - /* successive ue count in EDC_CNT */ - for (i = 0; i < 5; i++) { - err_data->ue_count += (ea0_edc_cnt & EA_EDC_CNT_MASK); - err_data->ue_count += (ea1_edc_cnt & EA_EDC_CNT_MASK); - ea0_edc_cnt >>= EA_EDC_CNT_SHIFT; - ea1_edc_cnt >>= EA_EDC_CNT_SHIFT; + uint32_t sec_count = 0, ded_count = 0; + uint32_t i; + uint32_t reg_value; + + err_data->ue_count = 0; + err_data->ce_count = 0; + + for (i = 0; i < ARRAY_SIZE(mmhub_v1_0_edc_cnt_regs); i++) { + reg_value = + RREG32(SOC15_REG_ENTRY_OFFSET(mmhub_v1_0_edc_cnt_regs[i])); + if (reg_value) + mmhub_v1_0_get_ras_error_count(&mmhub_v1_0_edc_cnt_regs[i], + reg_value, &sec_count, &ded_count); } - /* ce and ue count in EDC_CNT2 */ - for (i = 0; i < 3; i++) { - err_data->ce_count += (ea0_edc_cnt2 & EA_EDC_CNT_MASK); - err_data->ce_count += (ea1_edc_cnt2 & EA_EDC_CNT_MASK); - ea0_edc_cnt2 >>= EA_EDC_CNT_SHIFT; - ea1_edc_cnt2 >>= EA_EDC_CNT_SHIFT; - err_data->ue_count += (ea0_edc_cnt2 & EA_EDC_CNT_MASK); - err_data->ue_count += (ea1_edc_cnt2 & EA_EDC_CNT_MASK); - ea0_edc_cnt2 >>= EA_EDC_CNT_SHIFT; - ea1_edc_cnt2 >>= EA_EDC_CNT_SHIFT; - } - /* successive ue count in EDC_CNT2 */ - for (i = 0; i < 6; i++) { - err_data->ue_count += (ea0_edc_cnt2 & EA_EDC_CNT_MASK); - err_data->ue_count += (ea1_edc_cnt2 & EA_EDC_CNT_MASK); - ea0_edc_cnt2 >>= EA_EDC_CNT_SHIFT; - ea1_edc_cnt2 >>= EA_EDC_CNT_SHIFT; - } + err_data->ce_count += sec_count; + err_data->ue_count += ded_count; } const struct amdgpu_mmhub_funcs mmhub_v1_0_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c index 66efe2f7bd7697f9740520515b74ccb9e80e7c28..d9301e80522aa9c9c7b9fde080487be4ba1bbcfb 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c @@ -21,6 +21,7 @@ * */ #include "amdgpu.h" +#include "amdgpu_ras.h" #include "mmhub_v9_4.h" #include "mmhub/mmhub_9_4_1_offset.h" @@ -29,7 +30,7 @@ #include "athub/athub_1_0_offset.h" #include "athub/athub_1_0_sh_mask.h" #include "vega10_enum.h" - +#include "soc15.h" #include "soc15_common.h" #define MMHUB_NUM_INSTANCES 2 @@ -53,7 +54,7 @@ u64 mmhub_v9_4_get_fb_location(struct amdgpu_device *adev) return base; } -void mmhub_v9_4_setup_vm_pt_regs(struct amdgpu_device *adev, int hubid, +static void mmhub_v9_4_setup_hubid_vm_pt_regs(struct amdgpu_device *adev, int hubid, uint32_t vmid, uint64_t value) { /* two registers distance between mmVML2VC0_VM_CONTEXT0_* to @@ -79,7 +80,7 @@ static void mmhub_v9_4_init_gart_aperture_regs(struct amdgpu_device *adev, { uint64_t pt_base = amdgpu_gmc_pd_addr(adev->gart.bo); - mmhub_v9_4_setup_vm_pt_regs(adev, hubid, 0, pt_base); + mmhub_v9_4_setup_hubid_vm_pt_regs(adev, hubid, 0, pt_base); WREG32_SOC15_OFFSET(MMHUB, 0, mmVML2VC0_VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32, @@ -100,6 +101,16 @@ 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, + uint64_t page_table_base) +{ + int i; + + for (i = 0; i < MMHUB_NUM_INSTANCES; i++) + mmhub_v9_4_setup_hubid_vm_pt_regs(adev, i, vmid, + page_table_base); +} + static void mmhub_v9_4_init_system_aperture_regs(struct amdgpu_device *adev, int hubid) { @@ -313,7 +324,8 @@ static void mmhub_v9_4_setup_vmid_config(struct amdgpu_device *adev, int hubid) adev->vm_manager.block_size - 9); /* Send no-retry XNACK on fault to suppress VM fault storm. */ tmp = REG_SET_FIELD(tmp, VML2VC0_VM_CONTEXT1_CNTL, - RETRY_PERMISSION_OR_INVALID_PAGE_FAULT, 0); + RETRY_PERMISSION_OR_INVALID_PAGE_FAULT, + !amdgpu_noretry); WREG32_SOC15_OFFSET(MMHUB, 0, mmVML2VC0_VM_CONTEXT1_CNTL, hubid * MMHUB_INSTANCE_REGISTER_OFFSET + i, tmp); @@ -655,3 +667,253 @@ void mmhub_v9_4_get_clockgating(struct amdgpu_device *adev, u32 *flags) if (data & ATCL2_0_ATC_L2_MISC_CG__MEM_LS_ENABLE_MASK) *flags |= AMD_CG_SUPPORT_MC_LS; } + +static const struct soc15_ras_field_entry mmhub_v9_4_ras_fields[] = { + { "MMEA0_DRAMRD_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT, DRAMRD_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT, DRAMRD_CMDMEM_DED_COUNT), + }, + { "MMEA0_DRAMWR_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT, DRAMWR_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT, DRAMWR_CMDMEM_DED_COUNT), + }, + { "MMEA0_DRAMWR_DATAMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT, DRAMWR_DATAMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT, DRAMWR_DATAMEM_DED_COUNT), + }, + { "MMEA0_RRET_TAGMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT, RRET_TAGMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT, RRET_TAGMEM_DED_COUNT), + }, + { "MMEA0_WRET_TAGMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT, WRET_TAGMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT, WRET_TAGMEM_DED_COUNT), + }, + { "MMEA0_DRAMRD_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT, DRAMRD_PAGEMEM_SED_COUNT), + 0, 0, + }, + { "MMEA0_DRAMWR_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT, DRAMWR_PAGEMEM_SED_COUNT), + 0, 0, + }, + { "MMEA0_IORD_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT, IORD_CMDMEM_SED_COUNT), + 0, 0, + }, + { "MMEA0_IOWR_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT, IOWR_CMDMEM_SED_COUNT), + 0, 0, + }, + { "MMEA0_IOWR_DATAMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT, IOWR_DATAMEM_SED_COUNT), + 0, 0, + }, + { "MMEA0_GMIRD_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT2), + SOC15_REG_FIELD(MMEA0_EDC_CNT2, GMIRD_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT2, GMIRD_CMDMEM_DED_COUNT), + }, + { "MMEA0_GMIWR_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT2), + SOC15_REG_FIELD(MMEA0_EDC_CNT2, GMIWR_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT2, GMIWR_CMDMEM_DED_COUNT), + }, + { "MMEA0_GMIWR_DATAMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT2), + SOC15_REG_FIELD(MMEA0_EDC_CNT2, GMIWR_DATAMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA0_EDC_CNT2, GMIWR_DATAMEM_DED_COUNT), + }, + { "MMEA0_GMIRD_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT2), + SOC15_REG_FIELD(MMEA0_EDC_CNT2, GMIRD_PAGEMEM_SED_COUNT), + 0, 0, + }, + { "MMEA0_GMIWR_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT2), + SOC15_REG_FIELD(MMEA0_EDC_CNT2, GMIWR_PAGEMEM_SED_COUNT), + 0, 0, + }, + { "MMEA0_DRAMRD_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT3), + 0, 0, + SOC15_REG_FIELD(MMEA0_EDC_CNT3, DRAMRD_PAGEMEM_DED_COUNT), + }, + { "MMEA0_DRAMWR_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT3), + 0, 0, + SOC15_REG_FIELD(MMEA0_EDC_CNT3, DRAMWR_PAGEMEM_DED_COUNT), + }, + { "MMEA0_IORD_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT3), + 0, 0, + SOC15_REG_FIELD(MMEA0_EDC_CNT3, IORD_CMDMEM_DED_COUNT), + }, + { "MMEA0_IOWR_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT3), + 0, 0, + SOC15_REG_FIELD(MMEA0_EDC_CNT3, IOWR_CMDMEM_DED_COUNT), + }, + { "MMEA0_IOWR_DATAMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT3), + 0, 0, + SOC15_REG_FIELD(MMEA0_EDC_CNT3, IOWR_DATAMEM_DED_COUNT), + }, + { "MMEA0_GMIRD_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT3), + 0, 0, + SOC15_REG_FIELD(MMEA0_EDC_CNT3, GMIRD_PAGEMEM_DED_COUNT), + }, + { "MMEA0_GMIWR_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT3), + 0, 0, + SOC15_REG_FIELD(MMEA0_EDC_CNT3, GMIWR_PAGEMEM_DED_COUNT), + }, + { "MMEA1_DRAMRD_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT, DRAMRD_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT, DRAMRD_CMDMEM_DED_COUNT), + }, + { "MMEA1_DRAMWR_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT, DRAMWR_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT, DRAMWR_CMDMEM_DED_COUNT), + }, + { "MMEA1_DRAMWR_DATAMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT, DRAMWR_DATAMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT, DRAMWR_DATAMEM_DED_COUNT), + }, + { "MMEA1_RRET_TAGMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT, RRET_TAGMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT, RRET_TAGMEM_DED_COUNT), + }, + { "MMEA1_WRET_TAGMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT, WRET_TAGMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT, WRET_TAGMEM_DED_COUNT), + }, + { "MMEA1_DRAMRD_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT, DRAMRD_PAGEMEM_SED_COUNT), + 0, 0, + }, + { "MMEA1_DRAMWR_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT, DRAMWR_PAGEMEM_SED_COUNT), + 0, 0, + }, + { "MMEA1_IORD_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT, IORD_CMDMEM_SED_COUNT), + 0, 0, + }, + { "MMEA1_IOWR_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT, IOWR_CMDMEM_SED_COUNT), + 0, 0, + }, + { "MMEA1_IOWR_DATAMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT, IOWR_DATAMEM_SED_COUNT), + 0, 0, + }, + { "MMEA1_GMIRD_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT2), + SOC15_REG_FIELD(MMEA1_EDC_CNT2, GMIRD_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT2, GMIRD_CMDMEM_DED_COUNT), + }, + { "MMEA1_GMIWR_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT2), + SOC15_REG_FIELD(MMEA1_EDC_CNT2, GMIWR_CMDMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT2, GMIWR_CMDMEM_DED_COUNT), + }, + { "MMEA1_GMIWR_DATAMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT2), + SOC15_REG_FIELD(MMEA1_EDC_CNT2, GMIWR_DATAMEM_SEC_COUNT), + SOC15_REG_FIELD(MMEA1_EDC_CNT2, GMIWR_DATAMEM_DED_COUNT), + }, + { "MMEA1_GMIRD_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT2), + SOC15_REG_FIELD(MMEA1_EDC_CNT2, GMIRD_PAGEMEM_SED_COUNT), + 0, 0, + }, + { "MMEA1_GMIWR_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT2), + SOC15_REG_FIELD(MMEA1_EDC_CNT2, GMIWR_PAGEMEM_SED_COUNT), + 0, 0, + }, + { "MMEA1_DRAMRD_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT3), + 0, 0, + SOC15_REG_FIELD(MMEA1_EDC_CNT3, DRAMRD_PAGEMEM_DED_COUNT), + }, + { "MMEA1_DRAMWR_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT3), + 0, 0, + SOC15_REG_FIELD(MMEA1_EDC_CNT3, DRAMWR_PAGEMEM_DED_COUNT), + }, + { "MMEA1_IORD_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT3), + 0, 0, + SOC15_REG_FIELD(MMEA1_EDC_CNT3, IORD_CMDMEM_DED_COUNT), + }, + { "MMEA1_IOWR_CMDMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT3), + 0, 0, + SOC15_REG_FIELD(MMEA1_EDC_CNT3, IOWR_CMDMEM_DED_COUNT), + }, + { "MMEA1_IOWR_DATAMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT3), + 0, 0, + SOC15_REG_FIELD(MMEA1_EDC_CNT3, IOWR_DATAMEM_DED_COUNT), + }, + { "MMEA1_GMIRD_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT3), + 0, 0, + SOC15_REG_FIELD(MMEA1_EDC_CNT3, GMIRD_PAGEMEM_DED_COUNT), + }, + { "MMEA1_GMIWR_PAGEMEM", SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT3), + 0, 0, + SOC15_REG_FIELD(MMEA1_EDC_CNT3, GMIWR_PAGEMEM_DED_COUNT), + } +}; + +static const struct soc15_reg_entry mmhub_v9_4_edc_cnt_regs[] = { + { SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT), 0, 0, 0}, + { SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT2), 0, 0, 0}, + { SOC15_REG_ENTRY(MMHUB, 0, mmMMEA0_EDC_CNT3), 0, 0, 0}, + { SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT), 0, 0, 0}, + { SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT2), 0, 0, 0}, + { SOC15_REG_ENTRY(MMHUB, 0, mmMMEA1_EDC_CNT3), 0, 0, 0}, +}; + +static int mmhub_v9_4_get_ras_error_count(const struct soc15_reg_entry *reg, + uint32_t value, uint32_t *sec_count, uint32_t *ded_count) +{ + uint32_t i; + uint32_t sec_cnt, ded_cnt; + + for (i = 0; i < ARRAY_SIZE(mmhub_v9_4_ras_fields); i++) { + if(mmhub_v9_4_ras_fields[i].reg_offset != reg->reg_offset) + continue; + + sec_cnt = (value & + mmhub_v9_4_ras_fields[i].sec_count_mask) >> + mmhub_v9_4_ras_fields[i].sec_count_shift; + if (sec_cnt) { + DRM_INFO("MMHUB SubBlock %s, SEC %d\n", + mmhub_v9_4_ras_fields[i].name, + sec_cnt); + *sec_count += sec_cnt; + } + + ded_cnt = (value & + mmhub_v9_4_ras_fields[i].ded_count_mask) >> + mmhub_v9_4_ras_fields[i].ded_count_shift; + if (ded_cnt) { + DRM_INFO("MMHUB SubBlock %s, DED %d\n", + mmhub_v9_4_ras_fields[i].name, + ded_cnt); + *ded_count += ded_cnt; + } + } + + return 0; +} + +static void mmhub_v9_4_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 sec_count = 0, ded_count = 0; + uint32_t i; + uint32_t reg_value; + + err_data->ue_count = 0; + err_data->ce_count = 0; + + for (i = 0; i < ARRAY_SIZE(mmhub_v9_4_edc_cnt_regs); i++) { + reg_value = + RREG32(SOC15_REG_ENTRY_OFFSET(mmhub_v9_4_edc_cnt_regs[i])); + if (reg_value) + mmhub_v9_4_get_ras_error_count(&mmhub_v9_4_edc_cnt_regs[i], + reg_value, &sec_count, &ded_count); + } + + err_data->ce_count += sec_count; + err_data->ue_count += ded_count; +} + +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, +}; diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.h b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.h index d435cfcec1a8038d2bff1aaa030d206a76cc2e30..1b979773776c0a02e0a5089ca12c4db51b1c2e62 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.h +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.h @@ -23,6 +23,8 @@ #ifndef __MMHUB_V9_4_H__ #define __MMHUB_V9_4_H__ +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); @@ -32,5 +34,7 @@ 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 cc5bf595f9b1c2a49b49dc5d3b3ecd092f6c3be7..43305afa3d6f6f8bfc6b41b121f6a9e4b8cdee03 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c @@ -158,82 +158,6 @@ static void xgpu_ai_mailbox_trans_msg (struct amdgpu_device *adev, xgpu_ai_mailbox_set_valid(adev, false); } -static int xgpu_ai_get_pp_clk(struct amdgpu_device *adev, u32 type, char *buf) -{ - int r = 0; - u32 req, val, size; - - if (!amdgim_is_hwperf(adev) || buf == NULL) - return -EBADRQC; - - switch(type) { - case PP_SCLK: - req = IDH_IRQ_GET_PP_SCLK; - break; - case PP_MCLK: - req = IDH_IRQ_GET_PP_MCLK; - break; - default: - return -EBADRQC; - } - - mutex_lock(&adev->virt.dpm_mutex); - - xgpu_ai_mailbox_trans_msg(adev, req, 0, 0, 0); - - r = xgpu_ai_poll_msg(adev, IDH_SUCCESS); - if (!r && adev->fw_vram_usage.va != NULL) { - val = RREG32_NO_KIQ( - SOC15_REG_OFFSET(NBIO, 0, - mmBIF_BX_PF0_MAILBOX_MSGBUF_RCV_DW1)); - size = strnlen((((char *)adev->virt.fw_reserve.p_pf2vf) + - val), PAGE_SIZE); - - if (size < PAGE_SIZE) - strcpy(buf,((char *)adev->virt.fw_reserve.p_pf2vf + val)); - else - size = 0; - - r = size; - goto out; - } - - r = xgpu_ai_poll_msg(adev, IDH_FAIL); - if(r) - pr_info("%s DPM request failed", - (type == PP_SCLK)? "SCLK" : "MCLK"); - -out: - mutex_unlock(&adev->virt.dpm_mutex); - return r; -} - -static int xgpu_ai_force_dpm_level(struct amdgpu_device *adev, u32 level) -{ - int r = 0; - u32 req = IDH_IRQ_FORCE_DPM_LEVEL; - - if (!amdgim_is_hwperf(adev)) - return -EBADRQC; - - mutex_lock(&adev->virt.dpm_mutex); - xgpu_ai_mailbox_trans_msg(adev, req, level, 0, 0); - - r = xgpu_ai_poll_msg(adev, IDH_SUCCESS); - if (!r) - goto out; - - r = xgpu_ai_poll_msg(adev, IDH_FAIL); - if (!r) - pr_info("DPM request failed"); - else - pr_info("Mailbox is broken"); - -out: - mutex_unlock(&adev->virt.dpm_mutex); - return r; -} - static int xgpu_ai_send_access_requests(struct amdgpu_device *adev, enum idh_request req) { @@ -455,6 +379,4 @@ const struct amdgpu_virt_ops xgpu_ai_virt_ops = { .reset_gpu = xgpu_ai_request_reset, .wait_reset = NULL, .trans_msg = xgpu_ai_mailbox_trans_msg, - .get_pp_clk = xgpu_ai_get_pp_clk, - .force_dpm_level = xgpu_ai_force_dpm_level, }; diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h index 077e91a33d62d632c48c0eed5ddf0b3a997be676..37dbe0f2142f54fc7730b212710b4dfea0a9bec3 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h @@ -35,10 +35,6 @@ enum idh_request { IDH_REL_GPU_FINI_ACCESS, IDH_REQ_GPU_RESET_ACCESS, - IDH_IRQ_FORCE_DPM_LEVEL = 10, - IDH_IRQ_GET_PP_SCLK, - IDH_IRQ_GET_PP_MCLK, - IDH_LOG_VF_ERROR = 200, }; diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c index 0db458f9fafcc2f3e1b924da2d2909eea03e9739..bb701dbfd472957b3763b3a3d9c44acd146db6b2 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c @@ -52,6 +52,9 @@ #define BIF_MMSCH1_DOORBELL_RANGE__OFFSET_MASK 0x00000FFCL #define BIF_MMSCH1_DOORBELL_RANGE__SIZE_MASK 0x001F0000L +static void nbio_v7_4_query_ras_error_count(struct amdgpu_device *adev, + void *ras_error_status); + static void nbio_v7_4_remap_hdp_registers(struct amdgpu_device *adev) { WREG32_SOC15(NBIO, 0, mmREMAP_HDP_MEM_FLUSH_CNTL, @@ -314,6 +317,7 @@ static void nbio_v7_4_init_registers(struct amdgpu_device *adev) static void nbio_v7_4_handle_ras_controller_intr_no_bifring(struct amdgpu_device *adev) { uint32_t bif_doorbell_intr_cntl; + struct ras_manager *obj = amdgpu_ras_find_obj(adev, adev->nbio.ras_if); bif_doorbell_intr_cntl = RREG32_SOC15(NBIO, 0, mmBIF_DOORBELL_INT_CNTL); if (REG_GET_FIELD(bif_doorbell_intr_cntl, @@ -324,7 +328,18 @@ 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); - amdgpu_ras_global_ras_isr(adev); + /* + * 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, &obj->err_data); + + DRM_WARN("RAS controller interrupt triggered by NBIF error\n"); + + /* ras_controller_int is dedicated for nbif ras error, + * not the global interrupt for sync flood + */ + amdgpu_ras_reset_gpu(adev, true); } } @@ -467,10 +482,12 @@ static int nbio_v7_4_init_ras_err_event_athub_interrupt (struct amdgpu_device *a return 0; } +#define smnPARITY_ERROR_STATUS_UNCORR_GRP2 0x13a20030 + static void nbio_v7_4_query_ras_error_count(struct amdgpu_device *adev, void *ras_error_status) { - uint32_t global_sts, central_sts, int_eoi; + uint32_t global_sts, central_sts, int_eoi, parity_sts; uint32_t corr, fatal, non_fatal; struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; @@ -479,6 +496,7 @@ static void nbio_v7_4_query_ras_error_count(struct amdgpu_device *adev, fatal = REG_GET_FIELD(global_sts, RAS_GLOBAL_STATUS_LO, ParityErrFatal); non_fatal = REG_GET_FIELD(global_sts, RAS_GLOBAL_STATUS_LO, ParityErrNonFatal); + parity_sts = RREG32_PCIE(smnPARITY_ERROR_STATUS_UNCORR_GRP2); if (corr) err_data->ce_count++; @@ -490,6 +508,11 @@ static void nbio_v7_4_query_ras_error_count(struct amdgpu_device *adev, /* clear error status register */ WREG32_PCIE(smnRAS_GLOBAL_STATUS_LO, global_sts); + if (fatal) + /* clear parity fatal error indication field */ + WREG32_PCIE(smnPARITY_ERROR_STATUS_UNCORR_GRP2, + parity_sts); + if (REG_GET_FIELD(central_sts, BIFL_RAS_CENTRAL_STATUS, BIFL_RasContller_Intr_Recv)) { /* clear interrupt status register */ diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c index 0ba66bef57468849a5d00d89ff51e90394862dda..b0229543e8875da44b8e0c0a195dfed2f763ca33 100644 --- a/drivers/gpu/drm/amd/amdgpu/nv.c +++ b/drivers/gpu/drm/amd/amdgpu/nv.c @@ -53,6 +53,7 @@ #include "gfx_v10_0.h" #include "sdma_v5_0.h" #include "vcn_v2_0.h" +#include "jpeg_v2_0.h" #include "dce_virtual.h" #include "mes_v10_1.h" #include "mxgpu_nv.h" @@ -314,6 +315,16 @@ static int nv_asic_mode1_reset(struct amdgpu_device *adev) return ret; } +static bool nv_asic_supports_baco(struct amdgpu_device *adev) +{ + struct smu_context *smu = &adev->smu; + + if (smu_baco_is_support(smu)) + return true; + else + return false; +} + static enum amd_reset_method nv_asic_reset_method(struct amdgpu_device *adev) { @@ -342,7 +353,12 @@ static int nv_asic_reset(struct amdgpu_device *adev) if (nv_asic_reset_method(adev) == AMD_RESET_METHOD_BACO) { if (!adev->in_suspend) amdgpu_inc_vram_lost(adev); - ret = smu_baco_reset(smu); + ret = smu_baco_enter(smu); + if (ret) + return ret; + ret = smu_baco_exit(smu); + if (ret) + return ret; } else { if (!adev->in_suspend) amdgpu_inc_vram_lost(adev); @@ -476,6 +492,7 @@ int nv_set_ip_blocks(struct amdgpu_device *adev) is_support_sw_smu(adev) && !amdgpu_sriov_vf(adev)) amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); amdgpu_device_ip_block_add(adev, &vcn_v2_0_ip_block); + amdgpu_device_ip_block_add(adev, &jpeg_v2_0_ip_block); if (adev->enable_mes) amdgpu_device_ip_block_add(adev, &mes_v10_1_ip_block); break; @@ -499,6 +516,7 @@ int nv_set_ip_blocks(struct amdgpu_device *adev) is_support_sw_smu(adev) && !amdgpu_sriov_vf(adev)) amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); amdgpu_device_ip_block_add(adev, &vcn_v2_0_ip_block); + amdgpu_device_ip_block_add(adev, &jpeg_v2_0_ip_block); break; default: return -EINVAL; @@ -617,6 +635,7 @@ static const struct amdgpu_asic_funcs nv_asic_funcs = .get_pcie_usage = &nv_get_pcie_usage, .need_reset_on_init = &nv_need_reset_on_init, .get_pcie_replay_count = &nv_get_pcie_replay_count, + .supports_baco = &nv_asic_supports_baco, }; static int nv_common_early_init(void *handle) @@ -656,10 +675,12 @@ static int nv_common_early_init(void *handle) AMD_CG_SUPPORT_ATHUB_MGCG | AMD_CG_SUPPORT_ATHUB_LS | AMD_CG_SUPPORT_VCN_MGCG | + AMD_CG_SUPPORT_JPEG_MGCG | AMD_CG_SUPPORT_BIF_MGCG | AMD_CG_SUPPORT_BIF_LS; adev->pg_flags = AMD_PG_SUPPORT_VCN | AMD_PG_SUPPORT_VCN_DPG | + AMD_PG_SUPPORT_JPEG | AMD_PG_SUPPORT_ATHUB; adev->external_rev_id = adev->rev_id + 0x1; break; @@ -676,9 +697,11 @@ static int nv_common_early_init(void *handle) AMD_CG_SUPPORT_ATHUB_MGCG | AMD_CG_SUPPORT_ATHUB_LS | AMD_CG_SUPPORT_VCN_MGCG | + AMD_CG_SUPPORT_JPEG_MGCG | AMD_CG_SUPPORT_BIF_MGCG | AMD_CG_SUPPORT_BIF_LS; adev->pg_flags = AMD_PG_SUPPORT_VCN | + AMD_PG_SUPPORT_JPEG | AMD_PG_SUPPORT_VCN_DPG; adev->external_rev_id = adev->rev_id + 20; break; @@ -697,9 +720,11 @@ static int nv_common_early_init(void *handle) AMD_CG_SUPPORT_MC_LS | AMD_CG_SUPPORT_ATHUB_MGCG | AMD_CG_SUPPORT_ATHUB_LS | - AMD_CG_SUPPORT_VCN_MGCG; + AMD_CG_SUPPORT_VCN_MGCG | + AMD_CG_SUPPORT_JPEG_MGCG; adev->pg_flags = AMD_PG_SUPPORT_VCN | AMD_PG_SUPPORT_VCN_DPG | + AMD_PG_SUPPORT_JPEG | AMD_PG_SUPPORT_ATHUB; adev->external_rev_id = adev->rev_id + 0xa; break; diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c index b345e69ba2460d5850aadd67701909adcadfe731..7539104175e8ae451520e618c4886b67f5d35e37 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c @@ -230,54 +230,6 @@ static int psp_v10_0_ring_destroy(struct psp_context *psp, return ret; } -static int psp_v10_0_cmd_submit(struct psp_context *psp, - uint64_t cmd_buf_mc_addr, uint64_t fence_mc_addr, - int index) -{ - unsigned int psp_write_ptr_reg = 0; - struct psp_gfx_rb_frame * write_frame = psp->km_ring.ring_mem; - struct psp_ring *ring = &psp->km_ring; - struct psp_gfx_rb_frame *ring_buffer_start = ring->ring_mem; - struct psp_gfx_rb_frame *ring_buffer_end = ring_buffer_start + - ring->ring_size / sizeof(struct psp_gfx_rb_frame) - 1; - struct amdgpu_device *adev = psp->adev; - uint32_t ring_size_dw = ring->ring_size / 4; - uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4; - - /* KM (GPCOM) prepare write pointer */ - psp_write_ptr_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67); - - /* Update KM RB frame pointer to new frame */ - if ((psp_write_ptr_reg % ring_size_dw) == 0) - write_frame = ring_buffer_start; - else - write_frame = ring_buffer_start + (psp_write_ptr_reg / rb_frame_size_dw); - /* Check invalid write_frame ptr address */ - if ((write_frame < ring_buffer_start) || (ring_buffer_end < write_frame)) { - DRM_ERROR("ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n", - ring_buffer_start, ring_buffer_end, write_frame); - DRM_ERROR("write_frame is pointing to address out of bounds\n"); - return -EINVAL; - } - - /* Initialize KM RB frame */ - memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame)); - - /* Update KM RB frame */ - write_frame->cmd_buf_addr_hi = upper_32_bits(cmd_buf_mc_addr); - write_frame->cmd_buf_addr_lo = lower_32_bits(cmd_buf_mc_addr); - write_frame->fence_addr_hi = upper_32_bits(fence_mc_addr); - write_frame->fence_addr_lo = lower_32_bits(fence_mc_addr); - write_frame->fence_value = index; - amdgpu_asic_flush_hdp(adev, NULL); - - /* Update the write Pointer in DWORDs */ - psp_write_ptr_reg = (psp_write_ptr_reg + rb_frame_size_dw) % ring_size_dw; - WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, psp_write_ptr_reg); - - return 0; -} - static int psp_v10_0_sram_map(struct amdgpu_device *adev, unsigned int *sram_offset, unsigned int *sram_addr_reg_offset, @@ -407,15 +359,30 @@ static int psp_v10_0_mode1_reset(struct psp_context *psp) return -EINVAL; } +static uint32_t psp_v10_0_ring_get_wptr(struct psp_context *psp) +{ + struct amdgpu_device *adev = psp->adev; + + return RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67); +} + +static void psp_v10_0_ring_set_wptr(struct psp_context *psp, uint32_t value) +{ + struct amdgpu_device *adev = psp->adev; + + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, value); +} + static const struct psp_funcs psp_v10_0_funcs = { .init_microcode = psp_v10_0_init_microcode, .ring_init = psp_v10_0_ring_init, .ring_create = psp_v10_0_ring_create, .ring_stop = psp_v10_0_ring_stop, .ring_destroy = psp_v10_0_ring_destroy, - .cmd_submit = psp_v10_0_cmd_submit, .compare_sram_data = psp_v10_0_compare_sram_data, .mode1_reset = psp_v10_0_mode1_reset, + .ring_get_wptr = psp_v10_0_ring_get_wptr, + .ring_set_wptr = psp_v10_0_ring_set_wptr, }; void psp_v10_0_set_psp_funcs(struct psp_context *psp) diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c index ffeaa2f5588d05757fce353eaa5550a9a1253970..c66ca8cc2ebdbd23b0a8ae77aad335a0dfb37bd9 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c @@ -186,6 +186,31 @@ static int psp_v11_0_init_microcode(struct psp_context *psp) case CHIP_NAVI10: case CHIP_NAVI14: case CHIP_NAVI12: + 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 v11.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); + } break; default: BUG(); @@ -519,63 +544,6 @@ static int psp_v11_0_ring_destroy(struct psp_context *psp, return ret; } -static int psp_v11_0_cmd_submit(struct psp_context *psp, - uint64_t cmd_buf_mc_addr, uint64_t fence_mc_addr, - int index) -{ - unsigned int psp_write_ptr_reg = 0; - struct psp_gfx_rb_frame *write_frame = psp->km_ring.ring_mem; - struct psp_ring *ring = &psp->km_ring; - struct psp_gfx_rb_frame *ring_buffer_start = ring->ring_mem; - struct psp_gfx_rb_frame *ring_buffer_end = ring_buffer_start + - ring->ring_size / sizeof(struct psp_gfx_rb_frame) - 1; - struct amdgpu_device *adev = psp->adev; - uint32_t ring_size_dw = ring->ring_size / 4; - uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4; - - /* KM (GPCOM) prepare write pointer */ - if (psp_v11_0_support_vmr_ring(psp)) - psp_write_ptr_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102); - else - psp_write_ptr_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67); - - /* Update KM RB frame pointer to new frame */ - /* write_frame ptr increments by size of rb_frame in bytes */ - /* psp_write_ptr_reg increments by size of rb_frame in DWORDs */ - if ((psp_write_ptr_reg % ring_size_dw) == 0) - write_frame = ring_buffer_start; - else - write_frame = ring_buffer_start + (psp_write_ptr_reg / rb_frame_size_dw); - /* Check invalid write_frame ptr address */ - if ((write_frame < ring_buffer_start) || (ring_buffer_end < write_frame)) { - DRM_ERROR("ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n", - ring_buffer_start, ring_buffer_end, write_frame); - DRM_ERROR("write_frame is pointing to address out of bounds\n"); - return -EINVAL; - } - - /* Initialize KM RB frame */ - memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame)); - - /* Update KM RB frame */ - write_frame->cmd_buf_addr_hi = upper_32_bits(cmd_buf_mc_addr); - write_frame->cmd_buf_addr_lo = lower_32_bits(cmd_buf_mc_addr); - write_frame->fence_addr_hi = upper_32_bits(fence_mc_addr); - write_frame->fence_addr_lo = lower_32_bits(fence_mc_addr); - write_frame->fence_value = index; - amdgpu_asic_flush_hdp(adev, NULL); - - /* Update the write Pointer in DWORDs */ - psp_write_ptr_reg = (psp_write_ptr_reg + rb_frame_size_dw) % ring_size_dw; - if (psp_v11_0_support_vmr_ring(psp)) { - WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102, psp_write_ptr_reg); - WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101, GFX_CTRL_CMD_ID_CONSUME_CMD); - } else - WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, psp_write_ptr_reg); - - return 0; -} - static int psp_v11_0_sram_map(struct amdgpu_device *adev, unsigned int *sram_offset, unsigned int *sram_addr_reg_offset, @@ -1068,6 +1036,30 @@ static int psp_v11_0_memory_training(struct psp_context *psp, uint32_t ops) return 0; } +static uint32_t psp_v11_0_ring_get_wptr(struct psp_context *psp) +{ + uint32_t data; + struct amdgpu_device *adev = psp->adev; + + if (psp_v11_0_support_vmr_ring(psp)) + data = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102); + else + data = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67); + + return data; +} + +static void psp_v11_0_ring_set_wptr(struct psp_context *psp, uint32_t value) +{ + struct amdgpu_device *adev = psp->adev; + + if (psp_v11_0_support_vmr_ring(psp)) { + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102, value); + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101, GFX_CTRL_CMD_ID_CONSUME_CMD); + } else + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, value); +} + static const struct psp_funcs psp_v11_0_funcs = { .init_microcode = psp_v11_0_init_microcode, .bootloader_load_kdb = psp_v11_0_bootloader_load_kdb, @@ -1077,7 +1069,6 @@ static const struct psp_funcs psp_v11_0_funcs = { .ring_create = psp_v11_0_ring_create, .ring_stop = psp_v11_0_ring_stop, .ring_destroy = psp_v11_0_ring_destroy, - .cmd_submit = psp_v11_0_cmd_submit, .compare_sram_data = psp_v11_0_compare_sram_data, .mode1_reset = psp_v11_0_mode1_reset, .xgmi_get_topology_info = psp_v11_0_xgmi_get_topology_info, @@ -1091,6 +1082,8 @@ static const struct psp_funcs psp_v11_0_funcs = { .mem_training_init = psp_v11_0_memory_training_init, .mem_training_fini = psp_v11_0_memory_training_fini, .mem_training = psp_v11_0_memory_training, + .ring_get_wptr = psp_v11_0_ring_get_wptr, + .ring_set_wptr = psp_v11_0_ring_set_wptr, }; void psp_v11_0_set_psp_funcs(struct psp_context *psp) diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c index 8f553f6f92d61b1a117b485e4a667fd0415d5f48..58d8b6d732e8f0b6e26fc52738dad013813c03e7 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c @@ -334,63 +334,6 @@ static int psp_v12_0_ring_destroy(struct psp_context *psp, return ret; } -static int psp_v12_0_cmd_submit(struct psp_context *psp, - uint64_t cmd_buf_mc_addr, uint64_t fence_mc_addr, - int index) -{ - unsigned int psp_write_ptr_reg = 0; - struct psp_gfx_rb_frame *write_frame = psp->km_ring.ring_mem; - struct psp_ring *ring = &psp->km_ring; - struct psp_gfx_rb_frame *ring_buffer_start = ring->ring_mem; - struct psp_gfx_rb_frame *ring_buffer_end = ring_buffer_start + - ring->ring_size / sizeof(struct psp_gfx_rb_frame) - 1; - struct amdgpu_device *adev = psp->adev; - uint32_t ring_size_dw = ring->ring_size / 4; - uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4; - - /* KM (GPCOM) prepare write pointer */ - if (psp_v12_0_support_vmr_ring(psp)) - psp_write_ptr_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102); - else - psp_write_ptr_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67); - - /* Update KM RB frame pointer to new frame */ - /* write_frame ptr increments by size of rb_frame in bytes */ - /* psp_write_ptr_reg increments by size of rb_frame in DWORDs */ - if ((psp_write_ptr_reg % ring_size_dw) == 0) - write_frame = ring_buffer_start; - else - write_frame = ring_buffer_start + (psp_write_ptr_reg / rb_frame_size_dw); - /* Check invalid write_frame ptr address */ - if ((write_frame < ring_buffer_start) || (ring_buffer_end < write_frame)) { - DRM_ERROR("ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n", - ring_buffer_start, ring_buffer_end, write_frame); - DRM_ERROR("write_frame is pointing to address out of bounds\n"); - return -EINVAL; - } - - /* Initialize KM RB frame */ - memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame)); - - /* Update KM RB frame */ - write_frame->cmd_buf_addr_hi = upper_32_bits(cmd_buf_mc_addr); - write_frame->cmd_buf_addr_lo = lower_32_bits(cmd_buf_mc_addr); - write_frame->fence_addr_hi = upper_32_bits(fence_mc_addr); - write_frame->fence_addr_lo = lower_32_bits(fence_mc_addr); - write_frame->fence_value = index; - amdgpu_asic_flush_hdp(adev, NULL); - - /* Update the write Pointer in DWORDs */ - psp_write_ptr_reg = (psp_write_ptr_reg + rb_frame_size_dw) % ring_size_dw; - if (psp_v12_0_support_vmr_ring(psp)) { - WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102, psp_write_ptr_reg); - WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101, GFX_CTRL_CMD_ID_CONSUME_CMD); - } else - WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, psp_write_ptr_reg); - - return 0; -} - static int psp_v12_0_sram_map(struct amdgpu_device *adev, unsigned int *sram_offset, unsigned int *sram_addr_reg_offset, @@ -547,6 +490,30 @@ static int psp_v12_0_mode1_reset(struct psp_context *psp) return 0; } +static uint32_t psp_v12_0_ring_get_wptr(struct psp_context *psp) +{ + uint32_t data; + struct amdgpu_device *adev = psp->adev; + + if (psp_v12_0_support_vmr_ring(psp)) + data = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102); + else + data = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67); + + return data; +} + +static void psp_v12_0_ring_set_wptr(struct psp_context *psp, uint32_t value) +{ + struct amdgpu_device *adev = psp->adev; + + if (psp_v12_0_support_vmr_ring(psp)) { + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102, value); + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101, GFX_CTRL_CMD_ID_CONSUME_CMD); + } else + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, value); +} + static const struct psp_funcs psp_v12_0_funcs = { .init_microcode = psp_v12_0_init_microcode, .bootloader_load_sysdrv = psp_v12_0_bootloader_load_sysdrv, @@ -555,9 +522,10 @@ static const struct psp_funcs psp_v12_0_funcs = { .ring_create = psp_v12_0_ring_create, .ring_stop = psp_v12_0_ring_stop, .ring_destroy = psp_v12_0_ring_destroy, - .cmd_submit = psp_v12_0_cmd_submit, .compare_sram_data = psp_v12_0_compare_sram_data, .mode1_reset = psp_v12_0_mode1_reset, + .ring_get_wptr = psp_v12_0_ring_get_wptr, + .ring_set_wptr = psp_v12_0_ring_set_wptr, }; void psp_v12_0_set_psp_funcs(struct psp_context *psp) diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c index fdc00938327b8b60e73c9e93429862f76dd64cb9..735c43c7daab921e283f8bcf7aedcde5c8cae386 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c @@ -179,7 +179,7 @@ static bool psp_v3_1_match_version(struct amdgpu_device *adev, uint32_t ver) * Double check if the latest four legacy versions. * If yes, it is still the right version. */ - for (i = 0; i < sizeof(sos_old_versions) / sizeof(uint32_t); i++) { + for (i = 0; i < ARRAY_SIZE(sos_old_versions); i++) { if (sos_old_versions[i] == adev->psp.sos_fw_version) return true; } @@ -410,65 +410,6 @@ static int psp_v3_1_ring_destroy(struct psp_context *psp, return ret; } -static int psp_v3_1_cmd_submit(struct psp_context *psp, - uint64_t cmd_buf_mc_addr, uint64_t fence_mc_addr, - int index) -{ - unsigned int psp_write_ptr_reg = 0; - struct psp_gfx_rb_frame * write_frame = psp->km_ring.ring_mem; - struct psp_ring *ring = &psp->km_ring; - struct psp_gfx_rb_frame *ring_buffer_start = ring->ring_mem; - struct psp_gfx_rb_frame *ring_buffer_end = ring_buffer_start + - ring->ring_size / sizeof(struct psp_gfx_rb_frame) - 1; - struct amdgpu_device *adev = psp->adev; - uint32_t ring_size_dw = ring->ring_size / 4; - uint32_t rb_frame_size_dw = sizeof(struct psp_gfx_rb_frame) / 4; - - /* KM (GPCOM) prepare write pointer */ - if (psp_v3_1_support_vmr_ring(psp)) - psp_write_ptr_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102); - else - psp_write_ptr_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67); - - /* Update KM RB frame pointer to new frame */ - /* write_frame ptr increments by size of rb_frame in bytes */ - /* psp_write_ptr_reg increments by size of rb_frame in DWORDs */ - if ((psp_write_ptr_reg % ring_size_dw) == 0) - write_frame = ring_buffer_start; - else - write_frame = ring_buffer_start + (psp_write_ptr_reg / rb_frame_size_dw); - /* Check invalid write_frame ptr address */ - if ((write_frame < ring_buffer_start) || (ring_buffer_end < write_frame)) { - DRM_ERROR("ring_buffer_start = %p; ring_buffer_end = %p; write_frame = %p\n", - ring_buffer_start, ring_buffer_end, write_frame); - DRM_ERROR("write_frame is pointing to address out of bounds\n"); - return -EINVAL; - } - - /* Initialize KM RB frame */ - memset(write_frame, 0, sizeof(struct psp_gfx_rb_frame)); - - /* Update KM RB frame */ - write_frame->cmd_buf_addr_hi = upper_32_bits(cmd_buf_mc_addr); - write_frame->cmd_buf_addr_lo = lower_32_bits(cmd_buf_mc_addr); - write_frame->fence_addr_hi = upper_32_bits(fence_mc_addr); - write_frame->fence_addr_lo = lower_32_bits(fence_mc_addr); - write_frame->fence_value = index; - amdgpu_asic_flush_hdp(adev, NULL); - - /* Update the write Pointer in DWORDs */ - psp_write_ptr_reg = (psp_write_ptr_reg + rb_frame_size_dw) % ring_size_dw; - if (psp_v3_1_support_vmr_ring(psp)) { - WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102, psp_write_ptr_reg); - /* send interrupt to PSP for SRIOV ring write pointer update */ - WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101, - GFX_CTRL_CMD_ID_CONSUME_CMD); - } else - WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, psp_write_ptr_reg); - - return 0; -} - static int psp_v3_1_sram_map(struct amdgpu_device *adev, unsigned int *sram_offset, unsigned int *sram_addr_reg_offset, @@ -642,6 +583,31 @@ static bool psp_v3_1_support_vmr_ring(struct psp_context *psp) return false; } +static uint32_t psp_v3_1_ring_get_wptr(struct psp_context *psp) +{ + uint32_t data; + struct amdgpu_device *adev = psp->adev; + + if (psp_v3_1_support_vmr_ring(psp)) + data = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102); + else + data = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67); + return data; +} + +static void psp_v3_1_ring_set_wptr(struct psp_context *psp, uint32_t value) +{ + struct amdgpu_device *adev = psp->adev; + + if (psp_v3_1_support_vmr_ring(psp)) { + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_102, value); + /* send interrupt to PSP for SRIOV ring write pointer update */ + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_101, + GFX_CTRL_CMD_ID_CONSUME_CMD); + } else + WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_67, value); +} + static const struct psp_funcs psp_v3_1_funcs = { .init_microcode = psp_v3_1_init_microcode, .bootloader_load_sysdrv = psp_v3_1_bootloader_load_sysdrv, @@ -650,11 +616,12 @@ static const struct psp_funcs psp_v3_1_funcs = { .ring_create = psp_v3_1_ring_create, .ring_stop = psp_v3_1_ring_stop, .ring_destroy = psp_v3_1_ring_destroy, - .cmd_submit = psp_v3_1_cmd_submit, .compare_sram_data = psp_v3_1_compare_sram_data, .smu_reload_quirk = psp_v3_1_smu_reload_quirk, .mode1_reset = psp_v3_1_mode1_reset, .support_vmr_ring = psp_v3_1_support_vmr_ring, + .ring_get_wptr = psp_v3_1_ring_get_wptr, + .ring_set_wptr = psp_v3_1_ring_set_wptr, }; void psp_v3_1_set_psp_funcs(struct psp_context *psp) diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index f2d70a47a3af20970a4b5d24076e4af02637791e..4d415bfdb42ff2ac62e4431d90a64a9ee3692b2d 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -1197,6 +1197,11 @@ static int si_asic_reset(struct amdgpu_device *adev) return 0; } +static bool si_asic_supports_baco(struct amdgpu_device *adev) +{ + return false; +} + static enum amd_reset_method si_asic_reset_method(struct amdgpu_device *adev) { @@ -1425,6 +1430,7 @@ static const struct amdgpu_asic_funcs si_asic_funcs = .get_pcie_usage = &si_get_pcie_usage, .need_reset_on_init = &si_need_reset_on_init, .get_pcie_replay_count = &si_get_pcie_replay_count, + .supports_baco = &si_asic_supports_baco, }; static uint32_t si_get_rev_id(struct amdgpu_device *adev) 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 c44723c267c93cb18279e532a3c4ec1ce63ee2d7..c902f26cf50d74be8a55fa3df05f6165363f4f35 100644 --- a/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c @@ -234,7 +234,7 @@ static uint32_t smu_v11_0_i2c_transmit(struct i2c_adapter *control, DRM_DEBUG_DRIVER("I2C_Transmit(), address = %x, bytes = %d , data: ", (uint16_t)address, numbytes); - if (drm_debug & DRM_UT_DRIVER) { + if (drm_debug_enabled(DRM_UT_DRIVER)) { print_hex_dump(KERN_INFO, "data: ", DUMP_PREFIX_NONE, 16, 1, data, numbytes, false); } @@ -388,7 +388,7 @@ static uint32_t smu_v11_0_i2c_receive(struct i2c_adapter *control, DRM_DEBUG_DRIVER("I2C_Receive(), address = %x, bytes = %d, data :", (uint16_t)address, bytes_received); - if (drm_debug & DRM_UT_DRIVER) { + if (drm_debug_enabled(DRM_UT_DRIVER)) { print_hex_dump(KERN_INFO, "data: ", DUMP_PREFIX_NONE, 16, 1, data, bytes_received, false); } diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 8e1640bc07aff47de2da4b0a44649c112b69bb5b..5bd6ae7a52fe8e035eadd3aafaacdf1ae72e9cb9 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -67,7 +67,9 @@ #include "vce_v4_0.h" #include "vcn_v1_0.h" #include "vcn_v2_0.h" +#include "jpeg_v2_0.h" #include "vcn_v2_5.h" +#include "jpeg_v2_5.h" #include "dce_virtual.h" #include "mxgpu_ai.h" #include "amdgpu_smu.h" @@ -509,9 +511,15 @@ static int soc15_asic_baco_reset(struct amdgpu_device *adev) if (is_support_sw_smu(adev)) { struct smu_context *smu = &adev->smu; + int ret; - if (smu_baco_reset(smu)) - return -EIO; + ret = smu_baco_enter(smu); + if (ret) + return ret; + + ret = smu_baco_exit(smu); + if (ret) + return ret; } else { void *pp_handle = adev->powerplay.pp_handle; const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; @@ -549,7 +557,8 @@ static int soc15_mode2_reset(struct amdgpu_device *adev) static enum amd_reset_method soc15_asic_reset_method(struct amdgpu_device *adev) { - bool baco_reset; + bool baco_reset = false; + struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); switch (adev->asic_type) { case CHIP_RAVEN: @@ -557,23 +566,21 @@ soc15_asic_reset_method(struct amdgpu_device *adev) return AMD_RESET_METHOD_MODE2; case CHIP_VEGA10: case CHIP_VEGA12: + case CHIP_ARCTURUS: soc15_asic_get_baco_capability(adev, &baco_reset); break; case CHIP_VEGA20: if (adev->psp.sos_fw_version >= 0x80067) soc15_asic_get_baco_capability(adev, &baco_reset); - else - baco_reset = false; - if (baco_reset) { - struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev, 0); - struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); - if (hive || (ras && ras->supported)) - baco_reset = false; - } + /* + * 1. PMFW version > 0x284300: all cases use baco + * 2. PMFW version <= 0x284300: only sGPU w/o RAS use baco + */ + if ((ras && ras->supported) && adev->pm.fw_version <= 0x283400) + baco_reset = false; break; default: - baco_reset = false; break; } @@ -599,6 +606,28 @@ static int soc15_asic_reset(struct amdgpu_device *adev) } } +static bool soc15_supports_baco(struct amdgpu_device *adev) +{ + bool baco_support; + + switch (adev->asic_type) { + case CHIP_VEGA10: + case CHIP_VEGA12: + soc15_asic_get_baco_capability(adev, &baco_support); + break; + case CHIP_VEGA20: + if (adev->psp.sos_fw_version >= 0x80067) + soc15_asic_get_baco_capability(adev, &baco_support); + else + baco_support = false; + break; + default: + return false; + } + + return baco_support; +} + /*static int soc15_set_uvd_clock(struct amdgpu_device *adev, u32 clock, u32 cntl_reg, u32 status_reg) { @@ -746,11 +775,11 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev) } amdgpu_device_ip_block_add(adev, &gfx_v9_0_ip_block); amdgpu_device_ip_block_add(adev, &sdma_v4_0_ip_block); - if (!amdgpu_sriov_vf(adev)) { - if (is_support_sw_smu(adev)) + if (is_support_sw_smu(adev)) { + if (!amdgpu_sriov_vf(adev)) amdgpu_device_ip_block_add(adev, &smu_v11_0_ip_block); - else - amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); + } else { + amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); } if (adev->enable_virtual_display || amdgpu_sriov_vf(adev)) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); @@ -803,6 +832,8 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev) if (unlikely(adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT)) amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block); + if (!amdgpu_sriov_vf(adev)) + amdgpu_device_ip_block_add(adev, &jpeg_v2_5_ip_block); break; case CHIP_RENOIR: amdgpu_device_ip_block_add(adev, &vega10_common_ip_block); @@ -821,6 +852,7 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &dm_ip_block); #endif amdgpu_device_ip_block_add(adev, &vcn_v2_0_ip_block); + amdgpu_device_ip_block_add(adev, &jpeg_v2_0_ip_block); break; default: return -EINVAL; @@ -999,6 +1031,7 @@ static const struct amdgpu_asic_funcs soc15_asic_funcs = .get_pcie_usage = &soc15_get_pcie_usage, .need_reset_on_init = &soc15_need_reset_on_init, .get_pcie_replay_count = &soc15_get_pcie_replay_count, + .supports_baco = &soc15_supports_baco, }; static const struct amdgpu_asic_funcs vega20_asic_funcs = @@ -1007,6 +1040,7 @@ static const struct amdgpu_asic_funcs vega20_asic_funcs = .read_bios_from_rom = &soc15_read_bios_from_rom, .read_register = &soc15_read_register, .reset = &soc15_asic_reset, + .reset_method = &soc15_asic_reset_method, .set_vga_state = &soc15_vga_set_state, .get_xclk = &soc15_get_xclk, .set_uvd_clocks = &soc15_set_uvd_clocks, @@ -1019,7 +1053,7 @@ static const struct amdgpu_asic_funcs vega20_asic_funcs = .get_pcie_usage = &vega20_get_pcie_usage, .need_reset_on_init = &soc15_need_reset_on_init, .get_pcie_replay_count = &soc15_get_pcie_replay_count, - .reset_method = &soc15_asic_reset_method + .supports_baco = &soc15_supports_baco, }; static int soc15_common_early_init(void *handle) @@ -1145,9 +1179,7 @@ static int soc15_common_early_init(void *handle) AMD_CG_SUPPORT_SDMA_LS | AMD_CG_SUPPORT_VCN_MGCG; - adev->pg_flags = AMD_PG_SUPPORT_SDMA | - AMD_PG_SUPPORT_VCN | - AMD_PG_SUPPORT_VCN_DPG; + adev->pg_flags = AMD_PG_SUPPORT_SDMA | AMD_PG_SUPPORT_VCN; } else if (adev->pdev->device == 0x15d8) { adev->cg_flags = AMD_CG_SUPPORT_GFX_MGCG | AMD_CG_SUPPORT_GFX_MGLS | @@ -1190,9 +1222,7 @@ static int soc15_common_early_init(void *handle) AMD_CG_SUPPORT_SDMA_LS | AMD_CG_SUPPORT_VCN_MGCG; - adev->pg_flags = AMD_PG_SUPPORT_SDMA | - AMD_PG_SUPPORT_VCN | - AMD_PG_SUPPORT_VCN_DPG; + adev->pg_flags = AMD_PG_SUPPORT_SDMA | AMD_PG_SUPPORT_VCN; } break; case CHIP_ARCTURUS: @@ -1208,7 +1238,9 @@ static int soc15_common_early_init(void *handle) AMD_CG_SUPPORT_SDMA_LS | AMD_CG_SUPPORT_MC_MGCG | AMD_CG_SUPPORT_MC_LS | - AMD_CG_SUPPORT_IH_CG; + AMD_CG_SUPPORT_IH_CG | + AMD_CG_SUPPORT_VCN_MGCG | + AMD_CG_SUPPORT_JPEG_MGCG; adev->pg_flags = 0; adev->external_rev_id = adev->rev_id + 0x32; break; @@ -1229,12 +1261,14 @@ static int soc15_common_early_init(void *handle) AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_ROM_MGCG | AMD_CG_SUPPORT_VCN_MGCG | + AMD_CG_SUPPORT_JPEG_MGCG | AMD_CG_SUPPORT_IH_CG | AMD_CG_SUPPORT_ATHUB_LS | AMD_CG_SUPPORT_ATHUB_MGCG | AMD_CG_SUPPORT_DF_MGCG; adev->pg_flags = AMD_PG_SUPPORT_SDMA | AMD_PG_SUPPORT_VCN | + AMD_PG_SUPPORT_JPEG | AMD_PG_SUPPORT_VCN_DPG; adev->external_rev_id = adev->rev_id + 0x91; break; diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.h b/drivers/gpu/drm/amd/amdgpu/soc15.h index 57af489a5de3ec7f4bcdc7f31998f9e8ee594ab1..d0fb7a67c1a38d59f3d2622947adaf66452dc215 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.h +++ b/drivers/gpu/drm/amd/amdgpu/soc15.h @@ -60,6 +60,18 @@ struct soc15_allowed_register_entry { bool grbm_indexed; }; +struct soc15_ras_field_entry { + const char *name; + uint32_t hwip; + uint32_t inst; + uint32_t seg; + uint32_t reg_offset; + uint32_t sec_count_mask; + uint32_t sec_count_shift; + uint32_t ded_count_mask; + uint32_t ded_count_shift; +}; + #define SOC15_REG_ENTRY(ip, inst, reg) ip##_HWIP, inst, reg##_BASE_IDX, reg #define SOC15_REG_ENTRY_OFFSET(entry) (adev->reg_offset[entry.hwip][entry.inst][entry.seg] + entry.reg_offset) diff --git a/drivers/gpu/drm/amd/amdgpu/soc15_common.h b/drivers/gpu/drm/amd/amdgpu/soc15_common.h index 839f186e1182ae247bcf992da41e47c1b6209e41..19e870c798967129f317b148719a41bd6a48d8f9 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15_common.h +++ b/drivers/gpu/drm/amd/amdgpu/soc15_common.h @@ -52,6 +52,7 @@ uint32_t old_ = 0; \ uint32_t tmp_ = RREG32(adev->reg_offset[ip##_HWIP][inst][reg##_BASE_IDX] + reg); \ uint32_t loop = adev->usec_timeout; \ + ret = 0; \ while ((tmp_ & (mask)) != (expected_value)) { \ if (old_ != tmp_) { \ loop = adev->usec_timeout; \ diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v6_1.c b/drivers/gpu/drm/amd/amdgpu/umc_v6_1.c index 47c4b96b14d18725eda054756e2eff36acdb7d7c..515eb50cd0f8db9ee9104952e242047d7d21f356 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v6_1.c +++ b/drivers/gpu/drm/amd/amdgpu/umc_v6_1.c @@ -31,6 +31,14 @@ #define smnMCA_UMC0_MCUMC_ADDRT0 0x50f10 +/* UMC 6_1_2 register offsets */ +#define mmUMCCH0_0_EccErrCntSel_ARCT 0x0360 +#define mmUMCCH0_0_EccErrCntSel_ARCT_BASE_IDX 1 +#define mmUMCCH0_0_EccErrCnt_ARCT 0x0361 +#define mmUMCCH0_0_EccErrCnt_ARCT_BASE_IDX 1 +#define mmMCA_UMC_UMC0_MCUMC_STATUST0_ARCT 0x03c2 +#define mmMCA_UMC_UMC0_MCUMC_STATUST0_ARCT_BASE_IDX 1 + /* * (addr / 256) * 8192, the higher 26 bits in ErrorAddr * is the index of 8KB block @@ -95,12 +103,25 @@ static void umc_v6_1_query_correctable_error_count(struct amdgpu_device *adev, uint64_t mc_umc_status; uint32_t mc_umc_status_addr; - ecc_err_cnt_sel_addr = - SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_EccErrCntSel); - ecc_err_cnt_addr = - SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_EccErrCnt); - mc_umc_status_addr = - SOC15_REG_OFFSET(UMC, 0, mmMCA_UMC_UMC0_MCUMC_STATUST0); + if (adev->asic_type == CHIP_ARCTURUS) { + /* UMC 6_1_2 registers */ + + ecc_err_cnt_sel_addr = + SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_EccErrCntSel_ARCT); + ecc_err_cnt_addr = + SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_EccErrCnt_ARCT); + mc_umc_status_addr = + SOC15_REG_OFFSET(UMC, 0, mmMCA_UMC_UMC0_MCUMC_STATUST0_ARCT); + } else { + /* UMC 6_1_1 registers */ + + ecc_err_cnt_sel_addr = + SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_EccErrCntSel); + ecc_err_cnt_addr = + SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_EccErrCnt); + 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(ecc_err_cnt_sel_addr + umc_reg_offset); @@ -141,8 +162,17 @@ static void umc_v6_1_querry_uncorrectable_error_count(struct amdgpu_device *adev 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); + if (adev->asic_type == CHIP_ARCTURUS) { + /* UMC 6_1_2 registers */ + + mc_umc_status_addr = + SOC15_REG_OFFSET(UMC, 0, mmMCA_UMC_UMC0_MCUMC_STATUST0_ARCT); + } else { + /* UMC 6_1_1 registers */ + + mc_umc_status_addr = + SOC15_REG_OFFSET(UMC, 0, mmMCA_UMC_UMC0_MCUMC_STATUST0); + } /* check the MCUMC_STATUS */ mc_umc_status = RREG64_UMC(mc_umc_status_addr + umc_reg_offset); @@ -179,8 +209,17 @@ static void umc_v6_1_query_error_address(struct amdgpu_device *adev, uint64_t mc_umc_status, err_addr, retired_page; struct eeprom_table_record *err_rec; - mc_umc_status_addr = - SOC15_REG_OFFSET(UMC, 0, mmMCA_UMC_UMC0_MCUMC_STATUST0); + if (adev->asic_type == CHIP_ARCTURUS) { + /* UMC 6_1_2 registers */ + + mc_umc_status_addr = + SOC15_REG_OFFSET(UMC, 0, mmMCA_UMC_UMC0_MCUMC_STATUST0_ARCT); + } else { + /* UMC 6_1_1 registers */ + + mc_umc_status_addr = + SOC15_REG_OFFSET(UMC, 0, mmMCA_UMC_UMC0_MCUMC_STATUST0); + } /* skip error address process if -ENOMEM */ if (!err_data->err_addr) { @@ -241,10 +280,21 @@ static void umc_v6_1_err_cnt_init_per_channel(struct amdgpu_device *adev, 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_EccErrCntSel); - ecc_err_cnt_addr = - SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_EccErrCnt); + if (adev->asic_type == CHIP_ARCTURUS) { + /* UMC 6_1_2 registers */ + + ecc_err_cnt_sel_addr = + SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_EccErrCntSel_ARCT); + ecc_err_cnt_addr = + SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_EccErrCnt_ARCT); + } else { + /* UMC 6_1_1 registers */ + + ecc_err_cnt_sel_addr = + SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_EccErrCntSel); + ecc_err_cnt_addr = + SOC15_REG_OFFSET(UMC, 0, mmUMCCH0_0_EccErrCnt); + } /* select the lower chip and check the error count */ ecc_err_cnt_sel = RREG32(ecc_err_cnt_sel_addr + umc_reg_offset); diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v6_1.h b/drivers/gpu/drm/amd/amdgpu/umc_v6_1.h index dab9cbd292c5d40ec67ee12bdc4e0021830608ad..0ce1d323cfddfaae4d7ad92d837320b24c879143 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v6_1.h +++ b/drivers/gpu/drm/amd/amdgpu/umc_v6_1.h @@ -35,7 +35,8 @@ /* total channel instances in one umc block */ #define UMC_V6_1_TOTAL_CHANNEL_NUM (UMC_V6_1_CHANNEL_INSTANCE_NUM * UMC_V6_1_UMC_INSTANCE_NUM) /* UMC regiser per channel offset */ -#define UMC_V6_1_PER_CHANNEL_OFFSET 0x800 +#define UMC_V6_1_PER_CHANNEL_OFFSET_VG20 0x800 +#define UMC_V6_1_PER_CHANNEL_OFFSET_ARCT 0x400 /* EccErrCnt max value */ #define UMC_V6_1_CE_CNT_MAX 0xffff diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index b4f84a820a448a847f21447998c39173ecb6fce9..652cecc030b365bb2286aa8c348242c8aa55ff14 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -36,6 +36,7 @@ #include "mmhub/mmhub_9_1_sh_mask.h" #include "ivsrcid/vcn/irqsrcs_vcn_1_0.h" +#include "jpeg_v1_0.h" #define mmUVD_RBC_XX_IB_REG_CHECK 0x05ab #define mmUVD_RBC_XX_IB_REG_CHECK_BASE_IDX 1 @@ -45,9 +46,7 @@ static int vcn_v1_0_stop(struct amdgpu_device *adev); static void vcn_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev); static void vcn_v1_0_set_enc_ring_funcs(struct amdgpu_device *adev); -static void vcn_v1_0_set_jpeg_ring_funcs(struct amdgpu_device *adev); static void vcn_v1_0_set_irq_funcs(struct amdgpu_device *adev); -static void vcn_v1_0_jpeg_ring_set_patch_ring(struct amdgpu_ring *ring, uint32_t ptr); static int vcn_v1_0_set_powergating_state(void *handle, enum amd_powergating_state state); static int vcn_v1_0_pause_dpg_mode(struct amdgpu_device *adev, struct dpg_pause_state *new_state); @@ -68,9 +67,10 @@ static int vcn_v1_0_early_init(void *handle) vcn_v1_0_set_dec_ring_funcs(adev); vcn_v1_0_set_enc_ring_funcs(adev); - vcn_v1_0_set_jpeg_ring_funcs(adev); vcn_v1_0_set_irq_funcs(adev); + jpeg_v1_0_early_init(handle); + return 0; } @@ -101,11 +101,6 @@ static int vcn_v1_0_sw_init(void *handle) return r; } - /* VCN JPEG TRAP */ - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, 126, &adev->vcn.inst->irq); - if (r) - return r; - r = amdgpu_vcn_sw_init(adev); if (r) return r; @@ -149,17 +144,11 @@ static int vcn_v1_0_sw_init(void *handle) return r; } - ring = &adev->vcn.inst->ring_jpeg; - sprintf(ring->name, "vcn_jpeg"); - r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst->irq, 0); - if (r) - return r; - adev->vcn.pause_dpg_mode = vcn_v1_0_pause_dpg_mode; - adev->vcn.internal.jpeg_pitch = adev->vcn.inst->external.jpeg_pitch = - SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_PITCH); - return 0; + r = jpeg_v1_0_sw_init(handle); + + return r; } /** @@ -178,6 +167,8 @@ static int vcn_v1_0_sw_fini(void *handle) if (r) return r; + jpeg_v1_0_sw_fini(handle); + r = amdgpu_vcn_sw_fini(adev); return r; @@ -207,7 +198,7 @@ static int vcn_v1_0_hw_init(void *handle) goto done; } - ring = &adev->vcn.inst->ring_jpeg; + ring = &adev->jpeg.inst->ring_dec; r = amdgpu_ring_test_helper(ring); if (r) goto done; @@ -947,22 +938,7 @@ static int vcn_v1_0_start_spg_mode(struct amdgpu_device *adev) WREG32_SOC15(UVD, 0, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); WREG32_SOC15(UVD, 0, mmUVD_RB_SIZE2, ring->ring_size / 4); - ring = &adev->vcn.inst->ring_jpeg; - WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_VMID, 0); - WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_CNTL, UVD_JRBC_RB_CNTL__RB_NO_FETCH_MASK | - UVD_JRBC_RB_CNTL__RB_RPTR_WR_EN_MASK); - WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_LOW, lower_32_bits(ring->gpu_addr)); - WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_HIGH, upper_32_bits(ring->gpu_addr)); - WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_RPTR, 0); - WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR, 0); - WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_CNTL, UVD_JRBC_RB_CNTL__RB_RPTR_WR_EN_MASK); - - /* initialize wptr */ - ring->wptr = RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR); - - /* copy patch commands to the jpeg ring */ - vcn_v1_0_jpeg_ring_set_patch_ring(ring, - (ring->wptr + ring->max_dw * amdgpu_sched_hw_submission)); + jpeg_v1_0_start(adev, 0); return 0; } @@ -1106,13 +1082,7 @@ static int vcn_v1_0_start_dpg_mode(struct amdgpu_device *adev) WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_RBC_RB_CNTL), 0, ~UVD_RBC_RB_CNTL__RB_NO_FETCH_MASK); - /* initialize JPEG wptr */ - ring = &adev->vcn.inst->ring_jpeg; - ring->wptr = RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR); - - /* copy patch commands to the jpeg ring */ - vcn_v1_0_jpeg_ring_set_patch_ring(ring, - (ring->wptr + ring->max_dw * amdgpu_sched_hw_submission)); + jpeg_v1_0_start(adev, 1); return 0; } @@ -1316,7 +1286,7 @@ static int vcn_v1_0_pause_dpg_mode(struct amdgpu_device *adev, UVD_DPG_PAUSE__JPEG_PAUSE_DPG_ACK_MASK, ret_code); /* Restore */ - ring = &adev->vcn.inst->ring_jpeg; + ring = &adev->jpeg.inst->ring_dec; WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_VMID, 0); WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_CNTL, UVD_JRBC_RB_CNTL__RB_NO_FETCH_MASK | @@ -1716,389 +1686,6 @@ static void vcn_v1_0_enc_ring_emit_wreg(struct amdgpu_ring *ring, amdgpu_ring_write(ring, val); } - -/** - * vcn_v1_0_jpeg_ring_get_rptr - get read pointer - * - * @ring: amdgpu_ring pointer - * - * Returns the current hardware read pointer - */ -static uint64_t vcn_v1_0_jpeg_ring_get_rptr(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - return RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_RPTR); -} - -/** - * vcn_v1_0_jpeg_ring_get_wptr - get write pointer - * - * @ring: amdgpu_ring pointer - * - * Returns the current hardware write pointer - */ -static uint64_t vcn_v1_0_jpeg_ring_get_wptr(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - return RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR); -} - -/** - * vcn_v1_0_jpeg_ring_set_wptr - set write pointer - * - * @ring: amdgpu_ring pointer - * - * Commits the write pointer to the hardware - */ -static void vcn_v1_0_jpeg_ring_set_wptr(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR, lower_32_bits(ring->wptr)); -} - -/** - * vcn_v1_0_jpeg_ring_insert_start - insert a start command - * - * @ring: amdgpu_ring pointer - * - * Write a start command to the ring. - */ -static void vcn_v1_0_jpeg_ring_insert_start(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x68e04); - - amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x80010000); -} - -/** - * vcn_v1_0_jpeg_ring_insert_end - insert a end command - * - * @ring: amdgpu_ring pointer - * - * Write a end command to the ring. - */ -static void vcn_v1_0_jpeg_ring_insert_end(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x68e04); - - amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x00010000); -} - -/** - * vcn_v1_0_jpeg_ring_emit_fence - emit an fence & trap command - * - * @ring: amdgpu_ring pointer - * @fence: fence to emit - * - * Write a fence and a trap command to the ring. - */ -static void vcn_v1_0_jpeg_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq, - unsigned flags) -{ - struct amdgpu_device *adev = ring->adev; - - WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_DATA0), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, seq); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_DATA1), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, seq); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, lower_32_bits(addr)); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, upper_32_bits(addr)); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_CMD), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x8); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_CMD), 0, PACKETJ_CONDITION_CHECK0, PACKETJ_TYPE4)); - amdgpu_ring_write(ring, 0); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x01400200); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, seq); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, lower_32_bits(addr)); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, upper_32_bits(addr)); - - amdgpu_ring_write(ring, - PACKETJ(0, 0, PACKETJ_CONDITION_CHECK3, PACKETJ_TYPE2)); - amdgpu_ring_write(ring, 0xffffffff); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x3fbc); - - amdgpu_ring_write(ring, - PACKETJ(0, 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x1); - - /* emit trap */ - amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE7)); - amdgpu_ring_write(ring, 0); -} - -/** - * vcn_v1_0_jpeg_ring_emit_ib - execute indirect buffer - * - * @ring: amdgpu_ring pointer - * @ib: indirect buffer to execute - * - * Write ring commands to execute the indirect buffer. - */ -static void vcn_v1_0_jpeg_ring_emit_ib(struct amdgpu_ring *ring, - struct amdgpu_job *job, - struct amdgpu_ib *ib, - uint32_t flags) -{ - struct amdgpu_device *adev = ring->adev; - unsigned vmid = AMDGPU_JOB_GET_VMID(job); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_IB_VMID), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, (vmid | (vmid << 4))); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JPEG_VMID), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, (vmid | (vmid << 4))); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_IB_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr)); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_IB_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr)); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_IB_SIZE), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, ib->length_dw); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, lower_32_bits(ring->gpu_addr)); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, upper_32_bits(ring->gpu_addr)); - - amdgpu_ring_write(ring, - PACKETJ(0, 0, PACKETJ_CONDITION_CHECK0, PACKETJ_TYPE2)); - amdgpu_ring_write(ring, 0); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x01400200); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x2); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_STATUS), 0, PACKETJ_CONDITION_CHECK3, PACKETJ_TYPE3)); - amdgpu_ring_write(ring, 0x2); -} - -static void vcn_v1_0_jpeg_ring_emit_reg_wait(struct amdgpu_ring *ring, - uint32_t reg, uint32_t val, - uint32_t mask) -{ - struct amdgpu_device *adev = ring->adev; - uint32_t reg_offset = (reg << 2); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x01400200); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, val); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0)); - if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) || - ((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) { - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, - PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE3)); - } else { - amdgpu_ring_write(ring, reg_offset); - amdgpu_ring_write(ring, - PACKETJ(0, 0, 0, PACKETJ_TYPE3)); - } - amdgpu_ring_write(ring, mask); -} - -static void vcn_v1_0_jpeg_ring_emit_vm_flush(struct amdgpu_ring *ring, - unsigned vmid, uint64_t pd_addr) -{ - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; - uint32_t data0, data1, mask; - - pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); - - /* wait for register write */ - data0 = hub->ctx0_ptb_addr_lo32 + vmid * 2; - data1 = lower_32_bits(pd_addr); - mask = 0xffffffff; - vcn_v1_0_jpeg_ring_emit_reg_wait(ring, data0, data1, mask); -} - -static void vcn_v1_0_jpeg_ring_emit_wreg(struct amdgpu_ring *ring, - uint32_t reg, uint32_t val) -{ - struct amdgpu_device *adev = ring->adev; - uint32_t reg_offset = (reg << 2); - - amdgpu_ring_write(ring, - PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0)); - if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) || - ((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) { - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, - PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE0)); - } else { - amdgpu_ring_write(ring, reg_offset); - amdgpu_ring_write(ring, - PACKETJ(0, 0, 0, PACKETJ_TYPE0)); - } - amdgpu_ring_write(ring, val); -} - -static void vcn_v1_0_jpeg_ring_nop(struct amdgpu_ring *ring, uint32_t count) -{ - int i; - - WARN_ON(ring->wptr % 2 || count % 2); - - for (i = 0; i < count / 2; i++) { - amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE6)); - amdgpu_ring_write(ring, 0); - } -} - -static void vcn_v1_0_jpeg_ring_patch_wreg(struct amdgpu_ring *ring, uint32_t *ptr, uint32_t reg_offset, uint32_t val) -{ - struct amdgpu_device *adev = ring->adev; - ring->ring[(*ptr)++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0); - if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) || - ((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) { - ring->ring[(*ptr)++] = 0; - ring->ring[(*ptr)++] = PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE0); - } else { - ring->ring[(*ptr)++] = reg_offset; - ring->ring[(*ptr)++] = PACKETJ(0, 0, 0, PACKETJ_TYPE0); - } - ring->ring[(*ptr)++] = val; -} - -static void vcn_v1_0_jpeg_ring_set_patch_ring(struct amdgpu_ring *ring, uint32_t ptr) -{ - struct amdgpu_device *adev = ring->adev; - - uint32_t reg, reg_offset, val, mask, i; - - // 1st: program mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW - reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW); - reg_offset = (reg << 2); - val = lower_32_bits(ring->gpu_addr); - vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val); - - // 2nd: program mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH - reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH); - reg_offset = (reg << 2); - val = upper_32_bits(ring->gpu_addr); - vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val); - - // 3rd to 5th: issue MEM_READ commands - for (i = 0; i <= 2; i++) { - ring->ring[ptr++] = PACKETJ(0, 0, 0, PACKETJ_TYPE2); - ring->ring[ptr++] = 0; - } - - // 6th: program mmUVD_JRBC_RB_CNTL register to enable NO_FETCH and RPTR write ability - reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_CNTL); - reg_offset = (reg << 2); - val = 0x13; - vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val); - - // 7th: program mmUVD_JRBC_RB_REF_DATA - reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA); - reg_offset = (reg << 2); - val = 0x1; - vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val); - - // 8th: issue conditional register read mmUVD_JRBC_RB_CNTL - reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_CNTL); - reg_offset = (reg << 2); - val = 0x1; - mask = 0x1; - - ring->ring[ptr++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0); - ring->ring[ptr++] = 0x01400200; - ring->ring[ptr++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0); - ring->ring[ptr++] = val; - ring->ring[ptr++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0); - if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) || - ((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) { - ring->ring[ptr++] = 0; - ring->ring[ptr++] = PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE3); - } else { - ring->ring[ptr++] = reg_offset; - ring->ring[ptr++] = PACKETJ(0, 0, 0, PACKETJ_TYPE3); - } - ring->ring[ptr++] = mask; - - //9th to 21st: insert no-op - for (i = 0; i <= 12; i++) { - ring->ring[ptr++] = PACKETJ(0, 0, 0, PACKETJ_TYPE6); - ring->ring[ptr++] = 0; - } - - //22nd: reset mmUVD_JRBC_RB_RPTR - reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_RPTR); - reg_offset = (reg << 2); - val = 0; - vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val); - - //23rd: program mmUVD_JRBC_RB_CNTL to disable no_fetch - reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_CNTL); - reg_offset = (reg << 2); - val = 0x12; - vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val); -} - static int vcn_v1_0_set_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *source, unsigned type, @@ -2123,9 +1710,6 @@ static int vcn_v1_0_process_interrupt(struct amdgpu_device *adev, case 120: amdgpu_fence_process(&adev->vcn.inst->ring_enc[1]); break; - case 126: - amdgpu_fence_process(&adev->vcn.inst->ring_jpeg); - break; default: DRM_ERROR("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data[0]); @@ -2259,41 +1843,6 @@ static const struct amdgpu_ring_funcs vcn_v1_0_enc_ring_vm_funcs = { .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, }; -static const struct amdgpu_ring_funcs vcn_v1_0_jpeg_ring_vm_funcs = { - .type = AMDGPU_RING_TYPE_VCN_JPEG, - .align_mask = 0xf, - .nop = PACKET0(0x81ff, 0), - .support_64bit_ptrs = false, - .no_user_fence = true, - .vmhub = AMDGPU_MMHUB_0, - .extra_dw = 64, - .get_rptr = vcn_v1_0_jpeg_ring_get_rptr, - .get_wptr = vcn_v1_0_jpeg_ring_get_wptr, - .set_wptr = vcn_v1_0_jpeg_ring_set_wptr, - .emit_frame_size = - 6 + 6 + /* hdp invalidate / flush */ - SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + - SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 + - 8 + /* vcn_v1_0_jpeg_ring_emit_vm_flush */ - 26 + 26 + /* vcn_v1_0_jpeg_ring_emit_fence x2 vm fence */ - 6, - .emit_ib_size = 22, /* vcn_v1_0_jpeg_ring_emit_ib */ - .emit_ib = vcn_v1_0_jpeg_ring_emit_ib, - .emit_fence = vcn_v1_0_jpeg_ring_emit_fence, - .emit_vm_flush = vcn_v1_0_jpeg_ring_emit_vm_flush, - .test_ring = amdgpu_vcn_jpeg_ring_test_ring, - .test_ib = amdgpu_vcn_jpeg_ring_test_ib, - .insert_nop = vcn_v1_0_jpeg_ring_nop, - .insert_start = vcn_v1_0_jpeg_ring_insert_start, - .insert_end = vcn_v1_0_jpeg_ring_insert_end, - .pad_ib = amdgpu_ring_generic_pad_ib, - .begin_use = amdgpu_vcn_ring_begin_use, - .end_use = amdgpu_vcn_ring_end_use, - .emit_wreg = vcn_v1_0_jpeg_ring_emit_wreg, - .emit_reg_wait = vcn_v1_0_jpeg_ring_emit_reg_wait, - .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, -}; - static void vcn_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev) { adev->vcn.inst->ring_dec.funcs = &vcn_v1_0_dec_ring_vm_funcs; @@ -2310,12 +1859,6 @@ static void vcn_v1_0_set_enc_ring_funcs(struct amdgpu_device *adev) DRM_INFO("VCN encode is enabled in VM mode\n"); } -static void vcn_v1_0_set_jpeg_ring_funcs(struct amdgpu_device *adev) -{ - adev->vcn.inst->ring_jpeg.funcs = &vcn_v1_0_jpeg_ring_vm_funcs; - DRM_INFO("VCN jpeg decode is enabled in VM mode\n"); -} - static const struct amdgpu_irq_src_funcs vcn_v1_0_irq_funcs = { .set = vcn_v1_0_set_interrupt_state, .process = vcn_v1_0_process_interrupt, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c index 38f787a560cb6ebdac85c5f8449f02d674fbe242..d76ece38c97bce370976ed21119d41c69a67ad88 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c @@ -47,26 +47,6 @@ #define mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET 0x5a7 #define mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET 0x1e2 -#define mmUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET 0x1bfff -#define mmUVD_JPEG_GPCOM_CMD_INTERNAL_OFFSET 0x4029 -#define mmUVD_JPEG_GPCOM_DATA0_INTERNAL_OFFSET 0x402a -#define mmUVD_JPEG_GPCOM_DATA1_INTERNAL_OFFSET 0x402b -#define mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_LOW_INTERNAL_OFFSET 0x40ea -#define mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_HIGH_INTERNAL_OFFSET 0x40eb -#define mmUVD_LMI_JRBC_IB_VMID_INTERNAL_OFFSET 0x40cf -#define mmUVD_LMI_JPEG_VMID_INTERNAL_OFFSET 0x40d1 -#define mmUVD_LMI_JRBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET 0x40e8 -#define mmUVD_LMI_JRBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET 0x40e9 -#define mmUVD_JRBC_IB_SIZE_INTERNAL_OFFSET 0x4082 -#define mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW_INTERNAL_OFFSET 0x40ec -#define mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH_INTERNAL_OFFSET 0x40ed -#define mmUVD_JRBC_RB_COND_RD_TIMER_INTERNAL_OFFSET 0x4085 -#define mmUVD_JRBC_RB_REF_DATA_INTERNAL_OFFSET 0x4084 -#define mmUVD_JRBC_STATUS_INTERNAL_OFFSET 0x4089 -#define mmUVD_JPEG_PITCH_INTERNAL_OFFSET 0x401f - -#define JRBC_DEC_EXTERNAL_REG_WRITE_ADDR 0x18000 - #define mmUVD_RBC_XX_IB_REG_CHECK 0x026b #define mmUVD_RBC_XX_IB_REG_CHECK_BASE_IDX 1 #define mmUVD_REG_XX_MASK 0x026c @@ -74,7 +54,6 @@ static void vcn_v2_0_set_dec_ring_funcs(struct amdgpu_device *adev); static void vcn_v2_0_set_enc_ring_funcs(struct amdgpu_device *adev); -static void vcn_v2_0_set_jpeg_ring_funcs(struct amdgpu_device *adev); static void vcn_v2_0_set_irq_funcs(struct amdgpu_device *adev); static int vcn_v2_0_set_powergating_state(void *handle, enum amd_powergating_state state); @@ -97,7 +76,6 @@ static int vcn_v2_0_early_init(void *handle) vcn_v2_0_set_dec_ring_funcs(adev); vcn_v2_0_set_enc_ring_funcs(adev); - vcn_v2_0_set_jpeg_ring_funcs(adev); vcn_v2_0_set_irq_funcs(adev); return 0; @@ -132,12 +110,6 @@ static int vcn_v2_0_sw_init(void *handle) return r; } - /* VCN JPEG TRAP */ - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, - VCN_2_0__SRCID__JPEG_DECODE, &adev->vcn.inst->irq); - if (r) - return r; - r = amdgpu_vcn_sw_init(adev); if (r) return r; @@ -194,19 +166,8 @@ static int vcn_v2_0_sw_init(void *handle) return r; } - ring = &adev->vcn.inst->ring_jpeg; - ring->use_doorbell = true; - ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 1; - sprintf(ring->name, "vcn_jpeg"); - r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst->irq, 0); - if (r) - return r; - adev->vcn.pause_dpg_mode = vcn_v2_0_pause_dpg_mode; - adev->vcn.internal.jpeg_pitch = mmUVD_JPEG_PITCH_INTERNAL_OFFSET; - adev->vcn.inst->external.jpeg_pitch = SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_PITCH); - return 0; } @@ -258,11 +219,6 @@ static int vcn_v2_0_hw_init(void *handle) goto done; } - ring = &adev->vcn.inst->ring_jpeg; - r = amdgpu_ring_test_helper(ring); - if (r) - goto done; - done: if (!r) DRM_INFO("VCN decode and encode initialized successfully(under %s).\n", @@ -296,9 +252,6 @@ static int vcn_v2_0_hw_fini(void *handle) ring->sched.ready = false; } - ring = &adev->vcn.inst->ring_jpeg; - ring->sched.ready = false; - return 0; } @@ -393,7 +346,6 @@ static void vcn_v2_0_mc_resume(struct amdgpu_device *adev) WREG32_SOC15(UVD, 0, mmUVD_VCPU_CACHE_SIZE2, AMDGPU_VCN_CONTEXT_SIZE); WREG32_SOC15(UVD, 0, mmUVD_GFX10_ADDR_CONFIG, adev->gfx.config.gb_addr_config); - WREG32_SOC15(UVD, 0, mmJPEG_DEC_GFX10_ADDR_CONFIG, adev->gfx.config.gb_addr_config); } static void vcn_v2_0_mc_resume_dpg_mode(struct amdgpu_device *adev, bool indirect) @@ -647,129 +599,6 @@ static void vcn_v2_0_clock_gating_dpg_mode(struct amdgpu_device *adev, UVD, 0, mmUVD_SUVD_CGC_CTRL), 0, sram_sel, indirect); } -/** - * jpeg_v2_0_start - start JPEG block - * - * @adev: amdgpu_device pointer - * - * Setup and start the JPEG block - */ -static int jpeg_v2_0_start(struct amdgpu_device *adev) -{ - struct amdgpu_ring *ring = &adev->vcn.inst->ring_jpeg; - uint32_t tmp; - int r = 0; - - /* disable power gating */ - tmp = 1 << UVD_PGFSM_CONFIG__UVDJ_PWR_CONFIG__SHIFT; - WREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_PGFSM_CONFIG), tmp); - - SOC15_WAIT_ON_RREG(VCN, 0, - mmUVD_PGFSM_STATUS, UVD_PGFSM_STATUS_UVDJ_PWR_ON, - UVD_PGFSM_STATUS__UVDJ_PWR_STATUS_MASK, r); - - if (r) { - DRM_ERROR("amdgpu: JPEG disable power gating failed\n"); - return r; - } - - /* Removing the anti hang mechanism to indicate the UVDJ tile is ON */ - tmp = RREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_POWER_STATUS)) & ~0x1; - WREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_POWER_STATUS), tmp); - - /* JPEG disable CGC */ - tmp = RREG32_SOC15(VCN, 0, mmJPEG_CGC_CTRL); - tmp |= 1 << JPEG_CGC_CTRL__DYN_CLOCK_MODE__SHIFT; - tmp |= 1 << JPEG_CGC_CTRL__CLK_GATE_DLY_TIMER__SHIFT; - tmp |= 4 << JPEG_CGC_CTRL__CLK_OFF_DELAY__SHIFT; - WREG32_SOC15(VCN, 0, mmJPEG_CGC_CTRL, tmp); - - tmp = RREG32_SOC15(VCN, 0, mmJPEG_CGC_GATE); - tmp &= ~(JPEG_CGC_GATE__JPEG_DEC_MASK - | JPEG_CGC_GATE__JPEG2_DEC_MASK - | JPEG_CGC_GATE__JPEG_ENC_MASK - | JPEG_CGC_GATE__JMCIF_MASK - | JPEG_CGC_GATE__JRBBM_MASK); - WREG32_SOC15(VCN, 0, mmJPEG_CGC_GATE, tmp); - - /* enable JMI channel */ - WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_JMI_CNTL), 0, - ~UVD_JMI_CNTL__SOFT_RESET_MASK); - - /* enable System Interrupt for JRBC */ - WREG32_P(SOC15_REG_OFFSET(VCN, 0, mmJPEG_SYS_INT_EN), - JPEG_SYS_INT_EN__DJRBC_MASK, - ~JPEG_SYS_INT_EN__DJRBC_MASK); - - WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_VMID, 0); - WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_CNTL, (0x00000001L | 0x00000002L)); - WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_LOW, - lower_32_bits(ring->gpu_addr)); - WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_HIGH, - upper_32_bits(ring->gpu_addr)); - WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_RPTR, 0); - WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR, 0); - WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_CNTL, 0x00000002L); - WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_SIZE, ring->ring_size / 4); - ring->wptr = RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR); - - return 0; -} - -/** - * jpeg_v2_0_stop - stop JPEG block - * - * @adev: amdgpu_device pointer - * - * stop the JPEG block - */ -static int jpeg_v2_0_stop(struct amdgpu_device *adev) -{ - uint32_t tmp; - int r = 0; - - /* reset JMI */ - WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_JMI_CNTL), - UVD_JMI_CNTL__SOFT_RESET_MASK, - ~UVD_JMI_CNTL__SOFT_RESET_MASK); - - /* enable JPEG CGC */ - tmp = RREG32_SOC15(VCN, 0, mmJPEG_CGC_CTRL); - tmp |= 1 << JPEG_CGC_CTRL__DYN_CLOCK_MODE__SHIFT; - tmp |= 1 << JPEG_CGC_CTRL__CLK_GATE_DLY_TIMER__SHIFT; - tmp |= 4 << JPEG_CGC_CTRL__CLK_OFF_DELAY__SHIFT; - WREG32_SOC15(VCN, 0, mmJPEG_CGC_CTRL, tmp); - - - tmp = RREG32_SOC15(VCN, 0, mmJPEG_CGC_GATE); - tmp |= (JPEG_CGC_GATE__JPEG_DEC_MASK - |JPEG_CGC_GATE__JPEG2_DEC_MASK - |JPEG_CGC_GATE__JPEG_ENC_MASK - |JPEG_CGC_GATE__JMCIF_MASK - |JPEG_CGC_GATE__JRBBM_MASK); - WREG32_SOC15(VCN, 0, mmJPEG_CGC_GATE, tmp); - - /* enable power gating */ - tmp = RREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_POWER_STATUS)); - tmp &= ~UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_MASK; - tmp |= 0x1; //UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_TILES_OFF; - WREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_POWER_STATUS), tmp); - - tmp = 2 << UVD_PGFSM_CONFIG__UVDJ_PWR_CONFIG__SHIFT; - WREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_PGFSM_CONFIG), tmp); - - SOC15_WAIT_ON_RREG(VCN, 0, mmUVD_PGFSM_STATUS, - (2 << UVD_PGFSM_STATUS__UVDJ_PWR_STATUS__SHIFT), - UVD_PGFSM_STATUS__UVDJ_PWR_STATUS_MASK, r); - - if (r) { - DRM_ERROR("amdgpu: JPEG enable power gating failed\n"); - return r; - } - - return r; -} - /** * vcn_v2_0_enable_clock_gating - enable VCN clock gating * @@ -1052,12 +881,8 @@ static int vcn_v2_0_start(struct amdgpu_device *adev) if (adev->pm.dpm_enabled) amdgpu_dpm_enable_uvd(adev, true); - if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) { - r = vcn_v2_0_start_dpg_mode(adev, adev->vcn.indirect_sram); - if (r) - return r; - goto jpeg; - } + if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) + return vcn_v2_0_start_dpg_mode(adev, adev->vcn.indirect_sram); vcn_v2_0_disable_static_power_gating(adev); @@ -1209,10 +1034,7 @@ static int vcn_v2_0_start(struct amdgpu_device *adev) WREG32_SOC15(UVD, 0, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); WREG32_SOC15(UVD, 0, mmUVD_RB_SIZE2, ring->ring_size / 4); -jpeg: - r = jpeg_v2_0_start(adev); - - return r; + return 0; } static int vcn_v2_0_stop_dpg_mode(struct amdgpu_device *adev) @@ -1231,9 +1053,6 @@ static int vcn_v2_0_stop_dpg_mode(struct amdgpu_device *adev) tmp = RREG32_SOC15(UVD, 0, mmUVD_RB_WPTR2); SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_RB_RPTR2, tmp, 0xFFFFFFFF, ret_code); - tmp = RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR); - SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_JRBC_RB_RPTR, tmp, 0xFFFFFFFF, ret_code); - tmp = RREG32_SOC15(UVD, 0, mmUVD_RBC_RB_WPTR) & 0x7FFFFFFF; SOC15_WAIT_ON_RREG(UVD, 0, mmUVD_RBC_RB_RPTR, tmp, 0xFFFFFFFF, ret_code); @@ -1252,10 +1071,6 @@ static int vcn_v2_0_stop(struct amdgpu_device *adev) uint32_t tmp; int r; - r = jpeg_v2_0_stop(adev); - if (r) - return r; - if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) { r = vcn_v2_0_stop_dpg_mode(adev); if (r) @@ -1781,272 +1596,6 @@ void vcn_v2_0_enc_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg, uint32_ amdgpu_ring_write(ring, val); } -/** - * vcn_v2_0_jpeg_ring_get_rptr - get read pointer - * - * @ring: amdgpu_ring pointer - * - * Returns the current hardware read pointer - */ -static uint64_t vcn_v2_0_jpeg_ring_get_rptr(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - return RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_RPTR); -} - -/** - * vcn_v2_0_jpeg_ring_get_wptr - get write pointer - * - * @ring: amdgpu_ring pointer - * - * Returns the current hardware write pointer - */ -static uint64_t vcn_v2_0_jpeg_ring_get_wptr(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - if (ring->use_doorbell) - return adev->wb.wb[ring->wptr_offs]; - else - return RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR); -} - -/** - * vcn_v2_0_jpeg_ring_set_wptr - set write pointer - * - * @ring: amdgpu_ring pointer - * - * Commits the write pointer to the hardware - */ -static void vcn_v2_0_jpeg_ring_set_wptr(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - if (ring->use_doorbell) { - adev->wb.wb[ring->wptr_offs] = lower_32_bits(ring->wptr); - WDOORBELL32(ring->doorbell_index, lower_32_bits(ring->wptr)); - } else { - WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR, lower_32_bits(ring->wptr)); - } -} - -/** - * vcn_v2_0_jpeg_ring_insert_start - insert a start command - * - * @ring: amdgpu_ring pointer - * - * Write a start command to the ring. - */ -void vcn_v2_0_jpeg_ring_insert_start(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x68e04); - - amdgpu_ring_write(ring, PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x80010000); -} - -/** - * vcn_v2_0_jpeg_ring_insert_end - insert a end command - * - * @ring: amdgpu_ring pointer - * - * Write a end command to the ring. - */ -void vcn_v2_0_jpeg_ring_insert_end(struct amdgpu_ring *ring) -{ - amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x68e04); - - amdgpu_ring_write(ring, PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x00010000); -} - -/** - * vcn_v2_0_jpeg_ring_emit_fence - emit an fence & trap command - * - * @ring: amdgpu_ring pointer - * @fence: fence to emit - * - * Write a fence and a trap command to the ring. - */ -void vcn_v2_0_jpeg_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq, - unsigned flags) -{ - WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_JPEG_GPCOM_DATA0_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, seq); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_JPEG_GPCOM_DATA1_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, seq); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_LOW_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, lower_32_bits(addr)); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_HIGH_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, upper_32_bits(addr)); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_JPEG_GPCOM_CMD_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x8); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_JPEG_GPCOM_CMD_INTERNAL_OFFSET, - 0, PACKETJ_CONDITION_CHECK0, PACKETJ_TYPE4)); - amdgpu_ring_write(ring, 0); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x3fbc); - - amdgpu_ring_write(ring, PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x1); - - amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE7)); - amdgpu_ring_write(ring, 0); -} - -/** - * vcn_v2_0_jpeg_ring_emit_ib - execute indirect buffer - * - * @ring: amdgpu_ring pointer - * @ib: indirect buffer to execute - * - * Write ring commands to execute the indirect buffer. - */ -void vcn_v2_0_jpeg_ring_emit_ib(struct amdgpu_ring *ring, - struct amdgpu_job *job, - struct amdgpu_ib *ib, - uint32_t flags) -{ - unsigned vmid = AMDGPU_JOB_GET_VMID(job); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_IB_VMID_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, (vmid | (vmid << 4))); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JPEG_VMID_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, (vmid | (vmid << 4))); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr)); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr)); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_IB_SIZE_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, ib->length_dw); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, lower_32_bits(ring->gpu_addr)); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, upper_32_bits(ring->gpu_addr)); - - amdgpu_ring_write(ring, PACKETJ(0, 0, PACKETJ_CONDITION_CHECK0, PACKETJ_TYPE2)); - amdgpu_ring_write(ring, 0); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_RB_COND_RD_TIMER_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x01400200); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_RB_REF_DATA_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x2); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_STATUS_INTERNAL_OFFSET, - 0, PACKETJ_CONDITION_CHECK3, PACKETJ_TYPE3)); - amdgpu_ring_write(ring, 0x2); -} - -void vcn_v2_0_jpeg_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, - uint32_t val, uint32_t mask) -{ - uint32_t reg_offset = (reg << 2); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_RB_COND_RD_TIMER_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x01400200); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_RB_REF_DATA_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, val); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - if (reg_offset >= 0x10000 && reg_offset <= 0x105ff) { - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, - PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE3)); - } else { - amdgpu_ring_write(ring, reg_offset); - amdgpu_ring_write(ring, PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, - 0, 0, PACKETJ_TYPE3)); - } - amdgpu_ring_write(ring, mask); -} - -void vcn_v2_0_jpeg_ring_emit_vm_flush(struct amdgpu_ring *ring, - unsigned vmid, uint64_t pd_addr) -{ - struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; - uint32_t data0, data1, mask; - - pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); - - /* wait for register write */ - data0 = hub->ctx0_ptb_addr_lo32 + vmid * 2; - data1 = lower_32_bits(pd_addr); - mask = 0xffffffff; - vcn_v2_0_jpeg_ring_emit_reg_wait(ring, data0, data1, mask); -} - -void vcn_v2_0_jpeg_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg, uint32_t val) -{ - uint32_t reg_offset = (reg << 2); - - amdgpu_ring_write(ring, PACKETJ(mmUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - if (reg_offset >= 0x10000 && reg_offset <= 0x105ff) { - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, - PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE0)); - } else { - amdgpu_ring_write(ring, reg_offset); - amdgpu_ring_write(ring, PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, - 0, 0, PACKETJ_TYPE0)); - } - amdgpu_ring_write(ring, val); -} - -void vcn_v2_0_jpeg_ring_nop(struct amdgpu_ring *ring, uint32_t count) -{ - int i; - - WARN_ON(ring->wptr % 2 || count % 2); - - for (i = 0; i < count / 2; i++) { - amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE6)); - amdgpu_ring_write(ring, 0); - } -} - static int vcn_v2_0_set_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *source, unsigned type, @@ -2071,9 +1620,6 @@ static int vcn_v2_0_process_interrupt(struct amdgpu_device *adev, case VCN_2_0__SRCID__UVD_ENC_LOW_LATENCY: amdgpu_fence_process(&adev->vcn.inst->ring_enc[1]); break; - case VCN_2_0__SRCID__JPEG_DECODE: - amdgpu_fence_process(&adev->vcn.inst->ring_jpeg); - break; default: DRM_ERROR("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data[0]); @@ -2219,36 +1765,6 @@ static const struct amdgpu_ring_funcs vcn_v2_0_enc_ring_vm_funcs = { .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, }; -static const struct amdgpu_ring_funcs vcn_v2_0_jpeg_ring_vm_funcs = { - .type = AMDGPU_RING_TYPE_VCN_JPEG, - .align_mask = 0xf, - .vmhub = AMDGPU_MMHUB_0, - .get_rptr = vcn_v2_0_jpeg_ring_get_rptr, - .get_wptr = vcn_v2_0_jpeg_ring_get_wptr, - .set_wptr = vcn_v2_0_jpeg_ring_set_wptr, - .emit_frame_size = - SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + - SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 + - 8 + /* vcn_v2_0_jpeg_ring_emit_vm_flush */ - 18 + 18 + /* vcn_v2_0_jpeg_ring_emit_fence x2 vm fence */ - 8 + 16, - .emit_ib_size = 22, /* vcn_v2_0_jpeg_ring_emit_ib */ - .emit_ib = vcn_v2_0_jpeg_ring_emit_ib, - .emit_fence = vcn_v2_0_jpeg_ring_emit_fence, - .emit_vm_flush = vcn_v2_0_jpeg_ring_emit_vm_flush, - .test_ring = amdgpu_vcn_jpeg_ring_test_ring, - .test_ib = amdgpu_vcn_jpeg_ring_test_ib, - .insert_nop = vcn_v2_0_jpeg_ring_nop, - .insert_start = vcn_v2_0_jpeg_ring_insert_start, - .insert_end = vcn_v2_0_jpeg_ring_insert_end, - .pad_ib = amdgpu_ring_generic_pad_ib, - .begin_use = amdgpu_vcn_ring_begin_use, - .end_use = amdgpu_vcn_ring_end_use, - .emit_wreg = vcn_v2_0_jpeg_ring_emit_wreg, - .emit_reg_wait = vcn_v2_0_jpeg_ring_emit_reg_wait, - .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, -}; - static void vcn_v2_0_set_dec_ring_funcs(struct amdgpu_device *adev) { adev->vcn.inst->ring_dec.funcs = &vcn_v2_0_dec_ring_vm_funcs; @@ -2265,12 +1781,6 @@ static void vcn_v2_0_set_enc_ring_funcs(struct amdgpu_device *adev) DRM_INFO("VCN encode is enabled in VM mode\n"); } -static void vcn_v2_0_set_jpeg_ring_funcs(struct amdgpu_device *adev) -{ - adev->vcn.inst->ring_jpeg.funcs = &vcn_v2_0_jpeg_ring_vm_funcs; - DRM_INFO("VCN jpeg decode is enabled in VM mode\n"); -} - static const struct amdgpu_irq_src_funcs vcn_v2_0_irq_funcs = { .set = vcn_v2_0_set_interrupt_state, .process = vcn_v2_0_process_interrupt, @@ -2278,7 +1788,7 @@ static const struct amdgpu_irq_src_funcs vcn_v2_0_irq_funcs = { static void vcn_v2_0_set_irq_funcs(struct amdgpu_device *adev) { - adev->vcn.inst->irq.num_types = adev->vcn.num_enc_rings + 2; + adev->vcn.inst->irq.num_types = adev->vcn.num_enc_rings + 1; adev->vcn.inst->irq.funcs = &vcn_v2_0_irq_funcs; } diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.h b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.h index 8467292f32e566e90fb54eb40171ec581c4d3874..ef749b02ded9eba74d1ef5944a95aa3886e20eb4 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.h +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.h @@ -49,19 +49,6 @@ extern void vcn_v2_0_enc_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned int vmid, uint64_t pd_addr); extern void vcn_v2_0_enc_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg, uint32_t val); -extern void vcn_v2_0_jpeg_ring_insert_start(struct amdgpu_ring *ring); -extern void vcn_v2_0_jpeg_ring_insert_end(struct amdgpu_ring *ring); -extern void vcn_v2_0_jpeg_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq, - unsigned flags); -extern void vcn_v2_0_jpeg_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_job *job, - struct amdgpu_ib *ib, uint32_t flags); -extern void vcn_v2_0_jpeg_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, - uint32_t val, uint32_t mask); -extern void vcn_v2_0_jpeg_ring_emit_vm_flush(struct amdgpu_ring *ring, - unsigned vmid, uint64_t pd_addr); -extern void vcn_v2_0_jpeg_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg, uint32_t val); -extern void vcn_v2_0_jpeg_ring_nop(struct amdgpu_ring *ring, uint32_t count); - extern const struct amdgpu_ip_block_version vcn_v2_0_ip_block; #endif /* __VCN_V2_0_H__ */ diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c index 93edf9193a7b48588e716b36a34d80b59c5a47e8..f67fca38c1a9f68bf1e81a42bc2b37298b99062a 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c @@ -47,13 +47,10 @@ #define mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET 0x3b5 #define mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET 0x25c -#define mmUVD_JPEG_PITCH_INTERNAL_OFFSET 0x401f - -#define VCN25_MAX_HW_INSTANCES_ARCTURUS 2 +#define VCN25_MAX_HW_INSTANCES_ARCTURUS 2 static void vcn_v2_5_set_dec_ring_funcs(struct amdgpu_device *adev); static void vcn_v2_5_set_enc_ring_funcs(struct amdgpu_device *adev); -static void vcn_v2_5_set_jpeg_ring_funcs(struct amdgpu_device *adev); static void vcn_v2_5_set_irq_funcs(struct amdgpu_device *adev); static int vcn_v2_5_set_powergating_state(void *handle, enum amd_powergating_state state); @@ -95,7 +92,6 @@ static int vcn_v2_5_early_init(void *handle) vcn_v2_5_set_dec_ring_funcs(adev); vcn_v2_5_set_enc_ring_funcs(adev); - vcn_v2_5_set_jpeg_ring_funcs(adev); vcn_v2_5_set_irq_funcs(adev); return 0; @@ -130,12 +126,6 @@ static int vcn_v2_5_sw_init(void *handle) if (r) return r; } - - /* VCN JPEG TRAP */ - r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j], - VCN_2_0__SRCID__JPEG_DECODE, &adev->vcn.inst[j].irq); - if (r) - return r; } r = amdgpu_vcn_sw_init(adev); @@ -184,9 +174,6 @@ static int vcn_v2_5_sw_init(void *handle) adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET; adev->vcn.inst[j].external.nop = SOC15_REG_OFFSET(UVD, j, mmUVD_NO_OP); - adev->vcn.internal.jpeg_pitch = mmUVD_JPEG_PITCH_INTERNAL_OFFSET; - adev->vcn.inst[j].external.jpeg_pitch = SOC15_REG_OFFSET(UVD, j, mmUVD_JPEG_PITCH); - ring = &adev->vcn.inst[j].ring_dec; ring->use_doorbell = true; ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 8*j; @@ -204,14 +191,6 @@ static int vcn_v2_5_sw_init(void *handle) if (r) return r; } - - ring = &adev->vcn.inst[j].ring_jpeg; - ring->use_doorbell = true; - ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 1 + 8*j; - sprintf(ring->name, "vcn_jpeg_%d", j); - r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[j].irq, 0); - if (r) - return r; } return 0; @@ -269,12 +248,8 @@ static int vcn_v2_5_hw_init(void *handle) if (r) goto done; } - - ring = &adev->vcn.inst[j].ring_jpeg; - r = amdgpu_ring_test_helper(ring); - if (r) - goto done; } + done: if (!r) DRM_INFO("VCN decode and encode initialized successfully.\n"); @@ -309,9 +284,6 @@ static int vcn_v2_5_hw_fini(void *handle) ring = &adev->vcn.inst[i].ring_enc[j]; ring->sched.ready = false; } - - ring = &adev->vcn.inst[i].ring_jpeg; - ring->sched.ready = false; } return 0; @@ -592,115 +564,6 @@ static void vcn_v2_5_enable_clock_gating(struct amdgpu_device *adev) } } -/** - * jpeg_v2_5_start - start JPEG block - * - * @adev: amdgpu_device pointer - * - * Setup and start the JPEG block - */ -static int jpeg_v2_5_start(struct amdgpu_device *adev) -{ - struct amdgpu_ring *ring; - uint32_t tmp; - int i; - - for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { - if (adev->vcn.harvest_config & (1 << i)) - continue; - ring = &adev->vcn.inst[i].ring_jpeg; - /* disable anti hang mechanism */ - WREG32_P(SOC15_REG_OFFSET(UVD, i, mmUVD_JPEG_POWER_STATUS), 0, - ~UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_MASK); - - /* JPEG disable CGC */ - tmp = RREG32_SOC15(VCN, i, mmJPEG_CGC_CTRL); - tmp |= 1 << JPEG_CGC_CTRL__DYN_CLOCK_MODE__SHIFT; - tmp |= 1 << JPEG_CGC_CTRL__CLK_GATE_DLY_TIMER__SHIFT; - tmp |= 4 << JPEG_CGC_CTRL__CLK_OFF_DELAY__SHIFT; - WREG32_SOC15(VCN, i, mmJPEG_CGC_CTRL, tmp); - - tmp = RREG32_SOC15(VCN, i, mmJPEG_CGC_GATE); - tmp &= ~(JPEG_CGC_GATE__JPEG_DEC_MASK - | JPEG_CGC_GATE__JPEG2_DEC_MASK - | JPEG_CGC_GATE__JMCIF_MASK - | JPEG_CGC_GATE__JRBBM_MASK); - WREG32_SOC15(VCN, i, mmJPEG_CGC_GATE, tmp); - - tmp = RREG32_SOC15(VCN, i, mmJPEG_CGC_CTRL); - tmp &= ~(JPEG_CGC_CTRL__JPEG_DEC_MODE_MASK - | JPEG_CGC_CTRL__JPEG2_DEC_MODE_MASK - | JPEG_CGC_CTRL__JMCIF_MODE_MASK - | JPEG_CGC_CTRL__JRBBM_MODE_MASK); - WREG32_SOC15(VCN, i, mmJPEG_CGC_CTRL, tmp); - - /* MJPEG global tiling registers */ - WREG32_SOC15(UVD, i, mmJPEG_DEC_GFX8_ADDR_CONFIG, - adev->gfx.config.gb_addr_config); - WREG32_SOC15(UVD, i, mmJPEG_DEC_GFX10_ADDR_CONFIG, - adev->gfx.config.gb_addr_config); - - /* enable JMI channel */ - WREG32_P(SOC15_REG_OFFSET(UVD, i, mmUVD_JMI_CNTL), 0, - ~UVD_JMI_CNTL__SOFT_RESET_MASK); - - /* enable System Interrupt for JRBC */ - WREG32_P(SOC15_REG_OFFSET(VCN, i, mmJPEG_SYS_INT_EN), - JPEG_SYS_INT_EN__DJRBC_MASK, - ~JPEG_SYS_INT_EN__DJRBC_MASK); - - WREG32_SOC15(UVD, i, mmUVD_LMI_JRBC_RB_VMID, 0); - WREG32_SOC15(UVD, i, mmUVD_JRBC_RB_CNTL, (0x00000001L | 0x00000002L)); - WREG32_SOC15(UVD, i, mmUVD_LMI_JRBC_RB_64BIT_BAR_LOW, - lower_32_bits(ring->gpu_addr)); - WREG32_SOC15(UVD, i, mmUVD_LMI_JRBC_RB_64BIT_BAR_HIGH, - upper_32_bits(ring->gpu_addr)); - WREG32_SOC15(UVD, i, mmUVD_JRBC_RB_RPTR, 0); - WREG32_SOC15(UVD, i, mmUVD_JRBC_RB_WPTR, 0); - WREG32_SOC15(UVD, i, mmUVD_JRBC_RB_CNTL, 0x00000002L); - WREG32_SOC15(UVD, i, mmUVD_JRBC_RB_SIZE, ring->ring_size / 4); - ring->wptr = RREG32_SOC15(UVD, i, mmUVD_JRBC_RB_WPTR); - } - - return 0; -} - -/** - * jpeg_v2_5_stop - stop JPEG block - * - * @adev: amdgpu_device pointer - * - * stop the JPEG block - */ -static int jpeg_v2_5_stop(struct amdgpu_device *adev) -{ - uint32_t tmp; - int i; - - for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { - if (adev->vcn.harvest_config & (1 << i)) - continue; - /* reset JMI */ - WREG32_P(SOC15_REG_OFFSET(UVD, i, mmUVD_JMI_CNTL), - UVD_JMI_CNTL__SOFT_RESET_MASK, - ~UVD_JMI_CNTL__SOFT_RESET_MASK); - - tmp = RREG32_SOC15(VCN, i, mmJPEG_CGC_GATE); - tmp |= (JPEG_CGC_GATE__JPEG_DEC_MASK - |JPEG_CGC_GATE__JPEG2_DEC_MASK - |JPEG_CGC_GATE__JMCIF_MASK - |JPEG_CGC_GATE__JRBBM_MASK); - WREG32_SOC15(VCN, i, mmJPEG_CGC_GATE, tmp); - - /* enable anti hang mechanism */ - WREG32_P(SOC15_REG_OFFSET(UVD, i, mmUVD_JPEG_POWER_STATUS), - UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_MASK, - ~UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_MASK); - } - - return 0; -} - static int vcn_v2_5_start(struct amdgpu_device *adev) { struct amdgpu_ring *ring; @@ -874,19 +737,14 @@ static int vcn_v2_5_start(struct amdgpu_device *adev) WREG32_SOC15(UVD, i, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); WREG32_SOC15(UVD, i, mmUVD_RB_SIZE2, ring->ring_size / 4); } - r = jpeg_v2_5_start(adev); - return r; + return 0; } static int vcn_v2_5_stop(struct amdgpu_device *adev) { uint32_t tmp; - int i, r; - - r = jpeg_v2_5_stop(adev); - if (r) - return r; + int i, r = 0; for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { if (adev->vcn.harvest_config & (1 << i)) @@ -1125,86 +983,6 @@ static const struct amdgpu_ring_funcs vcn_v2_5_enc_ring_vm_funcs = { .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, }; -/** - * vcn_v2_5_jpeg_ring_get_rptr - get read pointer - * - * @ring: amdgpu_ring pointer - * - * Returns the current hardware read pointer - */ -static uint64_t vcn_v2_5_jpeg_ring_get_rptr(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - return RREG32_SOC15(UVD, ring->me, mmUVD_JRBC_RB_RPTR); -} - -/** - * vcn_v2_5_jpeg_ring_get_wptr - get write pointer - * - * @ring: amdgpu_ring pointer - * - * Returns the current hardware write pointer - */ -static uint64_t vcn_v2_5_jpeg_ring_get_wptr(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - if (ring->use_doorbell) - return adev->wb.wb[ring->wptr_offs]; - else - return RREG32_SOC15(UVD, ring->me, mmUVD_JRBC_RB_WPTR); -} - -/** - * vcn_v2_5_jpeg_ring_set_wptr - set write pointer - * - * @ring: amdgpu_ring pointer - * - * Commits the write pointer to the hardware - */ -static void vcn_v2_5_jpeg_ring_set_wptr(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - - if (ring->use_doorbell) { - adev->wb.wb[ring->wptr_offs] = lower_32_bits(ring->wptr); - WDOORBELL32(ring->doorbell_index, lower_32_bits(ring->wptr)); - } else { - WREG32_SOC15(UVD, ring->me, mmUVD_JRBC_RB_WPTR, lower_32_bits(ring->wptr)); - } -} - -static const struct amdgpu_ring_funcs vcn_v2_5_jpeg_ring_vm_funcs = { - .type = AMDGPU_RING_TYPE_VCN_JPEG, - .align_mask = 0xf, - .vmhub = AMDGPU_MMHUB_1, - .get_rptr = vcn_v2_5_jpeg_ring_get_rptr, - .get_wptr = vcn_v2_5_jpeg_ring_get_wptr, - .set_wptr = vcn_v2_5_jpeg_ring_set_wptr, - .emit_frame_size = - SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + - SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 + - 8 + /* vcn_v2_0_jpeg_ring_emit_vm_flush */ - 18 + 18 + /* vcn_v2_0_jpeg_ring_emit_fence x2 vm fence */ - 8 + 16, - .emit_ib_size = 22, /* vcn_v2_0_jpeg_ring_emit_ib */ - .emit_ib = vcn_v2_0_jpeg_ring_emit_ib, - .emit_fence = vcn_v2_0_jpeg_ring_emit_fence, - .emit_vm_flush = vcn_v2_0_jpeg_ring_emit_vm_flush, - .test_ring = amdgpu_vcn_jpeg_ring_test_ring, - .test_ib = amdgpu_vcn_jpeg_ring_test_ib, - .insert_nop = vcn_v2_0_jpeg_ring_nop, - .insert_start = vcn_v2_0_jpeg_ring_insert_start, - .insert_end = vcn_v2_0_jpeg_ring_insert_end, - .pad_ib = amdgpu_ring_generic_pad_ib, - .begin_use = amdgpu_vcn_ring_begin_use, - .end_use = amdgpu_vcn_ring_end_use, - .emit_wreg = vcn_v2_0_jpeg_ring_emit_wreg, - .emit_reg_wait = vcn_v2_0_jpeg_ring_emit_reg_wait, - .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, -}; - static void vcn_v2_5_set_dec_ring_funcs(struct amdgpu_device *adev) { int i; @@ -1233,19 +1011,6 @@ static void vcn_v2_5_set_enc_ring_funcs(struct amdgpu_device *adev) } } -static void vcn_v2_5_set_jpeg_ring_funcs(struct amdgpu_device *adev) -{ - int i; - - for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { - if (adev->vcn.harvest_config & (1 << i)) - continue; - adev->vcn.inst[i].ring_jpeg.funcs = &vcn_v2_5_jpeg_ring_vm_funcs; - adev->vcn.inst[i].ring_jpeg.me = i; - DRM_INFO("VCN(%d) jpeg decode is enabled in VM mode\n", i); - } -} - static bool vcn_v2_5_is_idle(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -1352,9 +1117,6 @@ static int vcn_v2_5_process_interrupt(struct amdgpu_device *adev, case VCN_2_0__SRCID__UVD_ENC_LOW_LATENCY: amdgpu_fence_process(&adev->vcn.inst[ip_instance].ring_enc[1]); break; - case VCN_2_0__SRCID__JPEG_DECODE: - amdgpu_fence_process(&adev->vcn.inst[ip_instance].ring_jpeg); - break; default: DRM_ERROR("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data[0]); @@ -1376,7 +1138,7 @@ static void vcn_v2_5_set_irq_funcs(struct amdgpu_device *adev) for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { if (adev->vcn.harvest_config & (1 << i)) continue; - adev->vcn.inst[i].irq.num_types = adev->vcn.num_enc_rings + 2; + adev->vcn.inst[i].irq.num_types = adev->vcn.num_enc_rings + 1; adev->vcn.inst[i].irq.funcs = &vcn_v2_5_irq_funcs; } } diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index f1b171e30774cc6fbd309ed7a69247c27e9a0b65..e4f4201b3c347091e2715c1eb378d279b59eca96 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -745,6 +745,27 @@ static int vi_asic_pci_config_reset(struct amdgpu_device *adev) return r; } +static bool vi_asic_supports_baco(struct amdgpu_device *adev) +{ + bool baco_support; + + switch (adev->asic_type) { + case CHIP_FIJI: + case CHIP_TONGA: + case CHIP_POLARIS10: + case CHIP_POLARIS11: + case CHIP_POLARIS12: + case CHIP_TOPAZ: + smu7_asic_get_baco_capability(adev, &baco_support); + break; + default: + baco_support = false; + break; + } + + return baco_support; +} + static enum amd_reset_method vi_asic_reset_method(struct amdgpu_device *adev) { @@ -1119,6 +1140,7 @@ static const struct amdgpu_asic_funcs vi_asic_funcs = .get_pcie_usage = &vi_get_pcie_usage, .need_reset_on_init = &vi_need_reset_on_init, .get_pcie_replay_count = &vi_get_pcie_replay_count, + .supports_baco = &vi_asic_supports_baco, }; #define CZ_REV_BRISTOL(rev) \ diff --git a/drivers/gpu/drm/amd/amdkfd/Kconfig b/drivers/gpu/drm/amd/amdkfd/Kconfig index ba0e68057a89207df912040a37c49278b3a839d3..b3672d10ea54bfa76f01631265ca08fc0ccaa1e9 100644 --- a/drivers/gpu/drm/amd/amdkfd/Kconfig +++ b/drivers/gpu/drm/amd/amdkfd/Kconfig @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-only +# SPDX-License-Identifier: MIT # # Heterogenous system architecture configuration # diff --git a/drivers/gpu/drm/amd/amdkfd/Makefile b/drivers/gpu/drm/amd/amdkfd/Makefile index 48155060a57c063ae6213ce2349e43cb1d9f4c30..61474627a32c614964c1a24e5132969a53a74096 100644 --- a/drivers/gpu/drm/amd/amdkfd/Makefile +++ b/drivers/gpu/drm/amd/amdkfd/Makefile @@ -38,11 +38,9 @@ AMDKFD_FILES := $(AMDKFD_PATH)/kfd_module.o \ $(AMDKFD_PATH)/kfd_mqd_manager_v9.o \ $(AMDKFD_PATH)/kfd_mqd_manager_v10.o \ $(AMDKFD_PATH)/kfd_kernel_queue.o \ - $(AMDKFD_PATH)/kfd_kernel_queue_cik.o \ - $(AMDKFD_PATH)/kfd_kernel_queue_vi.o \ - $(AMDKFD_PATH)/kfd_kernel_queue_v9.o \ - $(AMDKFD_PATH)/kfd_kernel_queue_v10.o \ $(AMDKFD_PATH)/kfd_packet_manager.o \ + $(AMDKFD_PATH)/kfd_packet_manager_vi.o \ + $(AMDKFD_PATH)/kfd_packet_manager_v9.o \ $(AMDKFD_PATH)/kfd_process_queue_manager.o \ $(AMDKFD_PATH)/kfd_device_queue_manager.o \ $(AMDKFD_PATH)/kfd_device_queue_manager_cik.o \ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 1544007af34acc8050292489a1c292a25befa634..b6ba0697c53117dfe54decfec2fcfac369bce11f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -258,6 +258,7 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p, unsigned int queue_id; struct kfd_process_device *pdd; struct queue_properties q_properties; + uint32_t doorbell_offset_in_process = 0; memset(&q_properties, 0, sizeof(struct queue_properties)); @@ -286,7 +287,8 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p, p->pasid, dev->id); - err = pqm_create_queue(&p->pqm, dev, filep, &q_properties, &queue_id); + err = pqm_create_queue(&p->pqm, dev, filep, &q_properties, &queue_id, + &doorbell_offset_in_process); if (err != 0) goto err_create_queue; @@ -296,14 +298,11 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p, /* Return gpu_id as doorbell offset for mmap usage */ args->doorbell_offset = KFD_MMAP_TYPE_DOORBELL; args->doorbell_offset |= KFD_MMAP_GPU_ID(args->gpu_id); - args->doorbell_offset <<= PAGE_SHIFT; if (KFD_IS_SOC15(dev->device_info->asic_family)) - /* On SOC15 ASICs, doorbell allocation must be - * per-device, and independent from the per-process - * queue_id. Return the doorbell offset within the - * doorbell aperture to user mode. + /* On SOC15 ASICs, include the doorbell offset within the + * process doorbell frame, which is 2 pages. */ - args->doorbell_offset |= q_properties.doorbell_off; + args->doorbell_offset |= doorbell_offset_in_process; mutex_unlock(&p->mutex); @@ -1312,10 +1311,9 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep, /* MMIO is mapped through kfd device * Generate a kfd mmap offset */ - if (flags & KFD_IOC_ALLOC_MEM_FLAGS_MMIO_REMAP) { - args->mmap_offset = KFD_MMAP_TYPE_MMIO | KFD_MMAP_GPU_ID(args->gpu_id); - args->mmap_offset <<= PAGE_SHIFT; - } + if (flags & KFD_IOC_ALLOC_MEM_FLAGS_MMIO_REMAP) + args->mmap_offset = KFD_MMAP_TYPE_MMIO + | KFD_MMAP_GPU_ID(args->gpu_id); return 0; @@ -1899,20 +1897,19 @@ static int kfd_mmap(struct file *filp, struct vm_area_struct *vma) { struct kfd_process *process; struct kfd_dev *dev = NULL; - unsigned long vm_pgoff; + unsigned long mmap_offset; unsigned int gpu_id; process = kfd_get_process(current); if (IS_ERR(process)) return PTR_ERR(process); - vm_pgoff = vma->vm_pgoff; - vma->vm_pgoff = KFD_MMAP_OFFSET_VALUE_GET(vm_pgoff); - gpu_id = KFD_MMAP_GPU_ID_GET(vm_pgoff); + mmap_offset = vma->vm_pgoff << PAGE_SHIFT; + gpu_id = KFD_MMAP_GET_GPU_ID(mmap_offset); if (gpu_id) dev = kfd_device_by_id(gpu_id); - switch (vm_pgoff & KFD_MMAP_TYPE_MASK) { + switch (mmap_offset & KFD_MMAP_TYPE_MASK) { case KFD_MMAP_TYPE_DOORBELL: if (!dev) return -ENODEV; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c b/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c index d59f2cd056c648ee9d64c43c3fadda140b9b4dc1..27bcc5b472f68fafc0019a7f3bd9af291b96e0f8 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c @@ -72,11 +72,11 @@ static int dbgdev_diq_submit_ib(struct kfd_dbgdev *dbgdev, * The receive packet buff will be sitting on the Indirect Buffer * and in the PQ we put the IB packet + sync packet(s). */ - status = kq->ops.acquire_packet_buffer(kq, + status = kq_acquire_packet_buffer(kq, pq_packets_size_in_bytes / sizeof(uint32_t), &ib_packet_buff); if (status) { - pr_err("acquire_packet_buffer failed\n"); + pr_err("kq_acquire_packet_buffer failed\n"); return status; } @@ -115,7 +115,7 @@ static int dbgdev_diq_submit_ib(struct kfd_dbgdev *dbgdev, if (status) { pr_err("Failed to allocate GART memory\n"); - kq->ops.rollback_packet(kq); + kq_rollback_packet(kq); return status; } @@ -151,7 +151,7 @@ static int dbgdev_diq_submit_ib(struct kfd_dbgdev *dbgdev, rm_packet->data_lo = QUEUESTATE__ACTIVE; - kq->ops.submit_packet(kq); + kq_submit_packet(kq); /* Wait till CP writes sync code: */ status = amdkfd_fence_wait_timeout( @@ -185,7 +185,7 @@ static int dbgdev_register_diq(struct kfd_dbgdev *dbgdev) properties.type = KFD_QUEUE_TYPE_DIQ; status = pqm_create_queue(dbgdev->pqm, dbgdev->dev, NULL, - &properties, &qid); + &properties, &qid, NULL); if (status) { pr_err("Failed to create DIQ\n"); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 4fa8834ce7cb011f388e2c5cb5b62355a0c116c7..209bfc849352b9f20abb06e9d1930c1257f69914 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -742,7 +742,7 @@ int kgd2kfd_pre_reset(struct kfd_dev *kfd) int kgd2kfd_post_reset(struct kfd_dev *kfd) { - int ret, count; + int ret; if (!kfd->init_complete) return 0; @@ -750,7 +750,7 @@ int kgd2kfd_post_reset(struct kfd_dev *kfd) ret = kfd_resume(kfd); if (ret) return ret; - count = atomic_dec_return(&kfd_locked); + atomic_dec(&kfd_locked); atomic_set(&kfd->sram_ecc_flag, 0); 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 984c2f2b24b607dcc40848844796234694004f08..f7f6df40875e5b430df7fe9e581d6d9776f60490 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -170,7 +170,7 @@ static int allocate_doorbell(struct qcm_process_device *qpd, struct queue *q) } q->properties.doorbell_off = - kfd_doorbell_id_to_offset(dev, q->process, + kfd_get_doorbell_dw_offset_in_bar(dev, q->process, q->doorbell_id); return 0; @@ -1595,7 +1595,7 @@ static int get_wave_state(struct device_queue_manager *dqm, goto dqm_unlock; } - mqd_mgr = dqm->mqd_mgrs[KFD_MQD_TYPE_COMPUTE]; + mqd_mgr = dqm->mqd_mgrs[KFD_MQD_TYPE_CP]; if (!mqd_mgr->get_wave_state) { r = -EINVAL; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c index ebe79bf00145b2d0d2163a472a2c0123cb43805d..8e0c00b9555eddd4235f3a792a0c4ed56f0ae5f0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c @@ -91,7 +91,7 @@ int kfd_doorbell_init(struct kfd_dev *kfd) kfd->doorbell_base = kfd->shared_resources.doorbell_physical_address + doorbell_start_offset; - kfd->doorbell_id_offset = doorbell_start_offset / sizeof(u32); + kfd->doorbell_base_dw_offset = doorbell_start_offset / sizeof(u32); kfd->doorbell_kernel_ptr = ioremap(kfd->doorbell_base, kfd_doorbell_process_slice(kfd)); @@ -103,8 +103,8 @@ int kfd_doorbell_init(struct kfd_dev *kfd) pr_debug("doorbell base == 0x%08lX\n", (uintptr_t)kfd->doorbell_base); - pr_debug("doorbell_id_offset == 0x%08lX\n", - kfd->doorbell_id_offset); + pr_debug("doorbell_base_dw_offset == 0x%08lX\n", + kfd->doorbell_base_dw_offset); pr_debug("doorbell_process_limit == 0x%08lX\n", doorbell_process_limit); @@ -185,7 +185,7 @@ void __iomem *kfd_get_kernel_doorbell(struct kfd_dev *kfd, * Calculating the kernel doorbell offset using the first * doorbell page. */ - *doorbell_off = kfd->doorbell_id_offset + inx; + *doorbell_off = kfd->doorbell_base_dw_offset + inx; pr_debug("Get kernel queue doorbell\n" " doorbell offset == 0x%08X\n" @@ -225,17 +225,17 @@ void write_kernel_doorbell64(void __iomem *db, u64 value) } } -unsigned int kfd_doorbell_id_to_offset(struct kfd_dev *kfd, +unsigned int kfd_get_doorbell_dw_offset_in_bar(struct kfd_dev *kfd, struct kfd_process *process, unsigned int doorbell_id) { /* - * doorbell_id_offset accounts for doorbells taken by KGD. + * doorbell_base_dw_offset accounts for doorbells taken by KGD. * index * kfd_doorbell_process_slice/sizeof(u32) adjusts to * the process's doorbells. The offset returned is in dword * units regardless of the ASIC-dependent doorbell size. */ - return kfd->doorbell_id_offset + + return kfd->doorbell_base_dw_offset + process->doorbell_index * kfd_doorbell_process_slice(kfd) / sizeof(u32) + doorbell_id * kfd->device_info->doorbell_size / sizeof(u32); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index 908081c85de1da238c6f0762c9c22817100a0bc1..1f8365575b12563a5ee039e0724a9cc5955bd402 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -346,7 +346,6 @@ int kfd_event_create(struct file *devkfd, struct kfd_process *p, ret = create_signal_event(devkfd, p, ev); if (!ret) { *event_page_offset = KFD_MMAP_TYPE_EVENTS; - *event_page_offset <<= PAGE_SHIFT; *event_slot_index = ev->event_id; } break; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c index 193e2835bd4d26b7709cae4305cd7544c41b2567..8d871514671eb737e498b2dcfb76d80ec08961ed 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c @@ -62,9 +62,6 @@ int kfd_iommu_device_init(struct kfd_dev *kfd) struct amd_iommu_device_info iommu_info; unsigned int pasid_limit; int err; - struct kfd_topology_device *top_dev; - - top_dev = kfd_topology_device_by_id(kfd->id); if (!kfd->device_info->needs_iommu_device) return 0; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c index 11d2448913938ddc0f65e3ff56fa87d8f4e3d451..2d56dc534459670298f300010e1679e59682cea6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c @@ -34,7 +34,10 @@ #define PM4_COUNT_ZERO (((1 << 15) - 1) << 16) -static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, +/* Initialize a kernel queue, including allocations of GART memory + * needed for the queue. + */ +static bool kq_initialize(struct kernel_queue *kq, struct kfd_dev *dev, enum kfd_queue_type type, unsigned int queue_size) { struct queue_properties prop; @@ -87,9 +90,17 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, kq->pq_kernel_addr = kq->pq->cpu_ptr; kq->pq_gpu_addr = kq->pq->gpu_addr; - retval = kq->ops_asic_specific.initialize(kq, dev, type, queue_size); - if (!retval) - goto err_eop_allocate_vidmem; + /* For CIK family asics, kq->eop_mem is not needed */ + if (dev->device_info->asic_family > CHIP_MULLINS) { + retval = kfd_gtt_sa_allocate(dev, PAGE_SIZE, &kq->eop_mem); + if (retval != 0) + goto err_eop_allocate_vidmem; + + kq->eop_gpu_addr = kq->eop_mem->gpu_addr; + kq->eop_kernel_addr = kq->eop_mem->cpu_ptr; + + memset(kq->eop_kernel_addr, 0, PAGE_SIZE); + } retval = kfd_gtt_sa_allocate(dev, sizeof(*kq->rptr_kernel), &kq->rptr_mem); @@ -183,7 +194,8 @@ err_get_kernel_doorbell: } -static void uninitialize(struct kernel_queue *kq) +/* Uninitialize a kernel queue and free all its memory usages. */ +static void kq_uninitialize(struct kernel_queue *kq) { if (kq->queue->properties.type == KFD_QUEUE_TYPE_HIQ) kq->mqd_mgr->destroy_mqd(kq->mqd_mgr, @@ -200,14 +212,19 @@ static void uninitialize(struct kernel_queue *kq) kfd_gtt_sa_free(kq->dev, kq->rptr_mem); kfd_gtt_sa_free(kq->dev, kq->wptr_mem); - kq->ops_asic_specific.uninitialize(kq); + + /* For CIK family asics, kq->eop_mem is Null, kfd_gtt_sa_free() + * is able to handle NULL properly. + */ + kfd_gtt_sa_free(kq->dev, kq->eop_mem); + kfd_gtt_sa_free(kq->dev, kq->pq); kfd_release_kernel_doorbell(kq->dev, kq->queue->properties.doorbell_ptr); uninit_queue(kq->queue); } -static int acquire_packet_buffer(struct kernel_queue *kq, +int kq_acquire_packet_buffer(struct kernel_queue *kq, size_t packet_size_in_dwords, unsigned int **buffer_ptr) { size_t available_size; @@ -268,7 +285,7 @@ err_no_space: return -ENOMEM; } -static void submit_packet(struct kernel_queue *kq) +void kq_submit_packet(struct kernel_queue *kq) { #ifdef DEBUG int i; @@ -280,11 +297,18 @@ static void submit_packet(struct kernel_queue *kq) } pr_debug("\n"); #endif - - kq->ops_asic_specific.submit_packet(kq); + if (kq->dev->device_info->doorbell_size == 8) { + *kq->wptr64_kernel = kq->pending_wptr64; + write_kernel_doorbell64(kq->queue->properties.doorbell_ptr, + kq->pending_wptr64); + } else { + *kq->wptr_kernel = kq->pending_wptr; + write_kernel_doorbell(kq->queue->properties.doorbell_ptr, + kq->pending_wptr); + } } -static void rollback_packet(struct kernel_queue *kq) +void kq_rollback_packet(struct kernel_queue *kq) { if (kq->dev->device_info->doorbell_size == 8) { kq->pending_wptr64 = *kq->wptr64_kernel; @@ -304,60 +328,18 @@ struct kernel_queue *kernel_queue_init(struct kfd_dev *dev, if (!kq) return NULL; - kq->ops.initialize = initialize; - kq->ops.uninitialize = uninitialize; - kq->ops.acquire_packet_buffer = acquire_packet_buffer; - kq->ops.submit_packet = submit_packet; - kq->ops.rollback_packet = rollback_packet; - - switch (dev->device_info->asic_family) { - case CHIP_CARRIZO: - case CHIP_TONGA: - case CHIP_FIJI: - case CHIP_POLARIS10: - case CHIP_POLARIS11: - case CHIP_POLARIS12: - case CHIP_VEGAM: - kernel_queue_init_vi(&kq->ops_asic_specific); - break; - - case CHIP_KAVERI: - case CHIP_HAWAII: - kernel_queue_init_cik(&kq->ops_asic_specific); - break; - - case CHIP_VEGA10: - case CHIP_VEGA12: - case CHIP_VEGA20: - case CHIP_RAVEN: - case CHIP_RENOIR: - case CHIP_ARCTURUS: - kernel_queue_init_v9(&kq->ops_asic_specific); - break; - case CHIP_NAVI10: - case CHIP_NAVI12: - case CHIP_NAVI14: - kernel_queue_init_v10(&kq->ops_asic_specific); - break; - default: - WARN(1, "Unexpected ASIC family %u", - dev->device_info->asic_family); - goto out_free; - } - - if (kq->ops.initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE)) + if (kq_initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE)) return kq; pr_err("Failed to init kernel queue\n"); -out_free: kfree(kq); return NULL; } void kernel_queue_uninit(struct kernel_queue *kq) { - kq->ops.uninitialize(kq); + kq_uninitialize(kq); kfree(kq); } @@ -377,7 +359,7 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev) return; } - retval = kq->ops.acquire_packet_buffer(kq, 5, &buffer); + retval = kq_acquire_packet_buffer(kq, 5, &buffer); if (unlikely(retval != 0)) { pr_err(" Failed to acquire packet buffer\n"); pr_err("Kernel queue test failed\n"); @@ -385,7 +367,7 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev) } for (i = 0; i < 5; i++) buffer[i] = kq->nop_packet; - kq->ops.submit_packet(kq); + kq_submit_packet(kq); pr_err("Ending kernel queue test\n"); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h index 365fc674fea40152b22e4f0a341141f3ab482850..f4cfe9f1871c2a88965208c54dddffc9cca75614 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h @@ -29,45 +29,28 @@ #include "kfd_priv.h" /** - * struct kernel_queue_ops - * - * @initialize: Initialize a kernel queue, including allocations of GART memory - * needed for the queue. - * - * @uninitialize: Uninitialize a kernel queue and free all its memory usages. - * - * @acquire_packet_buffer: Returns a pointer to the location in the kernel + * kq_acquire_packet_buffer: Returns a pointer to the location in the kernel * queue ring buffer where the calling function can write its packet. It is * Guaranteed that there is enough space for that packet. It also updates the * pending write pointer to that location so subsequent calls to * acquire_packet_buffer will get a correct write pointer * - * @submit_packet: Update the write pointer and doorbell of a kernel queue. - * - * @sync_with_hw: Wait until the write pointer and the read pointer of a kernel - * queue are equal, which means the CP has read all the submitted packets. + * kq_submit_packet: Update the write pointer and doorbell of a kernel queue. * - * @rollback_packet: This routine is called if we failed to build an acquired + * kq_rollback_packet: This routine is called if we failed to build an acquired * packet for some reason. It just overwrites the pending wptr with the current * one * */ -struct kernel_queue_ops { - bool (*initialize)(struct kernel_queue *kq, struct kfd_dev *dev, - enum kfd_queue_type type, unsigned int queue_size); - void (*uninitialize)(struct kernel_queue *kq); - int (*acquire_packet_buffer)(struct kernel_queue *kq, - size_t packet_size_in_dwords, - unsigned int **buffer_ptr); - void (*submit_packet)(struct kernel_queue *kq); - void (*rollback_packet)(struct kernel_queue *kq); -}; +int kq_acquire_packet_buffer(struct kernel_queue *kq, + size_t packet_size_in_dwords, + unsigned int **buffer_ptr); +void kq_submit_packet(struct kernel_queue *kq); +void kq_rollback_packet(struct kernel_queue *kq); -struct kernel_queue { - struct kernel_queue_ops ops; - struct kernel_queue_ops ops_asic_specific; +struct kernel_queue { /* data */ struct kfd_dev *dev; struct mqd_manager *mqd_mgr; @@ -99,9 +82,4 @@ struct kernel_queue { struct list_head list; }; -void kernel_queue_init_cik(struct kernel_queue_ops *ops); -void kernel_queue_init_vi(struct kernel_queue_ops *ops); -void kernel_queue_init_v9(struct kernel_queue_ops *ops); -void kernel_queue_init_v10(struct kernel_queue_ops *ops); - #endif /* KFD_KERNEL_QUEUE_H_ */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_v10.c deleted file mode 100644 index aed32ab7102e24e4f722b65d43aabfff79f450c7..0000000000000000000000000000000000000000 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_v10.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright 2018 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 "kfd_kernel_queue.h" -#include "kfd_device_queue_manager.h" -#include "kfd_pm4_headers_ai.h" -#include "kfd_pm4_opcodes.h" -#include "gc/gc_10_1_0_sh_mask.h" - -static bool initialize_v10(struct kernel_queue *kq, struct kfd_dev *dev, - enum kfd_queue_type type, unsigned int queue_size); -static void uninitialize_v10(struct kernel_queue *kq); -static void submit_packet_v10(struct kernel_queue *kq); - -void kernel_queue_init_v10(struct kernel_queue_ops *ops) -{ - ops->initialize = initialize_v10; - ops->uninitialize = uninitialize_v10; - ops->submit_packet = submit_packet_v10; -} - -static bool initialize_v10(struct kernel_queue *kq, struct kfd_dev *dev, - enum kfd_queue_type type, unsigned int queue_size) -{ - int retval; - - retval = kfd_gtt_sa_allocate(dev, PAGE_SIZE, &kq->eop_mem); - if (retval != 0) - return false; - - kq->eop_gpu_addr = kq->eop_mem->gpu_addr; - kq->eop_kernel_addr = kq->eop_mem->cpu_ptr; - - memset(kq->eop_kernel_addr, 0, PAGE_SIZE); - - return true; -} - -static void uninitialize_v10(struct kernel_queue *kq) -{ - kfd_gtt_sa_free(kq->dev, kq->eop_mem); -} - -static void submit_packet_v10(struct kernel_queue *kq) -{ - *kq->wptr64_kernel = kq->pending_wptr64; - write_kernel_doorbell64(kq->queue->properties.doorbell_ptr, - kq->pending_wptr64); -} - -static int pm_map_process_v10(struct packet_manager *pm, - uint32_t *buffer, struct qcm_process_device *qpd) -{ - struct pm4_mes_map_process *packet; - uint64_t vm_page_table_base_addr = qpd->page_table_base; - - packet = (struct pm4_mes_map_process *)buffer; - memset(buffer, 0, sizeof(struct pm4_mes_map_process)); - - packet->header.u32All = pm_build_pm4_header(IT_MAP_PROCESS, - sizeof(struct pm4_mes_map_process)); - packet->bitfields2.diq_enable = (qpd->is_debug) ? 1 : 0; - packet->bitfields2.process_quantum = 1; - packet->bitfields2.pasid = qpd->pqm->process->pasid; - packet->bitfields14.gds_size = qpd->gds_size; - packet->bitfields14.num_gws = qpd->num_gws; - packet->bitfields14.num_oac = qpd->num_oac; - packet->bitfields14.sdma_enable = 1; - - packet->bitfields14.num_queues = (qpd->is_debug) ? 0 : qpd->queue_count; - - packet->sh_mem_config = qpd->sh_mem_config; - packet->sh_mem_bases = qpd->sh_mem_bases; - if (qpd->tba_addr) { - packet->sq_shader_tba_lo = lower_32_bits(qpd->tba_addr >> 8); - packet->sq_shader_tba_hi = (1 << SQ_SHADER_TBA_HI__TRAP_EN__SHIFT) | - upper_32_bits(qpd->tba_addr >> 8); - packet->sq_shader_tma_lo = lower_32_bits(qpd->tma_addr >> 8); - packet->sq_shader_tma_hi = upper_32_bits(qpd->tma_addr >> 8); - } - - packet->gds_addr_lo = lower_32_bits(qpd->gds_context_area); - packet->gds_addr_hi = upper_32_bits(qpd->gds_context_area); - - packet->vm_context_page_table_base_addr_lo32 = - lower_32_bits(vm_page_table_base_addr); - packet->vm_context_page_table_base_addr_hi32 = - upper_32_bits(vm_page_table_base_addr); - - return 0; -} - -static int pm_runlist_v10(struct packet_manager *pm, uint32_t *buffer, - uint64_t ib, size_t ib_size_in_dwords, bool chain) -{ - struct pm4_mes_runlist *packet; - - int concurrent_proc_cnt = 0; - struct kfd_dev *kfd = pm->dqm->dev; - - /* Determine the number of processes to map together to HW: - * it can not exceed the number of VMIDs available to the - * scheduler, and it is determined by the smaller of the number - * of processes in the runlist and kfd module parameter - * hws_max_conc_proc. - * Note: the arbitration between the number of VMIDs and - * hws_max_conc_proc has been done in - * kgd2kfd_device_init(). - */ - concurrent_proc_cnt = min(pm->dqm->processes_count, - kfd->max_proc_per_quantum); - - - packet = (struct pm4_mes_runlist *)buffer; - - memset(buffer, 0, sizeof(struct pm4_mes_runlist)); - packet->header.u32All = pm_build_pm4_header(IT_RUN_LIST, - sizeof(struct pm4_mes_runlist)); - - packet->bitfields4.ib_size = ib_size_in_dwords; - packet->bitfields4.chain = chain ? 1 : 0; - packet->bitfields4.offload_polling = 0; - packet->bitfields4.valid = 1; - packet->bitfields4.process_cnt = concurrent_proc_cnt; - packet->ordinal2 = lower_32_bits(ib); - packet->ib_base_hi = upper_32_bits(ib); - - return 0; -} - -static int pm_map_queues_v10(struct packet_manager *pm, uint32_t *buffer, - struct queue *q, bool is_static) -{ - struct pm4_mes_map_queues *packet; - bool use_static = is_static; - - packet = (struct pm4_mes_map_queues *)buffer; - memset(buffer, 0, sizeof(struct pm4_mes_map_queues)); - - packet->header.u32All = pm_build_pm4_header(IT_MAP_QUEUES, - sizeof(struct pm4_mes_map_queues)); - packet->bitfields2.num_queues = 1; - packet->bitfields2.queue_sel = - queue_sel__mes_map_queues__map_to_hws_determined_queue_slots_vi; - - packet->bitfields2.engine_sel = - engine_sel__mes_map_queues__compute_vi; - packet->bitfields2.queue_type = - queue_type__mes_map_queues__normal_compute_vi; - - switch (q->properties.type) { - case KFD_QUEUE_TYPE_COMPUTE: - if (use_static) - packet->bitfields2.queue_type = - queue_type__mes_map_queues__normal_latency_static_queue_vi; - break; - case KFD_QUEUE_TYPE_DIQ: - packet->bitfields2.queue_type = - queue_type__mes_map_queues__debug_interface_queue_vi; - break; - case KFD_QUEUE_TYPE_SDMA: - case KFD_QUEUE_TYPE_SDMA_XGMI: - packet->bitfields2.engine_sel = q->properties.sdma_engine_id + - engine_sel__mes_map_queues__sdma0_vi; - use_static = false; /* no static queues under SDMA */ - break; - default: - WARN(1, "queue type %d\n", q->properties.type); - return -EINVAL; - } - packet->bitfields3.doorbell_offset = - q->properties.doorbell_off; - - packet->mqd_addr_lo = - lower_32_bits(q->gart_mqd_addr); - - packet->mqd_addr_hi = - upper_32_bits(q->gart_mqd_addr); - - packet->wptr_addr_lo = - lower_32_bits((uint64_t)q->properties.write_ptr); - - packet->wptr_addr_hi = - upper_32_bits((uint64_t)q->properties.write_ptr); - - return 0; -} - -static int pm_unmap_queues_v10(struct packet_manager *pm, uint32_t *buffer, - enum kfd_queue_type type, - enum kfd_unmap_queues_filter filter, - uint32_t filter_param, bool reset, - unsigned int sdma_engine) -{ - struct pm4_mes_unmap_queues *packet; - - packet = (struct pm4_mes_unmap_queues *)buffer; - memset(buffer, 0, sizeof(struct pm4_mes_unmap_queues)); - - packet->header.u32All = pm_build_pm4_header(IT_UNMAP_QUEUES, - sizeof(struct pm4_mes_unmap_queues)); - switch (type) { - case KFD_QUEUE_TYPE_COMPUTE: - case KFD_QUEUE_TYPE_DIQ: - packet->bitfields2.engine_sel = - engine_sel__mes_unmap_queues__compute; - break; - case KFD_QUEUE_TYPE_SDMA: - case KFD_QUEUE_TYPE_SDMA_XGMI: - packet->bitfields2.engine_sel = - engine_sel__mes_unmap_queues__sdma0 + sdma_engine; - break; - default: - WARN(1, "queue type %d\n", type); - break; - } - - if (reset) - packet->bitfields2.action = - action__mes_unmap_queues__reset_queues; - else - packet->bitfields2.action = - action__mes_unmap_queues__preempt_queues; - - switch (filter) { - case KFD_UNMAP_QUEUES_FILTER_SINGLE_QUEUE: - packet->bitfields2.queue_sel = - queue_sel__mes_unmap_queues__perform_request_on_specified_queues; - packet->bitfields2.num_queues = 1; - packet->bitfields3b.doorbell_offset0 = filter_param; - break; - case KFD_UNMAP_QUEUES_FILTER_BY_PASID: - packet->bitfields2.queue_sel = - queue_sel__mes_unmap_queues__perform_request_on_pasid_queues; - packet->bitfields3a.pasid = filter_param; - break; - case KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES: - packet->bitfields2.queue_sel = - queue_sel__mes_unmap_queues__unmap_all_queues; - break; - case KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES: - /* in this case, we do not preempt static queues */ - packet->bitfields2.queue_sel = - queue_sel__mes_unmap_queues__unmap_all_non_static_queues; - break; - default: - WARN(1, "filter %d\n", filter); - break; - } - - return 0; - -} - -static int pm_query_status_v10(struct packet_manager *pm, uint32_t *buffer, - uint64_t fence_address, uint32_t fence_value) -{ - struct pm4_mes_query_status *packet; - - packet = (struct pm4_mes_query_status *)buffer; - memset(buffer, 0, sizeof(struct pm4_mes_query_status)); - - - packet->header.u32All = pm_build_pm4_header(IT_QUERY_STATUS, - sizeof(struct pm4_mes_query_status)); - - packet->bitfields2.context_id = 0; - packet->bitfields2.interrupt_sel = - interrupt_sel__mes_query_status__completion_status; - packet->bitfields2.command = - command__mes_query_status__fence_only_after_write_ack; - - packet->addr_hi = upper_32_bits((uint64_t)fence_address); - packet->addr_lo = lower_32_bits((uint64_t)fence_address); - packet->data_hi = upper_32_bits((uint64_t)fence_value); - packet->data_lo = lower_32_bits((uint64_t)fence_value); - - return 0; -} - - -static int pm_release_mem_v10(uint64_t gpu_addr, uint32_t *buffer) -{ - struct pm4_mec_release_mem *packet; - - WARN_ON(!buffer); - - packet = (struct pm4_mec_release_mem *)buffer; - memset(buffer, 0, sizeof(struct pm4_mec_release_mem)); - - packet->header.u32All = pm_build_pm4_header(IT_RELEASE_MEM, - sizeof(struct pm4_mec_release_mem)); - - packet->bitfields2.event_type = CACHE_FLUSH_AND_INV_TS_EVENT; - packet->bitfields2.event_index = event_index__mec_release_mem__end_of_pipe; - packet->bitfields2.tcl1_action_ena = 1; - packet->bitfields2.tc_action_ena = 1; - packet->bitfields2.cache_policy = cache_policy__mec_release_mem__lru; - - packet->bitfields3.data_sel = data_sel__mec_release_mem__send_32_bit_low; - packet->bitfields3.int_sel = - int_sel__mec_release_mem__send_interrupt_after_write_confirm; - - packet->bitfields4.address_lo_32b = (gpu_addr & 0xffffffff) >> 2; - packet->address_hi = upper_32_bits(gpu_addr); - - packet->data_lo = 0; - - return sizeof(struct pm4_mec_release_mem) / sizeof(unsigned int); -} - -const struct packet_manager_funcs kfd_v10_pm_funcs = { - .map_process = pm_map_process_v10, - .runlist = pm_runlist_v10, - .set_resources = pm_set_resources_vi, - .map_queues = pm_map_queues_v10, - .unmap_queues = pm_unmap_queues_v10, - .query_status = pm_query_status_v10, - .release_mem = pm_release_mem_v10, - .map_process_size = sizeof(struct pm4_mes_map_process), - .runlist_size = sizeof(struct pm4_mes_runlist), - .set_resources_size = sizeof(struct pm4_mes_set_resources), - .map_queues_size = sizeof(struct pm4_mes_map_queues), - .unmap_queues_size = sizeof(struct pm4_mes_unmap_queues), - .query_status_size = sizeof(struct pm4_mes_query_status), - .release_mem_size = sizeof(struct pm4_mec_release_mem) -}; - diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c index 28876aceb14be6b7f24a37ffe733643515965e0b..19f0fe547c57582e42282cce14f5c3d154d1f888 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c @@ -374,7 +374,6 @@ struct mqd_manager *mqd_manager_init_cik(enum KFD_MQD_TYPE type, switch (type) { case KFD_MQD_TYPE_CP: - case KFD_MQD_TYPE_COMPUTE: mqd->allocate_mqd = allocate_mqd; mqd->init_mqd = init_mqd; mqd->free_mqd = free_mqd; @@ -401,7 +400,7 @@ struct mqd_manager *mqd_manager_init_cik(enum KFD_MQD_TYPE type, #endif break; case KFD_MQD_TYPE_DIQ: - mqd->allocate_mqd = allocate_hiq_mqd; + mqd->allocate_mqd = allocate_mqd; mqd->init_mqd = init_mqd_hiq; mqd->free_mqd = free_mqd; mqd->load_mqd = load_mqd; @@ -442,7 +441,7 @@ struct mqd_manager *mqd_manager_init_cik_hawaii(enum KFD_MQD_TYPE type, mqd = mqd_manager_init_cik(type, dev); if (!mqd) return NULL; - if ((type == KFD_MQD_TYPE_CP) || (type == KFD_MQD_TYPE_COMPUTE)) + if (type == KFD_MQD_TYPE_CP) mqd->update_mqd = update_mqd_hawaii; return mqd; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c index 4a236b2c2354effbfb82b9e03ea2e2a5a594aff7..7832ec6e480b8660afe83ae7e146a2399c054d20 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c @@ -66,6 +66,12 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd, m->compute_static_thread_mgmt_se3); } +static void set_priority(struct v10_compute_mqd *m, struct queue_properties *q) +{ + m->cp_hqd_pipe_priority = pipe_priority_map[q->priority]; + m->cp_hqd_queue_priority = q->priority; +} + static struct kfd_mem_obj *allocate_mqd(struct kfd_dev *kfd, struct queue_properties *q) { @@ -109,9 +115,6 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, 1 << CP_HQD_QUANTUM__QUANTUM_SCALE__SHIFT | 10 << CP_HQD_QUANTUM__QUANTUM_DURATION__SHIFT; - m->cp_hqd_pipe_priority = 1; - m->cp_hqd_queue_priority = 15; - if (q->format == KFD_QUEUE_FORMAT_AQL) { m->cp_hqd_aql_control = 1 << CP_HQD_AQL_CONTROL__CONTROL0__SHIFT; @@ -208,11 +211,9 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, m->cp_hqd_ctx_save_control = 0; update_cu_mask(mm, mqd, q); + set_priority(m, q); - q->is_active = (q->queue_size > 0 && - q->queue_address != 0 && - q->queue_percent > 0 && - !q->is_evicted); + q->is_active = QUEUE_IS_ACTIVE(*q); } static int destroy_mqd(struct mqd_manager *mm, void *mqd, @@ -247,18 +248,22 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd, { struct v10_compute_mqd *m; - /* Control stack is located one page after MQD. */ - void *mqd_ctl_stack = (void *)((uintptr_t)mqd + PAGE_SIZE); - m = get_mqd(mqd); + /* Control stack is written backwards, while workgroup context data + * is written forwards. Both starts from m->cp_hqd_cntl_stack_size. + * Current position is at m->cp_hqd_cntl_stack_offset and + * m->cp_hqd_wg_state_offset, respectively. + */ *ctl_stack_used_size = m->cp_hqd_cntl_stack_size - m->cp_hqd_cntl_stack_offset; *save_area_used_size = m->cp_hqd_wg_state_offset - m->cp_hqd_cntl_stack_size; - if (copy_to_user(ctl_stack, mqd_ctl_stack, m->cp_hqd_cntl_stack_size)) - return -EFAULT; + /* Control stack is not copied to user mode for GFXv10 because + * it's part of the context save area that is already + * accessible to user mode + */ return 0; } @@ -277,18 +282,6 @@ static void init_mqd_hiq(struct mqd_manager *mm, void **mqd, 1 << CP_HQD_PQ_CONTROL__KMD_QUEUE__SHIFT; } -static void update_mqd_hiq(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) -{ - struct v10_compute_mqd *m; - - update_mqd(mm, mqd, q); - - /* TODO: what's the point? update_mqd already does this. */ - m = get_mqd(mqd); - m->cp_hqd_vmid = q->vmid; -} - static void init_mqd_sdma(struct mqd_manager *mm, void **mqd, struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr, struct queue_properties *q) @@ -340,11 +333,7 @@ static void update_mqd_sdma(struct mqd_manager *mm, void *mqd, m->sdma_queue_id = q->sdma_queue_id; m->sdmax_rlcx_dummy_reg = SDMA_RLC_DUMMY_DEFAULT; - - q->is_active = (q->queue_size > 0 && - q->queue_address != 0 && - q->queue_percent > 0 && - !q->is_evicted); + q->is_active = QUEUE_IS_ACTIVE(*q); } /* @@ -392,7 +381,7 @@ struct mqd_manager *mqd_manager_init_v10(enum KFD_MQD_TYPE type, if (WARN_ON(type >= KFD_MQD_TYPE_MAX)) return NULL; - mqd = kzalloc(sizeof(*mqd), GFP_NOIO); + mqd = kzalloc(sizeof(*mqd), GFP_KERNEL); if (!mqd) return NULL; @@ -400,7 +389,6 @@ struct mqd_manager *mqd_manager_init_v10(enum KFD_MQD_TYPE type, switch (type) { case KFD_MQD_TYPE_CP: - case KFD_MQD_TYPE_COMPUTE: pr_debug("%s@%i\n", __func__, __LINE__); mqd->allocate_mqd = allocate_mqd; mqd->init_mqd = init_mqd; @@ -422,7 +410,7 @@ struct mqd_manager *mqd_manager_init_v10(enum KFD_MQD_TYPE type, mqd->init_mqd = init_mqd_hiq; mqd->free_mqd = free_mqd_hiq_sdma; mqd->load_mqd = load_mqd; - mqd->update_mqd = update_mqd_hiq; + mqd->update_mqd = update_mqd; mqd->destroy_mqd = destroy_mqd; mqd->is_occupied = is_occupied; mqd->mqd_size = sizeof(struct v10_compute_mqd); @@ -432,11 +420,11 @@ struct mqd_manager *mqd_manager_init_v10(enum KFD_MQD_TYPE type, pr_debug("%s@%i\n", __func__, __LINE__); break; case KFD_MQD_TYPE_DIQ: - mqd->allocate_mqd = allocate_hiq_mqd; + mqd->allocate_mqd = allocate_mqd; mqd->init_mqd = init_mqd_hiq; mqd->free_mqd = free_mqd; mqd->load_mqd = load_mqd; - mqd->update_mqd = update_mqd_hiq; + mqd->update_mqd = update_mqd; mqd->destroy_mqd = destroy_mqd; mqd->is_occupied = is_occupied; mqd->mqd_size = sizeof(struct v10_compute_mqd); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index d3380c5bdbdea8e18f1a107aeae057083dbda6a7..aa9010995eaf228469e43fafd4d4683c72bf3e4b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -92,7 +92,7 @@ static struct kfd_mem_obj *allocate_mqd(struct kfd_dev *kfd, * instead of sub-allocation function. */ if (kfd->cwsr_enabled && (q->type == KFD_QUEUE_TYPE_COMPUTE)) { - mqd_mem_obj = kzalloc(sizeof(struct kfd_mem_obj), GFP_NOIO); + mqd_mem_obj = kzalloc(sizeof(struct kfd_mem_obj), GFP_KERNEL); if (!mqd_mem_obj) return NULL; retval = amdgpu_amdkfd_alloc_gtt_mem(kfd->kgd, @@ -302,7 +302,8 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd, *ctl_stack_used_size = m->cp_hqd_cntl_stack_size - m->cp_hqd_cntl_stack_offset; - *save_area_used_size = m->cp_hqd_wg_state_offset; + *save_area_used_size = m->cp_hqd_wg_state_offset - + m->cp_hqd_cntl_stack_size; if (copy_to_user(ctl_stack, mqd_ctl_stack, m->cp_hqd_cntl_stack_size)) return -EFAULT; @@ -324,18 +325,6 @@ static void init_mqd_hiq(struct mqd_manager *mm, void **mqd, 1 << CP_HQD_PQ_CONTROL__KMD_QUEUE__SHIFT; } -static void update_mqd_hiq(struct mqd_manager *mm, void *mqd, - struct queue_properties *q) -{ - struct v9_mqd *m; - - update_mqd(mm, mqd, q); - - /* TODO: what's the point? update_mqd already does this. */ - m = get_mqd(mqd); - m->cp_hqd_vmid = q->vmid; -} - static void init_mqd_sdma(struct mqd_manager *mm, void **mqd, struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr, struct queue_properties *q) @@ -443,7 +432,6 @@ struct mqd_manager *mqd_manager_init_v9(enum KFD_MQD_TYPE type, switch (type) { case KFD_MQD_TYPE_CP: - case KFD_MQD_TYPE_COMPUTE: mqd->allocate_mqd = allocate_mqd; mqd->init_mqd = init_mqd; mqd->free_mqd = free_mqd; @@ -462,7 +450,7 @@ struct mqd_manager *mqd_manager_init_v9(enum KFD_MQD_TYPE type, mqd->init_mqd = init_mqd_hiq; mqd->free_mqd = free_mqd_hiq_sdma; mqd->load_mqd = load_mqd; - mqd->update_mqd = update_mqd_hiq; + mqd->update_mqd = update_mqd; mqd->destroy_mqd = destroy_mqd; mqd->is_occupied = is_occupied; mqd->mqd_size = sizeof(struct v9_mqd); @@ -471,11 +459,11 @@ struct mqd_manager *mqd_manager_init_v9(enum KFD_MQD_TYPE type, #endif break; case KFD_MQD_TYPE_DIQ: - mqd->allocate_mqd = allocate_hiq_mqd; + mqd->allocate_mqd = allocate_mqd; mqd->init_mqd = init_mqd_hiq; mqd->free_mqd = free_mqd; mqd->load_mqd = load_mqd; - mqd->update_mqd = update_mqd_hiq; + mqd->update_mqd = update_mqd; mqd->destroy_mqd = destroy_mqd; mqd->is_occupied = is_occupied; mqd->mqd_size = sizeof(struct v9_mqd); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c index 7d144f56f42159948cd69ee0a4b7000ca512f1d9..a5e8ff1e594550b1bbbbbf92a9865222d8f08fec 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -312,11 +312,7 @@ static void init_mqd_hiq(struct mqd_manager *mm, void **mqd, static void update_mqd_hiq(struct mqd_manager *mm, void *mqd, struct queue_properties *q) { - struct vi_mqd *m; __update_mqd(mm, mqd, q, MTYPE_UC, 0); - - m = get_mqd(mqd); - m->cp_hqd_vmid = q->vmid; } static void init_mqd_sdma(struct mqd_manager *mm, void **mqd, @@ -425,7 +421,6 @@ struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type, switch (type) { case KFD_MQD_TYPE_CP: - case KFD_MQD_TYPE_COMPUTE: mqd->allocate_mqd = allocate_mqd; mqd->init_mqd = init_mqd; mqd->free_mqd = free_mqd; @@ -453,7 +448,7 @@ struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type, #endif break; case KFD_MQD_TYPE_DIQ: - mqd->allocate_mqd = allocate_hiq_mqd; + mqd->allocate_mqd = allocate_mqd; mqd->init_mqd = init_mqd_hiq; mqd->free_mqd = free_mqd; mqd->load_mqd = load_mqd; @@ -494,7 +489,7 @@ struct mqd_manager *mqd_manager_init_vi_tonga(enum KFD_MQD_TYPE type, mqd = mqd_manager_init_vi(type, dev); if (!mqd) return NULL; - if ((type == KFD_MQD_TYPE_CP) || (type == KFD_MQD_TYPE_COMPUTE)) + if (type == KFD_MQD_TYPE_CP) mqd->update_mqd = update_mqd_tonga; return mqd; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c index 83ef4b3dd2fbb2ce1393c268c16c33388bc6136d..6cabed06ef5d75d169150247d805b4ac98e81dfa 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c @@ -241,12 +241,10 @@ int pm_init(struct packet_manager *pm, struct device_queue_manager *dqm) case CHIP_RAVEN: case CHIP_RENOIR: case CHIP_ARCTURUS: - pm->pmf = &kfd_v9_pm_funcs; - break; case CHIP_NAVI10: case CHIP_NAVI12: case CHIP_NAVI14: - pm->pmf = &kfd_v10_pm_funcs; + pm->pmf = &kfd_v9_pm_funcs; break; default: WARN(1, "Unexpected ASIC family %u", @@ -280,7 +278,7 @@ int pm_send_set_resources(struct packet_manager *pm, size = pm->pmf->set_resources_size; mutex_lock(&pm->lock); - pm->priv_queue->ops.acquire_packet_buffer(pm->priv_queue, + kq_acquire_packet_buffer(pm->priv_queue, size / sizeof(uint32_t), (unsigned int **)&buffer); if (!buffer) { @@ -291,9 +289,9 @@ int pm_send_set_resources(struct packet_manager *pm, retval = pm->pmf->set_resources(pm, buffer, res); if (!retval) - pm->priv_queue->ops.submit_packet(pm->priv_queue); + kq_submit_packet(pm->priv_queue); else - pm->priv_queue->ops.rollback_packet(pm->priv_queue); + kq_rollback_packet(pm->priv_queue); out: mutex_unlock(&pm->lock); @@ -318,7 +316,7 @@ int pm_send_runlist(struct packet_manager *pm, struct list_head *dqm_queues) packet_size_dwords = pm->pmf->runlist_size / sizeof(uint32_t); mutex_lock(&pm->lock); - retval = pm->priv_queue->ops.acquire_packet_buffer(pm->priv_queue, + retval = kq_acquire_packet_buffer(pm->priv_queue, packet_size_dwords, &rl_buffer); if (retval) goto fail_acquire_packet_buffer; @@ -328,14 +326,14 @@ int pm_send_runlist(struct packet_manager *pm, struct list_head *dqm_queues) if (retval) goto fail_create_runlist; - pm->priv_queue->ops.submit_packet(pm->priv_queue); + kq_submit_packet(pm->priv_queue); mutex_unlock(&pm->lock); return retval; fail_create_runlist: - pm->priv_queue->ops.rollback_packet(pm->priv_queue); + kq_rollback_packet(pm->priv_queue); fail_acquire_packet_buffer: mutex_unlock(&pm->lock); fail_create_runlist_ib: @@ -354,7 +352,7 @@ int pm_send_query_status(struct packet_manager *pm, uint64_t fence_address, size = pm->pmf->query_status_size; mutex_lock(&pm->lock); - pm->priv_queue->ops.acquire_packet_buffer(pm->priv_queue, + kq_acquire_packet_buffer(pm->priv_queue, size / sizeof(uint32_t), (unsigned int **)&buffer); if (!buffer) { pr_err("Failed to allocate buffer on kernel queue\n"); @@ -364,9 +362,9 @@ int pm_send_query_status(struct packet_manager *pm, uint64_t fence_address, retval = pm->pmf->query_status(pm, buffer, fence_address, fence_value); if (!retval) - pm->priv_queue->ops.submit_packet(pm->priv_queue); + kq_submit_packet(pm->priv_queue); else - pm->priv_queue->ops.rollback_packet(pm->priv_queue); + kq_rollback_packet(pm->priv_queue); out: mutex_unlock(&pm->lock); @@ -383,7 +381,7 @@ int pm_send_unmap_queue(struct packet_manager *pm, enum kfd_queue_type type, size = pm->pmf->unmap_queues_size; mutex_lock(&pm->lock); - pm->priv_queue->ops.acquire_packet_buffer(pm->priv_queue, + kq_acquire_packet_buffer(pm->priv_queue, size / sizeof(uint32_t), (unsigned int **)&buffer); if (!buffer) { pr_err("Failed to allocate buffer on kernel queue\n"); @@ -394,9 +392,9 @@ int pm_send_unmap_queue(struct packet_manager *pm, enum kfd_queue_type type, retval = pm->pmf->unmap_queues(pm, buffer, type, filter, filter_param, reset, sdma_engine); if (!retval) - pm->priv_queue->ops.submit_packet(pm->priv_queue); + kq_submit_packet(pm->priv_queue); else - pm->priv_queue->ops.rollback_packet(pm->priv_queue); + kq_rollback_packet(pm->priv_queue); out: mutex_unlock(&pm->lock); @@ -441,7 +439,7 @@ int pm_debugfs_hang_hws(struct packet_manager *pm) size = pm->pmf->query_status_size; mutex_lock(&pm->lock); - pm->priv_queue->ops.acquire_packet_buffer(pm->priv_queue, + kq_acquire_packet_buffer(pm->priv_queue, size / sizeof(uint32_t), (unsigned int **)&buffer); if (!buffer) { pr_err("Failed to allocate buffer on kernel queue\n"); @@ -449,7 +447,7 @@ int pm_debugfs_hang_hws(struct packet_manager *pm) goto out; } memset(buffer, 0x55, size); - pm->priv_queue->ops.submit_packet(pm->priv_queue); + kq_submit_packet(pm->priv_queue); pr_info("Submitting %x %x %x %x %x %x %x to HIQ to hang the HWS.", buffer[0], buffer[1], buffer[2], buffer[3], diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c similarity index 81% rename from drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_v9.c rename to drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c index 9a4bafb2e175bf367a21beca4bc4031c56fee9db..2de01009f1b6d6efc623b1800c8e60d260179589 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c @@ -25,47 +25,7 @@ #include "kfd_device_queue_manager.h" #include "kfd_pm4_headers_ai.h" #include "kfd_pm4_opcodes.h" - -static bool initialize_v9(struct kernel_queue *kq, struct kfd_dev *dev, - enum kfd_queue_type type, unsigned int queue_size); -static void uninitialize_v9(struct kernel_queue *kq); -static void submit_packet_v9(struct kernel_queue *kq); - -void kernel_queue_init_v9(struct kernel_queue_ops *ops) -{ - ops->initialize = initialize_v9; - ops->uninitialize = uninitialize_v9; - ops->submit_packet = submit_packet_v9; -} - -static bool initialize_v9(struct kernel_queue *kq, struct kfd_dev *dev, - enum kfd_queue_type type, unsigned int queue_size) -{ - int retval; - - retval = kfd_gtt_sa_allocate(dev, PAGE_SIZE, &kq->eop_mem); - if (retval) - return false; - - kq->eop_gpu_addr = kq->eop_mem->gpu_addr; - kq->eop_kernel_addr = kq->eop_mem->cpu_ptr; - - memset(kq->eop_kernel_addr, 0, PAGE_SIZE); - - return true; -} - -static void uninitialize_v9(struct kernel_queue *kq) -{ - kfd_gtt_sa_free(kq->dev, kq->eop_mem); -} - -static void submit_packet_v9(struct kernel_queue *kq) -{ - *kq->wptr64_kernel = kq->pending_wptr64; - write_kernel_doorbell64(kq->queue->properties.doorbell_ptr, - kq->pending_wptr64); -} +#include "gc/gc_10_1_0_sh_mask.h" static int pm_map_process_v9(struct packet_manager *pm, uint32_t *buffer, struct qcm_process_device *qpd) @@ -90,10 +50,17 @@ static int pm_map_process_v9(struct packet_manager *pm, packet->sh_mem_config = qpd->sh_mem_config; packet->sh_mem_bases = qpd->sh_mem_bases; - packet->sq_shader_tba_lo = lower_32_bits(qpd->tba_addr >> 8); - packet->sq_shader_tba_hi = upper_32_bits(qpd->tba_addr >> 8); - packet->sq_shader_tma_lo = lower_32_bits(qpd->tma_addr >> 8); - packet->sq_shader_tma_hi = upper_32_bits(qpd->tma_addr >> 8); + if (qpd->tba_addr) { + packet->sq_shader_tba_lo = lower_32_bits(qpd->tba_addr >> 8); + /* On GFX9, unlike GFX10, bit TRAP_EN of SQ_SHADER_TBA_HI is + * not defined, so setting it won't do any harm. + */ + packet->sq_shader_tba_hi = upper_32_bits(qpd->tba_addr >> 8) + | 1 << SQ_SHADER_TBA_HI__TRAP_EN__SHIFT; + + packet->sq_shader_tma_lo = lower_32_bits(qpd->tma_addr >> 8); + packet->sq_shader_tma_hi = upper_32_bits(qpd->tma_addr >> 8); + } packet->gds_addr_lo = lower_32_bits(qpd->gds_context_area); packet->gds_addr_hi = upper_32_bits(qpd->gds_context_area); @@ -341,35 +308,6 @@ static int pm_query_status_v9(struct packet_manager *pm, uint32_t *buffer, return 0; } - -static int pm_release_mem_v9(uint64_t gpu_addr, uint32_t *buffer) -{ - struct pm4_mec_release_mem *packet; - - packet = (struct pm4_mec_release_mem *)buffer; - memset(buffer, 0, sizeof(struct pm4_mec_release_mem)); - - packet->header.u32All = pm_build_pm4_header(IT_RELEASE_MEM, - sizeof(struct pm4_mec_release_mem)); - - packet->bitfields2.event_type = CACHE_FLUSH_AND_INV_TS_EVENT; - packet->bitfields2.event_index = event_index__mec_release_mem__end_of_pipe; - packet->bitfields2.tcl1_action_ena = 1; - packet->bitfields2.tc_action_ena = 1; - packet->bitfields2.cache_policy = cache_policy__mec_release_mem__lru; - - packet->bitfields3.data_sel = data_sel__mec_release_mem__send_32_bit_low; - packet->bitfields3.int_sel = - int_sel__mec_release_mem__send_interrupt_after_write_confirm; - - packet->bitfields4.address_lo_32b = (gpu_addr & 0xffffffff) >> 2; - packet->address_hi = upper_32_bits(gpu_addr); - - packet->data_lo = 0; - - return 0; -} - const struct packet_manager_funcs kfd_v9_pm_funcs = { .map_process = pm_map_process_v9, .runlist = pm_runlist_v9, @@ -377,12 +315,12 @@ const struct packet_manager_funcs kfd_v9_pm_funcs = { .map_queues = pm_map_queues_v9, .unmap_queues = pm_unmap_queues_v9, .query_status = pm_query_status_v9, - .release_mem = pm_release_mem_v9, + .release_mem = NULL, .map_process_size = sizeof(struct pm4_mes_map_process), .runlist_size = sizeof(struct pm4_mes_runlist), .set_resources_size = sizeof(struct pm4_mes_set_resources), .map_queues_size = sizeof(struct pm4_mes_map_queues), .unmap_queues_size = sizeof(struct pm4_mes_unmap_queues), .query_status_size = sizeof(struct pm4_mes_query_status), - .release_mem_size = sizeof(struct pm4_mec_release_mem) + .release_mem_size = 0, }; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_vi.c similarity index 91% rename from drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_vi.c rename to drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_vi.c index 2adaf40027eba09867877e46bd948744a35b509d..bed4d0ccb6b164c9f1e139e6a5308da0739191ef 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_vi.c @@ -26,47 +26,6 @@ #include "kfd_pm4_headers_vi.h" #include "kfd_pm4_opcodes.h" -static bool initialize_vi(struct kernel_queue *kq, struct kfd_dev *dev, - enum kfd_queue_type type, unsigned int queue_size); -static void uninitialize_vi(struct kernel_queue *kq); -static void submit_packet_vi(struct kernel_queue *kq); - -void kernel_queue_init_vi(struct kernel_queue_ops *ops) -{ - ops->initialize = initialize_vi; - ops->uninitialize = uninitialize_vi; - ops->submit_packet = submit_packet_vi; -} - -static bool initialize_vi(struct kernel_queue *kq, struct kfd_dev *dev, - enum kfd_queue_type type, unsigned int queue_size) -{ - int retval; - - retval = kfd_gtt_sa_allocate(dev, PAGE_SIZE, &kq->eop_mem); - if (retval != 0) - return false; - - kq->eop_gpu_addr = kq->eop_mem->gpu_addr; - kq->eop_kernel_addr = kq->eop_mem->cpu_ptr; - - memset(kq->eop_kernel_addr, 0, PAGE_SIZE); - - return true; -} - -static void uninitialize_vi(struct kernel_queue *kq) -{ - kfd_gtt_sa_free(kq->dev, kq->eop_mem); -} - -static void submit_packet_vi(struct kernel_queue *kq) -{ - *kq->wptr_kernel = kq->pending_wptr; - write_kernel_doorbell(kq->queue->properties.doorbell_ptr, - kq->pending_wptr); -} - unsigned int pm_build_pm4_header(unsigned int opcode, size_t packet_size) { union PM4_MES_TYPE_3_HEADER header; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 060a9e8b301e4a0cfc409badc943c10c9567b489..fc61b5ec068ed0066311a905d5eb88b097b2924c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -59,24 +59,21 @@ * NOTE: struct vm_area_struct.vm_pgoff uses offset in pages. Hence, these * defines are w.r.t to PAGE_SIZE */ -#define KFD_MMAP_TYPE_SHIFT (62 - PAGE_SHIFT) +#define KFD_MMAP_TYPE_SHIFT 62 #define KFD_MMAP_TYPE_MASK (0x3ULL << KFD_MMAP_TYPE_SHIFT) #define KFD_MMAP_TYPE_DOORBELL (0x3ULL << KFD_MMAP_TYPE_SHIFT) #define KFD_MMAP_TYPE_EVENTS (0x2ULL << KFD_MMAP_TYPE_SHIFT) #define KFD_MMAP_TYPE_RESERVED_MEM (0x1ULL << KFD_MMAP_TYPE_SHIFT) #define KFD_MMAP_TYPE_MMIO (0x0ULL << KFD_MMAP_TYPE_SHIFT) -#define KFD_MMAP_GPU_ID_SHIFT (46 - PAGE_SHIFT) +#define KFD_MMAP_GPU_ID_SHIFT 46 #define KFD_MMAP_GPU_ID_MASK (((1ULL << KFD_GPU_ID_HASH_WIDTH) - 1) \ << KFD_MMAP_GPU_ID_SHIFT) #define KFD_MMAP_GPU_ID(gpu_id) ((((uint64_t)gpu_id) << KFD_MMAP_GPU_ID_SHIFT)\ & KFD_MMAP_GPU_ID_MASK) -#define KFD_MMAP_GPU_ID_GET(offset) ((offset & KFD_MMAP_GPU_ID_MASK) \ +#define KFD_MMAP_GET_GPU_ID(offset) ((offset & KFD_MMAP_GPU_ID_MASK) \ >> KFD_MMAP_GPU_ID_SHIFT) -#define KFD_MMAP_OFFSET_VALUE_MASK (0x3FFFFFFFFFFFULL >> PAGE_SHIFT) -#define KFD_MMAP_OFFSET_VALUE_GET(offset) (offset & KFD_MMAP_OFFSET_VALUE_MASK) - /* * When working with cp scheduler we should assign the HIQ manually or via * the amdgpu driver to a fixed hqd slot, here are the fixed HIQ hqd slot @@ -238,9 +235,10 @@ struct kfd_dev { * KFD. It is aligned for mapping * into user mode */ - size_t doorbell_id_offset; /* Doorbell offset (from KFD doorbell - * to HW doorbell, GFX reserved some - * at the start) + size_t doorbell_base_dw_offset; /* Offset from the start of the PCI + * doorbell BAR to the first KFD + * doorbell in dwords. GFX reserves + * the segment before this offset. */ u32 __iomem *doorbell_kernel_ptr; /* This is a pointer for a doorbells * page used by kernel queue @@ -510,8 +508,7 @@ struct queue { * Please read the kfd_mqd_manager.h description. */ enum KFD_MQD_TYPE { - KFD_MQD_TYPE_COMPUTE = 0, /* for no cp scheduling */ - KFD_MQD_TYPE_HIQ, /* for hiq */ + KFD_MQD_TYPE_HIQ = 0, /* for hiq */ KFD_MQD_TYPE_CP, /* for cp queues and diq */ KFD_MQD_TYPE_SDMA, /* for sdma queues */ KFD_MQD_TYPE_DIQ, /* for diq */ @@ -818,7 +815,7 @@ void kfd_release_kernel_doorbell(struct kfd_dev *kfd, u32 __iomem *db_addr); u32 read_kernel_doorbell(u32 __iomem *db); void write_kernel_doorbell(void __iomem *db, u32 value); void write_kernel_doorbell64(void __iomem *db, u64 value); -unsigned int kfd_doorbell_id_to_offset(struct kfd_dev *kfd, +unsigned int kfd_get_doorbell_dw_offset_in_bar(struct kfd_dev *kfd, struct kfd_process *process, unsigned int doorbell_id); phys_addr_t kfd_get_process_doorbells(struct kfd_dev *dev, @@ -904,7 +901,8 @@ int pqm_create_queue(struct process_queue_manager *pqm, struct kfd_dev *dev, struct file *f, struct queue_properties *properties, - unsigned int *qid); + unsigned int *qid, + uint32_t *p_doorbell_offset_in_process); int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid); int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid, struct queue_properties *p); @@ -972,7 +970,6 @@ struct packet_manager_funcs { extern const struct packet_manager_funcs kfd_vi_pm_funcs; extern const struct packet_manager_funcs kfd_v9_pm_funcs; -extern const struct packet_manager_funcs kfd_v10_pm_funcs; int pm_init(struct packet_manager *pm, struct device_queue_manager *dqm); void pm_uninit(struct packet_manager *pm); @@ -991,9 +988,6 @@ void pm_release_ib(struct packet_manager *pm); /* Following PM funcs can be shared among VI and AI */ unsigned int pm_build_pm4_header(unsigned int opcode, size_t packet_size); -int pm_set_resources_vi(struct packet_manager *pm, uint32_t *buffer, - struct scheduling_resources *res); - uint64_t kfd_get_number_elems(struct kfd_dev *kfd); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 10f9af5784f25b98c25eafe2534a3d64e71d9c1c..8276601a122fc727296f2014be60d635af4e9e50 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -560,8 +560,7 @@ static int kfd_process_init_cwsr_apu(struct kfd_process *p, struct file *filep) if (!dev->cwsr_enabled || qpd->cwsr_kaddr || qpd->cwsr_base) continue; - offset = (KFD_MMAP_TYPE_RESERVED_MEM | KFD_MMAP_GPU_ID(dev->id)) - << PAGE_SHIFT; + offset = KFD_MMAP_TYPE_RESERVED_MEM | KFD_MMAP_GPU_ID(dev->id); qpd->tba_addr = (int64_t)vm_mmap(filep, 0, KFD_CWSR_TBA_TMA_SIZE, PROT_READ | PROT_EXEC, MAP_SHARED, offset); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index 2659d226c0565ee8594babd3d7f0fdfbdac4bedb..1152490bbf532c4bf144b3ecea35e60bfe166e03 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -162,7 +162,7 @@ void pqm_uninit(struct process_queue_manager *pqm) pqm->queue_slot_bitmap = NULL; } -static int create_cp_queue(struct process_queue_manager *pqm, +static int init_user_queue(struct process_queue_manager *pqm, struct kfd_dev *dev, struct queue **q, struct queue_properties *q_properties, struct file *f, unsigned int qid) @@ -192,7 +192,8 @@ int pqm_create_queue(struct process_queue_manager *pqm, struct kfd_dev *dev, struct file *f, struct queue_properties *properties, - unsigned int *qid) + unsigned int *qid, + uint32_t *p_doorbell_offset_in_process) { int retval; struct kfd_process_device *pdd; @@ -250,7 +251,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, goto err_create_queue; } - retval = create_cp_queue(pqm, dev, &q, properties, f, *qid); + retval = init_user_queue(pqm, dev, &q, properties, f, *qid); if (retval != 0) goto err_create_queue; pqn->q = q; @@ -271,7 +272,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, goto err_create_queue; } - retval = create_cp_queue(pqm, dev, &q, properties, f, *qid); + retval = init_user_queue(pqm, dev, &q, properties, f, *qid); if (retval != 0) goto err_create_queue; pqn->q = q; @@ -303,12 +304,15 @@ int pqm_create_queue(struct process_queue_manager *pqm, goto err_create_queue; } - if (q) + if (q && p_doorbell_offset_in_process) /* Return the doorbell offset within the doorbell page * to the caller so it can be passed up to user mode * (in bytes). + * There are always 1024 doorbells per process, so in case + * of 8-byte doorbells, there are two doorbell pages per + * process. */ - properties->doorbell_off = + *p_doorbell_offset_in_process = (q->properties.doorbell_off * sizeof(uint32_t)) & (kfd_doorbell_process_slice(dev) - 1); diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 313183b800328c11cb7c5ec8d25a362afbe7037c..096db863c345a3cdc13679b91e4238661669867d 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-only +# SPDX-License-Identifier: MIT menu "Display Engine Configuration" depends on DRM && DRM_AMDGPU @@ -6,43 +6,16 @@ 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_DCN1_0 if X86 && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS) + select DRM_AMD_DC_DCN if X86 && !(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 Raven ASICs. -config DRM_AMD_DC_DCN1_0 +config DRM_AMD_DC_DCN def_bool n help - RV family support for display engine - -config DRM_AMD_DC_DCN2_0 - bool "DCN 2.0 family" - default y - depends on DRM_AMD_DC && X86 - depends on DRM_AMD_DC_DCN1_0 - help - Choose this option if you want to have - Navi support for display engine - -config DRM_AMD_DC_DCN2_1 - bool "DCN 2.1 family" - depends on DRM_AMD_DC && X86 - depends on DRM_AMD_DC_DCN2_0 - help - Choose this option if you want to have - Renoir support for display engine - -config DRM_AMD_DC_DSC_SUPPORT - bool "DSC support" - default y - depends on DRM_AMD_DC && X86 - depends on DRM_AMD_DC_DCN1_0 - depends on DRM_AMD_DC_DCN2_0 - help - Choose this option if you want to have - Dynamic Stream Compression support + Raven, Navi and Renoir family support for display engine config DRM_AMD_DC_HDCP bool "Enable HDCP support in DC" diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile index 36b3d6a5d04d9fea4cb5d1b5a2969ea6d7f3f91b..2633de77de5e4fe4c4e76950f2fe66a2161cf8a4 100644 --- a/drivers/gpu/drm/amd/display/Makefile +++ b/drivers/gpu/drm/amd/display/Makefile @@ -34,6 +34,8 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/freesync subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/color subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/info_packet subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/power +subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dmub/inc + ifdef CONFIG_DRM_AMD_DC_HDCP subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/hdcp endif @@ -41,7 +43,7 @@ endif #TODO: remove when Timing Sync feature is complete subdir-ccflags-y += -DBUILD_FEATURE_TIMING_SYNC=0 -DAL_LIBS = amdgpu_dm dc modules/freesync modules/color modules/info_packet modules/power +DAL_LIBS = amdgpu_dm dc modules/freesync modules/color modules/info_packet modules/power dmub/src ifdef CONFIG_DRM_AMD_DC_HDCP DAL_LIBS += modules/hdcp 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 7aac9568d3bec2a95e5ef422a567a27f970ab83d..f2db400a39204c3f257392ed3009951679a98a9d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -30,6 +30,10 @@ #include "dc.h" #include "dc/inc/core_types.h" #include "dal_asic_id.h" +#include "dmub/inc/dmub_srv.h" +#include "dc/inc/hw/dmcu.h" +#include "dc/inc/hw/abm.h" +#include "dc/dc_dmub_srv.h" #include "vid.h" #include "amdgpu.h" @@ -39,6 +43,7 @@ #include "amdgpu_dm.h" #ifdef CONFIG_DRM_AMD_DC_HDCP #include "amdgpu_dm_hdcp.h" +#include #endif #include "amdgpu_pm.h" @@ -72,7 +77,7 @@ #include #include -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) #include "ivsrcid/dcn/irqsrcs_dcn_1_0.h" #include "dcn/dcn_1_0_offset.h" @@ -87,6 +92,9 @@ #include "modules/power/power_helpers.h" #include "modules/inc/mod_info_packet.h" +#define FIRMWARE_RENOIR_DMUB "amdgpu/renoir_dmcub.bin" +MODULE_FIRMWARE(FIRMWARE_RENOIR_DMUB); + #define FIRMWARE_RAVEN_DMCU "amdgpu/raven_dmcu.bin" MODULE_FIRMWARE(FIRMWARE_RAVEN_DMCU); @@ -478,6 +486,70 @@ static void dm_crtc_high_irq(void *interrupt_params) } } +#if defined(CONFIG_DRM_AMD_DC_DCN) +/** + * dm_dcn_crtc_high_irq() - Handles VStartup interrupt for DCN generation ASICs + * @interrupt params - interrupt parameters + * + * Notify DRM's vblank event handler at VSTARTUP + * + * Unlike DCE hardware, we trigger the handler at VSTARTUP. at which: + * * We are close enough to VUPDATE - the point of no return for hw + * * We are in the fixed portion of variable front porch when vrr is enabled + * * We are before VUPDATE, where double-buffered vrr registers are swapped + * + * It is therefore the correct place to signal vblank, send user flip events, + * and update VRR. + */ +static void dm_dcn_crtc_high_irq(void *interrupt_params) +{ + struct common_irq_params *irq_params = interrupt_params; + struct amdgpu_device *adev = irq_params->adev; + struct amdgpu_crtc *acrtc; + struct dm_crtc_state *acrtc_state; + unsigned long flags; + + acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK); + + if (!acrtc) + return; + + acrtc_state = to_dm_crtc_state(acrtc->base.state); + + DRM_DEBUG_DRIVER("crtc:%d, vupdate-vrr:%d\n", acrtc->crtc_id, + amdgpu_dm_vrr_active(acrtc_state)); + + amdgpu_dm_crtc_handle_crc_irq(&acrtc->base); + drm_crtc_handle_vblank(&acrtc->base); + + spin_lock_irqsave(&adev->ddev->event_lock, flags); + + if (acrtc_state->vrr_params.supported && + acrtc_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE) { + mod_freesync_handle_v_update( + adev->dm.freesync_module, + acrtc_state->stream, + &acrtc_state->vrr_params); + + dc_stream_adjust_vmin_vmax( + adev->dm.dc, + acrtc_state->stream, + &acrtc_state->vrr_params.adjust); + } + + if (acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED) { + if (acrtc->event) { + drm_crtc_send_vblank_event(&acrtc->base, acrtc->event); + acrtc->event = NULL; + drm_crtc_vblank_put(&acrtc->base); + } + acrtc->pflip_status = AMDGPU_FLIP_NONE; + } + + spin_unlock_irqrestore(&adev->ddev->event_lock, flags); +} +#endif + static int dm_set_clockgating_state(void *handle, enum amd_clockgating_state state) { @@ -667,12 +739,151 @@ void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin) } } +static int dm_dmub_hw_init(struct amdgpu_device *adev) +{ + const unsigned int psp_header_bytes = 0x100; + const unsigned int psp_footer_bytes = 0x100; + const struct dmcub_firmware_header_v1_0 *hdr; + struct dmub_srv *dmub_srv = adev->dm.dmub_srv; + const struct firmware *dmub_fw = adev->dm.dmub_fw; + struct dmcu *dmcu = adev->dm.dc->res_pool->dmcu; + struct abm *abm = adev->dm.dc->res_pool->abm; + struct dmub_srv_region_params region_params; + struct dmub_srv_region_info region_info; + struct dmub_srv_fb_params fb_params; + struct dmub_srv_fb_info fb_info; + struct dmub_srv_hw_params hw_params; + enum dmub_status status; + const unsigned char *fw_inst_const, *fw_bss_data; + uint32_t i; + int r; + bool has_hw_support; + + if (!dmub_srv) + /* DMUB isn't supported on the ASIC. */ + return 0; + + if (!dmub_fw) { + /* Firmware required for DMUB support. */ + DRM_ERROR("No firmware provided for DMUB.\n"); + return -EINVAL; + } + + status = dmub_srv_has_hw_support(dmub_srv, &has_hw_support); + if (status != DMUB_STATUS_OK) { + DRM_ERROR("Error checking HW support for DMUB: %d\n", status); + return -EINVAL; + } + + if (!has_hw_support) { + DRM_INFO("DMUB unsupported on ASIC\n"); + return 0; + } + + hdr = (const struct dmcub_firmware_header_v1_0 *)dmub_fw->data; + + /* Calculate the size of all the regions for the DMUB service. */ + memset(®ion_params, 0, sizeof(region_params)); + + region_params.inst_const_size = le32_to_cpu(hdr->inst_const_bytes) - + psp_header_bytes - psp_footer_bytes; + region_params.bss_data_size = le32_to_cpu(hdr->bss_data_bytes); + region_params.vbios_size = adev->dm.dc->ctx->dc_bios->bios_size; + + status = dmub_srv_calc_region_info(dmub_srv, ®ion_params, + ®ion_info); + + if (status != DMUB_STATUS_OK) { + DRM_ERROR("Error calculating DMUB region info: %d\n", status); + return -EINVAL; + } + + /* + * Allocate a framebuffer based on the total size of all the regions. + * TODO: Move this into GART. + */ + r = amdgpu_bo_create_kernel(adev, region_info.fb_size, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, &adev->dm.dmub_bo, + &adev->dm.dmub_bo_gpu_addr, + &adev->dm.dmub_bo_cpu_addr); + if (r) + return r; + + /* Rebase the regions on the framebuffer address. */ + memset(&fb_params, 0, sizeof(fb_params)); + fb_params.cpu_addr = adev->dm.dmub_bo_cpu_addr; + fb_params.gpu_addr = adev->dm.dmub_bo_gpu_addr; + fb_params.region_info = ®ion_info; + + status = dmub_srv_calc_fb_info(dmub_srv, &fb_params, &fb_info); + if (status != DMUB_STATUS_OK) { + DRM_ERROR("Error calculating DMUB FB info: %d\n", status); + return -EINVAL; + } + + fw_inst_const = dmub_fw->data + + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + + psp_header_bytes; + + fw_bss_data = dmub_fw->data + + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + + le32_to_cpu(hdr->inst_const_bytes); + + /* Copy firmware and bios info into FB memory. */ + memcpy(fb_info.fb[DMUB_WINDOW_0_INST_CONST].cpu_addr, fw_inst_const, + region_params.inst_const_size); + memcpy(fb_info.fb[DMUB_WINDOW_2_BSS_DATA].cpu_addr, fw_bss_data, + region_params.bss_data_size); + memcpy(fb_info.fb[DMUB_WINDOW_3_VBIOS].cpu_addr, + adev->dm.dc->ctx->dc_bios->bios, region_params.vbios_size); + + /* Initialize hardware. */ + memset(&hw_params, 0, sizeof(hw_params)); + hw_params.fb_base = adev->gmc.fb_start; + hw_params.fb_offset = adev->gmc.aper_base; + + if (dmcu) + hw_params.psp_version = dmcu->psp_version; + + for (i = 0; i < fb_info.num_fb; ++i) + hw_params.fb[i] = &fb_info.fb[i]; + + status = dmub_srv_hw_init(dmub_srv, &hw_params); + if (status != DMUB_STATUS_OK) { + DRM_ERROR("Error initializing DMUB HW: %d\n", status); + return -EINVAL; + } + + /* Wait for firmware load to finish. */ + status = dmub_srv_wait_for_auto_load(dmub_srv, 100000); + if (status != DMUB_STATUS_OK) + DRM_WARN("Wait for DMUB auto-load failed: %d\n", status); + + /* Init DMCU and ABM if available. */ + if (dmcu && abm) { + dmcu->funcs->dmcu_init(dmcu); + abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); + } + + adev->dm.dc->ctx->dmub_srv = dc_dmub_srv_create(adev->dm.dc, dmub_srv); + if (!adev->dm.dc->ctx->dmub_srv) { + DRM_ERROR("Couldn't allocate DC DMUB server!\n"); + return -ENOMEM; + } + + DRM_INFO("DMUB hardware initialized: version=0x%08X\n", + adev->dm.dmcub_fw_version); + + return 0; +} + static int amdgpu_dm_init(struct amdgpu_device *adev) { struct dc_init_data init_data; #ifdef CONFIG_DRM_AMD_DC_HDCP struct dc_callback_init init_params; #endif + int r; adev->dm.ddev = adev->ddev; adev->dm.adev = adev; @@ -733,9 +944,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) init_data.flags.power_down_display_on_boot = true; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 init_data.soc_bounding_box = adev->dm.soc_bounding_box; -#endif /* Display Core create. */ adev->dm.dc = dc_create(&init_data); @@ -749,6 +958,12 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) dc_hardware_init(adev->dm.dc); + r = dm_dmub_hw_init(adev); + if (r) { + DRM_ERROR("DMUB interface failed to initialize: status=%d\n", r); + goto error; + } + adev->dm.freesync_module = mod_freesync_create(adev->dm.dc); if (!adev->dm.freesync_module) { DRM_ERROR( @@ -821,6 +1036,15 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev) if (adev->dm.dc) dc_deinit_callbacks(adev->dm.dc); #endif + if (adev->dm.dc->ctx->dmub_srv) { + dc_dmub_srv_destroy(&adev->dm.dc->ctx->dmub_srv); + adev->dm.dc->ctx->dmub_srv = NULL; + } + + if (adev->dm.dmub_bo) + amdgpu_bo_free_kernel(&adev->dm.dmub_bo, + &adev->dm.dmub_bo_gpu_addr, + &adev->dm.dmub_bo_cpu_addr); /* DC Destroy TODO: Replace destroy DAL */ if (adev->dm.dc) @@ -932,9 +1156,99 @@ static int load_dmcu_fw(struct amdgpu_device *adev) return 0; } +static uint32_t amdgpu_dm_dmub_reg_read(void *ctx, uint32_t address) +{ + struct amdgpu_device *adev = ctx; + + return dm_read_reg(adev->dm.dc->ctx, address); +} + +static void amdgpu_dm_dmub_reg_write(void *ctx, uint32_t address, + uint32_t value) +{ + struct amdgpu_device *adev = ctx; + + return dm_write_reg(adev->dm.dc->ctx, address, value); +} + +static int dm_dmub_sw_init(struct amdgpu_device *adev) +{ + struct dmub_srv_create_params create_params; + const struct dmcub_firmware_header_v1_0 *hdr; + const char *fw_name_dmub; + enum dmub_asic dmub_asic; + enum dmub_status status; + int r; + + switch (adev->asic_type) { + case CHIP_RENOIR: + dmub_asic = DMUB_ASIC_DCN21; + fw_name_dmub = FIRMWARE_RENOIR_DMUB; + break; + + default: + /* ASIC doesn't support DMUB. */ + return 0; + } + + adev->dm.dmub_srv = kzalloc(sizeof(*adev->dm.dmub_srv), GFP_KERNEL); + if (!adev->dm.dmub_srv) { + DRM_ERROR("Failed to allocate DMUB service!\n"); + return -ENOMEM; + } + + memset(&create_params, 0, sizeof(create_params)); + create_params.user_ctx = adev; + create_params.funcs.reg_read = amdgpu_dm_dmub_reg_read; + create_params.funcs.reg_write = amdgpu_dm_dmub_reg_write; + create_params.asic = dmub_asic; + + status = dmub_srv_create(adev->dm.dmub_srv, &create_params); + if (status != DMUB_STATUS_OK) { + DRM_ERROR("Error creating DMUB service: %d\n", status); + return -EINVAL; + } + + r = request_firmware_direct(&adev->dm.dmub_fw, fw_name_dmub, adev->dev); + if (r) { + DRM_ERROR("DMUB firmware loading failed: %d\n", r); + return 0; + } + + r = amdgpu_ucode_validate(adev->dm.dmub_fw); + if (r) { + DRM_ERROR("Couldn't validate DMUB firmware: %d\n", r); + return 0; + } + + if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) { + DRM_WARN("Only PSP firmware loading is supported for DMUB\n"); + return 0; + } + + hdr = (const struct dmcub_firmware_header_v1_0 *)adev->dm.dmub_fw->data; + adev->firmware.ucode[AMDGPU_UCODE_ID_DMCUB].ucode_id = + AMDGPU_UCODE_ID_DMCUB; + adev->firmware.ucode[AMDGPU_UCODE_ID_DMCUB].fw = adev->dm.dmub_fw; + adev->firmware.fw_size += + ALIGN(le32_to_cpu(hdr->inst_const_bytes), PAGE_SIZE); + + adev->dm.dmcub_fw_version = le32_to_cpu(hdr->header.ucode_version); + + DRM_INFO("Loading DMUB firmware via PSP: version=0x%08X\n", + adev->dm.dmcub_fw_version); + + return 0; +} + static int dm_sw_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + int r; + + r = dm_dmub_sw_init(adev); + if (r) + return r; return load_dmcu_fw(adev); } @@ -943,6 +1257,16 @@ static int dm_sw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + if (adev->dm.dmub_srv) { + dmub_srv_destroy(adev->dm.dmub_srv); + adev->dm.dmub_srv = NULL; + } + + if (adev->dm.dmub_fw) { + release_firmware(adev->dm.dmub_fw); + adev->dm.dmub_fw = NULL; + } + if(adev->dm.fw_dmcu) { release_firmware(adev->dm.fw_dmcu); adev->dm.fw_dmcu = NULL; @@ -1868,7 +2192,7 @@ static int dce110_register_irq_handlers(struct amdgpu_device *adev) return 0; } -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) /* Register IRQ sources and initialize IRQ callbacks */ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) { @@ -1914,35 +2238,7 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *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 VUPDATE_NO_LOCK interrupt on DCN, which seems to correspond to - * the regular VUPDATE interrupt on DCE. We want DC_IRQ_SOURCE_VUPDATEx - * to trigger at end of each vblank, regardless of state of the lock, - * matching DCE behaviour. - */ - for (i = DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT; - i <= DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT + adev->mode_info.num_crtc - 1; - i++) { - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->vupdate_irq); - - if (r) { - DRM_ERROR("Failed to add vupdate 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.vupdate_params[int_params.irq_source - DC_IRQ_SOURCE_VUPDATE1]; - - c_irq_params->adev = adev; - c_irq_params->irq_src = int_params.irq_source; - - amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_vupdate_high_irq, c_irq_params); + dm_dcn_crtc_high_irq, c_irq_params); } /* Use GRPH_PFLIP interrupt */ @@ -2457,16 +2753,12 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) goto fail; } break; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) case CHIP_RAVEN: -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) case CHIP_NAVI12: case CHIP_NAVI10: case CHIP_NAVI14: -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) case CHIP_RENOIR: -#endif if (dcn10_register_irq_handlers(dm->adev)) { DRM_ERROR("DM: Failed to initialize IRQ\n"); goto fail; @@ -2612,14 +2904,13 @@ static int dm_early_init(void *handle) adev->mode_info.num_hpd = 6; adev->mode_info.num_dig = 6; break; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) case CHIP_RAVEN: adev->mode_info.num_crtc = 4; adev->mode_info.num_hpd = 4; adev->mode_info.num_dig = 4; break; #endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) case CHIP_NAVI10: case CHIP_NAVI12: adev->mode_info.num_crtc = 6; @@ -2631,14 +2922,11 @@ static int dm_early_init(void *handle) adev->mode_info.num_hpd = 5; adev->mode_info.num_dig = 5; break; -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) case CHIP_RENOIR: adev->mode_info.num_crtc = 4; adev->mode_info.num_hpd = 4; adev->mode_info.num_dig = 4; break; -#endif default: DRM_ERROR("Unsupported ASIC type: 0x%X\n", adev->asic_type); return -EINVAL; @@ -2931,14 +3219,10 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev, if (adev->asic_type == CHIP_VEGA10 || adev->asic_type == CHIP_VEGA12 || adev->asic_type == CHIP_VEGA20 || -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) adev->asic_type == CHIP_NAVI10 || adev->asic_type == CHIP_NAVI14 || adev->asic_type == CHIP_NAVI12 || -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) adev->asic_type == CHIP_RENOIR || -#endif adev->asic_type == CHIP_RAVEN) { /* Fill GFX9 params */ tiling_info->gfx9.num_pipes = @@ -3256,12 +3540,26 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, static enum dc_color_depth convert_color_depth_from_display_info(const struct drm_connector *connector, - const struct drm_connector_state *state) + const struct drm_connector_state *state, + bool is_y420) { - uint8_t bpc = (uint8_t)connector->display_info.bpc; + uint8_t bpc; - /* Assume 8 bpc by default if no bpc is specified. */ - bpc = bpc ? bpc : 8; + if (is_y420) { + bpc = 8; + + /* Cap display bpc based on HDMI 2.0 HF-VSDB */ + if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48) + bpc = 16; + else if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36) + bpc = 12; + else if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) + bpc = 10; + } else { + bpc = (uint8_t)connector->display_info.bpc; + /* Assume 8 bpc by default if no bpc is specified. */ + bpc = bpc ? bpc : 8; + } if (!state) state = connector->state; @@ -3432,7 +3730,8 @@ static void fill_stream_properties_from_drm_display_mode( timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE; timing_out->display_color_depth = convert_color_depth_from_display_info( - connector, connector_state); + connector, connector_state, + (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420)); timing_out->scan_type = SCANNING_TYPE_NODATA; timing_out->hdmi_vic = 0; @@ -3644,10 +3943,10 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, bool scale = dm_state ? (dm_state->scaling != RMX_OFF) : false; int mode_refresh; int preferred_refresh = 0; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +#if defined(CONFIG_DRM_AMD_DC_DCN) struct dsc_dec_dpcd_caps dsc_caps; - uint32_t link_bandwidth_kbps; #endif + uint32_t link_bandwidth_kbps; struct dc_sink *sink = NULL; if (aconnector == NULL) { @@ -3722,16 +4021,18 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, fill_stream_properties_from_drm_display_mode(stream, &mode, &aconnector->base, con_state, old_stream); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT stream->timing.flags.DSC = 0; if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT) { +#if defined(CONFIG_DRM_AMD_DC_DCN) dc_dsc_parse_dsc_dpcd(aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw, aconnector->dc_link->dpcd_caps.dsc_caps.dsc_ext_caps.raw, &dsc_caps); +#endif link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, dc_link_get_link_cap(aconnector->dc_link)); +#if defined(CONFIG_DRM_AMD_DC_DCN) if (dsc_caps.is_dsc_supported) if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0], &dsc_caps, @@ -3740,8 +4041,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, &stream->timing, &stream->timing.dsc_cfg)) stream->timing.flags.DSC = 1; - } #endif + } update_stream_scaling_settings(&mode, dm_state, stream); @@ -3761,7 +4062,9 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, struct dmcu *dmcu = core_dc->res_pool->dmcu; stream->psr_version = dmcu->dmcu_version.psr_version; - mod_build_vsc_infopacket(stream, &stream->vsc_infopacket); + mod_build_vsc_infopacket(stream, + &stream->vsc_infopacket, + &stream->use_vsc_sdp_for_colorimetry); } } finish: @@ -3852,6 +4155,10 @@ static inline int dm_set_vupdate_irq(struct drm_crtc *crtc, bool enable) struct amdgpu_device *adev = crtc->dev->dev_private; int rc; + /* Do not set vupdate for DCN hardware */ + if (adev->family > AMDGPU_FAMILY_AI) + return 0; + irq_source = IRQ_TYPE_VUPDATE + acrtc->otg_inst; rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY; @@ -4095,7 +4402,8 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector) state->underscan_hborder = 0; state->underscan_vborder = 0; state->base.max_requested_bpc = 8; - + state->vcpi_slots = 0; + state->pbn = 0; if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) state->abm_level = amdgpu_dm_abm_level; @@ -4123,7 +4431,8 @@ amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector) new_state->underscan_enable = state->underscan_enable; new_state->underscan_hborder = state->underscan_hborder; new_state->underscan_vborder = state->underscan_vborder; - + new_state->vcpi_slots = state->vcpi_slots; + new_state->pbn = state->pbn; return &new_state->base; } @@ -4520,10 +4829,68 @@ static void dm_encoder_helper_disable(struct drm_encoder *encoder) } +static int convert_dc_color_depth_into_bpc (enum dc_color_depth display_color_depth) +{ + switch (display_color_depth) { + case COLOR_DEPTH_666: + return 6; + case COLOR_DEPTH_888: + return 8; + case COLOR_DEPTH_101010: + return 10; + case COLOR_DEPTH_121212: + return 12; + case COLOR_DEPTH_141414: + return 14; + case COLOR_DEPTH_161616: + return 16; + default: + break; + } + return 0; +} + static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { + struct drm_atomic_state *state = crtc_state->state; + struct drm_connector *connector = conn_state->connector; + struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + struct dm_connector_state *dm_new_connector_state = to_dm_connector_state(conn_state); + const struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; + struct drm_dp_mst_topology_mgr *mst_mgr; + struct drm_dp_mst_port *mst_port; + enum dc_color_depth color_depth; + int clock, bpp = 0; + bool is_y420 = false; + + if (!aconnector->port || !aconnector->dc_sink) + return 0; + + mst_port = aconnector->port; + mst_mgr = &aconnector->mst_port->mst_mgr; + + if (!crtc_state->connectors_changed && !crtc_state->mode_changed) + return 0; + + if (!state->duplicated) { + is_y420 = drm_mode_is_420_also(&connector->display_info, adjusted_mode) && + aconnector->force_yuv420_output; + color_depth = convert_color_depth_from_display_info(connector, conn_state, + is_y420); + bpp = convert_dc_color_depth_into_bpc(color_depth) * 3; + clock = adjusted_mode->clock; + dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp); + } + dm_new_connector_state->vcpi_slots = drm_dp_atomic_find_vcpi_slots(state, + mst_mgr, + mst_port, + dm_new_connector_state->pbn); + if (dm_new_connector_state->vcpi_slots < 0) { + DRM_DEBUG_ATOMIC("failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots); + return dm_new_connector_state->vcpi_slots; + } return 0; } @@ -5215,7 +5582,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, &aconnector->base); #ifdef CONFIG_DRM_AMD_DC_HDCP if (adev->asic_type >= CHIP_RAVEN) - drm_connector_attach_content_protection_property(&aconnector->base, false); + drm_connector_attach_content_protection_property(&aconnector->base, true); #endif } } @@ -5324,11 +5691,12 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, connector_type = to_drm_connector_type(link->connector_signal); - res = drm_connector_init( + res = drm_connector_init_with_ddc( dm->ddev, &aconnector->base, &amdgpu_dm_connector_funcs, - connector_type); + connector_type, + &i2c->base); if (res) { DRM_ERROR("connector_init failed\n"); @@ -5466,6 +5834,12 @@ static bool is_content_protection_different(struct drm_connector_state *state, { struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + if (old_state->hdcp_content_type != state->hdcp_content_type && + state->content_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { + state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; + return true; + } + /* CP is being re enabled, ignore this */ if (old_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED && state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) { @@ -5494,17 +5868,6 @@ static bool is_content_protection_different(struct drm_connector_state *state, return false; } -static void update_content_protection(struct drm_connector_state *state, const struct drm_connector *connector, - struct hdcp_workqueue *hdcp_w) -{ - struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); - - if (state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) - hdcp_add_display(hdcp_w, aconnector->dc_link->link_index, aconnector); - else if (state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) - hdcp_remove_display(hdcp_w, aconnector->dc_link->link_index, aconnector->base.index); - -} #endif static void remove_stream(struct amdgpu_device *adev, struct amdgpu_crtc *acrtc, @@ -6474,7 +6837,11 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) } if (is_content_protection_different(new_con_state, old_con_state, connector, adev->dm.hdcp_workqueue)) - update_content_protection(new_con_state, connector, adev->dm.hdcp_workqueue); + hdcp_update_display( + adev->dm.hdcp_workqueue, aconnector->dc_link->link_index, aconnector, + new_con_state->hdcp_content_type, + new_con_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED ? true + : false); } #endif @@ -7264,7 +7631,7 @@ dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm, 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, *old_plane_crtc; + struct drm_crtc *new_plane_crtc; struct drm_plane *plane; struct drm_crtc *crtc; @@ -7310,7 +7677,6 @@ dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm, uint64_t tiling_flags; new_plane_crtc = new_plane_state->crtc; - old_plane_crtc = old_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); @@ -7566,6 +7932,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, if (ret) goto fail; + /* Perform validation of MST topology in the state*/ + ret = drm_dp_mst_atomic_check(state); + if (ret) + goto fail; + if (state->legacy_cursor_update) { /* * This is a fast cursor update coming from the plane update 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 77c5166e6b08263683c48019e230af612e580e32..a8fc90a927d64499af9dc38390d1f122178b437c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -57,6 +57,8 @@ struct amdgpu_device; struct drm_device; struct amdgpu_dm_irq_handler_data; struct dc; +struct amdgpu_bo; +struct dmub_srv; struct common_irq_params { struct amdgpu_device *adev; @@ -121,6 +123,50 @@ struct amdgpu_display_manager { struct dc *dc; + /** + * @dmub_srv: + * + * DMUB service, used for controlling the DMUB on hardware + * that supports it. The pointer to the dmub_srv will be + * NULL on hardware that does not support it. + */ + struct dmub_srv *dmub_srv; + + /** + * @dmub_fw: + * + * DMUB firmware, required on hardware that has DMUB support. + */ + const struct firmware *dmub_fw; + + /** + * @dmub_bo: + * + * Buffer object for the DMUB. + */ + struct amdgpu_bo *dmub_bo; + + /** + * @dmub_bo_gpu_addr: + * + * GPU virtual address for the DMUB buffer object. + */ + u64 dmub_bo_gpu_addr; + + /** + * @dmub_bo_cpu_addr: + * + * CPU address for the DMUB buffer object. + */ + void *dmub_bo_cpu_addr; + + /** + * @dmcub_fw_version: + * + * DMCUB firmware version. + */ + uint32_t dmcub_fw_version; + /** * @cgs_device: * @@ -241,7 +287,6 @@ struct amdgpu_display_manager { const struct firmware *fw_dmcu; uint32_t dmcu_fw_version; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 /** * @soc_bounding_box: * @@ -249,7 +294,6 @@ struct amdgpu_display_manager { * available in FW */ const struct gpu_info_soc_bounding_box_v1_0 *soc_bounding_box; -#endif }; struct amdgpu_dm_connector { @@ -359,6 +403,8 @@ struct dm_connector_state { bool underscan_enable; bool freesync_capable; uint8_t abm_level; + int vcpi_slots; + uint64_t pbn; }; #define to_dm_connector_state(x)\ 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 bdb37e611015fa1ff7def78c7140aa518be436a6..f81d3439ee8cb4b60ec97a6cb8539b9519bf72b0 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 @@ -657,6 +657,7 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us dc_link_set_test_pattern( link, test_pattern, + DP_TEST_PATTERN_COLOR_SPACE_RGB, &link_training_settings, custom_pattern, 10); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c index 77181ddf6c8e3bb3dfb9b3b5845d1ab301be7e74..ae329335dfcc7aa9ce3e8204e918737fb00c30b5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c @@ -85,42 +85,54 @@ static void process_output(struct hdcp_workqueue *hdcp_work) schedule_delayed_work(&hdcp_work->watchdog_timer_dwork, msecs_to_jiffies(output.watchdog_timer_delay)); + schedule_delayed_work(&hdcp_work->property_validate_dwork, msecs_to_jiffies(0)); } -void hdcp_add_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index, struct amdgpu_dm_connector *aconnector) +void hdcp_update_display(struct hdcp_workqueue *hdcp_work, + unsigned int link_index, + struct amdgpu_dm_connector *aconnector, + uint8_t content_type, + bool enable_encryption) { struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index]; struct mod_hdcp_display *display = &hdcp_work[link_index].display; struct mod_hdcp_link *link = &hdcp_work[link_index].link; + struct mod_hdcp_display_query query; mutex_lock(&hdcp_w->mutex); hdcp_w->aconnector = aconnector; - mod_hdcp_add_display(&hdcp_w->hdcp, link, display, &hdcp_w->output); - - schedule_delayed_work(&hdcp_w->property_validate_dwork, msecs_to_jiffies(DRM_HDCP_CHECK_PERIOD_MS)); - - process_output(hdcp_w); + query.display = NULL; + mod_hdcp_query_display(&hdcp_w->hdcp, aconnector->base.index, &query); - mutex_unlock(&hdcp_w->mutex); + if (query.display != NULL) { + memcpy(display, query.display, sizeof(struct mod_hdcp_display)); + mod_hdcp_remove_display(&hdcp_w->hdcp, aconnector->base.index, &hdcp_w->output); -} + hdcp_w->link.adjust.hdcp2.force_type = MOD_HDCP_FORCE_TYPE_0; -void hdcp_remove_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index, unsigned int display_index) -{ - struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index]; + if (enable_encryption) { + display->adjust.disable = 0; + if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0) + hdcp_w->link.adjust.hdcp2.force_type = MOD_HDCP_FORCE_TYPE_0; + else if (content_type == DRM_MODE_HDCP_CONTENT_TYPE1) + hdcp_w->link.adjust.hdcp2.force_type = MOD_HDCP_FORCE_TYPE_1; - mutex_lock(&hdcp_w->mutex); + schedule_delayed_work(&hdcp_w->property_validate_dwork, + msecs_to_jiffies(DRM_HDCP_CHECK_PERIOD_MS)); + } else { + display->adjust.disable = 1; + hdcp_w->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; + cancel_delayed_work(&hdcp_w->property_validate_dwork); + } - mod_hdcp_remove_display(&hdcp_w->hdcp, display_index, &hdcp_w->output); + display->state = MOD_HDCP_DISPLAY_ACTIVE; + } - cancel_delayed_work(&hdcp_w->property_validate_dwork); - hdcp_w->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; + mod_hdcp_add_display(&hdcp_w->hdcp, link, display, &hdcp_w->output); process_output(hdcp_w); - mutex_unlock(&hdcp_w->mutex); - } void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index) @@ -190,10 +202,16 @@ static void event_property_update(struct work_struct *work) } } - if (hdcp_work->encryption_status == MOD_HDCP_ENCRYPTION_STATUS_HDCP1_ON) - drm_hdcp_update_content_protection(&aconnector->base, DRM_MODE_CONTENT_PROTECTION_ENABLED); - else + if (hdcp_work->encryption_status != MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF) { + if (aconnector->base.state->hdcp_content_type == DRM_MODE_HDCP_CONTENT_TYPE0 && + hdcp_work->encryption_status <= MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON) + drm_hdcp_update_content_protection(&aconnector->base, DRM_MODE_CONTENT_PROTECTION_ENABLED); + else if (aconnector->base.state->hdcp_content_type == DRM_MODE_HDCP_CONTENT_TYPE1 && + hdcp_work->encryption_status == MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON) + drm_hdcp_update_content_protection(&aconnector->base, DRM_MODE_CONTENT_PROTECTION_ENABLED); + } else { drm_hdcp_update_content_protection(&aconnector->base, DRM_MODE_CONTENT_PROTECTION_DESIRED); + } mutex_unlock(&hdcp_work->mutex); @@ -207,6 +225,9 @@ static void event_property_validate(struct work_struct *work) struct mod_hdcp_display_query query; struct amdgpu_dm_connector *aconnector = hdcp_work->aconnector; + if (!aconnector) + return; + mutex_lock(&hdcp_work->mutex); query.encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; @@ -217,8 +238,6 @@ static void event_property_validate(struct work_struct *work) schedule_work(&hdcp_work->property_update_work); } - schedule_delayed_work(&hdcp_work->property_validate_dwork, msecs_to_jiffies(DRM_HDCP_CHECK_PERIOD_MS)); - mutex_unlock(&hdcp_work->mutex); } @@ -294,8 +313,10 @@ static void update_config(void *handle, struct cp_psp_stream_config *config) link->dig_be = config->link_enc_inst; link->ddc_line = aconnector->dc_link->ddc_hw_inst + 1; link->dp.rev = aconnector->dc_link->dpcd_caps.dpcd_rev.raw; - link->adjust.hdcp2.disable = 1; + display->adjust.disable = 1; + link->adjust.auth_delay = 2; + hdcp_update_display(hdcp_work, link_index, aconnector, DRM_MODE_HDCP_CONTENT_TYPE0, false); } struct hdcp_workqueue *hdcp_create_workqueue(void *psp_context, struct cp_psp *cp_psp, struct dc *dc) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h index d3ba505d0696ad69283d1d5c7ce9e0f9c382a281..6abde86bce4aaeb36b994f43b26df42f6e45aa55 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h @@ -54,9 +54,12 @@ struct hdcp_workqueue { uint8_t max_link; }; -void hdcp_add_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index, - struct amdgpu_dm_connector *aconnector); -void hdcp_remove_display(struct hdcp_workqueue *work, unsigned int link_index, unsigned int display_index); +void hdcp_update_display(struct hdcp_workqueue *hdcp_work, + unsigned int link_index, + struct amdgpu_dm_connector *aconnector, + uint8_t content_type, + bool enable_encryption); + void hdcp_reset_display(struct hdcp_workqueue *work, unsigned int link_index); void hdcp_handle_cpirq(struct hdcp_workqueue *work, unsigned int link_index); void hdcp_destroy(struct hdcp_workqueue *work); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 11e5784aa62a15cc2d66b0270c9d7dda99e2e2a8..66f266a5e10bf177f4c1bc16a21b20b880a84e7e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -97,8 +97,6 @@ enum dc_edid_status dm_helpers_parse_edid_caps( (struct edid *) edid->raw_edid); sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads); - if (sad_count < 0) - DRM_ERROR("Couldn't read SADs: %d\n", sad_count); if (sad_count <= 0) return result; @@ -182,19 +180,22 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( bool enable) { struct amdgpu_dm_connector *aconnector; + struct dm_connector_state *dm_conn_state; struct drm_dp_mst_topology_mgr *mst_mgr; struct drm_dp_mst_port *mst_port; - int slots = 0; bool ret; - int clock; - int bpp = 0; - int pbn = 0; aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; + /* Accessing the connector state is required for vcpi_slots allocation + * and directly relies on behaviour in commit check + * that blocks before commit guaranteeing that the state + * is not gonna be swapped while still in use in commit tail */ if (!aconnector || !aconnector->mst_port) return false; + dm_conn_state = to_dm_connector_state(aconnector->base.state); + mst_mgr = &aconnector->mst_port->mst_mgr; if (!mst_mgr->mst_state) @@ -203,42 +204,10 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( mst_port = aconnector->port; if (enable) { - clock = stream->timing.pix_clk_100hz / 10; - - switch (stream->timing.display_color_depth) { - - case COLOR_DEPTH_666: - bpp = 6; - break; - case COLOR_DEPTH_888: - bpp = 8; - break; - case COLOR_DEPTH_101010: - bpp = 10; - break; - case COLOR_DEPTH_121212: - bpp = 12; - break; - case COLOR_DEPTH_141414: - bpp = 14; - break; - case COLOR_DEPTH_161616: - bpp = 16; - break; - default: - ASSERT(bpp != 0); - break; - } - - bpp = bpp * 3; - - /* TODO need to know link rate */ - - pbn = drm_dp_calc_pbn_mode(clock, bpp); - - slots = drm_dp_find_vcpi_slots(mst_mgr, pbn); - ret = drm_dp_mst_allocate_vcpi(mst_mgr, mst_port, pbn, slots); + ret = drm_dp_mst_allocate_vcpi(mst_mgr, mst_port, + dm_conn_state->pbn, + dm_conn_state->vcpi_slots); if (!ret) return false; @@ -540,7 +509,6 @@ bool dm_helpers_submit_i2c( return result; } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT bool dm_helpers_dp_write_dsc_enable( struct dc_context *ctx, const struct dc_stream_state *stream, @@ -551,7 +519,6 @@ bool dm_helpers_dp_write_dsc_enable( return dm_helpers_dp_write_dpcd(ctx, stream->sink->link, DP_DSC_ENABLE, &enable_dsc, 1); } -#endif bool dm_helpers_is_dp_sink_present(struct dc_link *link) { 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 2bf8534c18fbedf0f246718942226eb3beccb67b..81367c869134d2c390699bec19c2b0ce019376de 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 @@ -254,11 +254,43 @@ dm_dp_mst_detect(struct drm_connector *connector, aconnector->port); } +static int dm_dp_mst_atomic_check(struct drm_connector *connector, + struct drm_atomic_state *state) +{ + struct drm_connector_state *new_conn_state = + drm_atomic_get_new_connector_state(state, connector); + struct drm_connector_state *old_conn_state = + drm_atomic_get_old_connector_state(state, connector); + struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + struct drm_crtc_state *new_crtc_state; + struct drm_dp_mst_topology_mgr *mst_mgr; + struct drm_dp_mst_port *mst_port; + + mst_port = aconnector->port; + mst_mgr = &aconnector->mst_port->mst_mgr; + + if (!old_conn_state->crtc) + return 0; + + if (new_conn_state->crtc) { + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc); + if (!new_crtc_state || + !drm_atomic_crtc_needs_modeset(new_crtc_state) || + new_crtc_state->enable) + return 0; + } + + return drm_dp_atomic_release_vcpi_slots(state, + mst_mgr, + mst_port); +} + static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs = { .get_modes = dm_dp_mst_get_modes, .mode_valid = amdgpu_dm_connector_mode_valid, .atomic_best_encoder = dm_mst_atomic_best_encoder, .detect_ctx = dm_dp_mst_detect, + .atomic_check = dm_dp_mst_atomic_check, }; static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c index 778f186b3a05e5c45c6474913685ba3372e30123..a2e1a73f66b81d68ce19267a8f365f03778013e4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -892,7 +892,6 @@ enum pp_smu_status pp_nv_get_uclk_dpm_states(struct pp_smu *pp, return PP_SMU_RESULT_FAIL; } -#ifdef CONFIG_DRM_AMD_DC_DCN2_1 enum pp_smu_status pp_rn_get_dpm_clock_table( struct pp_smu *pp, struct dpm_clocks *clock_table) { @@ -974,7 +973,6 @@ enum pp_smu_status pp_rn_set_wm_ranges(struct pp_smu *pp, return PP_SMU_RESULT_OK; } -#endif void dm_pp_get_funcs( struct dc_context *ctx, @@ -996,7 +994,6 @@ void dm_pp_get_funcs( funcs->rv_funcs.set_hard_min_fclk_by_freq = pp_rv_set_hard_min_fclk_by_freq; break; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 case DCN_VERSION_2_0: funcs->ctx.ver = PP_SMU_VER_NV; funcs->nv_funcs.pp_smu.dm = ctx; @@ -1019,16 +1016,13 @@ void dm_pp_get_funcs( funcs->nv_funcs.get_uclk_dpm_states = pp_nv_get_uclk_dpm_states; funcs->nv_funcs.set_pstate_handshake_support = pp_nv_set_pstate_handshake_support; break; -#endif -#ifdef CONFIG_DRM_AMD_DC_DCN2_1 case DCN_VERSION_2_1: funcs->ctx.ver = PP_SMU_VER_RN; funcs->rn_funcs.pp_smu.dm = ctx; funcs->rn_funcs.set_wm_ranges = pp_rn_set_wm_ranges; funcs->rn_funcs.get_dpm_clock_table = pp_rn_get_dpm_clock_table; break; -#endif default: DRM_ERROR("smu version is not supported !\n"); break; diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index a160512a2f04d59e0140f01c9497e1d6556dde92..6e3dddc73246ddf7277512a3af4f233e1f06fde6 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -25,19 +25,10 @@ DC_LIBS = basics bios calcs clk_mgr dce gpio irq virtual -ifdef CONFIG_DRM_AMD_DC_DCN2_0 +ifdef CONFIG_DRM_AMD_DC_DCN DC_LIBS += dcn20 -endif - - -ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT DC_LIBS += dsc -endif - -ifdef CONFIG_DRM_AMD_DC_DCN1_0 DC_LIBS += dcn10 dml -endif -ifdef CONFIG_DRM_AMD_DC_DCN2_1 DC_LIBS += dcn21 endif @@ -59,7 +50,7 @@ include $(AMD_DC) DISPLAY_CORE = dc.o dc_link.o dc_resource.o dc_hw_sequencer.o dc_sink.o \ dc_surface.o dc_link_hwss.o dc_link_dp.o dc_link_ddc.o dc_debug.o dc_stream.o -ifdef CONFIG_DRM_AMD_DC_DCN2_0 +ifdef CONFIG_DRM_AMD_DC_DCN DISPLAY_CORE += dc_vm_helper.o endif @@ -70,5 +61,6 @@ AMD_DM_REG_UPDATE = $(addprefix $(AMDDALPATH)/dc/,dc_helper.o) AMD_DISPLAY_FILES += $(AMD_DISPLAY_CORE) AMD_DISPLAY_FILES += $(AMD_DM_REG_UPDATE) - - +DC_DMUB += dc_dmub_srv.o +AMD_DISPLAY_DMUB = $(addprefix $(AMDDALPATH)/dc/,$(DC_DMUB)) +AMD_DISPLAY_FILES += $(AMD_DISPLAY_DMUB) diff --git a/drivers/gpu/drm/amd/display/dc/basics/Makefile b/drivers/gpu/drm/amd/display/dc/basics/Makefile index a50a76471107eb768613239f984cbe9384ed628a..7ad0cad0f4efedd9fcec850d18b13c596872f21e 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/Makefile +++ b/drivers/gpu/drm/amd/display/dc/basics/Makefile @@ -25,7 +25,7 @@ # subcomponents. BASICS = conversion.o fixpt31_32.o \ - log_helpers.o vector.o + log_helpers.o vector.o dc_common.o AMD_DAL_BASICS = $(addprefix $(AMDDALPATH)/dc/basics/,$(BASICS)) diff --git a/drivers/gpu/drm/amd/display/dc/basics/dc_common.c b/drivers/gpu/drm/amd/display/dc/basics/dc_common.c new file mode 100644 index 0000000000000000000000000000000000000000..b2fc4f8e64825086855b28a11099312f2d06e5f8 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/basics/dc_common.c @@ -0,0 +1,101 @@ +/* + * Copyright 2012-15 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: AMD + * + */ + +#include "core_types.h" +#include "dc_common.h" +#include "basics/conversion.h" + +bool is_rgb_cspace(enum dc_color_space output_color_space) +{ + switch (output_color_space) { + case COLOR_SPACE_SRGB: + case COLOR_SPACE_SRGB_LIMITED: + case COLOR_SPACE_2020_RGB_FULLRANGE: + case COLOR_SPACE_2020_RGB_LIMITEDRANGE: + case COLOR_SPACE_ADOBERGB: + return true; + case COLOR_SPACE_YCBCR601: + case COLOR_SPACE_YCBCR709: + case COLOR_SPACE_YCBCR601_LIMITED: + case COLOR_SPACE_YCBCR709_LIMITED: + case COLOR_SPACE_2020_YCBCR: + return false; + default: + /* Add a case to switch */ + BREAK_TO_DEBUGGER(); + return false; + } +} + +bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx) +{ + if (pipe_ctx->plane_state && pipe_ctx->plane_state->visible) + return true; + if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe)) + return true; + return false; +} + +bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx) +{ + if (pipe_ctx->plane_state && pipe_ctx->plane_state->visible) + return true; + if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe)) + return true; + return false; +} + +bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx) +{ + if (pipe_ctx->plane_state && pipe_ctx->plane_state->visible) + return true; + if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe)) + return true; + if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe)) + return true; + return false; +} + +void build_prescale_params(struct dc_bias_and_scale *bias_and_scale, + const struct dc_plane_state *plane_state) +{ + if (plane_state->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN + && plane_state->format != SURFACE_PIXEL_FORMAT_INVALID + && plane_state->input_csc_color_matrix.enable_adjustment + && plane_state->coeff_reduction_factor.value != 0) { + bias_and_scale->scale_blue = fixed_point_to_int_frac( + dc_fixpt_mul(plane_state->coeff_reduction_factor, + dc_fixpt_from_fraction(256, 255)), + 2, + 13); + bias_and_scale->scale_red = bias_and_scale->scale_blue; + bias_and_scale->scale_green = bias_and_scale->scale_blue; + } else { + bias_and_scale->scale_blue = 0x2000; + bias_and_scale->scale_red = 0x2000; + bias_and_scale->scale_green = 0x2000; + } +} + diff --git a/drivers/gpu/drm/amd/display/dc/basics/dc_common.h b/drivers/gpu/drm/amd/display/dc/basics/dc_common.h new file mode 100644 index 0000000000000000000000000000000000000000..7c0cbf47e8cebabb05244a00f7f8b121fd78dc1a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/basics/dc_common.h @@ -0,0 +1,42 @@ +/* + * Copyright 2012-15 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: AMD + * + */ + +#ifndef __DAL_DC_COMMON_H__ +#define __DAL_DC_COMMON_H__ + +#include "core_types.h" + +bool is_rgb_cspace(enum dc_color_space output_color_space); + +bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx); + +bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx); + +bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx); + +void build_prescale_params(struct dc_bias_and_scale *bias_and_scale, + const struct dc_plane_state *plane_state); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index 823843cd261339a3d200d5f2884c98c8a7d442ab..008d4d11339d9056fe93d962503d267b4439457d 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -111,7 +111,7 @@ struct dc_bios *bios_parser_create( return NULL; } -static void destruct(struct bios_parser *bp) +static void bios_parser_destruct(struct bios_parser *bp) { kfree(bp->base.bios_local_image); kfree(bp->base.integrated_info); @@ -126,7 +126,7 @@ static void bios_parser_destroy(struct dc_bios **dcb) return; } - destruct(bp); + bios_parser_destruct(bp); kfree(bp); *dcb = NULL; @@ -2189,7 +2189,7 @@ static uint32_t get_support_mask_for_device_id(struct device_id device_id) break; default: break; - }; + } /* Unidentified device ID, return empty support mask. */ return 0; @@ -2739,7 +2739,6 @@ static enum bp_result bios_get_board_layout_info( struct board_layout_info *board_layout_info) { unsigned int i; - struct bios_parser *bp; enum bp_result record_result; const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = { @@ -2748,7 +2747,6 @@ static enum bp_result bios_get_board_layout_info( 0, 0 }; - bp = BP_FROM_DCB(dcb); if (board_layout_info == NULL) { DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n"); return BP_RESULT_BADINPUT; diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index 7873abea4112b434d0d1def2f5d3634aae0a9f23..2f1c9584ac32d5c03cd999a50fdf69cc52dffc4b 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -111,7 +111,7 @@ static struct atom_encoder_caps_record *get_encoder_cap_record( #define DATA_TABLES(table) (bp->master_data_tbl->listOfdatatables.table) -static void destruct(struct bios_parser *bp) +static void bios_parser2_destruct(struct bios_parser *bp) { kfree(bp->base.bios_local_image); kfree(bp->base.integrated_info); @@ -126,7 +126,7 @@ static void firmware_parser_destroy(struct dc_bios **dcb) return; } - destruct(bp); + bios_parser2_destruct(bp); kfree(bp); *dcb = NULL; @@ -294,11 +294,21 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb, struct atom_display_object_path_v2 *object; struct atom_common_record_header *header; struct atom_i2c_record *record; + struct atom_i2c_record dummy_record = {0}; struct bios_parser *bp = BP_FROM_DCB(dcb); if (!info) return BP_RESULT_BADINPUT; + if (id.type == OBJECT_TYPE_GENERIC) { + dummy_record.i2c_id = id.id; + + if (get_gpio_i2c_info(bp, &dummy_record, info) == BP_RESULT_OK) + return BP_RESULT_OK; + else + return BP_RESULT_NORECORD; + } + object = get_bios_object(bp, id); if (!object) @@ -341,6 +351,7 @@ static enum bp_result get_gpio_i2c_info( struct atom_gpio_pin_lut_v2_1 *header; uint32_t count = 0; unsigned int table_index = 0; + bool find_valid = false; if (!info) return BP_RESULT_BADINPUT; @@ -368,33 +379,28 @@ static enum bp_result get_gpio_i2c_info( - sizeof(struct atom_common_table_header)) / sizeof(struct atom_gpio_pin_assignment); - table_index = record->i2c_id & I2C_HW_LANE_MUX; - - if (count < table_index) { - bool find_valid = false; - - for (table_index = 0; table_index < count; table_index++) { - if (((record->i2c_id & I2C_HW_CAP) == ( - header->gpio_pin[table_index].gpio_id & - I2C_HW_CAP)) && - ((record->i2c_id & I2C_HW_ENGINE_ID_MASK) == - (header->gpio_pin[table_index].gpio_id & - I2C_HW_ENGINE_ID_MASK)) && - ((record->i2c_id & I2C_HW_LANE_MUX) == - (header->gpio_pin[table_index].gpio_id & - I2C_HW_LANE_MUX))) { - /* still valid */ - find_valid = true; - break; - } + for (table_index = 0; table_index < count; table_index++) { + if (((record->i2c_id & I2C_HW_CAP) == ( + header->gpio_pin[table_index].gpio_id & + I2C_HW_CAP)) && + ((record->i2c_id & I2C_HW_ENGINE_ID_MASK) == + (header->gpio_pin[table_index].gpio_id & + I2C_HW_ENGINE_ID_MASK)) && + ((record->i2c_id & I2C_HW_LANE_MUX) == + (header->gpio_pin[table_index].gpio_id & + I2C_HW_LANE_MUX))) { + /* still valid */ + find_valid = true; + break; } - /* If we don't find the entry that we are looking for then - * we will return BP_Result_BadBiosTable. - */ - if (find_valid == false) - return BP_RESULT_BADBIOSTABLE; } + /* If we don't find the entry that we are looking for then + * we will return BP_Result_BadBiosTable. + */ + if (find_valid == false) + return BP_RESULT_BADBIOSTABLE; + /* get the GPIO_I2C_INFO */ info->i2c_hw_assist = (record->i2c_id & I2C_HW_CAP) ? true : false; info->i2c_line = record->i2c_id & I2C_HW_LANE_MUX; @@ -828,6 +834,7 @@ static enum bp_result bios_parser_get_spread_spectrum_info( case 1: return get_ss_info_v4_1(bp, signal, index, ss_info); case 2: + case 3: return get_ss_info_v4_2(bp, signal, index, ss_info); default: break; @@ -986,7 +993,7 @@ static uint32_t get_support_mask_for_device_id(struct device_id device_id) break; default: break; - }; + } /* Unidentified device ID, return empty support mask. */ return 0; @@ -1205,6 +1212,8 @@ static enum bp_result get_firmware_info_v3_1( bp->cmd_tbl.get_smu_clock_info(bp, SMU9_SYSPLL0_ID) * 10; } + info->oem_i2c_present = false; + return BP_RESULT_OK; } @@ -1283,6 +1292,13 @@ static enum bp_result get_firmware_info_v3_2( bp->cmd_tbl.get_smu_clock_info(bp, SMU11_SYSPLL3_0_ID) * 10; } + if (firmware_info->board_i2c_feature_id == 0x2) { + info->oem_i2c_present = true; + info->oem_i2c_obj_id = firmware_info->board_i2c_feature_gpio_id; + } else { + info->oem_i2c_present = false; + } + return BP_RESULT_OK; } @@ -1402,10 +1418,8 @@ static enum bp_result get_integrated_info_v11( info->ma_channel_number = info_v11->umachannelnumber; info->lvds_ss_percentage = le16_to_cpu(info_v11->lvds_ss_percentage); -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 info->dp_ss_control = le16_to_cpu(info_v11->reserved1); -#endif info->lvds_sspread_rate_in_10hz = le16_to_cpu(info_v11->lvds_ss_rate_10hz); info->hdmi_ss_percentage = @@ -1625,6 +1639,7 @@ static enum bp_result construct_integrated_info( /* Don't need to check major revision as they are all 1 */ switch (revision.minor) { case 11: + case 12: result = get_integrated_info_v11(bp, info); break; default: @@ -1825,7 +1840,6 @@ static enum bp_result bios_get_board_layout_info( struct board_layout_info *board_layout_info) { unsigned int i; - struct bios_parser *bp; enum bp_result record_result; const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = { @@ -1834,7 +1848,6 @@ static enum bp_result bios_get_board_layout_info( 0, 0 }; - bp = BP_FROM_DCB(dcb); if (board_layout_info == NULL) { DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n"); return BP_RESULT_BADINPUT; @@ -1914,7 +1927,7 @@ static const struct dc_vbios_funcs vbios_funcs = { .get_board_layout_info = bios_get_board_layout_info, }; -static bool bios_parser_construct( +static bool bios_parser2_construct( struct bios_parser *bp, struct bp_init_data *init, enum dce_version dce_version) @@ -2007,7 +2020,7 @@ struct dc_bios *firmware_parser_create( if (!bp) return NULL; - if (bios_parser_construct(bp, init, dce_version)) + if (bios_parser2_construct(bp, init, dce_version)) return &bp->base; kfree(bp); 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 bb2e8105e6aba12229a87e51cbafeafc2d15b42b..2cb7a4288cb7840d943606254d7800294a52ea8a 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -37,6 +37,8 @@ #include "bios_parser_types_internal2.h" #include "amdgpu.h" +#include "dc_dmub_srv.h" +#include "dc.h" #define DC_LOGGER \ bp->base.ctx->logger @@ -103,6 +105,21 @@ static void init_dig_encoder_control(struct bios_parser *bp) } } +static void encoder_control_dmcub( + struct dc_dmub_srv *dmcub, + struct dig_encoder_stream_setup_parameters_v1_5 *dig) +{ + struct dmub_rb_cmd_digx_encoder_control encoder_control = { 0 }; + + encoder_control.header.type = DMUB_CMD__VBIOS; + encoder_control.header.sub_type = DMUB_CMD__VBIOS_DIGX_ENCODER_CONTROL; + encoder_control.encoder_control.dig.stream_param = *dig; + + dc_dmub_srv_cmd_queue(dmcub, &encoder_control.header); + dc_dmub_srv_cmd_execute(dmcub); + dc_dmub_srv_wait_idle(dmcub); +} + static enum bp_result encoder_control_digx_v1_5( struct bios_parser *bp, struct bp_encoder_control *cntl) @@ -155,6 +172,12 @@ static enum bp_result encoder_control_digx_v1_5( break; } + if (bp->base.ctx->dc->ctx->dmub_srv && + bp->base.ctx->dc->debug.dmub_command_table) { + encoder_control_dmcub(bp->base.ctx->dmub_srv, ¶ms); + return BP_RESULT_OK; + } + if (EXEC_BIOS_CMD_TABLE(digxencodercontrol, params)) result = BP_RESULT_OK; @@ -191,6 +214,22 @@ static void init_transmitter_control(struct bios_parser *bp) } } +static void transmitter_control_dmcub( + struct dc_dmub_srv *dmcub, + struct dig_transmitter_control_parameters_v1_6 *dig) +{ + struct dmub_rb_cmd_dig1_transmitter_control transmitter_control; + + transmitter_control.header.type = DMUB_CMD__VBIOS; + transmitter_control.header.sub_type = + DMUB_CMD__VBIOS_DIG1_TRANSMITTER_CONTROL; + transmitter_control.transmitter_control.dig = *dig; + + dc_dmub_srv_cmd_queue(dmcub, &transmitter_control.header); + dc_dmub_srv_cmd_execute(dmcub); + dc_dmub_srv_wait_idle(dmcub); +} + static enum bp_result transmitter_control_v1_6( struct bios_parser *bp, struct bp_transmitter_control *cntl) @@ -222,6 +261,11 @@ static enum bp_result transmitter_control_v1_6( __func__, ps.param.symclk_10khz); } + if (bp->base.ctx->dc->ctx->dmub_srv && + bp->base.ctx->dc->debug.dmub_command_table) { + transmitter_control_dmcub(bp->base.ctx->dmub_srv, &ps.param); + return BP_RESULT_OK; + } /*color_depth not used any more, driver has deep color factor in the Phyclk*/ if (EXEC_BIOS_CMD_TABLE(dig1transmittercontrol, ps)) @@ -255,7 +299,20 @@ static void init_set_pixel_clock(struct bios_parser *bp) } } +static void set_pixel_clock_dmcub( + struct dc_dmub_srv *dmcub, + struct set_pixel_clock_parameter_v1_7 *clk) +{ + struct dmub_rb_cmd_set_pixel_clock pixel_clock = { 0 }; + + pixel_clock.header.type = DMUB_CMD__VBIOS; + pixel_clock.header.sub_type = DMUB_CMD__VBIOS_SET_PIXEL_CLOCK; + pixel_clock.pixel_clock.clk = *clk; + dc_dmub_srv_cmd_queue(dmcub, &pixel_clock.header); + dc_dmub_srv_cmd_execute(dmcub); + dc_dmub_srv_wait_idle(dmcub); +} static enum bp_result set_pixel_clock_v7( struct bios_parser *bp, @@ -331,6 +388,12 @@ static enum bp_result set_pixel_clock_v7( if (bp_params->signal_type == SIGNAL_TYPE_DVI_DUAL_LINK) clk.miscinfo |= PIXEL_CLOCK_V7_MISC_DVI_DUALLINK_EN; + if (bp->base.ctx->dc->ctx->dmub_srv && + bp->base.ctx->dc->debug.dmub_command_table) { + set_pixel_clock_dmcub(bp->base.ctx->dmub_srv, &clk); + return BP_RESULT_OK; + } + if (EXEC_BIOS_CMD_TABLE(setpixelclock, clk)) result = BP_RESULT_OK; } @@ -585,6 +648,21 @@ static void init_enable_disp_power_gating( } } +static void enable_disp_power_gating_dmcub( + struct dc_dmub_srv *dmcub, + struct enable_disp_power_gating_parameters_v2_1 *pwr) +{ + struct dmub_rb_cmd_enable_disp_power_gating power_gating; + + power_gating.header.type = DMUB_CMD__VBIOS; + power_gating.header.sub_type = DMUB_CMD__VBIOS_ENABLE_DISP_POWER_GATING; + power_gating.power_gating.pwr = *pwr; + + dc_dmub_srv_cmd_queue(dmcub, &power_gating.header); + dc_dmub_srv_cmd_execute(dmcub); + dc_dmub_srv_wait_idle(dmcub); +} + static enum bp_result enable_disp_power_gating_v2_1( struct bios_parser *bp, enum controller_id crtc_id, @@ -604,6 +682,13 @@ static enum bp_result enable_disp_power_gating_v2_1( ps.param.enable = bp->cmd_helper->disp_power_gating_action_to_atom(action); + if (bp->base.ctx->dc->ctx->dmub_srv && + bp->base.ctx->dc->debug.dmub_command_table) { + enable_disp_power_gating_dmcub(bp->base.ctx->dmub_srv, + &ps.param); + return BP_RESULT_OK; + } + if (EXEC_BIOS_CMD_TABLE(enabledisppowergating, ps.param)) result = BP_RESULT_OK; 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 db153ddf0fee0363e71f6737af9fe5c31d5ae9f2..7388c987c595ad39df328e3958d052686bdcea4e 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 @@ -55,23 +55,19 @@ bool dal_bios_parser_init_cmd_tbl_helper2( case DCE_VERSION_11_22: *h = dal_cmd_tbl_helper_dce112_get_table2(); return true; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) case DCN_VERSION_1_0: case DCN_VERSION_1_01: *h = dal_cmd_tbl_helper_dce112_get_table2(); return true; #endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) case DCN_VERSION_2_0: *h = dal_cmd_tbl_helper_dce112_get_table2(); return true; -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) case DCN_VERSION_2_1: *h = dal_cmd_tbl_helper_dce112_get_table2(); return true; -#endif case DCE_VERSION_12_0: case DCE_VERSION_12_1: *h = dal_cmd_tbl_helper_dce112_get_table2(); diff --git a/drivers/gpu/drm/amd/display/dc/calcs/Makefile b/drivers/gpu/drm/amd/display/dc/calcs/Makefile index 26c6d735cdc78523af4d6186ac05c50cf7845512..d0714a3d63c8dd09ef096120d3e09a2027126d62 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/Makefile +++ b/drivers/gpu/drm/amd/display/dc/calcs/Makefile @@ -47,7 +47,7 @@ CFLAGS_$(AMDDALPATH)/dc/calcs/dcn_calc_math.o := $(calcs_ccflags) -Wno-tautologi BW_CALCS = dce_calcs.o bw_fixed.o custom_float.o -ifdef CONFIG_DRM_AMD_DC_DCN1_0 +ifdef CONFIG_DRM_AMD_DC_DCN BW_CALCS += dcn_calcs.o dcn_calc_math.o dcn_calc_auto.o endif diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 9b2cb57bf2bada07c7ab9b8988ac0b548c4e3a1d..a4ddd657598f5b78c0be7a3a728878f406f8774d 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -53,13 +53,9 @@ * remain as-is as it provides us with a guarantee from HW that it is correct. */ -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 /* Defaults from spreadsheet rev#247. * RV2 delta: dram_clock_change_latency, max_num_dpp */ -#else -/* Defaults from spreadsheet rev#247 */ -#endif const struct dcn_soc_bounding_box dcn10_soc_defaults = { /* latencies */ .sr_exit_time = 17, /*us*/ diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile index b864869cc7e3e16ef66b8d97282dc00621d65578..3cd2831950919e82bad51ad38797c3b7fa930c7e 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile @@ -63,7 +63,7 @@ CLK_MGR_DCE120 = dce120_clk_mgr.o AMD_DAL_CLK_MGR_DCE120 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dce120/,$(CLK_MGR_DCE120)) AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCE120) -ifdef CONFIG_DRM_AMD_DC_DCN1_0 +ifdef CONFIG_DRM_AMD_DC_DCN ############################################################################### # DCN10 ############################################################################### @@ -72,9 +72,7 @@ CLK_MGR_DCN10 = rv1_clk_mgr.o rv1_clk_mgr_vbios_smu.o rv2_clk_mgr.o AMD_DAL_CLK_MGR_DCN10 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn10/,$(CLK_MGR_DCN10)) AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN10) -endif -ifdef CONFIG_DRM_AMD_DC_DCN2_0 ############################################################################### # DCN20 ############################################################################### @@ -83,9 +81,7 @@ CLK_MGR_DCN20 = dcn20_clk_mgr.o AMD_DAL_CLK_MGR_DCN20 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn20/,$(CLK_MGR_DCN20)) AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN20) -endif -ifdef CONFIG_DRM_AMD_DC_DCN2_1 ############################################################################### # 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 8828dd9c3783537d95f5e024cbe9b243aaa481eb..6d60ef82261929bff810c677badc597fb32dcca0 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 @@ -37,9 +37,7 @@ #include "dcn10/rv1_clk_mgr.h" #include "dcn10/rv2_clk_mgr.h" #include "dcn20/dcn20_clk_mgr.h" -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) #include "dcn21/rn_clk_mgr.h" -#endif int clk_mgr_helper_get_active_display_cnt( @@ -134,14 +132,19 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p dce120_clk_mgr_construct(ctx, clk_mgr); break; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) case FAMILY_RV: -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + if (ASICREV_IS_DALI(asic_id.hw_internal_rev)) { + /* TEMP: this check has to come before ASICREV_IS_RENOIR */ + /* which also incorrectly returns true for Dali */ + rv2_clk_mgr_construct(ctx, clk_mgr, pp_smu); + break; + } + if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev)) { rn_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg); break; } -#endif /* DCN2_1 */ if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev)) { rv2_clk_mgr_construct(ctx, clk_mgr, pp_smu); break; @@ -152,13 +155,11 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p break; } break; -#endif /* Family RV */ -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) case FAMILY_NV: dcn20_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg); break; -#endif /* Family NV */ +#endif /* Family RV and NV*/ default: ASSERT(0); /* Unknown Asic */ diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce112/dce112_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce112/dce112_clk_mgr.c index a6c46e903ff92ce52e4402b0eabec85e715c54cc..d031bd3d3072497d7fb8605714461e70eb1710ea 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce112/dce112_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce112/dce112_clk_mgr.c @@ -72,8 +72,8 @@ int dce112_set_clock(struct clk_mgr *clk_mgr_base, int requested_clk_khz) struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base); struct bp_set_dce_clock_parameters dce_clk_params; struct dc_bios *bp = clk_mgr_base->ctx->dc_bios; - struct dc *core_dc = clk_mgr_base->ctx->dc; - struct dmcu *dmcu = core_dc->res_pool->dmcu; + struct dc *dc = clk_mgr_base->ctx->dc; + struct dmcu *dmcu = dc->res_pool->dmcu; int actual_clock = requested_clk_khz; /* Prepare to program display clock*/ memset(&dce_clk_params, 0, sizeof(dce_clk_params)); @@ -110,7 +110,7 @@ int dce112_set_clock(struct clk_mgr *clk_mgr_base, int requested_clk_khz) bp->funcs->set_dce_clock(bp, &dce_clk_params); - if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) { if (clk_mgr_dce->dfs_bypass_disp_clk != actual_clock) dmcu->funcs->set_psr_wait_loop(dmcu, @@ -126,8 +126,8 @@ int dce112_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_clk_khz) { struct bp_set_dce_clock_parameters dce_clk_params; struct dc_bios *bp = clk_mgr->base.ctx->dc_bios; - struct dc *core_dc = clk_mgr->base.ctx->dc; - struct dmcu *dmcu = core_dc->res_pool->dmcu; + struct dc *dc = clk_mgr->base.ctx->dc; + struct dmcu *dmcu = dc->res_pool->dmcu; int actual_clock = requested_clk_khz; /* Prepare to program display clock*/ memset(&dce_clk_params, 0, sizeof(dce_clk_params)); @@ -152,7 +152,7 @@ int dce112_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_clk_khz) clk_mgr->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL; - if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) { if (clk_mgr->dfs_bypass_disp_clk != actual_clock) dmcu->funcs->set_psr_wait_loop(dmcu, diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr_vbios_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr_vbios_smu.c index 1897e91c8ccbe5587efa050004ca724fea5a37ab..97b7f32294fd85943b916505e76f5f8adb4bb0f2 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr_vbios_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr_vbios_smu.c @@ -88,8 +88,8 @@ int rv1_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned int rv1_vbios_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz) { int actual_dispclk_set_mhz = -1; - struct dc *core_dc = clk_mgr->base.ctx->dc; - struct dmcu *dmcu = core_dc->res_pool->dmcu; + struct dc *dc = clk_mgr->base.ctx->dc; + struct dmcu *dmcu = dc->res_pool->dmcu; /* Unit of SMU msg parameter is Mhz */ actual_dispclk_set_mhz = rv1_vbios_smu_send_msg_with_param( @@ -100,7 +100,7 @@ int rv1_vbios_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_di /* Actual dispclk set is returned in the parameter register */ actual_dispclk_set_mhz = REG_READ(MP1_SMN_C2PMSG_83) * 1000; - if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) { if (clk_mgr->dfs_bypass_disp_clk != actual_dispclk_set_mhz) dmcu->funcs->set_psr_wait_loop(dmcu, diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c index 790a2d211bd6db21a6a04cccd4c7bc9cad0f4a60..de51ef12e33a37aa9665e5a3c5a24bb118811b4b 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c @@ -471,12 +471,28 @@ static void rn_notify_wm_ranges(struct clk_mgr *clk_mgr_base) } +static bool rn_are_clock_states_equal(struct dc_clocks *a, + struct dc_clocks *b) +{ + if (a->dispclk_khz != b->dispclk_khz) + return false; + else if (a->dppclk_khz != b->dppclk_khz) + return false; + else if (a->dcfclk_khz != b->dcfclk_khz) + return false; + else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz) + return false; + + return true; +} + + static struct clk_mgr_funcs dcn21_funcs = { .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .update_clocks = rn_update_clocks, .init_clocks = rn_init_clocks, .enable_pme_wa = rn_enable_pme_wa, - /* .dump_clk_registers = rn_dump_clk_registers, */ + .are_clock_states_equal = rn_are_clock_states_equal, .notify_wm_ranges = rn_notify_wm_ranges }; @@ -518,36 +534,83 @@ struct clk_bw_params rn_bw_params = { .num_entries = 4, }, - .wm_table = { - .entries = { - { - .wm_inst = WM_A, - .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 23.84, - .valid = true, - }, - { - .wm_inst = WM_B, - .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 23.84, - .valid = true, - }, - { - .wm_inst = WM_C, - .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 23.84, - .valid = true, - }, - { - .wm_inst = WM_D, - .wm_type = WM_TYPE_PSTATE_CHG, - .pstate_latency_us = 23.84, - .valid = true, - }, +}; + +struct wm_table ddr4_wm_table = { + .entries = { + { + .wm_inst = WM_A, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.72, + .sr_exit_time_us = 6.09, + .sr_enter_plus_exit_time_us = 7.14, + .valid = true, + }, + { + .wm_inst = WM_B, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.72, + .sr_exit_time_us = 10.12, + .sr_enter_plus_exit_time_us = 11.48, + .valid = true, + }, + { + .wm_inst = WM_C, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.72, + .sr_exit_time_us = 10.12, + .sr_enter_plus_exit_time_us = 11.48, + .valid = true, + }, + { + .wm_inst = WM_D, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.72, + .sr_exit_time_us = 10.12, + .sr_enter_plus_exit_time_us = 11.48, + .valid = true, }, } }; +struct wm_table lpddr4_wm_table = { + .entries = { + { + .wm_inst = WM_A, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, + .sr_exit_time_us = 5.32, + .sr_enter_plus_exit_time_us = 6.38, + .valid = true, + }, + { + .wm_inst = WM_B, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, + .sr_exit_time_us = 9.82, + .sr_enter_plus_exit_time_us = 11.196, + .valid = true, + }, + { + .wm_inst = WM_C, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, + .sr_exit_time_us = 9.89, + .sr_enter_plus_exit_time_us = 11.24, + .valid = true, + }, + { + .wm_inst = WM_D, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 11.65333, + .sr_exit_time_us = 9.748, + .sr_enter_plus_exit_time_us = 11.102, + .valid = true, + }, + } +}; + + static unsigned int find_dcfclk_for_voltage(struct dpm_clocks *clock_table, unsigned int voltage) { int i; @@ -561,7 +624,7 @@ static unsigned int find_dcfclk_for_voltage(struct dpm_clocks *clock_table, unsi return 0; } -static void rn_clk_mgr_helper_populate_bw_params(struct clk_bw_params *bw_params, struct dpm_clocks *clock_table, struct hw_asic_id *asic_id) +static void rn_clk_mgr_helper_populate_bw_params(struct clk_bw_params *bw_params, struct dpm_clocks *clock_table, struct integrated_info *bios_info) { int i, j = 0; @@ -593,8 +656,8 @@ static void rn_clk_mgr_helper_populate_bw_params(struct clk_bw_params *bw_params bw_params->clk_table.entries[i].dcfclk_mhz = find_dcfclk_for_voltage(clock_table, clock_table->FClocks[j].Vol); } - bw_params->vram_type = asic_id->vram_type; - bw_params->num_channels = asic_id->vram_width / DDR4_DRAM_WIDTH; + bw_params->vram_type = bios_info->memory_type; + bw_params->num_channels = bios_info->ma_channel_number; for (i = 0; i < WM_SET_COUNT; i++) { bw_params->wm_table.entries[i].wm_inst = i; @@ -628,7 +691,6 @@ void rn_clk_mgr_construct( { struct dc_debug_options *debug = &ctx->dc->debug; struct dpm_clocks clock_table = { 0 }; - struct clk_state_registers_and_bypass s = { 0 }; clk_mgr->base.ctx = ctx; clk_mgr->base.funcs = &dcn21_funcs; @@ -648,7 +710,6 @@ void rn_clk_mgr_construct( if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) { dcn21_funcs.update_clocks = dcn2_update_clocks_fpga; clk_mgr->base.dentist_vco_freq_khz = 3600000; - clk_mgr->base.dprefclk_khz = 600000; } else { struct clk_log_info log_info = {0}; @@ -659,25 +720,26 @@ void rn_clk_mgr_construct( if (clk_mgr->base.dentist_vco_freq_khz == 0) clk_mgr->base.dentist_vco_freq_khz = 3600000; - rn_dump_clk_registers(&s, &clk_mgr->base, &log_info); - /* Convert dprefclk units from MHz to KHz */ - /* Value already divided by 10, some resolution lost */ - clk_mgr->base.dprefclk_khz = s.dprefclk * 1000; - - /* in case we don't get a value from the register, use default */ - if (clk_mgr->base.dprefclk_khz == 0) { - ASSERT(clk_mgr->base.dprefclk_khz == 600000); - clk_mgr->base.dprefclk_khz = 600000; + if (ctx->dc_bios->integrated_info->memory_type == LpDdr4MemType) { + rn_bw_params.wm_table = lpddr4_wm_table; + } else { + rn_bw_params.wm_table = ddr4_wm_table; } + /* Saved clocks configured at boot for debug purposes */ + rn_dump_clk_registers(&clk_mgr->base.boot_snapshot, &clk_mgr->base, &log_info); } + clk_mgr->base.dprefclk_khz = 600000; dce_clock_read_ss_info(clk_mgr); + clk_mgr->base.bw_params = &rn_bw_params; if (pp_smu && pp_smu->rn_funcs.get_dpm_clock_table) { pp_smu->rn_funcs.get_dpm_clock_table(&pp_smu->rn_funcs.pp_smu, &clock_table); - rn_clk_mgr_helper_populate_bw_params(clk_mgr->base.bw_params, &clock_table, &ctx->asic_id); + if (ctx->dc_bios && ctx->dc_bios->integrated_info) { + rn_clk_mgr_helper_populate_bw_params (clk_mgr->base.bw_params, &clock_table, ctx->dc_bios->integrated_info); + } } if (!IS_FPGA_MAXIMUS_DC(ctx->dce_environment) && clk_mgr->smu_ver >= 0x00371500) { diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c index cb7c0e8b7e1b01379b591ac757a8f915bb38dcf6..6878aedf1d3e7e923fa9485f276028bbd2e78abe 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c @@ -82,8 +82,8 @@ int rn_vbios_smu_get_smu_version(struct clk_mgr_internal *clk_mgr) int rn_vbios_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz) { int actual_dispclk_set_mhz = -1; - struct dc *core_dc = clk_mgr->base.ctx->dc; - struct dmcu *dmcu = core_dc->res_pool->dmcu; + struct dc *dc = clk_mgr->base.ctx->dc; + struct dmcu *dmcu = dc->res_pool->dmcu; /* Unit of SMU msg parameter is Mhz */ actual_dispclk_set_mhz = rn_vbios_smu_send_msg_with_param( @@ -91,7 +91,7 @@ int rn_vbios_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dis VBIOSSMC_MSG_SetDispclkFreq, requested_dispclk_khz / 1000); - if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) { if (clk_mgr->dfs_bypass_disp_clk != actual_dispclk_set_mhz) dmcu->funcs->set_psr_wait_loop(dmcu, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 32f31bf91915194f52447f30e766fc92e221b8d6..39fe38cb39b6e44b0bc5b7ca7cebe86334fba4dd 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -58,21 +58,18 @@ #include "hubp.h" #include "dc_link_dp.h" +#include "dc_dmub_srv.h" -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #include "dsc.h" -#endif -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 #include "vm_helper.h" -#endif #include "dce/dce_i2c.h" #define DC_LOGGER \ dc->ctx->logger -const static char DC_BUILD_ID[] = "production-build"; +static const char DC_BUILD_ID[] = "production-build"; /** * DOC: Overview @@ -536,7 +533,7 @@ void dc_stream_set_static_screen_events(struct dc *dc, dc->hwss.set_static_screen_control(pipes_affected, num_pipes_affected, events); } -static void destruct(struct dc *dc) +static void dc_destruct(struct dc *dc) { if (dc->current_state) { dc_release_state(dc->current_state); @@ -569,7 +566,7 @@ static void destruct(struct dc *dc) kfree(dc->bw_dceip); dc->bw_dceip = NULL; -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_DRM_AMD_DC_DCN kfree(dc->dcn_soc); dc->dcn_soc = NULL; @@ -577,20 +574,18 @@ static void destruct(struct dc *dc) dc->dcn_ip = NULL; #endif -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 kfree(dc->vm_helper); dc->vm_helper = NULL; -#endif } -static bool construct(struct dc *dc, +static bool dc_construct(struct dc *dc, const struct dc_init_data *init_params) { struct dc_context *dc_ctx; struct bw_calcs_dceip *dc_dceip; struct bw_calcs_vbios *dc_vbios; -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_DRM_AMD_DC_DCN struct dcn_soc_bounding_box *dcn_soc; struct dcn_ip_params *dcn_ip; #endif @@ -598,7 +593,6 @@ static bool construct(struct dc *dc, enum dce_version dc_version = DCE_VERSION_UNKNOWN; dc->config = init_params->flags; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 // Allocate memory for the vm_helper dc->vm_helper = kzalloc(sizeof(struct vm_helper), GFP_KERNEL); if (!dc->vm_helper) { @@ -606,7 +600,6 @@ static bool construct(struct dc *dc, goto fail; } -#endif memcpy(&dc->bb_overrides, &init_params->bb_overrides, sizeof(dc->bb_overrides)); dc_dceip = kzalloc(sizeof(*dc_dceip), GFP_KERNEL); @@ -624,7 +617,7 @@ static bool construct(struct dc *dc, } dc->bw_vbios = dc_vbios; -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_DRM_AMD_DC_DCN dcn_soc = kzalloc(sizeof(*dcn_soc), GFP_KERNEL); if (!dcn_soc) { dm_error("%s: failed to create dcn_soc\n", __func__); @@ -640,9 +633,7 @@ static bool construct(struct dc *dc, } dc->dcn_ip = dcn_ip; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 dc->soc_bounding_box = init_params->soc_bounding_box; -#endif #endif dc_ctx = kzalloc(sizeof(*dc_ctx), GFP_KERNEL); @@ -714,10 +705,8 @@ static bool construct(struct dc *dc, if (!dc->clk_mgr) goto fail; -#ifdef CONFIG_DRM_AMD_DC_DCN2_1 if (dc->res_pool->funcs->update_bw_bounding_box) dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params); -#endif /* Creation of current_state must occur after dc->dml * is initialized in dc_create_resource_pool because @@ -740,11 +729,10 @@ static bool construct(struct dc *dc, fail: - destruct(dc); + dc_destruct(dc); return false; } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) static bool disable_all_writeback_pipes_for_stream( const struct dc *dc, struct dc_stream_state *stream, @@ -757,7 +745,6 @@ static bool disable_all_writeback_pipes_for_stream( return true; } -#endif static void disable_dangling_plane(struct dc *dc, struct dc_state *context) { @@ -783,16 +770,12 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context) } if (should_disable && old_stream) { dc_rem_all_planes_for_stream(dc, old_stream, dangling_context); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) disable_all_writeback_pipes_for_stream(dc, old_stream, dangling_context); -#endif if (dc->hwss.apply_ctx_for_surface) dc->hwss.apply_ctx_for_surface(dc, old_stream, 0, dangling_context); } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) if (dc->hwss.program_front_end_for_ctx) dc->hwss.program_front_end_for_ctx(dc, dangling_context); -#endif } current_ctx = dc->current_state; @@ -812,7 +795,7 @@ struct dc *dc_create(const struct dc_init_data *init_params) if (NULL == dc) goto alloc_fail; - if (false == construct(dc, init_params)) + if (false == dc_construct(dc, init_params)) goto construct_fail; full_pipe_count = dc->res_pool->pipe_count; @@ -826,6 +809,8 @@ struct dc *dc_create(const struct dc_init_data *init_params) dc->caps.max_audios = dc->res_pool->audio_count; dc->caps.linear_pitch_alignment = 64; + dc->caps.max_dp_protocol_version = DP_VERSION_1_4; + /* Populate versioning information */ dc->versions.dc_ver = DC_VER; @@ -869,7 +854,7 @@ void dc_deinit_callbacks(struct dc *dc) void dc_destroy(struct dc **dc) { - destruct(*dc); + dc_destruct(*dc); kfree(*dc); *dc = NULL; } @@ -1182,10 +1167,6 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c context->stream_status[i].plane_count, context); /* use new pipe config in new context */ } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) - if (dc->hwss.program_front_end_for_ctx) - dc->hwss.program_front_end_for_ctx(dc, context); -#endif /* Program hardware */ for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -1204,10 +1185,8 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c } /* Program all planes within new context*/ -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) if (dc->hwss.program_front_end_for_ctx) dc->hwss.program_front_end_for_ctx(dc, context); -#endif for (i = 0; i < context->stream_count; i++) { const struct dc_link *link = context->streams[i]->link; @@ -1245,6 +1224,10 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c dc_enable_stereo(dc, context, dc_streams, context->stream_count); + if (!dc->optimize_seamless_boot) + /* pplib is notified if disp_num changed */ + dc->hwss.optimize_bandwidth(dc, context); + for (i = 0; i < context->stream_count; i++) context->streams[i]->mode_changed = false; @@ -1313,7 +1296,7 @@ struct dc_state *dc_create_state(struct dc *dc) * initialize and obtain IP and SOC the base DML instance from DC is * initially copied into every context */ -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_DRM_AMD_DC_DCN memcpy(&context->bw_ctx.dml, &dc->dml, sizeof(struct display_mode_lib)); #endif @@ -1486,11 +1469,6 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa elevate_update_type(&update_type, UPDATE_TYPE_MED); } - if (u->plane_info->sdr_white_level != u->surface->sdr_white_level) { - update_flags->bits.sdr_white_level = 1; - elevate_update_type(&update_type, UPDATE_TYPE_MED); - } - if (u->plane_info->dcc.enable != u->surface->dcc.enable || u->plane_info->dcc.independent_64b_blks != u->surface->dcc.independent_64b_blks || u->plane_info->dcc.meta_pitch != u->surface->dcc.meta_pitch) { @@ -1508,7 +1486,6 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa } if (u->plane_info->plane_size.surface_pitch != u->surface->plane_size.surface_pitch - || u->plane_info->plane_size.surface_pitch != u->surface->plane_size.surface_pitch || u->plane_info->plane_size.chroma_pitch != u->surface->plane_size.chroma_pitch) { update_flags->bits.plane_size_change = 1; elevate_update_type(&update_type, UPDATE_TYPE_MED); @@ -1547,7 +1524,10 @@ static enum surface_update_type get_scaling_info_update_type( if (u->scaling_info->clip_rect.width != u->surface->clip_rect.width || u->scaling_info->clip_rect.height != u->surface->clip_rect.height || u->scaling_info->dst_rect.width != u->surface->dst_rect.width - || u->scaling_info->dst_rect.height != u->surface->dst_rect.height) { + || u->scaling_info->dst_rect.height != u->surface->dst_rect.height + || u->scaling_info->scaling_quality.integer_scaling != + u->surface->scaling_quality.integer_scaling + ) { update_flags->bits.scaling_change = 1; if ((u->scaling_info->dst_rect.width < u->surface->dst_rect.width @@ -1635,6 +1615,12 @@ static enum surface_update_type det_surface_update(const struct dc *dc, update_flags->bits.gamma_change = 1; } + if (u->hdr_mult.value) + if (u->hdr_mult.value != u->surface->hdr_mult.value) { + update_flags->bits.hdr_mult = 1; + elevate_update_type(&overall_type, UPDATE_TYPE_MED); + } + if (update_flags->bits.in_transfer_func_change) { type = UPDATE_TYPE_MED; elevate_update_type(&overall_type, type); @@ -1668,7 +1654,8 @@ static enum surface_update_type check_update_surfaces_for_stream( union stream_update_flags *su_flags = &stream_update->stream->update_flags; if ((stream_update->src.height != 0 && stream_update->src.width != 0) || - (stream_update->dst.height != 0 && stream_update->dst.width != 0)) + (stream_update->dst.height != 0 && stream_update->dst.width != 0) || + stream_update->integer_scaling_update) su_flags->bits.scaling = 1; if (stream_update->out_transfer_func) @@ -1683,15 +1670,16 @@ static enum surface_update_type check_update_surfaces_for_stream( if (stream_update->gamut_remap) su_flags->bits.gamut_remap = 1; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) if (stream_update->wb_update) su_flags->bits.wb_update = 1; -#endif if (su_flags->raw != 0) overall_type = UPDATE_TYPE_FULL; if (stream_update->output_csc_transform || stream_update->output_color_space) su_flags->bits.out_csc = 1; + + if (stream_update->dsc_config) + overall_type = UPDATE_TYPE_FULL; } for (i = 0 ; i < surface_count; i++) { @@ -1817,8 +1805,6 @@ static void copy_surface_update_to_plane( srf_update->plane_info->global_alpha_value; surface->dcc = srf_update->plane_info->dcc; - surface->sdr_white_level = - srf_update->plane_info->sdr_white_level; surface->layer_index = srf_update->plane_info->layer_index; } @@ -1851,7 +1837,6 @@ static void copy_surface_update_to_plane( sizeof(struct dc_transfer_func_distributed_points)); } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) if (srf_update->func_shaper && (surface->in_shaper_func != srf_update->func_shaper)) @@ -1864,13 +1849,16 @@ static void copy_surface_update_to_plane( memcpy(surface->lut3d_func, srf_update->lut3d_func, sizeof(*surface->lut3d_func)); + if (srf_update->hdr_mult.value) + surface->hdr_mult = + srf_update->hdr_mult; + if (srf_update->blend_tf && (surface->blend_tf != srf_update->blend_tf)) memcpy(surface->blend_tf, srf_update->blend_tf, sizeof(*surface->blend_tf)); -#endif if (srf_update->input_csc_color_matrix) surface->input_csc_color_matrix = *srf_update->input_csc_color_matrix; @@ -1883,8 +1871,10 @@ static void copy_surface_update_to_plane( static void copy_stream_update_to_stream(struct dc *dc, struct dc_state *context, struct dc_stream_state *stream, - const struct dc_stream_update *update) + struct dc_stream_update *update) { + struct dc_context *dc_ctx = dc->ctx; + if (update == NULL || stream == NULL) return; @@ -1945,7 +1935,6 @@ static void copy_stream_update_to_stream(struct dc *dc, if (update->dither_option) stream->dither_option = *update->dither_option; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) /* update current stream with writeback info */ if (update->wb_update) { int i; @@ -1956,23 +1945,32 @@ static void copy_stream_update_to_stream(struct dc *dc, stream->writeback_info[i] = update->wb_update->writeback_info[i]; } -#endif -#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT) if (update->dsc_config) { struct dc_dsc_config old_dsc_cfg = stream->timing.dsc_cfg; uint32_t old_dsc_enabled = stream->timing.flags.DSC; uint32_t enable_dsc = (update->dsc_config->num_slices_h != 0 && update->dsc_config->num_slices_v != 0); - stream->timing.dsc_cfg = *update->dsc_config; - stream->timing.flags.DSC = enable_dsc; - if (!dc->res_pool->funcs->validate_bandwidth(dc, context, - true)) { - stream->timing.dsc_cfg = old_dsc_cfg; - stream->timing.flags.DSC = old_dsc_enabled; + /* Use temporarry context for validating new DSC config */ + struct dc_state *dsc_validate_context = dc_create_state(dc); + + if (dsc_validate_context) { + dc_resource_state_copy_construct(dc->current_state, dsc_validate_context); + + stream->timing.dsc_cfg = *update->dsc_config; + stream->timing.flags.DSC = enable_dsc; + if (!dc->res_pool->funcs->validate_bandwidth(dc, dsc_validate_context, true)) { + stream->timing.dsc_cfg = old_dsc_cfg; + stream->timing.flags.DSC = old_dsc_enabled; + update->dsc_config = NULL; + } + + dc_release_state(dsc_validate_context); + } else { + DC_ERROR("Failed to allocate new validate context for DSC change\n"); + update->dsc_config = NULL; } } -#endif } static void commit_planes_do_stream_update(struct dc *dc, @@ -1992,11 +1990,11 @@ static void commit_planes_do_stream_update(struct dc *dc, if (stream_update->periodic_interrupt0 && dc->hwss.setup_periodic_interrupt) - dc->hwss.setup_periodic_interrupt(pipe_ctx, VLINE0); + dc->hwss.setup_periodic_interrupt(dc, pipe_ctx, VLINE0); if (stream_update->periodic_interrupt1 && dc->hwss.setup_periodic_interrupt) - dc->hwss.setup_periodic_interrupt(pipe_ctx, VLINE1); + dc->hwss.setup_periodic_interrupt(dc, pipe_ctx, VLINE1); if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) || stream_update->vrr_infopacket || @@ -2006,6 +2004,12 @@ static void commit_planes_do_stream_update(struct dc *dc, dc->hwss.update_info_frame(pipe_ctx); } + if (stream_update->hdr_static_metadata && + stream->use_dynamic_meta && + dc->hwss.set_dmdata_attributes && + pipe_ctx->stream->dmdata_address.quad_part != 0) + dc->hwss.set_dmdata_attributes(pipe_ctx); + if (stream_update->gamut_remap) dc_stream_set_gamut_remap(dc, stream); @@ -2013,31 +2017,25 @@ static void commit_planes_do_stream_update(struct dc *dc, dc_stream_program_csc_matrix(dc, stream); if (stream_update->dither_option) { -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; -#endif resource_build_bit_depth_reduction_params(pipe_ctx->stream, &pipe_ctx->stream->bit_depth_params); pipe_ctx->stream_res.opp->funcs->opp_program_fmt(pipe_ctx->stream_res.opp, &stream->bit_depth_params, &stream->clamping); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) while (odm_pipe) { odm_pipe->stream_res.opp->funcs->opp_program_fmt(odm_pipe->stream_res.opp, &stream->bit_depth_params, &stream->clamping); odm_pipe = odm_pipe->next_odm_pipe; } -#endif } -#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT) if (stream_update->dsc_config && dc->hwss.pipe_control_lock_global) { dc->hwss.pipe_control_lock_global(dc, pipe_ctx, true); dp_update_dsc_config(pipe_ctx); dc->hwss.pipe_control_lock_global(dc, pipe_ctx, false); } -#endif /* Full fe update*/ if (update_type == UPDATE_TYPE_FAST) continue; @@ -2124,15 +2122,12 @@ static void commit_planes_for_stream(struct dc *dc, */ if (dc->hwss.apply_ctx_for_surface) dc->hwss.apply_ctx_for_surface(dc, stream, 0, context); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) if (dc->hwss.program_front_end_for_ctx) dc->hwss.program_front_end_for_ctx(dc, context); -#endif return; } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) if (!IS_DIAG_DC(dc->ctx->dce_environment)) { for (i = 0; i < surface_count; i++) { struct dc_plane_state *plane_state = srf_updates[i].surface; @@ -2154,7 +2149,6 @@ static void commit_planes_for_stream(struct dc *dc, } } } -#endif // Update Type FULL, Surface updates for (j = 0; j < dc->res_pool->pipe_count; j++) { @@ -2175,7 +2169,6 @@ static void commit_planes_for_stream(struct dc *dc, if (update_type == UPDATE_TYPE_FAST) continue; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) ASSERT(!pipe_ctx->plane_state->triplebuffer_flips); if (dc->hwss.program_triplebuffer != NULL && @@ -2184,7 +2177,6 @@ static void commit_planes_for_stream(struct dc *dc, dc->hwss.program_triplebuffer( dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips); } -#endif stream_status = stream_get_status(context, pipe_ctx->stream); @@ -2193,10 +2185,24 @@ static void commit_planes_for_stream(struct dc *dc, dc, pipe_ctx->stream, stream_status->plane_count, context); } } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) - if (dc->hwss.program_front_end_for_ctx && update_type != UPDATE_TYPE_FAST) + if (dc->hwss.program_front_end_for_ctx && update_type != UPDATE_TYPE_FAST) { dc->hwss.program_front_end_for_ctx(dc, context); +#ifdef CONFIG_DRM_AMD_DC_DCN + if (dc->debug.validate_dml_output) { + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx cur_pipe = context->res_ctx.pipe_ctx[i]; + if (cur_pipe.stream == NULL) + continue; + + cur_pipe.plane_res.hubp->funcs->validate_dml_output( + cur_pipe.plane_res.hubp, dc->ctx, + &context->res_ctx.pipe_ctx[i].rq_regs, + &context->res_ctx.pipe_ctx[i].dlg_regs, + &context->res_ctx.pipe_ctx[i].ttu_regs); + } + } #endif + } // Update Type FAST, Surface updates if (update_type == UPDATE_TYPE_FAST) { @@ -2206,7 +2212,6 @@ static void commit_planes_for_stream(struct dc *dc, */ dc->hwss.pipe_control_lock(dc, top_pipe_to_program, true); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) if (dc->hwss.set_flip_control_gsl) for (i = 0; i < surface_count; i++) { struct dc_plane_state *plane_state = srf_updates[i].surface; @@ -2225,7 +2230,6 @@ static void commit_planes_for_stream(struct dc *dc, plane_state->flip_immediate); } } -#endif /* Perform requested Updates */ for (i = 0; i < surface_count; i++) { struct dc_plane_state *plane_state = srf_updates[i].surface; @@ -2238,7 +2242,6 @@ static void commit_planes_for_stream(struct dc *dc, if (pipe_ctx->plane_state != plane_state) continue; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) /*program triple buffer after lock based on flip type*/ if (dc->hwss.program_triplebuffer != NULL && !dc->debug.disable_tri_buf) { @@ -2246,7 +2249,6 @@ static void commit_planes_for_stream(struct dc *dc, dc->hwss.program_triplebuffer( dc, pipe_ctx, plane_state->triplebuffer_flips); } -#endif if (srf_updates[i].flip_addr) dc->hwss.update_plane_addr(dc, pipe_ctx); } @@ -2407,14 +2409,15 @@ void dc_set_power_state( case DC_ACPI_CM_POWER_STATE_D0: dc_resource_state_construct(dc, dc->current_state); + if (dc->ctx->dmub_srv) + dc_dmub_srv_wait_phy_init(dc->ctx->dmub_srv); + dc->hwss.init_hw(dc); -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 if (dc->hwss.init_sys_ctx != NULL && dc->vm_pa_config.valid) { dc->hwss.init_sys_ctx(dc->hwseq, dc, &dc->vm_pa_config); } -#endif break; default: @@ -2494,6 +2497,17 @@ bool dc_submit_i2c( cmd); } +bool dc_submit_i2c_oem( + struct dc *dc, + struct i2c_command *cmd) +{ + struct ddc_service *ddc = dc->res_pool->oem_device; + return dce_i2c_submit_command( + dc->res_pool, + ddc->ddc_pin, + cmd); +} + static bool link_add_remote_sink_helper(struct dc_link *dc_link, struct dc_sink *sink) { if (dc_link->sink_count >= MAX_SINKS_PER_LINK) { diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c index b9227d5de3a36823176e449073cd933dd81136bf..502ed3c7959d2ba04d9bcae41478638c55473f84 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c @@ -33,7 +33,6 @@ #include "core_status.h" #include "core_types.h" -#include "hw_sequencer.h" #include "resource.h" @@ -310,14 +309,13 @@ void context_timing_trace( struct resource_context *res_ctx) { int i; - struct dc *core_dc = dc; int h_pos[MAX_PIPES] = {0}, v_pos[MAX_PIPES] = {0}; struct crtc_position position; - unsigned int underlay_idx = core_dc->res_pool->underlay_pipe_index; + unsigned int underlay_idx = dc->res_pool->underlay_pipe_index; DC_LOGGER_INIT(dc->ctx->logger); - for (i = 0; i < core_dc->res_pool->pipe_count; i++) { + for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; /* get_position() returns CRTC vertical/horizontal counter * hence not applicable for underlay pipe @@ -329,7 +327,7 @@ void context_timing_trace( h_pos[i] = position.horizontal_count; v_pos[i] = position.vertical_count; } - for (i = 0; i < core_dc->res_pool->pipe_count; i++) { + for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; if (pipe_ctx->stream == NULL || pipe_ctx->pipe_idx == underlay_idx) @@ -347,7 +345,7 @@ void context_clock_trace( struct dc *dc, struct dc_state *context) { -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) DC_LOGGER_INIT(dc->ctx->logger); CLOCK_TRACE("Current: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 12ba6fdf89b73213dceed7ee0f925a2e79fd11ae..cef8c1ba9797a6b25c064aed04eb710ff4ed6744 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -74,7 +74,7 @@ enum { /******************************************************************************* * Private functions ******************************************************************************/ -static void destruct(struct dc_link *link) +static void dc_link_destruct(struct dc_link *link) { int i; @@ -372,7 +372,7 @@ bool dc_link_is_dp_sink_present(struct dc_link *link) if (GPIO_RESULT_OK != dal_ddc_open( ddc, GPIO_MODE_INPUT, GPIO_DDC_CONFIG_TYPE_MODE_I2C)) { - dal_gpio_destroy_ddc(&ddc); + dal_ddc_close(ddc); return present; } @@ -1244,7 +1244,7 @@ static enum transmitter translate_encoder_to_transmitter( } } -static bool construct( +static bool dc_link_construct( struct dc_link *link, const struct link_init_data *init_params) { @@ -1446,7 +1446,7 @@ struct dc_link *link_create(const struct link_init_data *init_params) if (NULL == link) goto alloc_fail; - if (false == construct(link, init_params)) + if (false == dc_link_construct(link, init_params)) goto construct_fail; return link; @@ -1460,7 +1460,7 @@ alloc_fail: void link_destroy(struct dc_link **link) { - destruct(*link); + dc_link_destruct(*link); kfree(*link); *link = NULL; } @@ -1495,10 +1495,7 @@ static enum dc_status enable_link_dp( bool skip_video_pattern; struct dc_link *link = stream->link; struct dc_link_settings link_settings = {0}; - enum dp_panel_mode panel_mode; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT bool fec_enable; -#endif int i; bool apply_seamless_boot_optimization = false; @@ -1514,15 +1511,6 @@ static enum dc_status enable_link_dp( decide_link_settings(stream, &link_settings); if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP) { - /* If link settings are different than current and link already enabled - * then need to disable before programming to new rate. - */ - if (link->link_status.link_active && - (link->cur_link_settings.lane_count != link_settings.lane_count || - link->cur_link_settings.link_rate != link_settings.link_rate)) { - dp_disable_link_phy(link, pipe_ctx->stream->signal); - } - /*in case it is not on*/ link->dc->hwss.edp_power_control(link, true); link->dc->hwss.edp_wait_for_hpd_ready(link, true); @@ -1533,50 +1521,29 @@ static enum dc_status enable_link_dp( if (state->clk_mgr && !apply_seamless_boot_optimization) state->clk_mgr->funcs->update_clocks(state->clk_mgr, state, false); - dp_enable_link_phy( - link, - pipe_ctx->stream->signal, - pipe_ctx->clock_source->id, - &link_settings); - - if (stream->sink_patches.dppowerup_delay > 0) { - int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay; - - msleep(delay_dp_power_up_in_ms); - } - - panel_mode = dp_get_panel_mode(link); - dp_set_panel_mode(link, panel_mode); - skip_video_pattern = true; if (link_settings.link_rate == LINK_RATE_LOW) skip_video_pattern = false; - if (link->aux_access_disabled) { - dc_link_dp_perform_link_training_skip_aux(link, &link_settings); - - link->cur_link_settings = link_settings; - status = DC_OK; - } else if (perform_link_training_with_retries( - link, + if (perform_link_training_with_retries( &link_settings, skip_video_pattern, - LINK_TRAINING_ATTEMPTS)) { + LINK_TRAINING_ATTEMPTS, + pipe_ctx, + pipe_ctx->stream->signal)) { link->cur_link_settings = link_settings; status = DC_OK; } else status = DC_FAIL_DP_LINK_TRAINING; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT if (link->preferred_training_settings.fec_enable != NULL) fec_enable = *link->preferred_training_settings.fec_enable; else fec_enable = true; dp_set_fec_enable(link, fec_enable); -#endif return status; } @@ -2063,6 +2030,45 @@ static void write_i2c_redriver_setting( ASSERT(i2c_success); } +static void disable_link(struct dc_link *link, enum signal_type signal) +{ + /* + * TODO: implement call for dp_set_hw_test_pattern + * it is needed for compliance testing + */ + + /* Here we need to specify that encoder output settings + * need to be calculated as for the set mode, + * it will lead to querying dynamic link capabilities + * which should be done before enable output + */ + + if (dc_is_dp_signal(signal)) { + /* SST DP, eDP */ + if (dc_is_dp_sst_signal(signal)) + dp_disable_link_phy(link, signal); + else + dp_disable_link_phy_mst(link, signal); + + if (dc_is_dp_sst_signal(signal) || + link->mst_stream_alloc_table.stream_count == 0) { + dp_set_fec_enable(link, false); + dp_set_fec_ready(link, false); + } + } else { + if (signal != SIGNAL_TYPE_VIRTUAL) + link->link_enc->funcs->disable_output(link->link_enc, signal); + } + + if (signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { + /* MST disable link only when no stream use the link */ + if (link->mst_stream_alloc_table.stream_count <= 0) + link->link_status.link_active = false; + } else { + link->link_status.link_active = false; + } +} + static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; @@ -2147,6 +2153,19 @@ static enum dc_status enable_link( struct pipe_ctx *pipe_ctx) { enum dc_status status = DC_ERROR_UNEXPECTED; + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->link; + + /* There's some scenarios where driver is unloaded with display + * still enabled. When driver is reloaded, it may cause a display + * to not light up if there is a mismatch between old and new + * link settings. Need to call disable first before enabling at + * new link settings. + */ + if (link->link_status.link_active) { + disable_link(link, pipe_ctx->stream->signal); + } + switch (pipe_ctx->stream->signal) { case SIGNAL_TYPE_DISPLAY_PORT: status = enable_link_dp(state, pipe_ctx); @@ -2181,46 +2200,6 @@ static enum dc_status enable_link( return status; } -static void disable_link(struct dc_link *link, enum signal_type signal) -{ - /* - * TODO: implement call for dp_set_hw_test_pattern - * it is needed for compliance testing - */ - - /* here we need to specify that encoder output settings - * need to be calculated as for the set mode, - * it will lead to querying dynamic link capabilities - * which should be done before enable output */ - - if (dc_is_dp_signal(signal)) { - /* SST DP, eDP */ - if (dc_is_dp_sst_signal(signal)) - dp_disable_link_phy(link, signal); - else - dp_disable_link_phy_mst(link, signal); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT - - if (dc_is_dp_sst_signal(signal) || - link->mst_stream_alloc_table.stream_count == 0) { - dp_set_fec_enable(link, false); - dp_set_fec_ready(link, false); - } -#endif - } else { - if (signal != SIGNAL_TYPE_VIRTUAL) - link->link_enc->funcs->disable_output(link->link_enc, signal); - } - - if (signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { - /* MST disable link only when no stream use the link */ - if (link->mst_stream_alloc_table.stream_count <= 0) - link->link_status.link_active = false; - } else { - link->link_status.link_active = false; - } -} - static uint32_t get_timing_pixel_clock_100hz(const struct dc_crtc_timing *timing) { @@ -2357,9 +2336,9 @@ bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t backlight_pwm_u16_16, uint32_t frame_ramp) { - struct dc *core_dc = link->ctx->dc; - struct abm *abm = core_dc->res_pool->abm; - struct dmcu *dmcu = core_dc->res_pool->dmcu; + struct dc *dc = link->ctx->dc; + struct abm *abm = dc->res_pool->abm; + struct dmcu *dmcu = dc->res_pool->dmcu; unsigned int controller_id = 0; bool use_smooth_brightness = true; int i; @@ -2377,22 +2356,22 @@ bool dc_link_set_backlight_level(const struct dc_link *link, if (dc_is_embedded_signal(link->connector_signal)) { for (i = 0; i < MAX_PIPES; i++) { - if (core_dc->current_state->res_ctx.pipe_ctx[i].stream) { - if (core_dc->current_state->res_ctx. + if (dc->current_state->res_ctx.pipe_ctx[i].stream) { + if (dc->current_state->res_ctx. pipe_ctx[i].stream->link == link) { /* DMCU -1 for all controller id values, * therefore +1 here */ controller_id = - core_dc->current_state-> + dc->current_state-> res_ctx.pipe_ctx[i].stream_res.tg->inst + 1; /* Disable brightness ramping when the display is blanked * as it can hang the DMCU */ - if (core_dc->current_state->res_ctx.pipe_ctx[i].plane_state == NULL) + if (dc->current_state->res_ctx.pipe_ctx[i].plane_state == NULL) frame_ramp = 0; } } @@ -2410,8 +2389,8 @@ bool dc_link_set_backlight_level(const struct dc_link *link, bool dc_link_set_abm_disable(const struct dc_link *link) { - struct dc *core_dc = link->ctx->dc; - struct abm *abm = core_dc->res_pool->abm; + struct dc *dc = link->ctx->dc; + struct abm *abm = dc->res_pool->abm; if ((abm == NULL) || (abm->funcs->set_backlight_level_pwm == NULL)) return false; @@ -2423,8 +2402,8 @@ bool dc_link_set_abm_disable(const struct dc_link *link) bool dc_link_set_psr_allow_active(struct dc_link *link, bool allow_active, bool wait) { - struct dc *core_dc = link->ctx->dc; - struct dmcu *dmcu = core_dc->res_pool->dmcu; + struct dc *dc = link->ctx->dc; + struct dmcu *dmcu = dc->res_pool->dmcu; @@ -2438,8 +2417,8 @@ bool dc_link_set_psr_allow_active(struct dc_link *link, bool allow_active, bool bool dc_link_get_psr_state(const struct dc_link *link, uint32_t *psr_state) { - struct dc *core_dc = link->ctx->dc; - struct dmcu *dmcu = core_dc->res_pool->dmcu; + struct dc *dc = link->ctx->dc; + struct dmcu *dmcu = dc->res_pool->dmcu; if (dmcu != NULL && link->psr_feature_enabled) dmcu->funcs->get_psr_state(dmcu, psr_state); @@ -2486,7 +2465,7 @@ bool dc_link_setup_psr(struct dc_link *link, const struct dc_stream_state *stream, struct psr_config *psr_config, struct psr_context *psr_context) { - struct dc *core_dc; + struct dc *dc; struct dmcu *dmcu; int i; /* updateSinkPsrDpcdConfig*/ @@ -2497,8 +2476,8 @@ bool dc_link_setup_psr(struct dc_link *link, if (!link) return false; - core_dc = link->ctx->dc; - dmcu = core_dc->res_pool->dmcu; + dc = link->ctx->dc; + dmcu = dc->res_pool->dmcu; if (!dmcu) return false; @@ -2537,13 +2516,13 @@ bool dc_link_setup_psr(struct dc_link *link, psr_context->engineId = link->link_enc->preferred_engine; for (i = 0; i < MAX_PIPES; i++) { - if (core_dc->current_state->res_ctx.pipe_ctx[i].stream + if (dc->current_state->res_ctx.pipe_ctx[i].stream == stream) { /* dmcu -1 for all controller id values, * therefore +1 here */ psr_context->controllerId = - core_dc->current_state->res_ctx. + dc->current_state->res_ctx. pipe_ctx[i].stream_res.tg->inst + 1; break; } @@ -2586,7 +2565,7 @@ bool dc_link_setup_psr(struct dc_link *link, psr_context->psr_level.u32all = 0; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) /*skip power down the single pipe since it blocks the cstate*/ if (ASICREV_IS_RAVEN(link->ctx->asic_id.hw_internal_rev)) psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true; @@ -2644,28 +2623,13 @@ static struct fixed31_32 get_pbn_per_slot(struct dc_stream_state *stream) return dc_fixpt_div_int(mbytes_per_sec, 54); } -static int get_color_depth(enum dc_color_depth color_depth) -{ - switch (color_depth) { - case COLOR_DEPTH_666: return 6; - case COLOR_DEPTH_888: return 8; - case COLOR_DEPTH_101010: return 10; - case COLOR_DEPTH_121212: return 12; - case COLOR_DEPTH_141414: return 14; - case COLOR_DEPTH_161616: return 16; - default: return 0; - } -} - static struct fixed31_32 get_pbn_from_timing(struct pipe_ctx *pipe_ctx) { - uint32_t bpc; uint64_t kbps; struct fixed31_32 peak_kbps; uint32_t numerator; uint32_t denominator; - bpc = get_color_depth(pipe_ctx->stream_res.pix_clk_params.color_depth); kbps = dc_bandwidth_in_kbps_from_timing(&pipe_ctx->stream->timing); /* @@ -2922,12 +2886,12 @@ void core_link_enable_stream( struct dc_state *state, struct pipe_ctx *pipe_ctx) { - struct dc *core_dc = pipe_ctx->stream->ctx->dc; + struct dc *dc = pipe_ctx->stream->ctx->dc; struct dc_stream_state *stream = pipe_ctx->stream; enum dc_status status; DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); - if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment) && + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) && dc_is_virtual_signal(pipe_ctx->stream->signal)) return; @@ -2946,6 +2910,7 @@ void core_link_enable_stream( pipe_ctx->stream_res.stream_enc, &stream->timing, stream->output_color_space, + stream->use_vsc_sdp_for_colorimetry, stream->link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP); if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) @@ -2969,14 +2934,14 @@ void core_link_enable_stream( pipe_ctx->stream_res.stream_enc, &stream->timing); - if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { bool apply_edp_fast_boot_optimization = pipe_ctx->stream->apply_edp_fast_boot_optimization; pipe_ctx->stream->apply_edp_fast_boot_optimization = false; resource_build_info_frame(pipe_ctx); - core_dc->hwss.update_info_frame(pipe_ctx); + dc->hwss.update_info_frame(pipe_ctx); /* Do not touch link on seamless boot optimization. */ if (pipe_ctx->stream->apply_seamless_boot_optimization) { @@ -3019,7 +2984,7 @@ void core_link_enable_stream( } } - core_dc->hwss.enable_audio_stream(pipe_ctx); + dc->hwss.enable_audio_stream(pipe_ctx); /* turn off otg test pattern if enable */ if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) @@ -3027,28 +2992,24 @@ void core_link_enable_stream( CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, COLOR_DEPTH_UNDEFINED); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT if (pipe_ctx->stream->timing.flags.DSC) { if (dc_is_dp_signal(pipe_ctx->stream->signal) || dc_is_virtual_signal(pipe_ctx->stream->signal)) dp_set_dsc_enable(pipe_ctx, true); } -#endif - core_dc->hwss.enable_stream(pipe_ctx); + dc->hwss.enable_stream(pipe_ctx); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT /* Set DPS PPS SDP (AKA "info frames") */ if (pipe_ctx->stream->timing.flags.DSC) { if (dc_is_dp_signal(pipe_ctx->stream->signal) || dc_is_virtual_signal(pipe_ctx->stream->signal)) dp_set_dsc_pps_sdp(pipe_ctx, true); } -#endif if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) dc_link_allocate_mst_payload(pipe_ctx); - core_dc->hwss.unblank_stream(pipe_ctx, + dc->hwss.unblank_stream(pipe_ctx, &pipe_ctx->stream->link->cur_link_settings); if (dc_is_dp_signal(pipe_ctx->stream->signal)) @@ -3056,24 +3017,21 @@ void core_link_enable_stream( #if defined(CONFIG_DRM_AMD_DC_HDCP) update_psp_stream_config(pipe_ctx, false); #endif - } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT - else { // if (IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) + } else { // if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) if (dc_is_dp_signal(pipe_ctx->stream->signal) || dc_is_virtual_signal(pipe_ctx->stream->signal)) dp_set_dsc_enable(pipe_ctx, true); } -#endif } void core_link_disable_stream(struct pipe_ctx *pipe_ctx) { - struct dc *core_dc = pipe_ctx->stream->ctx->dc; + struct dc *dc = pipe_ctx->stream->ctx->dc; struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->sink->link; - if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment) && + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) && dc_is_virtual_signal(pipe_ctx->stream->signal)) return; @@ -3081,7 +3039,7 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx) update_psp_stream_config(pipe_ctx, true); #endif - core_dc->hwss.blank_stream(pipe_ctx); + dc->hwss.blank_stream(pipe_ctx); if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) deallocate_mst_payload(pipe_ctx); @@ -3110,25 +3068,23 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx) write_i2c_redriver_setting(pipe_ctx, false); } } - core_dc->hwss.disable_stream(pipe_ctx); + dc->hwss.disable_stream(pipe_ctx); disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT if (pipe_ctx->stream->timing.flags.DSC) { if (dc_is_dp_signal(pipe_ctx->stream->signal)) dp_set_dsc_enable(pipe_ctx, false); } -#endif } void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) { - struct dc *core_dc = pipe_ctx->stream->ctx->dc; + struct dc *dc = pipe_ctx->stream->ctx->dc; if (!dc_is_hdmi_signal(pipe_ctx->stream->signal)) return; - core_dc->hwss.set_avmute(pipe_ctx, enable); + dc->hwss.set_avmute(pipe_ctx, enable); } /** @@ -3186,13 +3142,11 @@ uint32_t dc_bandwidth_in_kbps_from_timing( uint32_t bits_per_channel = 0; uint32_t kbps; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT if (timing->flags.DSC) { kbps = (timing->pix_clk_100hz * timing->dsc_cfg.bits_per_pixel); kbps = kbps / 160 + ((kbps % 160) ? 1 : 0); return kbps; } -#endif switch (timing->display_color_depth) { case COLOR_DEPTH_666: @@ -3345,6 +3299,7 @@ void dc_link_disable_hpd(const struct dc_link *link) void dc_link_set_test_pattern(struct dc_link *link, enum dp_test_pattern test_pattern, + enum dp_test_pattern_color_space test_pattern_color_space, const struct link_training_settings *p_link_settings, const unsigned char *p_custom_pattern, unsigned int cust_pattern_size) @@ -3353,6 +3308,7 @@ void dc_link_set_test_pattern(struct dc_link *link, dc_link_dp_set_test_pattern( link, test_pattern, + test_pattern_color_space, p_link_settings, p_custom_pattern, cust_pattern_size); @@ -3368,7 +3324,6 @@ uint32_t dc_link_bandwidth_kbps( link_bw_kbps *= 8; /* 8 bits per byte*/ link_bw_kbps *= link_setting->lane_count; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT if (link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) { /* Account for FEC overhead. * We have to do it based on caps, @@ -3393,7 +3348,6 @@ uint32_t dc_link_bandwidth_kbps( link_bw_kbps = mul_u64_u32_shr(BIT_ULL(32) * 970LL / 1000, link_bw_kbps, 32); } -#endif return link_bw_kbps; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c index 7f904d55c1bceb6b136b64ad0818daddd2d778f4..c2c136b121849765889616a68a2d77d65f786064 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c @@ -187,7 +187,7 @@ void dal_ddc_i2c_payloads_add( } -static void construct( +static void ddc_service_construct( struct ddc_service *ddc_service, struct ddc_service_init_data *init_data) { @@ -206,7 +206,10 @@ static void construct( ddc_service->ddc_pin = NULL; } else { hw_info.ddc_channel = i2c_info.i2c_line; - hw_info.hw_supported = i2c_info.i2c_hw_assist; + if (ddc_service->link != NULL) + hw_info.hw_supported = i2c_info.i2c_hw_assist; + else + hw_info.hw_supported = false; ddc_service->ddc_pin = dal_gpio_create_ddc( gpio_service, @@ -236,11 +239,11 @@ struct ddc_service *dal_ddc_service_create( if (!ddc_service) return NULL; - construct(ddc_service, init_data); + ddc_service_construct(ddc_service, init_data); return ddc_service; } -static void destruct(struct ddc_service *ddc) +static void ddc_service_destruct(struct ddc_service *ddc) { if (ddc->ddc_pin) dal_gpio_destroy_ddc(&ddc->ddc_pin); @@ -252,7 +255,7 @@ void dal_ddc_service_destroy(struct ddc_service **ddc) BREAK_TO_DEBUGGER(); return; } - destruct(*ddc); + ddc_service_destruct(*ddc); kfree(*ddc); *ddc = NULL; } @@ -586,7 +589,7 @@ bool dal_ddc_service_query_ddc_data( bool dal_ddc_submit_aux_command(struct ddc_service *ddc, struct aux_payload *payload) { - uint8_t retrieved = 0; + uint32_t retrieved = 0; bool ret = 0; if (!ddc) @@ -647,17 +650,16 @@ bool dc_link_aux_transfer_with_retries(struct ddc_service *ddc, } -enum dc_status dc_link_aux_configure_timeout(struct ddc_service *ddc, +uint32_t dc_link_aux_configure_timeout(struct ddc_service *ddc, uint32_t timeout) { - enum dc_status status = DC_OK; + uint32_t prev_timeout = 0; struct ddc *ddc_pin = ddc->ddc_pin; - if (ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout == NULL) - return DC_ERROR_UNEXPECTED; - if (!ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout(ddc, timeout)) - status = DC_ERROR_UNEXPECTED; - return status; + if (ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout) + prev_timeout = + ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout(ddc, timeout); + return prev_timeout; } /*test only function*/ 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 0f59b68aa4c245e0d7cc4b18150ddb53c741a663..42aa889fd0f5dabb9404d8246e893fc1fd5eee19 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 @@ -4,12 +4,8 @@ #include "dc_link_dp.h" #include "dm_helpers.h" #include "opp.h" -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #include "dsc.h" -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "resource.h" -#endif #include "inc/core_types.h" #include "link_hwss.h" @@ -21,6 +17,9 @@ #define DC_LOGGER \ link->ctx->logger + +#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50 + /* maximum pre emphasis level allowed for each voltage swing level*/ static const enum dc_pre_emphasis voltage_swing_to_pre_emphasis[] = { PRE_EMPHASIS_LEVEL3, @@ -221,19 +220,31 @@ static enum dpcd_training_patterns return dpcd_tr_pattern; } +static inline bool is_repeater(struct dc_link *link, uint32_t offset) +{ + return (!link->is_lttpr_mode_transparent && offset != 0); +} + static void dpcd_set_lt_pattern_and_lane_settings( struct dc_link *link, const struct link_training_settings *lt_settings, - enum dc_dp_training_pattern pattern) + enum dc_dp_training_pattern pattern, + uint32_t offset) { union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = { { {0} } }; - const uint32_t dpcd_base_lt_offset = - DP_TRAINING_PATTERN_SET; + + uint32_t dpcd_base_lt_offset; + uint8_t dpcd_lt_buffer[5] = {0}; union dpcd_training_pattern dpcd_pattern = { {0} }; uint32_t lane; uint32_t size_in_bytes; bool edp_workaround = false; /* TODO link_prop.INTERNAL */ + dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET; + + if (is_repeater(link, offset)) + dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 + + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); /***************************************************************** * DpcdAddress_TrainingPatternSet @@ -241,14 +252,21 @@ static void dpcd_set_lt_pattern_and_lane_settings( dpcd_pattern.v1_4.TRAINING_PATTERN_SET = dc_dp_training_pattern_to_dpcd_training_pattern(link, pattern); - dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - dpcd_base_lt_offset] + dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - DP_TRAINING_PATTERN_SET] = dpcd_pattern.raw; - DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n", - __func__, - DP_TRAINING_PATTERN_SET, - dpcd_pattern.v1_4.TRAINING_PATTERN_SET); - + if (is_repeater(link, offset)) { + DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n", + __func__, + offset, + dpcd_base_lt_offset, + dpcd_pattern.v1_4.TRAINING_PATTERN_SET); + } else { + DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n", + __func__, + dpcd_base_lt_offset, + dpcd_pattern.v1_4.TRAINING_PATTERN_SET); + } /***************************************************************** * DpcdAddress_Lane0Set -> DpcdAddress_Lane3Set *****************************************************************/ @@ -268,24 +286,35 @@ static void dpcd_set_lt_pattern_and_lane_settings( PRE_EMPHASIS_MAX_LEVEL ? 1 : 0); } - /* concatinate everything into one buffer*/ + /* concatenate everything into one buffer*/ size_in_bytes = lt_settings->link_settings.lane_count * sizeof(dpcd_lane[0]); // 0x00103 - 0x00102 memmove( - &dpcd_lt_buffer[DP_TRAINING_LANE0_SET - dpcd_base_lt_offset], + &dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET], dpcd_lane, size_in_bytes); - DC_LOG_HW_LINK_TRAINING("%s:\n %x VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", - __func__, - DP_TRAINING_LANE0_SET, - dpcd_lane[0].bits.VOLTAGE_SWING_SET, - dpcd_lane[0].bits.PRE_EMPHASIS_SET, - dpcd_lane[0].bits.MAX_SWING_REACHED, - dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED); - + if (is_repeater(link, offset)) { + DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" + " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", + __func__, + offset, + dpcd_base_lt_offset, + dpcd_lane[0].bits.VOLTAGE_SWING_SET, + dpcd_lane[0].bits.PRE_EMPHASIS_SET, + dpcd_lane[0].bits.MAX_SWING_REACHED, + dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED); + } else { + DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", + __func__, + dpcd_base_lt_offset, + dpcd_lane[0].bits.VOLTAGE_SWING_SET, + dpcd_lane[0].bits.PRE_EMPHASIS_SET, + dpcd_lane[0].bits.MAX_SWING_REACHED, + dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED); + } if (edp_workaround) { /* for eDP write in 2 parts because the 5-byte burst is * causing issues on some eDP panels (EPR#366724) @@ -495,8 +524,12 @@ static void get_lane_status_and_drive_settings( const struct link_training_settings *link_training_setting, union lane_status *ln_status, union lane_align_status_updated *ln_status_updated, - struct link_training_settings *req_settings) + struct link_training_settings *req_settings, + uint32_t offset) { + unsigned int lane01_status_address = DP_LANE0_1_STATUS; + uint8_t lane_adjust_offset = 4; + unsigned int lane01_adjust_address; uint8_t dpcd_buf[6] = {0}; union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; struct link_training_settings request_settings = { {0} }; @@ -504,9 +537,16 @@ static void get_lane_status_and_drive_settings( memset(req_settings, '\0', sizeof(struct link_training_settings)); + if (is_repeater(link, offset)) { + lane01_status_address = + DP_LANE0_1_STATUS_PHY_REPEATER1 + + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + lane_adjust_offset = 3; + } + core_link_read_dpcd( link, - DP_LANE0_1_STATUS, + lane01_status_address, (uint8_t *)(dpcd_buf), sizeof(dpcd_buf)); @@ -517,22 +557,47 @@ static void get_lane_status_and_drive_settings( ln_status[lane].raw = get_nibble_at_index(&dpcd_buf[0], lane); dpcd_lane_adjust[lane].raw = - get_nibble_at_index(&dpcd_buf[4], lane); + get_nibble_at_index(&dpcd_buf[lane_adjust_offset], lane); } ln_status_updated->raw = dpcd_buf[2]; - DC_LOG_HW_LINK_TRAINING("%s:\n%x Lane01Status = %x\n %x Lane23Status = %x\n ", - __func__, - DP_LANE0_1_STATUS, dpcd_buf[0], - DP_LANE2_3_STATUS, dpcd_buf[1]); - - DC_LOG_HW_LINK_TRAINING("%s:\n %x Lane01AdjustRequest = %x\n %x Lane23AdjustRequest = %x\n", - __func__, - DP_ADJUST_REQUEST_LANE0_1, - dpcd_buf[4], - DP_ADJUST_REQUEST_LANE2_3, - dpcd_buf[5]); + if (is_repeater(link, offset)) { + DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" + " 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ", + __func__, + offset, + lane01_status_address, dpcd_buf[0], + lane01_status_address + 1, dpcd_buf[1]); + } else { + DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ", + __func__, + lane01_status_address, dpcd_buf[0], + lane01_status_address + 1, dpcd_buf[1]); + } + lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1; + + if (is_repeater(link, offset)) + lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 + + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + + if (is_repeater(link, offset)) { + DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n" + " 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n", + __func__, + offset, + lane01_adjust_address, + dpcd_buf[lane_adjust_offset], + lane01_adjust_address + 1, + dpcd_buf[lane_adjust_offset + 1]); + } else { + DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n", + __func__, + lane01_adjust_address, + dpcd_buf[lane_adjust_offset], + lane01_adjust_address + 1, + dpcd_buf[lane_adjust_offset + 1]); + } /*copy to req_settings*/ request_settings.link_settings.lane_count = @@ -571,10 +636,18 @@ static void get_lane_status_and_drive_settings( static void dpcd_set_lane_settings( struct dc_link *link, - const struct link_training_settings *link_training_setting) + const struct link_training_settings *link_training_setting, + uint32_t offset) { union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = {{{0}}}; uint32_t lane; + unsigned int lane0_set_address; + + lane0_set_address = DP_TRAINING_LANE0_SET; + + if (is_repeater(link, offset)) + lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 + + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); for (lane = 0; lane < (uint32_t)(link_training_setting-> @@ -597,7 +670,7 @@ static void dpcd_set_lane_settings( } core_link_write_dpcd(link, - DP_TRAINING_LANE0_SET, + lane0_set_address, (uint8_t *)(dpcd_lane), link_training_setting->link_settings.lane_count); @@ -620,14 +693,26 @@ static void dpcd_set_lane_settings( } */ - DC_LOG_HW_LINK_TRAINING("%s\n %x VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", - __func__, - DP_TRAINING_LANE0_SET, - dpcd_lane[0].bits.VOLTAGE_SWING_SET, - dpcd_lane[0].bits.PRE_EMPHASIS_SET, - dpcd_lane[0].bits.MAX_SWING_REACHED, - dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED); + if (is_repeater(link, offset)) { + DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n" + " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", + __func__, + offset, + lane0_set_address, + dpcd_lane[0].bits.VOLTAGE_SWING_SET, + dpcd_lane[0].bits.PRE_EMPHASIS_SET, + dpcd_lane[0].bits.MAX_SWING_REACHED, + dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED); + } else { + DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n", + __func__, + lane0_set_address, + dpcd_lane[0].bits.VOLTAGE_SWING_SET, + dpcd_lane[0].bits.PRE_EMPHASIS_SET, + dpcd_lane[0].bits.MAX_SWING_REACHED, + dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED); + } link->cur_lane_setting = link_training_setting->lane_settings[0]; } @@ -647,17 +732,6 @@ static bool is_max_vs_reached( } -void dc_link_dp_set_drive_settings( - struct dc_link *link, - struct link_training_settings *lt_settings) -{ - /* program ASIC PHY settings*/ - dp_set_hw_lane_settings(link, lt_settings); - - /* Notify DP sink the PHY settings from source */ - dpcd_set_lane_settings(link, lt_settings); -} - static bool perform_post_lt_adj_req_sequence( struct dc_link *link, struct link_training_settings *lt_settings) @@ -690,7 +764,8 @@ static bool perform_post_lt_adj_req_sequence( lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, - &req_settings); + &req_settings, + DPRX); if (dpcd_lane_status_updated.bits. POST_LT_ADJ_REQ_IN_PROGRESS == 0) @@ -747,6 +822,31 @@ static bool perform_post_lt_adj_req_sequence( } +/* Only used for channel equalization */ +static uint32_t translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval) +{ + unsigned int aux_rd_interval_us = 400; + + switch (dpcd_aux_read_interval) { + case 0x01: + aux_rd_interval_us = 400; + break; + case 0x02: + aux_rd_interval_us = 4000; + break; + case 0x03: + aux_rd_interval_us = 8000; + break; + case 0x04: + aux_rd_interval_us = 16000; + break; + default: + break; + } + + return aux_rd_interval_us; +} + static enum link_training_result get_cr_failure(enum dc_lane_count ln_count, union lane_status *dpcd_lane_status) { @@ -765,37 +865,55 @@ static enum link_training_result get_cr_failure(enum dc_lane_count ln_count, static enum link_training_result perform_channel_equalization_sequence( struct dc_link *link, - struct link_training_settings *lt_settings) + struct link_training_settings *lt_settings, + uint32_t offset) { struct link_training_settings req_settings; enum dc_dp_training_pattern tr_pattern; uint32_t retries_ch_eq; + uint32_t wait_time_microsec; enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; union lane_align_status_updated dpcd_lane_status_updated = { {0} }; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } }; + /* Note: also check that TPS4 is a supported feature*/ + tr_pattern = lt_settings->pattern_for_eq; - dp_set_hw_training_pattern(link, tr_pattern); + if (is_repeater(link, offset)) + tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4; + + dp_set_hw_training_pattern(link, tr_pattern, offset); for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; retries_ch_eq++) { - dp_set_hw_lane_settings(link, lt_settings); + dp_set_hw_lane_settings(link, lt_settings, offset); /* 2. update DPCD*/ if (!retries_ch_eq) /* EPR #361076 - write as a 5-byte burst, - * but only for the 1-st iteration*/ + * but only for the 1-st iteration + */ + dpcd_set_lt_pattern_and_lane_settings( link, lt_settings, - tr_pattern); + tr_pattern, offset); else - dpcd_set_lane_settings(link, lt_settings); + dpcd_set_lane_settings(link, lt_settings, offset); /* 3. wait for receiver to lock-on*/ - wait_for_training_aux_rd_interval(link, lt_settings->eq_pattern_time); + wait_time_microsec = lt_settings->eq_pattern_time; + + if (is_repeater(link, offset)) + wait_time_microsec = + translate_training_aux_read_interval( + link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]); + + wait_for_training_aux_rd_interval( + link, + wait_time_microsec); /* 4. Read lane status and requested * drive settings as set by the sink*/ @@ -805,7 +923,8 @@ static enum link_training_result perform_channel_equalization_sequence( lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, - &req_settings); + &req_settings, + offset); /* 5. check CR done*/ if (!is_cr_done(lane_count, dpcd_lane_status)) @@ -824,13 +943,16 @@ static enum link_training_result perform_channel_equalization_sequence( return LINK_TRAINING_EQ_FAIL_EQ; } +#define TRAINING_AUX_RD_INTERVAL 100 //us static enum link_training_result perform_clock_recovery_sequence( struct dc_link *link, - struct link_training_settings *lt_settings) + struct link_training_settings *lt_settings, + uint32_t offset) { uint32_t retries_cr; uint32_t retry_count; + uint32_t wait_time_microsec; struct link_training_settings req_settings; enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; enum dc_dp_training_pattern tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_1; @@ -840,7 +962,7 @@ static enum link_training_result perform_clock_recovery_sequence( retries_cr = 0; retry_count = 0; - dp_set_hw_training_pattern(link, tr_pattern); + dp_set_hw_training_pattern(link, tr_pattern, offset); /* najeeb - The synaptics MST hub can put the LT in * infinite loop by switching the VS @@ -857,7 +979,8 @@ static enum link_training_result perform_clock_recovery_sequence( /* 1. call HWSS to set lane settings*/ dp_set_hw_lane_settings( link, - lt_settings); + lt_settings, + offset); /* 2. update DPCD of the receiver*/ if (!retries_cr) @@ -866,16 +989,23 @@ static enum link_training_result perform_clock_recovery_sequence( dpcd_set_lt_pattern_and_lane_settings( link, lt_settings, - tr_pattern); + tr_pattern, + offset); else dpcd_set_lane_settings( link, - lt_settings); + lt_settings, + offset); /* 3. wait receiver to lock-on*/ + wait_time_microsec = lt_settings->cr_pattern_time; + + if (!link->is_lttpr_mode_transparent) + wait_time_microsec = TRAINING_AUX_RD_INTERVAL; + wait_for_training_aux_rd_interval( link, - lt_settings->cr_pattern_time); + wait_time_microsec); /* 4. Read lane status and requested drive * settings as set by the sink @@ -885,7 +1015,8 @@ static enum link_training_result perform_clock_recovery_sequence( lt_settings, dpcd_lane_status, &dpcd_lane_status_updated, - &req_settings); + &req_settings, + offset); /* 5. check CR done*/ if (is_cr_done(lane_count, dpcd_lane_status)) @@ -1054,6 +1185,93 @@ static void initialize_training_settings( lt_settings->enhanced_framing = 1; } +static uint8_t convert_to_count(uint8_t lttpr_repeater_count) +{ + switch (lttpr_repeater_count) { + case 0x80: // 1 lttpr repeater + return 1; + case 0x40: // 2 lttpr repeaters + return 2; + case 0x20: // 3 lttpr repeaters + return 3; + case 0x10: // 4 lttpr repeaters + return 4; + case 0x08: // 5 lttpr repeaters + return 5; + case 0x04: // 6 lttpr repeaters + return 6; + case 0x02: // 7 lttpr repeaters + return 7; + case 0x01: // 8 lttpr repeaters + return 8; + default: + break; + } + return 0; // invalid value +} + +static void configure_lttpr_mode(struct dc_link *link) +{ + /* aux timeout is already set to extended */ + /* RESET/SET lttpr mode to enable non transparent mode */ + uint8_t repeater_cnt; + uint32_t aux_interval_address; + uint8_t repeater_id; + uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT; + + DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__); + core_link_write_dpcd(link, + DP_PHY_REPEATER_MODE, + (uint8_t *)&repeater_mode, + sizeof(repeater_mode)); + + if (!link->is_lttpr_mode_transparent) { + + DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Non Transparent Mode\n", __func__); + + repeater_mode = DP_PHY_REPEATER_MODE_NON_TRANSPARENT; + core_link_write_dpcd(link, + DP_PHY_REPEATER_MODE, + (uint8_t *)&repeater_mode, + sizeof(repeater_mode)); + + repeater_cnt = convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + for (repeater_id = repeater_cnt; repeater_id > 0; repeater_id--) { + aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 + + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (repeater_id - 1)); + core_link_read_dpcd( + link, + aux_interval_address, + (uint8_t *)&link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1], + sizeof(link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1])); + link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1] &= 0x7F; + } + } +} + +static void repeater_training_done(struct dc_link *link, uint32_t offset) +{ + union dpcd_training_pattern dpcd_pattern = { {0} }; + + const uint32_t dpcd_base_lt_offset = + DP_TRAINING_PATTERN_SET_PHY_REPEATER1 + + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + /* Set training not in progress*/ + dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE; + + core_link_write_dpcd( + link, + dpcd_base_lt_offset, + &dpcd_pattern.raw, + 1); + + DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Id: %d 0x%X pattern = %x\n", + __func__, + offset, + dpcd_base_lt_offset, + dpcd_pattern.v1_4.TRAINING_PATTERN_SET); +} + static void print_status_message( struct dc_link *link, const struct link_training_settings *lt_settings, @@ -1133,6 +1351,17 @@ static void print_status_message( lt_spread); } +void dc_link_dp_set_drive_settings( + struct dc_link *link, + struct link_training_settings *lt_settings) +{ + /* program ASIC PHY settings*/ + dp_set_hw_lane_settings(link, lt_settings, DPRX); + + /* Notify DP sink the PHY settings from source */ + dpcd_set_lane_settings(link, lt_settings, DPRX); +} + bool dc_link_dp_perform_link_training_skip_aux( struct dc_link *link, const struct dc_link_settings *link_setting) @@ -1149,10 +1378,10 @@ bool dc_link_dp_perform_link_training_skip_aux( /* 1. Perform_clock_recovery_sequence. */ /* transmit training pattern for clock recovery */ - dp_set_hw_training_pattern(link, pattern_for_cr); + dp_set_hw_training_pattern(link, pattern_for_cr, DPRX); /* call HWSS to set lane settings*/ - dp_set_hw_lane_settings(link, <_settings); + dp_set_hw_lane_settings(link, <_settings, DPRX); /* wait receiver to lock-on*/ wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time); @@ -1160,10 +1389,10 @@ bool dc_link_dp_perform_link_training_skip_aux( /* 2. Perform_channel_equalization_sequence. */ /* transmit training pattern for channel equalization. */ - dp_set_hw_training_pattern(link, lt_settings.pattern_for_eq); + dp_set_hw_training_pattern(link, lt_settings.pattern_for_eq, DPRX); /* call HWSS to set lane settings*/ - dp_set_hw_lane_settings(link, <_settings); + dp_set_hw_lane_settings(link, <_settings, DPRX); /* wait receiver to lock-on. */ wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time); @@ -1185,9 +1414,10 @@ enum link_training_result dc_link_dp_perform_link_training( { enum link_training_result status = LINK_TRAINING_SUCCESS; struct link_training_settings lt_settings; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + bool fec_enable; -#endif + uint8_t repeater_cnt; + uint8_t repeater_id; initialize_training_settings( link, @@ -1198,23 +1428,47 @@ enum link_training_result dc_link_dp_perform_link_training( /* 1. set link rate, lane count and spread. */ dpcd_set_link_settings(link, <_settings); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT if (link->preferred_training_settings.fec_enable != NULL) fec_enable = *link->preferred_training_settings.fec_enable; else fec_enable = true; dp_set_fec_ready(link, fec_enable); -#endif + if (!link->is_lttpr_mode_transparent) { + /* Configure lttpr mode */ + configure_lttpr_mode(link); - /* 2. perform link training (set link training done - * to false is done as well) - */ - status = perform_clock_recovery_sequence(link, <_settings); + /* 2. perform link training (set link training done + * to false is done as well) + */ + repeater_cnt = convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + + for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS); + repeater_id--) { + status = perform_clock_recovery_sequence(link, <_settings, repeater_id); + + if (status != LINK_TRAINING_SUCCESS) + break; + + status = perform_channel_equalization_sequence(link, + <_settings, + repeater_id); + + if (status != LINK_TRAINING_SUCCESS) + break; + + repeater_training_done(link, repeater_id); + } + } + + if (status == LINK_TRAINING_SUCCESS) { + status = perform_clock_recovery_sequence(link, <_settings, DPRX); if (status == LINK_TRAINING_SUCCESS) { status = perform_channel_equalization_sequence(link, - <_settings); + <_settings, + DPRX); + } } if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) { @@ -1233,23 +1487,58 @@ enum link_training_result dc_link_dp_perform_link_training( } bool perform_link_training_with_retries( - struct dc_link *link, const struct dc_link_settings *link_setting, bool skip_video_pattern, - int attempts) + int attempts, + struct pipe_ctx *pipe_ctx, + enum signal_type signal) { uint8_t j; uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY; + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->link; + enum dp_panel_mode panel_mode = dp_get_panel_mode(link); for (j = 0; j < attempts; ++j) { - if (dc_link_dp_perform_link_training( + dp_enable_link_phy( + link, + signal, + pipe_ctx->clock_source->id, + link_setting); + + if (stream->sink_patches.dppowerup_delay > 0) { + int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay; + + msleep(delay_dp_power_up_in_ms); + } + + dp_set_panel_mode(link, panel_mode); + + /* We need to do this before the link training to ensure the idle pattern in SST + * mode will be sent right after the link training + */ + link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, + pipe_ctx->stream_res.stream_enc->id, true); + + if (link->aux_access_disabled) { + dc_link_dp_perform_link_training_skip_aux(link, link_setting); + return true; + } else if (dc_link_dp_perform_link_training( link, link_setting, skip_video_pattern) == LINK_TRAINING_SUCCESS) return true; + /* latest link training still fail, skip delay and keep PHY on + */ + if (j == (attempts - 1)) + break; + + dp_disable_link_phy(link, signal); + msleep(delay_between_attempts); + delay_between_attempts += LINK_TRAINING_RETRY_DELAY; } @@ -1321,9 +1610,7 @@ enum link_training_result dc_link_dp_sync_lt_attempt( enum link_training_result lt_status = LINK_TRAINING_SUCCESS; enum dp_panel_mode panel_mode = DP_PANEL_MODE_DEFAULT; enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT bool fec_enable = false; -#endif initialize_training_settings( link, @@ -1343,11 +1630,9 @@ enum link_training_result dc_link_dp_sync_lt_attempt( dp_enable_link_phy(link, link->connector_signal, dp_cs_id, link_settings); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT /* Set FEC enable */ fec_enable = lt_overrides->fec_enable && *lt_overrides->fec_enable; dp_set_fec_ready(link, fec_enable); -#endif if (lt_overrides->alternate_scrambler_reset) { if (*lt_overrides->alternate_scrambler_reset) @@ -1367,10 +1652,11 @@ enum link_training_result dc_link_dp_sync_lt_attempt( /* 2. perform link training (set link training done * to false is done as well) */ - lt_status = perform_clock_recovery_sequence(link, <_settings); + lt_status = perform_clock_recovery_sequence(link, <_settings, DPRX); if (lt_status == LINK_TRAINING_SUCCESS) { lt_status = perform_channel_equalization_sequence(link, - <_settings); + <_settings, + DPRX); } /* 3. Sync LT must skip TRAINING_PATTERN_SET:0 (video pattern)*/ @@ -1387,9 +1673,7 @@ bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down) */ if (link_down == true) { dp_disable_link_phy(link, link->connector_signal); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT dp_set_fec_ready(link, false); -#endif } link->sync_lt_in_progress = false; @@ -1423,6 +1707,22 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *link) max_link_cap.link_spread) max_link_cap.link_spread = link->reported_link_cap.link_spread; + /* + * account for lttpr repeaters cap + * notes: repeaters do not snoop in the DPRX Capabilities addresses (3.6.3). + */ + if (!link->is_lttpr_mode_transparent) { + if (link->dpcd_caps.lttpr_caps.max_lane_count < max_link_cap.lane_count) + max_link_cap.lane_count = link->dpcd_caps.lttpr_caps.max_lane_count; + + if (link->dpcd_caps.lttpr_caps.max_link_rate < max_link_cap.link_rate) + max_link_cap.link_rate = link->dpcd_caps.lttpr_caps.max_link_rate; + + DC_LOG_HW_LINK_TRAINING("%s\n Training with LTTPR, max_lane count %d max_link rate %d \n", + __func__, + max_link_cap.lane_count, + max_link_cap.link_rate); + } return max_link_cap; } @@ -1568,6 +1868,13 @@ bool dp_verify_link_cap( max_link_cap = get_max_link_cap(link); + /* Grant extended timeout request */ + if (!link->is_lttpr_mode_transparent && link->dpcd_caps.lttpr_caps.max_ext_timeout > 0) { + uint8_t grant = link->dpcd_caps.lttpr_caps.max_ext_timeout & 0x80; + + core_link_write_dpcd(link, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT, &grant, sizeof(grant)); + } + /* TODO implement override and monitor patch later */ /* try to train the link from high to low to @@ -2280,6 +2587,7 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) dc_link_dp_set_test_pattern( link, test_pattern, + DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED, &link_training_settings, test_80_bit_pattern, (DP_TEST_80BIT_CUSTOM_PATTERN_79_72 - @@ -2291,6 +2599,8 @@ static void dp_test_send_link_test_pattern(struct dc_link *link) union link_test_pattern dpcd_test_pattern; union test_misc dpcd_test_params; enum dp_test_pattern test_pattern; + enum dp_test_pattern_color_space test_pattern_color_space = + DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED; memset(&dpcd_test_pattern, 0, sizeof(dpcd_test_pattern)); memset(&dpcd_test_params, 0, sizeof(dpcd_test_params)); @@ -2325,14 +2635,105 @@ static void dp_test_send_link_test_pattern(struct dc_link *link) break; } + test_pattern_color_space = dpcd_test_params.bits.YCBCR_COEFS ? + DP_TEST_PATTERN_COLOR_SPACE_YCBCR709 : + DP_TEST_PATTERN_COLOR_SPACE_YCBCR601; + dc_link_dp_set_test_pattern( link, test_pattern, + test_pattern_color_space, NULL, NULL, 0); } +static void dp_test_get_audio_test_data(struct dc_link *link, bool disable_video) +{ + union audio_test_mode dpcd_test_mode = {0}; + struct audio_test_pattern_type dpcd_pattern_type = {0}; + union audio_test_pattern_period dpcd_pattern_period[AUDIO_CHANNELS_COUNT] = {0}; + enum dp_test_pattern test_pattern = DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED; + + struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx; + struct pipe_ctx *pipe_ctx = &pipes[0]; + unsigned int channel_count; + unsigned int channel = 0; + unsigned int modes = 0; + unsigned int sampling_rate_in_hz = 0; + + // get audio test mode and test pattern parameters + core_link_read_dpcd( + link, + DP_TEST_AUDIO_MODE, + &dpcd_test_mode.raw, + sizeof(dpcd_test_mode)); + + core_link_read_dpcd( + link, + DP_TEST_AUDIO_PATTERN_TYPE, + &dpcd_pattern_type.value, + sizeof(dpcd_pattern_type)); + + channel_count = dpcd_test_mode.bits.channel_count + 1; + + // read pattern periods for requested channels when sawTooth pattern is requested + if (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH || + dpcd_pattern_type.value == AUDIO_TEST_PATTERN_OPERATOR_DEFINED) { + + test_pattern = (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH) ? + DP_TEST_PATTERN_AUDIO_SAWTOOTH : DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED; + // read period for each channel + for (channel = 0; channel < channel_count; channel++) { + core_link_read_dpcd( + link, + DP_TEST_AUDIO_PERIOD_CH1 + channel, + &dpcd_pattern_period[channel].raw, + sizeof(dpcd_pattern_period[channel])); + } + } + + // translate sampling rate + switch (dpcd_test_mode.bits.sampling_rate) { + case AUDIO_SAMPLING_RATE_32KHZ: + sampling_rate_in_hz = 32000; + break; + case AUDIO_SAMPLING_RATE_44_1KHZ: + sampling_rate_in_hz = 44100; + break; + case AUDIO_SAMPLING_RATE_48KHZ: + sampling_rate_in_hz = 48000; + break; + case AUDIO_SAMPLING_RATE_88_2KHZ: + sampling_rate_in_hz = 88200; + break; + case AUDIO_SAMPLING_RATE_96KHZ: + sampling_rate_in_hz = 96000; + break; + case AUDIO_SAMPLING_RATE_176_4KHZ: + sampling_rate_in_hz = 176400; + break; + case AUDIO_SAMPLING_RATE_192KHZ: + sampling_rate_in_hz = 192000; + break; + default: + sampling_rate_in_hz = 0; + break; + } + + link->audio_test_data.flags.test_requested = 1; + link->audio_test_data.flags.disable_video = disable_video; + link->audio_test_data.sampling_rate = sampling_rate_in_hz; + link->audio_test_data.channel_count = channel_count; + link->audio_test_data.pattern_type = test_pattern; + + if (test_pattern == DP_TEST_PATTERN_AUDIO_SAWTOOTH) { + for (modes = 0; modes < pipe_ctx->stream->audio_info.mode_count; modes++) { + link->audio_test_data.pattern_period[modes] = dpcd_pattern_period[modes].bits.pattern_period; + } + } +} + static void handle_automated_test(struct dc_link *link) { union test_request test_request; @@ -2362,6 +2763,12 @@ static void handle_automated_test(struct dc_link *link) dp_test_send_link_test_pattern(link); test_response.bits.ACK = 1; } + + if (test_request.bits.AUDIO_TEST_PATTERN) { + dp_test_get_audio_test_data(link, test_request.bits.TEST_AUDIO_DISABLED_VIDEO); + test_response.bits.ACK = 1; + } + if (test_request.bits.PHY_TEST_PATTERN) { dp_test_send_phy_test_pattern(link); test_response.bits.ACK = 1; @@ -2381,9 +2788,9 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd union hpd_irq_data hpd_irq_dpcd_data = { { { {0} } } }; union device_service_irq device_service_clear = { { 0 } }; enum dc_status result; - bool status = false; struct pipe_ctx *pipe_ctx; + struct dc_link_settings previous_link_settings; int i; if (out_link_loss) @@ -2457,17 +2864,27 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd sizeof(hpd_irq_dpcd_data), "Status: "); - perform_link_training_with_retries(link, - &link->cur_link_settings, - true, LINK_TRAINING_ATTEMPTS); - for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link && - pipe_ctx->stream->dpms_off == false && - pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { - dc_link_allocate_mst_payload(pipe_ctx); - } + if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link) + break; + } + + if (pipe_ctx == NULL || pipe_ctx->stream == NULL) + return false; + + previous_link_settings = link->cur_link_settings; + dp_disable_link_phy(link, pipe_ctx->stream->signal); + + perform_link_training_with_retries(&previous_link_settings, + true, LINK_TRAINING_ATTEMPTS, + pipe_ctx, + pipe_ctx->stream->signal); + + if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link && + pipe_ctx->stream->dpms_off == false && + pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { + dc_link_allocate_mst_payload(pipe_ctx); } status = false; @@ -2697,7 +3114,6 @@ static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data, int length) { int retry = 0; - union dp_downstream_port_present ds_port = { 0 }; if (!link->dpcd_caps.dpcd_rev.raw) { do { @@ -2710,9 +3126,6 @@ static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data, } while (retry++ < 4 && !link->dpcd_caps.dpcd_rev.raw); } - ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT - - DP_DPCD_REV]; - if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER) { switch (link->dpcd_caps.branch_dev_id) { /* 0010FA active dongles (DP-VGA, DP-DLDVI converters) power down @@ -2737,7 +3150,11 @@ static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data, static bool retrieve_link_cap(struct dc_link *link) { - uint8_t dpcd_data[DP_ADAPTER_CAP - DP_DPCD_REV + 1]; + /* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16, + * which means size 16 will be good for both of those DPCD register block reads + */ + uint8_t dpcd_data[16]; + uint8_t lttpr_dpcd_data[6]; /*Only need to read 1 byte starting from DP_DPRX_FEATURE_ENUMERATION_LIST. */ @@ -2753,7 +3170,19 @@ static bool retrieve_link_cap(struct dc_link *link) int i; struct dp_sink_hw_fw_revision dp_hw_fw_revision; + /* Set default timeout to 3.2ms and read LTTPR capabilities */ + bool ext_timeout_support = link->dc->caps.extended_aux_timeout_support && + !link->dc->config.disable_extended_timeout_support; + + link->is_lttpr_mode_transparent = true; + + if (ext_timeout_support) { + dc_link_aux_configure_timeout(link->ddc, + LINK_AUX_DEFAULT_EXTENDED_TIMEOUT_PERIOD); + } + memset(dpcd_data, '\0', sizeof(dpcd_data)); + memset(lttpr_dpcd_data, '\0', sizeof(lttpr_dpcd_data)); memset(&down_strm_port_count, '\0', sizeof(union down_stream_port_count)); memset(&edp_config_cap, '\0', @@ -2785,6 +3214,52 @@ static bool retrieve_link_cap(struct dc_link *link) return false; } + if (ext_timeout_support) { + + status = core_link_read_dpcd( + link, + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, + lttpr_dpcd_data, + sizeof(lttpr_dpcd_data)); + + link->dpcd_caps.lttpr_caps.revision.raw = + lttpr_dpcd_data[DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.max_link_rate = + lttpr_dpcd_data[DP_MAX_LINK_RATE_PHY_REPEATER - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.phy_repeater_cnt = + lttpr_dpcd_data[DP_PHY_REPEATER_CNT - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.max_lane_count = + lttpr_dpcd_data[DP_MAX_LANE_COUNT_PHY_REPEATER - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.mode = + lttpr_dpcd_data[DP_PHY_REPEATER_MODE - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + link->dpcd_caps.lttpr_caps.max_ext_timeout = + lttpr_dpcd_data[DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT - + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; + + if (link->dpcd_caps.lttpr_caps.phy_repeater_cnt > 0 && + link->dpcd_caps.lttpr_caps.max_lane_count > 0 && + link->dpcd_caps.lttpr_caps.max_lane_count <= 4 && + link->dpcd_caps.lttpr_caps.revision.raw >= 0x14) { + link->is_lttpr_mode_transparent = false; + } else { + /*No lttpr reset timeout to its default value*/ + link->is_lttpr_mode_transparent = true; + dc_link_aux_configure_timeout(link->ddc, LINK_AUX_DEFAULT_TIMEOUT_PERIOD); + } + + CONN_DATA_DETECT(link, lttpr_dpcd_data, sizeof(lttpr_dpcd_data), "LTTPR Caps: "); + } + { union training_aux_rd_interval aux_rd_interval; @@ -2923,7 +3398,6 @@ static bool retrieve_link_cap(struct dc_link *link) dp_hw_fw_revision.ieee_fw_rev, sizeof(dp_hw_fw_revision.ieee_fw_rev)); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT memset(&link->dpcd_caps.dsc_caps, '\0', sizeof(link->dpcd_caps.dsc_caps)); memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap)); @@ -2945,7 +3419,6 @@ static bool retrieve_link_cap(struct dc_link *link) link->dpcd_caps.dsc_caps.dsc_ext_caps.raw, sizeof(link->dpcd_caps.dsc_caps.dsc_ext_caps.raw)); } -#endif /* Connectivity log: detection */ CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: "); @@ -3067,21 +3540,20 @@ static bool is_dp_phy_pattern(enum dp_test_pattern test_pattern) static void set_crtc_test_pattern(struct dc_link *link, struct pipe_ctx *pipe_ctx, - enum dp_test_pattern test_pattern) + enum dp_test_pattern test_pattern, + enum dp_test_pattern_color_space test_pattern_color_space) { enum controller_dp_test_pattern controller_test_pattern; enum dc_color_depth color_depth = pipe_ctx-> stream->timing.display_color_depth; struct bit_depth_reduction_params params; struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) int width = pipe_ctx->stream->timing.h_addressable + pipe_ctx->stream->timing.h_border_left + pipe_ctx->stream->timing.h_border_right; int height = pipe_ctx->stream->timing.v_addressable + pipe_ctx->stream->timing.v_border_bottom + pipe_ctx->stream->timing.v_border_top; -#endif memset(¶ms, 0, sizeof(params)); @@ -3125,11 +3597,29 @@ static void set_crtc_test_pattern(struct dc_link *link, if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, controller_test_pattern, color_depth); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) else if (opp->funcs->opp_set_disp_pattern_generator) { struct pipe_ctx *odm_pipe; + enum controller_dp_color_space controller_color_space; int opp_cnt = 1; + switch (test_pattern_color_space) { + case DP_TEST_PATTERN_COLOR_SPACE_RGB: + controller_color_space = CONTROLLER_DP_COLOR_SPACE_RGB; + break; + case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601: + controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR601; + break; + case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709: + controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR709; + break; + case DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED: + default: + controller_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED; + DC_LOG_ERROR("%s: Color space must be defined for test pattern", __func__); + ASSERT(0); + break; + } + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) opp_cnt++; @@ -3141,6 +3631,7 @@ static void set_crtc_test_pattern(struct dc_link *link, odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, ¶ms); odm_opp->funcs->opp_set_disp_pattern_generator(odm_opp, controller_test_pattern, + controller_color_space, color_depth, NULL, width, @@ -3148,12 +3639,12 @@ static void set_crtc_test_pattern(struct dc_link *link, } opp->funcs->opp_set_disp_pattern_generator(opp, controller_test_pattern, + controller_color_space, color_depth, NULL, width, height); } -#endif } break; case DP_TEST_PATTERN_VIDEO_MODE: @@ -3166,7 +3657,6 @@ static void set_crtc_test_pattern(struct dc_link *link, pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, color_depth); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) else if (opp->funcs->opp_set_disp_pattern_generator) { struct pipe_ctx *odm_pipe; int opp_cnt = 1; @@ -3181,6 +3671,7 @@ static void set_crtc_test_pattern(struct dc_link *link, odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, ¶ms); odm_opp->funcs->opp_set_disp_pattern_generator(odm_opp, CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, + CONTROLLER_DP_COLOR_SPACE_UDEFINED, color_depth, NULL, width, @@ -3188,12 +3679,12 @@ static void set_crtc_test_pattern(struct dc_link *link, } opp->funcs->opp_set_disp_pattern_generator(opp, CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, + CONTROLLER_DP_COLOR_SPACE_UDEFINED, color_depth, NULL, width, height); } -#endif } break; @@ -3205,6 +3696,7 @@ static void set_crtc_test_pattern(struct dc_link *link, bool dc_link_dp_set_test_pattern( struct dc_link *link, enum dp_test_pattern test_pattern, + enum dp_test_pattern_color_space test_pattern_color_space, const struct link_training_settings *p_link_settings, const unsigned char *p_custom_pattern, unsigned int cust_pattern_size) @@ -3233,7 +3725,7 @@ bool dc_link_dp_set_test_pattern( if (link->test_pattern_enabled && test_pattern == DP_TEST_PATTERN_VIDEO_MODE) { /* Set CRTC Test Pattern */ - set_crtc_test_pattern(link, pipe_ctx, test_pattern); + set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space); dp_set_hw_test_pattern(link, test_pattern, (uint8_t *)p_custom_pattern, (uint32_t)cust_pattern_size); @@ -3256,8 +3748,8 @@ bool dc_link_dp_set_test_pattern( if (is_dp_phy_pattern(test_pattern)) { /* Set DPCD Lane Settings before running test pattern */ if (p_link_settings != NULL) { - dp_set_hw_lane_settings(link, p_link_settings); - dpcd_set_lane_settings(link, p_link_settings); + dp_set_hw_lane_settings(link, p_link_settings, DPRX); + dpcd_set_lane_settings(link, p_link_settings, DPRX); } /* Blank stream if running test pattern */ @@ -3348,7 +3840,7 @@ bool dc_link_dp_set_test_pattern( } } else { /* CRTC Patterns */ - set_crtc_test_pattern(link, pipe_ctx, test_pattern); + set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space); /* Set Test Pattern state */ link->test_pattern_enabled = true; } @@ -3468,7 +3960,6 @@ enum dp_panel_mode dp_get_panel_mode(struct dc_link *link) return DP_PANEL_MODE_DEFAULT; } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT void dp_set_fec_ready(struct dc_link *link, bool ready) { /* FEC has to be "set ready" before the link training. @@ -3522,7 +4013,14 @@ void dp_set_fec_enable(struct dc_link *link, bool enable) if (link_enc->funcs->fec_set_enable && link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) { if (link->fec_state == dc_link_fec_ready && enable) { - msleep(1); + /* Accord to DP spec, FEC enable sequence can first + * be transmitted anytime after 1000 LL codes have + * been transmitted on the link after link training + * completion. Using 1 lane RBR should have the maximum + * time for transmitting 1000 LL codes which is 6.173 us. + * So use 7 microseconds delay instead. + */ + udelay(7); link_enc->funcs->fec_set_enable(link_enc, true); link->fec_state = dc_link_fec_enabled; } else if (link->fec_state == dc_link_fec_enabled && !enable) { @@ -3531,5 +4029,4 @@ void dp_set_fec_enable(struct dc_link *link, bool enable) } } } -#endif diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c index a519dbc5ecb65317b766ce92023a276303a23403..548aac02ca112f61a4e0ab21f1b677d06355ed05 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c @@ -12,12 +12,38 @@ #include "dc_link_ddc.h" #include "dm_helpers.h" #include "dpcd_defs.h" -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #include "dsc.h" -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "resource.h" -#endif + +static uint8_t convert_to_count(uint8_t lttpr_repeater_count) +{ + switch (lttpr_repeater_count) { + case 0x80: // 1 lttpr repeater + return 1; + case 0x40: // 2 lttpr repeaters + return 2; + case 0x20: // 3 lttpr repeaters + return 3; + case 0x10: // 4 lttpr repeaters + return 4; + case 0x08: // 5 lttpr repeaters + return 5; + case 0x04: // 6 lttpr repeaters + return 6; + case 0x02: // 7 lttpr repeaters + return 7; + case 0x01: // 8 lttpr repeaters + return 8; + default: + break; + } + return 0; // invalid value +} + +static inline bool is_immediate_downstream(struct dc_link *link, uint32_t offset) +{ + return (convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == offset); +} enum dc_status core_link_read_dpcd( struct dc_link *link, @@ -69,8 +95,8 @@ void dp_enable_link_phy( const struct dc_link_settings *link_settings) { struct link_encoder *link_enc = link->link_enc; - struct dc *core_dc = link->ctx->dc; - struct dmcu *dmcu = core_dc->res_pool->dmcu; + struct dc *dc = link->ctx->dc; + struct dmcu *dmcu = dc->res_pool->dmcu; struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx; @@ -174,8 +200,8 @@ bool edp_receiver_ready_T7(struct dc_link *link) void dp_disable_link_phy(struct dc_link *link, enum signal_type signal) { - struct dc *core_dc = link->ctx->dc; - struct dmcu *dmcu = core_dc->res_pool->dmcu; + struct dc *dc = link->ctx->dc; + struct dmcu *dmcu = dc->res_pool->dmcu; if (!link->wa_flags.dp_keep_receiver_powered) dp_receiver_power_ctrl(link, false); @@ -212,7 +238,8 @@ void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal) bool dp_set_hw_training_pattern( struct dc_link *link, - enum dc_dp_training_pattern pattern) + enum dc_dp_training_pattern pattern, + uint32_t offset) { enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED; @@ -240,10 +267,14 @@ bool dp_set_hw_training_pattern( void dp_set_hw_lane_settings( struct dc_link *link, - const struct link_training_settings *link_settings) + const struct link_training_settings *link_settings, + uint32_t offset) { struct link_encoder *encoder = link->link_enc; + if (!link->is_lttpr_mode_transparent && !is_immediate_downstream(link, offset)) + return; + /* call Encoder to set lane settings */ encoder->funcs->dp_set_lane_settings(encoder, link_settings); } @@ -302,20 +333,12 @@ void dp_retrain_link_dp_test(struct dc_link *link, memset(&link->cur_link_settings, 0, sizeof(link->cur_link_settings)); - link->link_enc->funcs->enable_dp_output( - link->link_enc, - link_setting, - pipes[i].clock_source->id); - link->cur_link_settings = *link_setting; - - dp_receiver_power_ctrl(link, true); - perform_link_training_with_retries( - link, link_setting, skip_video_pattern, - LINK_TRAINING_ATTEMPTS); - + LINK_TRAINING_ATTEMPTS, + &pipes[i], + SIGNAL_TYPE_DISPLAY_PORT); link->dc->hwss.enable_stream(&pipes[i]); @@ -339,7 +362,6 @@ void dp_retrain_link_dp_test(struct dc_link *link, } } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #define DC_LOGGER \ dsc->ctx->logger static void dsc_optc_config_log(struct display_stream_compressor *dsc, @@ -365,14 +387,14 @@ static void dsc_optc_config_log(struct display_stream_compressor *dsc, static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable) { - struct dc *core_dc = pipe_ctx->stream->ctx->dc; + struct dc *dc = pipe_ctx->stream->ctx->dc; struct dc_stream_state *stream = pipe_ctx->stream; bool result = false; - if (IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) result = true; else - result = dm_helpers_dp_write_dsc_enable(core_dc->ctx, stream, enable); + result = dm_helpers_dp_write_dsc_enable(dc->ctx, stream, enable); return result; } @@ -382,7 +404,7 @@ static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable) void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) { struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; - struct dc *core_dc = pipe_ctx->stream->ctx->dc; + struct dc *dc = pipe_ctx->stream->ctx->dc; struct dc_stream_state *stream = pipe_ctx->stream; struct pipe_ctx *odm_pipe; int opp_cnt = 1; @@ -418,7 +440,7 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED; /* Enable DSC in encoder */ - if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id); dsc_optc_config_log(dsc, &dsc_optc_cfg); pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc, @@ -443,7 +465,7 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) OPTC_DSC_DISABLED, 0, 0); /* disable DSC in stream encoder */ - if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config( pipe_ctx->stream_res.stream_enc, OPTC_DSC_DISABLED, 0, 0); @@ -486,7 +508,7 @@ out: bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable) { struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; - struct dc *core_dc = pipe_ctx->stream->ctx->dc; + struct dc *dc = pipe_ctx->stream->ctx->dc; struct dc_stream_state *stream = pipe_ctx->stream; if (!pipe_ctx->stream->timing.flags.DSC || !dsc) @@ -505,7 +527,7 @@ bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable) DC_LOG_DSC(" "); dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]); - if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { DC_LOG_DSC("Setting stream encoder DSC PPS SDP for engine %d\n", (int)pipe_ctx->stream_res.stream_enc->id); pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet( pipe_ctx->stream_res.stream_enc, @@ -514,7 +536,7 @@ bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable) } } else { /* disable DSC PPS in stream encoder */ - if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet( pipe_ctx->stream_res.stream_enc, false, NULL); } @@ -537,5 +559,4 @@ bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx) dp_set_dsc_pps_sdp(pipe_ctx, true); return true; } -#endif 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 37698305a2dc3492e534d1c3bcb9453a92db1aec..0c19de6783394079b0049931fbed3a83649be46c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -46,15 +46,11 @@ #include "dce100/dce100_resource.h" #include "dce110/dce110_resource.h" #include "dce112/dce112_resource.h" -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) #include "dcn10/dcn10_resource.h" #endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "dcn20/dcn20_resource.h" -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) #include "dcn21/dcn21_resource.h" -#endif #include "dce120/dce120_resource.h" #define DC_LOGGER_INIT(logger) @@ -99,23 +95,19 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id) else dc_version = DCE_VERSION_12_0; break; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) case FAMILY_RV: dc_version = DCN_VERSION_1_0; if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev)) dc_version = DCN_VERSION_1_01; -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev)) dc_version = DCN_VERSION_2_1; -#endif break; #endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) case FAMILY_NV: dc_version = DCN_VERSION_2_0; break; -#endif default: dc_version = DCE_VERSION_UNKNOWN; break; @@ -162,20 +154,16 @@ struct resource_pool *dc_create_resource_pool(struct dc *dc, init_data->num_virtual_links, dc); break; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) case DCN_VERSION_1_0: case DCN_VERSION_1_01: res_pool = dcn10_create_resource_pool(init_data, dc); break; -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) case DCN_VERSION_2_0: res_pool = dcn20_create_resource_pool(init_data, dc); break; -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) case DCN_VERSION_2_1: res_pool = dcn21_create_resource_pool(init_data, dc); break; @@ -951,25 +939,14 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx) data->inits.v_c_bot = dc_fixpt_add(data->inits.v_c, data->ratios.vert_c); } -static bool are_rects_integer_multiples(struct rect src, struct rect dest) -{ - if (dest.width >= src.width && dest.width % src.width == 0 && - dest.height >= src.height && dest.height % src.height == 0) - return true; - - return false; -} static void calculate_integer_scaling(struct pipe_ctx *pipe_ctx) { - if (!pipe_ctx->plane_state->scaling_quality.integer_scaling) - return; + unsigned int integer_multiple = 1; - //for Centered Mode - if (pipe_ctx->stream->dst.width == pipe_ctx->stream->src.width && - pipe_ctx->stream->dst.height == pipe_ctx->stream->src.height) { + if (pipe_ctx->plane_state->scaling_quality.integer_scaling) { // calculate maximum # of replication of src onto addressable - unsigned int integer_multiple = min( + integer_multiple = min( pipe_ctx->stream->timing.h_addressable / pipe_ctx->stream->src.width, pipe_ctx->stream->timing.v_addressable / pipe_ctx->stream->src.height); @@ -980,10 +957,8 @@ static void calculate_integer_scaling(struct pipe_ctx *pipe_ctx) //center dst onto addressable pipe_ctx->stream->dst.x = (pipe_ctx->stream->timing.h_addressable - pipe_ctx->stream->dst.width)/2; pipe_ctx->stream->dst.y = (pipe_ctx->stream->timing.v_addressable - pipe_ctx->stream->dst.height)/2; - } - //disable taps if src & dst are integer ratio - if (are_rects_integer_multiples(pipe_ctx->stream->src, pipe_ctx->stream->dst)) { + //We are guaranteed that we are scaling in integer ratio pipe_ctx->plane_state->scaling_quality.v_taps = 1; pipe_ctx->plane_state->scaling_quality.h_taps = 1; pipe_ctx->plane_state->scaling_quality.v_taps_c = 1; @@ -1217,7 +1192,7 @@ static struct pipe_ctx *acquire_free_pipe_for_head( return pool->funcs->acquire_idle_pipe_for_layer(context, pool, head_pipe->stream); } -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) static int acquire_first_split_pipe( struct resource_context *res_ctx, const struct resource_pool *pool, @@ -1298,7 +1273,7 @@ bool dc_add_plane_to_context( free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe); - #if defined(CONFIG_DRM_AMD_DC_DCN1_0) + #if defined(CONFIG_DRM_AMD_DC_DCN) if (!free_pipe) { int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); if (pipe_idx >= 0) @@ -1891,7 +1866,7 @@ static int acquire_resource_from_hw_enabled_state( inst = link->link_enc->funcs->get_dig_frontend(link->link_enc); if (inst == ENGINE_ID_UNKNOWN) - return false; + return -1; for (i = 0; i < pool->stream_enc_count; i++) { if (pool->stream_enc[i]->id == inst) { @@ -1903,10 +1878,10 @@ static int acquire_resource_from_hw_enabled_state( // tg_inst not found if (i == pool->stream_enc_count) - return false; + return -1; if (tg_inst >= pool->timing_generator_count) - return false; + return -1; if (!res_ctx->pipe_ctx[tg_inst].stream) { struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst]; @@ -1972,7 +1947,7 @@ enum dc_status resource_map_pool_resources( /* acquire new resources */ pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream); -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_DRM_AMD_DC_DCN if (pipe_idx < 0) pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); #endif @@ -2772,9 +2747,8 @@ void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream, enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream) { - struct dc *core_dc = dc; struct dc_link *link = stream->link; - struct timing_generator *tg = core_dc->res_pool->timing_generators[0]; + struct timing_generator *tg = dc->res_pool->timing_generators[0]; enum dc_status res = DC_OK; calculate_phy_pix_clks(stream); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_sink.c b/drivers/gpu/drm/amd/display/dc/core/dc_sink.c index 5cbfdf1c4b1180484c48643cbc3ce76b80cccbf5..a249a0e5edd0ff6b67894af5b557c561ac8f6200 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_sink.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_sink.c @@ -33,7 +33,7 @@ * Private functions ******************************************************************************/ -static void destruct(struct dc_sink *sink) +static void dc_sink_destruct(struct dc_sink *sink) { if (sink->dc_container_id) { kfree(sink->dc_container_id); @@ -41,7 +41,7 @@ static void destruct(struct dc_sink *sink) } } -static bool construct(struct dc_sink *sink, const struct dc_sink_init_data *init_params) +static bool dc_sink_construct(struct dc_sink *sink, const struct dc_sink_init_data *init_params) { struct dc_link *link = init_params->link; @@ -75,7 +75,7 @@ void dc_sink_retain(struct dc_sink *sink) static void dc_sink_free(struct kref *kref) { struct dc_sink *sink = container_of(kref, struct dc_sink, refcount); - destruct(sink); + dc_sink_destruct(sink); kfree(sink); } @@ -91,7 +91,7 @@ struct dc_sink *dc_sink_create(const struct dc_sink_init_data *init_params) if (NULL == sink) goto alloc_fail; - if (false == construct(sink, init_params)) + if (false == dc_sink_construct(sink, init_params)) goto construct_fail; kref_init(&sink->refcount); 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 bb09243758fe35e0768e2a74994df837112f5b7b..b43a4b115fd8ad3ffa71c675d0e56b409863ecd2 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -27,14 +27,12 @@ #include #include "dm_services.h" +#include "basics/dc_common.h" #include "dc.h" #include "core_types.h" #include "resource.h" #include "ipp.h" #include "timing_generator.h" -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) -#include "dcn10/dcn10_hw_sequencer.h" -#endif #define DC_LOGGER dc->ctx->logger @@ -58,7 +56,7 @@ void update_stream_signal(struct dc_stream_state *stream, struct dc_sink *sink) } } -static void construct(struct dc_stream_state *stream, +static void dc_stream_construct(struct dc_stream_state *stream, struct dc_sink *dc_sink_data) { uint32_t i = 0; @@ -108,7 +106,6 @@ static void construct(struct dc_stream_state *stream, /* EDID CAP translation for HDMI 2.0 */ stream->timing.flags.LTE_340MCSC_SCRAMBLE = dc_sink_data->edid_caps.lte_340mcsc_scramble; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT memset(&stream->timing.dsc_cfg, 0, sizeof(stream->timing.dsc_cfg)); stream->timing.dsc_cfg.num_slices_h = 0; stream->timing.dsc_cfg.num_slices_v = 0; @@ -117,7 +114,6 @@ static void construct(struct dc_stream_state *stream, stream->timing.dsc_cfg.linebuf_depth = 9; stream->timing.dsc_cfg.version_minor = 2; stream->timing.dsc_cfg.ycbcr422_simple = 0; -#endif update_stream_signal(stream, dc_sink_data); @@ -129,7 +125,7 @@ static void construct(struct dc_stream_state *stream, stream->ctx->dc_stream_id_count++; } -static void destruct(struct dc_stream_state *stream) +static void dc_stream_destruct(struct dc_stream_state *stream) { dc_sink_release(stream->sink); if (stream->out_transfer_func != NULL) { @@ -147,7 +143,7 @@ static void dc_stream_free(struct kref *kref) { struct dc_stream_state *stream = container_of(kref, struct dc_stream_state, refcount); - destruct(stream); + dc_stream_destruct(stream); kfree(stream); } @@ -170,7 +166,7 @@ struct dc_stream_state *dc_create_stream_for_sink( if (stream == NULL) return NULL; - construct(stream, sink); + dc_stream_construct(stream, sink); kref_init(&stream->refcount); @@ -237,7 +233,7 @@ struct dc_stream_status *dc_stream_get_status( static void delay_cursor_until_vupdate(struct pipe_ctx *pipe_ctx, struct dc *dc) { -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) unsigned int vupdate_line; unsigned int lines_to_vupdate, us_to_vupdate, vpos, nvpos; struct dc_stream_state *stream = pipe_ctx->stream; @@ -246,7 +242,7 @@ static void delay_cursor_until_vupdate(struct pipe_ctx *pipe_ctx, struct dc *dc) if (stream->ctx->asic_id.chip_family == FAMILY_RV && ASICREV_IS_RAVEN(stream->ctx->asic_id.hw_internal_rev)) { - vupdate_line = get_vupdate_offset_from_vsync(pipe_ctx); + vupdate_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); if (!dc_stream_get_crtc_position(dc, &stream, 1, &vpos, &nvpos)) return; @@ -272,7 +268,7 @@ bool dc_stream_set_cursor_attributes( const struct dc_cursor_attributes *attributes) { int i; - struct dc *core_dc; + struct dc *dc; struct resource_context *res_ctx; struct pipe_ctx *pipe_to_program = NULL; @@ -290,8 +286,8 @@ bool dc_stream_set_cursor_attributes( return false; } - core_dc = stream->ctx->dc; - res_ctx = &core_dc->current_state->res_ctx; + dc = stream->ctx->dc; + res_ctx = &dc->current_state->res_ctx; stream->cursor_attributes = *attributes; for (i = 0; i < MAX_PIPES; i++) { @@ -303,17 +299,17 @@ bool dc_stream_set_cursor_attributes( if (!pipe_to_program) { pipe_to_program = pipe_ctx; - delay_cursor_until_vupdate(pipe_ctx, core_dc); - core_dc->hwss.pipe_control_lock(core_dc, pipe_to_program, true); + delay_cursor_until_vupdate(pipe_ctx, dc); + dc->hwss.pipe_control_lock(dc, pipe_to_program, true); } - core_dc->hwss.set_cursor_attribute(pipe_ctx); - if (core_dc->hwss.set_cursor_sdr_white_level) - core_dc->hwss.set_cursor_sdr_white_level(pipe_ctx); + dc->hwss.set_cursor_attribute(pipe_ctx); + if (dc->hwss.set_cursor_sdr_white_level) + dc->hwss.set_cursor_sdr_white_level(pipe_ctx); } if (pipe_to_program) - core_dc->hwss.pipe_control_lock(core_dc, pipe_to_program, false); + dc->hwss.pipe_control_lock(dc, pipe_to_program, false); return true; } @@ -323,7 +319,7 @@ bool dc_stream_set_cursor_position( const struct dc_cursor_position *position) { int i; - struct dc *core_dc; + struct dc *dc; struct resource_context *res_ctx; struct pipe_ctx *pipe_to_program = NULL; @@ -337,8 +333,8 @@ bool dc_stream_set_cursor_position( return false; } - core_dc = stream->ctx->dc; - res_ctx = &core_dc->current_state->res_ctx; + dc = stream->ctx->dc; + res_ctx = &dc->current_state->res_ctx; stream->cursor_position = *position; for (i = 0; i < MAX_PIPES; i++) { @@ -354,20 +350,19 @@ bool dc_stream_set_cursor_position( if (!pipe_to_program) { pipe_to_program = pipe_ctx; - delay_cursor_until_vupdate(pipe_ctx, core_dc); - core_dc->hwss.pipe_control_lock(core_dc, pipe_to_program, true); + delay_cursor_until_vupdate(pipe_ctx, dc); + dc->hwss.pipe_control_lock(dc, pipe_to_program, true); } - core_dc->hwss.set_cursor_position(pipe_ctx); + dc->hwss.set_cursor_position(pipe_ctx); } if (pipe_to_program) - core_dc->hwss.pipe_control_lock(core_dc, pipe_to_program, false); + dc->hwss.pipe_control_lock(dc, pipe_to_program, false); return true; } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) bool dc_stream_add_writeback(struct dc *dc, struct dc_stream_state *stream, struct dc_writeback_info *wb_info) @@ -480,14 +475,13 @@ bool dc_stream_remove_writeback(struct dc *dc, return true; } -#endif uint32_t dc_stream_get_vblank_counter(const struct dc_stream_state *stream) { uint8_t i; - struct dc *core_dc = stream->ctx->dc; + struct dc *dc = stream->ctx->dc; struct resource_context *res_ctx = - &core_dc->current_state->res_ctx; + &dc->current_state->res_ctx; for (i = 0; i < MAX_PIPES; i++) { struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg; @@ -544,9 +538,9 @@ bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream, { uint8_t i; bool ret = false; - struct dc *core_dc = stream->ctx->dc; + struct dc *dc = stream->ctx->dc; struct resource_context *res_ctx = - &core_dc->current_state->res_ctx; + &dc->current_state->res_ctx; for (i = 0; i < MAX_PIPES; i++) { struct timing_generator *tg = res_ctx->pipe_ctx[i].stream_res.tg; @@ -567,10 +561,8 @@ bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream, return ret; } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) bool dc_stream_dmdata_status_done(struct dc *dc, struct dc_stream_state *stream) { - bool status = true; struct pipe_ctx *pipe = NULL; int i; @@ -586,8 +578,7 @@ bool dc_stream_dmdata_status_done(struct dc *dc, struct dc_stream_state *stream) if (i == MAX_PIPES) return true; - status = dc->hwss.dmdata_status_done(pipe); - return status; + return dc->hwss.dmdata_status_done(pipe); } bool dc_stream_set_dynamic_metadata(struct dc *dc, @@ -630,7 +621,6 @@ bool dc_stream_set_dynamic_metadata(struct dc *dc, return true; } -#endif void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream) { diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c index b9d6a5bd8522aca3f17148d5960bf285e8814d98..ea1229a3e2b2c62fa97be322a3523f876f16d87e 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c @@ -37,7 +37,7 @@ /******************************************************************************* * Private functions ******************************************************************************/ -static void construct(struct dc_context *ctx, struct dc_plane_state *plane_state) +static void dc_plane_construct(struct dc_context *ctx, struct dc_plane_state *plane_state) { plane_state->ctx = ctx; @@ -50,7 +50,6 @@ static void construct(struct dc_context *ctx, struct dc_plane_state *plane_state plane_state->in_transfer_func->type = TF_TYPE_BYPASS; plane_state->in_transfer_func->ctx = ctx; } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) plane_state->in_shaper_func = dc_create_transfer_func(); if (plane_state->in_shaper_func != NULL) { plane_state->in_shaper_func->type = TF_TYPE_BYPASS; @@ -67,10 +66,9 @@ static void construct(struct dc_context *ctx, struct dc_plane_state *plane_state plane_state->blend_tf->ctx = ctx; } -#endif } -static void destruct(struct dc_plane_state *plane_state) +static void dc_plane_destruct(struct dc_plane_state *plane_state) { if (plane_state->gamma_correction != NULL) { dc_gamma_release(&plane_state->gamma_correction); @@ -80,7 +78,6 @@ static void destruct(struct dc_plane_state *plane_state) plane_state->in_transfer_func); plane_state->in_transfer_func = NULL; } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) if (plane_state->in_shaper_func != NULL) { dc_transfer_func_release( plane_state->in_shaper_func); @@ -97,7 +94,6 @@ static void destruct(struct dc_plane_state *plane_state) plane_state->blend_tf = NULL; } -#endif } /******************************************************************************* @@ -112,16 +108,14 @@ void enable_surface_flip_reporting(struct dc_plane_state *plane_state, struct dc_plane_state *dc_create_plane_state(struct dc *dc) { - struct dc *core_dc = dc; - struct dc_plane_state *plane_state = kvzalloc(sizeof(*plane_state), - GFP_KERNEL); + GFP_KERNEL); if (NULL == plane_state) return NULL; kref_init(&plane_state->refcount); - construct(core_dc->ctx, plane_state); + dc_plane_construct(dc->ctx, plane_state); return plane_state; } @@ -141,7 +135,7 @@ const struct dc_plane_status *dc_plane_get_status( const struct dc_plane_state *plane_state) { const struct dc_plane_status *plane_status; - struct dc *core_dc; + struct dc *dc; int i; if (!plane_state || @@ -152,15 +146,15 @@ const struct dc_plane_status *dc_plane_get_status( } plane_status = &plane_state->status; - core_dc = plane_state->ctx->dc; + dc = plane_state->ctx->dc; - if (core_dc->current_state == NULL) + if (dc->current_state == NULL) return NULL; /* Find the current plane state and set its pending bit to false */ - for (i = 0; i < core_dc->res_pool->pipe_count; i++) { + for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = - &core_dc->current_state->res_ctx.pipe_ctx[i]; + &dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->plane_state != plane_state) continue; @@ -170,14 +164,14 @@ const struct dc_plane_status *dc_plane_get_status( break; } - for (i = 0; i < core_dc->res_pool->pipe_count; i++) { + for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = - &core_dc->current_state->res_ctx.pipe_ctx[i]; + &dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->plane_state != plane_state) continue; - core_dc->hwss.update_pending_status(pipe_ctx); + dc->hwss.update_pending_status(pipe_ctx); } return plane_status; @@ -191,7 +185,7 @@ void dc_plane_state_retain(struct dc_plane_state *plane_state) static void dc_plane_state_free(struct kref *kref) { struct dc_plane_state *plane_state = container_of(kref, struct dc_plane_state, refcount); - destruct(plane_state); + dc_plane_destruct(plane_state); kvfree(plane_state); } @@ -262,7 +256,6 @@ alloc_fail: return NULL; } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) static void dc_3dlut_func_free(struct kref *kref) { struct dc_3dlut *lut = container_of(kref, struct dc_3dlut, refcount); @@ -296,6 +289,5 @@ void dc_3dlut_func_retain(struct dc_3dlut *lut) { kref_get(&lut->refcount); } -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 0416a17b0897c40b141e1f83a05e2f212bdf9296..c24639080371f73f99a73dc48d4b02ee38bc0f06 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -39,7 +39,7 @@ #include "inc/hw/dmcu.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.2.56" +#define DC_VER "3.2.62" #define MAX_SURFACES 3 #define MAX_PLANES 6 @@ -54,6 +54,10 @@ struct dc_versions { struct dmcu_version dmcu_version; }; +enum dp_protocol_version { + DP_VERSION_1_4, +}; + enum dc_plane_type { DC_PLANE_TYPE_INVALID, DC_PLANE_TYPE_DCE_RGB, @@ -112,17 +116,15 @@ struct dc_caps { bool disable_dp_clk_share; bool psp_setup_panel_mode; bool extended_aux_timeout_support; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + bool dmcub_support; bool hw_3d_lut; -#endif + enum dp_protocol_version max_dp_protocol_version; struct dc_plane_cap planes[MAX_PLANES]; }; struct dc_bug_wa { -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) bool no_connect_phy_config; bool dedcn20_305_wa; -#endif bool skip_clock_update; }; @@ -363,10 +365,9 @@ struct dc_debug_options { bool disable_dfs_bypass; bool disable_dpp_power_gate; bool disable_hubp_power_gate; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT bool disable_dsc_power_gate; int dsc_min_slice_height_override; -#endif + bool native422_support; bool disable_pplib_wm_range; enum wm_report_mode pplib_wm_report_mode; unsigned int min_disp_clk_khz; @@ -401,22 +402,23 @@ struct dc_debug_options { unsigned int force_odm_combine; //bit vector based on otg inst unsigned int force_fclk_khz; bool disable_tri_buf; + bool dmub_offload_enabled; + bool dmcub_emulation; + bool dmub_command_table; /* for testing only */ struct dc_bw_validation_profile bw_val_profile; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT bool disable_fec; -#endif -#ifdef CONFIG_DRM_AMD_DC_DCN2_1 bool disable_48mhz_pwrdwn; -#endif /* This forces a hard min on the DCFCLK requested to SMU/PP * watermarks are not affected. */ unsigned int force_min_dcfclk_mhz; bool disable_timing_sync; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) bool cm_in_bypass; -#endif int force_clock_mode;/*every mode change.*/ + + bool nv12_iflip_vm_wa; + bool disable_dram_clock_change_vactive_support; + bool validate_dml_output; }; struct dc_debug_data { @@ -425,7 +427,6 @@ struct dc_debug_data { uint32_t auxErrorCount; }; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 struct dc_phy_addr_space_config { struct { uint64_t start_addr; @@ -455,7 +456,6 @@ struct dc_virtual_addr_space_config { uint32_t page_table_block_size_in_bytes; uint8_t page_table_depth; // 1 = 1 level, 2 = 2 level, etc. 0 = invalid }; -#endif struct dc_bounding_box_overrides { int sr_exit_time_ns; @@ -483,9 +483,7 @@ struct dc { struct dc_bounding_box_overrides bb_overrides; struct dc_bug_wa work_arounds; struct dc_context *ctx; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 struct dc_phy_addr_space_config vm_pa_config; -#endif uint8_t link_count; struct dc_link *links[MAX_PIPES * 2]; @@ -501,7 +499,7 @@ struct dc { /* Inputs into BW and WM calculations. */ struct bw_calcs_dceip *bw_dceip; struct bw_calcs_vbios *bw_vbios; -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_DRM_AMD_DC_DCN struct dcn_soc_bounding_box *dcn_soc; struct dcn_ip_params *dcn_ip; struct display_mode_lib dml; @@ -523,10 +521,8 @@ struct dc { struct dc_debug_data debug_data; const char *build_id; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 struct vm_helper *vm_helper; const struct gpu_info_soc_bounding_box_v1_0 *soc_bounding_box; -#endif }; enum frame_buffer_mode { @@ -558,15 +554,16 @@ struct dc_init_data { struct dc_bios *vbios_override; enum dce_environment dce_environment; + struct dmub_offload_funcs *dmub_if; + struct dc_reg_helper_state *dmub_offload; + struct dc_config flags; uint32_t log_mask; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 /** * gpu_info FW provided soc bounding box struct or 0 if not * available in FW */ const struct gpu_info_soc_bounding_box_v1_0 *soc_bounding_box; -#endif }; struct dc_callback_init { @@ -581,11 +578,9 @@ struct dc *dc_create(const struct dc_init_data *init_params); void dc_hardware_init(struct dc *dc); int dc_get_vmid_use_vector(struct dc *dc); -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 void dc_setup_vm_context(struct dc *dc, struct dc_virtual_addr_space_config *va_config, int vmid); /* Returns the number of vmids supported */ int dc_setup_system_context(struct dc *dc, struct dc_phy_addr_space_config *pa_config); -#endif void dc_init_callbacks(struct dc *dc, const struct dc_callback_init *init_params); void dc_deinit_callbacks(struct dc *dc); @@ -661,7 +656,6 @@ struct dc_transfer_func { }; }; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) union dc_3dlut_state { struct { @@ -680,12 +674,11 @@ union dc_3dlut_state { struct dc_3dlut { struct kref refcount; struct tetrahedral_params lut_3d; - uint32_t hdr_multiplier; + struct fixed31_32 hdr_multiplier; bool initialized; /*remove after diag fix*/ union dc_3dlut_state state; struct dc_context *ctx; }; -#endif /* * This structure is filled in by dc_surface_get_status and contains * the last requested address and the currently active address so the called @@ -708,7 +701,7 @@ union surface_update_flags { uint32_t horizontal_mirror_change:1; uint32_t per_pixel_alpha_change:1; uint32_t global_alpha_change:1; - uint32_t sdr_white_level:1; + uint32_t hdr_mult:1; uint32_t rotation_change:1; uint32_t swizzle_change:1; uint32_t scaling_change:1; @@ -736,9 +729,7 @@ union surface_update_flags { struct dc_plane_state { struct dc_plane_address address; struct dc_plane_flip_time time; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) bool triplebuffer_flips; -#endif struct scaling_taps scaling_quality; struct rect src_rect; struct rect dst_rect; @@ -754,18 +745,16 @@ struct dc_plane_state { struct dc_bias_and_scale *bias_and_scale; struct dc_csc_transform input_csc_color_matrix; struct fixed31_32 coeff_reduction_factor; - uint32_t sdr_white_level; + struct fixed31_32 hdr_mult; // TODO: No longer used, remove struct dc_hdr_static_metadata hdr_static_ctx; enum dc_color_space color_space; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct dc_3dlut *lut3d_func; struct dc_transfer_func *in_shaper_func; struct dc_transfer_func *blend_tf; -#endif enum surface_pixel_format format; enum dc_rotation_angle rotation; @@ -801,7 +790,6 @@ struct dc_plane_info { enum dc_rotation_angle rotation; enum plane_stereo_format stereo_format; enum dc_color_space color_space; - unsigned int sdr_white_level; bool horizontal_mirror; bool visible; bool per_pixel_alpha; @@ -825,7 +813,7 @@ struct dc_surface_update { const struct dc_flip_addrs *flip_addr; const struct dc_plane_info *plane_info; const struct dc_scaling_info *scaling_info; - + struct fixed31_32 hdr_mult; /* following updates require alloc/sleep/spin that is not isr safe, * null means no updates */ @@ -834,11 +822,9 @@ struct dc_surface_update { const struct dc_csc_transform *input_csc_color_matrix; const struct fixed31_32 *coeff_reduction_factor; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) const struct dc_transfer_func *func_shaper; const struct dc_3dlut *lut3d_func; const struct dc_transfer_func *blend_tf; -#endif }; /* @@ -859,11 +845,9 @@ void dc_transfer_func_retain(struct dc_transfer_func *dc_tf); void dc_transfer_func_release(struct dc_transfer_func *dc_tf); struct dc_transfer_func *dc_create_transfer_func(void); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct dc_3dlut *dc_create_3dlut_func(void); void dc_3dlut_func_release(struct dc_3dlut *lut); void dc_3dlut_func_retain(struct dc_3dlut *lut); -#endif /* * This structure holds a surface address. There could be multiple addresses * in cases such as Stereo 3D, Planar YUV, etc. Other per-flip attributes such @@ -980,10 +964,10 @@ struct dpcd_caps { bool panel_mode_edp; bool dpcd_display_control_capable; bool ext_receiver_cap_field_present; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT union dpcd_fec_capability fec_cap; struct dpcd_dsc_capabilities dsc_caps; -#endif + struct dc_lttpr_caps lttpr_caps; + }; #include "dc_link.h" @@ -1004,14 +988,12 @@ struct dc_container_id { }; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT struct dc_sink_dsc_caps { // 'true' if these are virtual DPCD's DSC caps (immediately upstream of sink in MST topology), // 'false' if they are sink's DSC caps bool is_virtual_dpcd_dsc; struct dsc_dec_dpcd_caps dsc_dec_caps; }; -#endif /* * The sink structure contains EDID and other display device properties @@ -1026,9 +1008,7 @@ struct dc_sink { struct stereo_3d_features features_3d[TIMING_3D_FORMAT_MAX]; bool converter_disable_audio; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT struct dc_sink_dsc_caps sink_dsc_caps; -#endif /* private to DC core */ struct dc_link *link; @@ -1089,10 +1069,8 @@ bool dc_is_dmcu_initialized(struct dc *dc); enum dc_status dc_set_clock(struct dc *dc, enum dc_clock_type clock_type, uint32_t clk_khz, uint32_t stepping); void dc_get_clock(struct dc *dc, enum dc_clock_type clock_type, struct dc_clock_config *clock_cfg); -#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT) /******************************************************************************* * DSC Interfaces ******************************************************************************/ #include "dc_dsc.h" -#endif #endif /* DC_INTERFACE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c new file mode 100644 index 0000000000000000000000000000000000000000..59c298a6484f396c3872dcb9d6ca32b6baa12a32 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -0,0 +1,134 @@ +/* + * Copyright 2019 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: AMD + * + */ + +#include "dc.h" +#include "dc_dmub_srv.h" +#include "../dmub/inc/dmub_srv.h" + +static void dc_dmub_srv_construct(struct dc_dmub_srv *dc_srv, struct dc *dc, + struct dmub_srv *dmub) +{ + dc_srv->dmub = dmub; + dc_srv->ctx = dc->ctx; +} + +struct dc_dmub_srv *dc_dmub_srv_create(struct dc *dc, struct dmub_srv *dmub) +{ + struct dc_dmub_srv *dc_srv = + kzalloc(sizeof(struct dc_dmub_srv), GFP_KERNEL); + + if (dc_srv == NULL) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dc_dmub_srv_construct(dc_srv, dc, dmub); + + return dc_srv; +} + +void dc_dmub_srv_destroy(struct dc_dmub_srv **dmub_srv) +{ + if (*dmub_srv) { + kfree(*dmub_srv); + *dmub_srv = NULL; + } +} + +void dc_dmub_srv_cmd_queue(struct dc_dmub_srv *dc_dmub_srv, + struct dmub_cmd_header *cmd) +{ + struct dmub_srv *dmub = dc_dmub_srv->dmub; + struct dc_context *dc_ctx = dc_dmub_srv->ctx; + enum dmub_status status; + + status = dmub_srv_cmd_queue(dmub, cmd); + if (status == DMUB_STATUS_OK) + return; + + if (status != DMUB_STATUS_QUEUE_FULL) + goto error; + + /* Execute and wait for queue to become empty again. */ + dc_dmub_srv_cmd_execute(dc_dmub_srv); + dc_dmub_srv_wait_idle(dc_dmub_srv); + + /* Requeue the command. */ + status = dmub_srv_cmd_queue(dmub, cmd); + if (status == DMUB_STATUS_OK) + return; + +error: + DC_ERROR("Error queuing DMUB command: status=%d\n", status); +} + +void dc_dmub_srv_cmd_execute(struct dc_dmub_srv *dc_dmub_srv) +{ + struct dmub_srv *dmub = dc_dmub_srv->dmub; + struct dc_context *dc_ctx = dc_dmub_srv->ctx; + enum dmub_status status; + + status = dmub_srv_cmd_execute(dmub); + if (status != DMUB_STATUS_OK) + DC_ERROR("Error starting DMUB execution: status=%d\n", status); +} + +void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv) +{ + struct dmub_srv *dmub = dc_dmub_srv->dmub; + struct dc_context *dc_ctx = dc_dmub_srv->ctx; + enum dmub_status status; + + status = dmub_srv_wait_for_idle(dmub, 100000); + if (status != DMUB_STATUS_OK) + DC_ERROR("Error waiting for DMUB idle: status=%d\n", status); +} + +void dc_dmub_srv_wait_phy_init(struct dc_dmub_srv *dc_dmub_srv) +{ + struct dmub_srv *dmub = dc_dmub_srv->dmub; + struct dc_context *dc_ctx = dc_dmub_srv->ctx; + enum dmub_status status; + + for (;;) { + /* Wait up to a second for PHY init. */ + status = dmub_srv_wait_for_phy_init(dmub, 1000000); + if (status == DMUB_STATUS_OK) + /* Initialization OK */ + break; + + DC_ERROR("DMCUB PHY init failed: status=%d\n", status); + ASSERT(0); + + if (status != DMUB_STATUS_TIMEOUT) + /* + * Server likely initialized or we don't have + * DMCUB HW support - this won't end. + */ + break; + + /* Continue spinning so we don't hang the ASIC. */ + } +} diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h new file mode 100644 index 0000000000000000000000000000000000000000..754b6077539cf8a0b8f6ff3778106cc7d288f6b3 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h @@ -0,0 +1,60 @@ +/* + * Copyright 2018 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: AMD + * + */ + +#ifndef _DMUB_DC_SRV_H_ +#define _DMUB_DC_SRV_H_ + +#include "os_types.h" +#include "../dmub/inc/dmub_cmd.h" + +struct dmub_srv; +struct dmub_cmd_header; + +struct dc_reg_helper_state { + bool gather_in_progress; + uint32_t same_addr_count; + bool should_burst_write; + union dmub_rb_cmd cmd_data; + unsigned int reg_seq_count; +}; + +struct dc_dmub_srv { + struct dmub_srv *dmub; + struct dc_reg_helper_state reg_helper_offload; + + struct dc_context *ctx; + void *dm; +}; + +void dc_dmub_srv_cmd_queue(struct dc_dmub_srv *dc_dmub_srv, + struct dmub_cmd_header *cmd); + +void dc_dmub_srv_cmd_execute(struct dc_dmub_srv *dc_dmub_srv); + +void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv); + +void dc_dmub_srv_wait_phy_init(struct dc_dmub_srv *dc_dmub_srv); + +#endif /* _DMUB_DC_SRV_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h index ef79a686e4c247cc398363a03c3eb6c45a8511b0..dfe4472c9e404eb8ecc569a9ea4199b7926641cc 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -129,9 +129,7 @@ struct dc_link_training_overrides { bool *alternate_scrambler_reset; bool *enhanced_framing; bool *mst_enable; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT bool *fec_enable; -#endif }; union dpcd_rev { @@ -471,13 +469,13 @@ union training_aux_rd_interval { /* Automated test structures */ union test_request { struct { - uint8_t LINK_TRAINING :1; - uint8_t LINK_TEST_PATTRN :1; - uint8_t EDID_READ :1; - uint8_t PHY_TEST_PATTERN :1; - uint8_t AUDIO_TEST_PATTERN :1; - uint8_t RESERVED :1; - uint8_t TEST_STEREO_3D :1; + uint8_t LINK_TRAINING :1; + uint8_t LINK_TEST_PATTRN :1; + uint8_t EDID_READ :1; + uint8_t PHY_TEST_PATTERN :1; + uint8_t RESERVED :1; + uint8_t AUDIO_TEST_PATTERN :1; + uint8_t TEST_AUDIO_DISABLED_VIDEO :1; } bits; uint8_t raw; }; @@ -524,19 +522,52 @@ union link_test_pattern { union test_misc { struct dpcd_test_misc_bits { - unsigned char SYNC_CLOCK :1; + unsigned char SYNC_CLOCK :1; /* dpcd_test_color_format */ - unsigned char CLR_FORMAT :2; + unsigned char CLR_FORMAT :2; /* dpcd_test_dyn_range */ - unsigned char DYN_RANGE :1; - unsigned char YCBCR :1; + unsigned char DYN_RANGE :1; + unsigned char YCBCR_COEFS :1; /* dpcd_test_bit_depth */ - unsigned char BPC :3; + unsigned char BPC :3; } bits; unsigned char raw; }; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +union audio_test_mode { + struct { + unsigned char sampling_rate :4; + unsigned char channel_count :4; + } bits; + unsigned char raw; +}; + +union audio_test_pattern_period { + struct { + unsigned char pattern_period :4; + unsigned char reserved :4; + } bits; + unsigned char raw; +}; + +struct audio_test_pattern_type { + unsigned char value; +}; + +struct dp_audio_test_data_flags { + uint8_t test_requested :1; + uint8_t disable_video :1; +}; + +struct dp_audio_test_data { + + struct dp_audio_test_data_flags flags; + uint8_t sampling_rate; + uint8_t channel_count; + uint8_t pattern_type; + uint8_t pattern_period[8]; +}; + /* FEC capability DPCD register field bits-*/ union dpcd_fec_capability { struct { @@ -661,6 +692,5 @@ struct dpcd_dsc_capabilities { union dpcd_dsc_ext_capabilities dsc_ext_caps; }; -#endif /* CONFIG_DRM_AMD_DC_DSC_SUPPORT */ #endif /* DC_DP_TYPES_H */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_dsc.h b/drivers/gpu/drm/amd/display/dc/dc_dsc.h index 0ed2962add5accf98c54ba8bd50e8d032126fe42..8ec09813ee17c3e5ac68d7215984b3fce291a19d 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dsc.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dsc.h @@ -1,4 +1,3 @@ -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #ifndef DC_DSC_H_ #define DC_DSC_H_ /* @@ -42,10 +41,16 @@ struct dc_dsc_bw_range { struct display_stream_compressor { const struct dsc_funcs *funcs; -#ifndef AMD_EDID_UTILITY struct dc_context *ctx; int inst; -#endif +}; + +struct dc_dsc_policy { + bool use_min_slices_h; + int max_slices_h; // Maximum available if 0 + int min_slice_height; // Must not be less than 8 + uint32_t max_target_bpp; + uint32_t min_target_bpp; }; bool dc_dsc_parse_dsc_dpcd(const uint8_t *dpcd_dsc_basic_data, @@ -55,8 +60,8 @@ bool dc_dsc_parse_dsc_dpcd(const uint8_t *dpcd_dsc_basic_data, bool dc_dsc_compute_bandwidth_range( const struct display_stream_compressor *dsc, const uint32_t dsc_min_slice_height_override, - const uint32_t min_kbps, - const uint32_t max_kbps, + const uint32_t min_bpp, + const uint32_t max_bpp, const struct dsc_dec_dpcd_caps *dsc_sink_caps, const struct dc_crtc_timing *timing, struct dc_dsc_bw_range *range); @@ -68,5 +73,8 @@ bool dc_dsc_compute_config( uint32_t target_bandwidth_kbps, const struct dc_crtc_timing *timing, struct dc_dsc_config *dsc_cfg); -#endif + +void dc_dsc_get_policy_for_timing(const struct dc_crtc_timing *timing, + struct dc_dsc_policy *policy); + #endif diff --git a/drivers/gpu/drm/amd/display/dc/dc_helper.c b/drivers/gpu/drm/amd/display/dc/dc_helper.c index 30b2f9edd42f5d988c3077bf9ef6bee4b3667c4b..02a63e9cb62ff555b2cb2945c05f1237001f079b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dc_helper.c @@ -32,6 +32,74 @@ #include "dm_services.h" #include +#include "dc.h" +#include "dc_dmub_srv.h" + +static inline void submit_dmub_read_modify_write( + struct dc_reg_helper_state *offload, + const struct dc_context *ctx) +{ + struct dmub_rb_cmd_read_modify_write *cmd_buf = &offload->cmd_data.read_modify_write; + bool gather = false; + + offload->should_burst_write = + (offload->same_addr_count == (DMUB_READ_MODIFY_WRITE_SEQ__MAX - 1)); + cmd_buf->header.payload_bytes = + sizeof(struct dmub_cmd_read_modify_write_sequence) * offload->reg_seq_count; + + gather = ctx->dmub_srv->reg_helper_offload.gather_in_progress; + ctx->dmub_srv->reg_helper_offload.gather_in_progress = false; + + dc_dmub_srv_cmd_queue(ctx->dmub_srv, &cmd_buf->header); + + ctx->dmub_srv->reg_helper_offload.gather_in_progress = gather; + + memset(cmd_buf, 0, sizeof(*cmd_buf)); + + offload->reg_seq_count = 0; + offload->same_addr_count = 0; +} + +static inline void submit_dmub_burst_write( + struct dc_reg_helper_state *offload, + const struct dc_context *ctx) +{ + struct dmub_rb_cmd_burst_write *cmd_buf = &offload->cmd_data.burst_write; + bool gather = false; + + cmd_buf->header.payload_bytes = + sizeof(uint32_t) * offload->reg_seq_count; + + gather = ctx->dmub_srv->reg_helper_offload.gather_in_progress; + ctx->dmub_srv->reg_helper_offload.gather_in_progress = false; + + dc_dmub_srv_cmd_queue(ctx->dmub_srv, &cmd_buf->header); + + ctx->dmub_srv->reg_helper_offload.gather_in_progress = gather; + + memset(cmd_buf, 0, sizeof(*cmd_buf)); + + offload->reg_seq_count = 0; +} + +static inline void submit_dmub_reg_wait( + struct dc_reg_helper_state *offload, + const struct dc_context *ctx) +{ + struct dmub_rb_cmd_reg_wait *cmd_buf = &offload->cmd_data.reg_wait; + bool gather = false; + + gather = ctx->dmub_srv->reg_helper_offload.gather_in_progress; + ctx->dmub_srv->reg_helper_offload.gather_in_progress = false; + + dc_dmub_srv_cmd_queue(ctx->dmub_srv, &cmd_buf->header); + + memset(cmd_buf, 0, sizeof(*cmd_buf)); + offload->reg_seq_count = 0; + + ctx->dmub_srv->reg_helper_offload.gather_in_progress = gather; +} + struct dc_reg_value_masks { uint32_t value; uint32_t mask; @@ -77,6 +145,100 @@ static void set_reg_field_values(struct dc_reg_value_masks *field_value_mask, } } +static void dmub_flush_buffer_execute( + struct dc_reg_helper_state *offload, + const struct dc_context *ctx) +{ + submit_dmub_read_modify_write(offload, ctx); + dc_dmub_srv_cmd_execute(ctx->dmub_srv); +} + +static void dmub_flush_burst_write_buffer_execute( + struct dc_reg_helper_state *offload, + const struct dc_context *ctx) +{ + submit_dmub_burst_write(offload, ctx); + dc_dmub_srv_cmd_execute(ctx->dmub_srv); +} + +static bool dmub_reg_value_burst_set_pack(const struct dc_context *ctx, uint32_t addr, + uint32_t reg_val) +{ + struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload; + struct dmub_rb_cmd_burst_write *cmd_buf = &offload->cmd_data.burst_write; + + /* flush command if buffer is full */ + if (offload->reg_seq_count == DMUB_BURST_WRITE_VALUES__MAX) + dmub_flush_burst_write_buffer_execute(offload, ctx); + + if (offload->cmd_data.cmd_common.header.type == DMUB_CMD__REG_SEQ_BURST_WRITE && + addr != cmd_buf->addr) { + dmub_flush_burst_write_buffer_execute(offload, ctx); + return false; + } + + cmd_buf->header.type = DMUB_CMD__REG_SEQ_BURST_WRITE; + cmd_buf->header.sub_type = 0; + cmd_buf->addr = addr; + cmd_buf->write_values[offload->reg_seq_count] = reg_val; + offload->reg_seq_count++; + + return true; +} + +static uint32_t dmub_reg_value_pack(const struct dc_context *ctx, uint32_t addr, + struct dc_reg_value_masks *field_value_mask) +{ + struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload; + struct dmub_rb_cmd_read_modify_write *cmd_buf = &offload->cmd_data.read_modify_write; + struct dmub_cmd_read_modify_write_sequence *seq; + + /* flush command if buffer is full */ + if (offload->cmd_data.cmd_common.header.type != DMUB_CMD__REG_SEQ_BURST_WRITE && + offload->reg_seq_count == DMUB_READ_MODIFY_WRITE_SEQ__MAX) + dmub_flush_buffer_execute(offload, ctx); + + if (offload->should_burst_write) { + if (dmub_reg_value_burst_set_pack(ctx, addr, field_value_mask->value)) + return field_value_mask->value; + else + offload->should_burst_write = false; + } + + /* pack commands */ + cmd_buf->header.type = DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE; + cmd_buf->header.sub_type = 0; + seq = &cmd_buf->seq[offload->reg_seq_count]; + + if (offload->reg_seq_count) { + if (cmd_buf->seq[offload->reg_seq_count - 1].addr == addr) + offload->same_addr_count++; + else + offload->same_addr_count = 0; + } + + seq->addr = addr; + seq->modify_mask = field_value_mask->mask; + seq->modify_value = field_value_mask->value; + offload->reg_seq_count++; + + return field_value_mask->value; +} + +static void dmub_reg_wait_done_pack(const struct dc_context *ctx, uint32_t addr, + uint32_t mask, uint32_t shift, uint32_t condition_value, uint32_t time_out_us) +{ + struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload; + struct dmub_rb_cmd_reg_wait *cmd_buf = &offload->cmd_data.reg_wait; + + cmd_buf->header.type = DMUB_CMD__REG_REG_WAIT; + cmd_buf->header.sub_type = 0; + cmd_buf->reg_wait.addr = addr; + cmd_buf->reg_wait.condition_field_value = mask & (condition_value << shift); + cmd_buf->reg_wait.mask = mask; + cmd_buf->reg_wait.time_out_us = time_out_us; +} + uint32_t generic_reg_update_ex(const struct dc_context *ctx, uint32_t addr, int n, uint8_t shift1, uint32_t mask1, uint32_t field_value1, @@ -93,6 +255,11 @@ uint32_t generic_reg_update_ex(const struct dc_context *ctx, va_end(ap); + if (ctx->dmub_srv && + ctx->dmub_srv->reg_helper_offload.gather_in_progress) + return dmub_reg_value_pack(ctx, addr, &field_value_mask); + /* todo: return void so we can decouple code running in driver from register states */ + /* mmio write directly */ reg_val = dm_read_reg(ctx, addr); reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value; @@ -118,6 +285,13 @@ uint32_t generic_reg_set_ex(const struct dc_context *ctx, /* mmio write directly */ reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value; + + if (ctx->dmub_srv && + ctx->dmub_srv->reg_helper_offload.gather_in_progress) { + return dmub_reg_value_burst_set_pack(ctx, addr, reg_val); + /* todo: return void so we can decouple code running in driver from register states */ + } + dm_write_reg(ctx, addr, reg_val); return reg_val; } @@ -134,6 +308,14 @@ uint32_t dm_read_reg_func( return 0; } #endif + + if (ctx->dmub_srv && + ctx->dmub_srv->reg_helper_offload.gather_in_progress && + !ctx->dmub_srv->reg_helper_offload.should_burst_write) { + ASSERT(false); + return 0; + } + value = cgs_read_register(ctx->cgs_device, address); trace_amdgpu_dc_rreg(&ctx->perf_trace->read_count, address, value); @@ -299,7 +481,19 @@ void generic_reg_wait(const struct dc_context *ctx, uint32_t reg_val; int i; - /* something is terribly wrong if time out is > 200ms. (5Hz) */ + if (ctx->dmub_srv && + ctx->dmub_srv->reg_helper_offload.gather_in_progress) { + dmub_reg_wait_done_pack(ctx, addr, mask, shift, condition_value, + delay_between_poll_us * time_out_num_tries); + return; + } + + /* + * Something is terribly wrong if time out is > 3000ms. + * 3000ms is the maximum time needed for SMU to pass values back. + * This value comes from experiments. + * + */ ASSERT(delay_between_poll_us * time_out_num_tries <= 3000000); for (i = 0; i <= time_out_num_tries; i++) { @@ -346,6 +540,12 @@ uint32_t generic_read_indirect_reg(const struct dc_context *ctx, { uint32_t value = 0; + // when reg read, there should not be any offload. + if (ctx->dmub_srv && + ctx->dmub_srv->reg_helper_offload.gather_in_progress) { + ASSERT(false); + } + dm_write_reg(ctx, addr_index, index); value = dm_read_reg(ctx, addr_data); @@ -382,3 +582,68 @@ uint32_t generic_indirect_reg_update_ex(const struct dc_context *ctx, return reg_val; } + +void reg_sequence_start_gather(const struct dc_context *ctx) +{ + /* if reg sequence is supported and enabled, set flag to + * indicate we want to have REG_SET, REG_UPDATE macro build + * reg sequence command buffer rather than MMIO directly. + */ + + if (ctx->dmub_srv && ctx->dc->debug.dmub_offload_enabled) { + struct dc_reg_helper_state *offload = + &ctx->dmub_srv->reg_helper_offload; + + /* caller sequence mismatch. need to debug caller. offload will not work!!! */ + ASSERT(!offload->gather_in_progress); + + offload->gather_in_progress = true; + } +} + +void reg_sequence_start_execute(const struct dc_context *ctx) +{ + struct dc_reg_helper_state *offload; + + if (!ctx->dmub_srv) + return; + + offload = &ctx->dmub_srv->reg_helper_offload; + + if (offload && offload->gather_in_progress) { + offload->gather_in_progress = false; + offload->should_burst_write = false; + switch (offload->cmd_data.cmd_common.header.type) { + case DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE: + submit_dmub_read_modify_write(offload, ctx); + break; + case DMUB_CMD__REG_REG_WAIT: + submit_dmub_reg_wait(offload, ctx); + break; + case DMUB_CMD__REG_SEQ_BURST_WRITE: + submit_dmub_burst_write(offload, ctx); + break; + default: + return; + } + + dc_dmub_srv_cmd_execute(ctx->dmub_srv); + } +} + +void reg_sequence_wait_done(const struct dc_context *ctx) +{ + /* callback to DM to poll for last submission done*/ + struct dc_reg_helper_state *offload; + + if (!ctx->dmub_srv) + return; + + offload = &ctx->dmub_srv->reg_helper_offload; + + if (offload && + ctx->dc->debug.dmub_offload_enabled && + !ctx->dc->debug.dmcub_emulation) { + dc_dmub_srv_wait_idle(ctx->dmub_srv); + } +} diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index e0856bb8511f6d9d7abfd4aecf7c87d18bd00e7a..25c50bcab9e962d43bd65ca2866f8d438c9b46c8 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -26,8 +26,6 @@ #ifndef DC_HW_TYPES_H #define DC_HW_TYPES_H -#ifndef AMD_EDID_UTILITY - #include "os_types.h" #include "fixed31_32.h" #include "signal_types.h" @@ -167,12 +165,10 @@ enum surface_pixel_format { /*swaped & float*/ SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F, /*grow graphics here if necessary */ -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FIX, SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FIX, SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FLOAT, SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FLOAT, -#endif SURFACE_PIXEL_FORMAT_VIDEO_BEGIN, SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr = SURFACE_PIXEL_FORMAT_VIDEO_BEGIN, @@ -180,10 +176,8 @@ enum surface_pixel_format { SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr, SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb, SURFACE_PIXEL_FORMAT_SUBSAMPLE_END, -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) SURFACE_PIXEL_FORMAT_VIDEO_ACrYCb2101010, SURFACE_PIXEL_FORMAT_VIDEO_CrYCbA1010102, -#endif SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888, SURFACE_PIXEL_FORMAT_INVALID @@ -222,12 +216,10 @@ enum tile_split_values { DC_ROTATED_MICRO_TILING = 0x3, }; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 enum tripleBuffer_enable { DC_TRIPLEBUFFER_DISABLE = 0x0, DC_TRIPLEBUFFER_ENABLE = 0x1, }; -#endif /* TODO: These values come from hardware spec. We need to readdress this * if they ever change. @@ -427,13 +419,11 @@ struct dc_csc_transform { bool enable_adjustment; }; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 struct dc_rgb_fixed { struct fixed31_32 red; struct fixed31_32 green; struct fixed31_32 blue; }; -#endif struct dc_gamma { struct kref refcount; @@ -468,10 +458,8 @@ enum dc_cursor_color_format { CURSOR_MODE_COLOR_1BIT_AND, CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA, CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA, -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED, CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED -#endif }; /* @@ -594,8 +582,6 @@ struct scaling_taps { bool integer_scaling; }; -#endif /* AMD_EDID_UTILITY */ - enum dc_timing_standard { DC_TIMING_STANDARD_UNDEFINED, DC_TIMING_STANDARD_DMT, @@ -626,10 +612,8 @@ enum dc_color_depth { COLOR_DEPTH_121212, COLOR_DEPTH_141414, COLOR_DEPTH_161616, -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 COLOR_DEPTH_999, COLOR_DEPTH_111111, -#endif COLOR_DEPTH_COUNT }; @@ -690,9 +674,7 @@ struct dc_crtc_timing_flags { * rates less than or equal to 340Mcsc */ uint32_t LTE_340MCSC_SCRAMBLE:1; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT uint32_t DSC : 1; /* Use DSC with this timing */ -#endif }; enum dc_timing_3d_format { @@ -717,7 +699,6 @@ enum dc_timing_3d_format { TIMING_3D_FORMAT_MAX, }; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT struct dc_dsc_config { uint32_t num_slices_h; /* Number of DSC slices - horizontal */ uint32_t num_slices_v; /* Number of DSC slices - vertical */ @@ -728,7 +709,6 @@ struct dc_dsc_config { bool ycbcr422_simple; /* Tell DSC engine to convert YCbCr 4:2:2 to 'YCbCr 4:2:2 simple'. */ int32_t rc_buffer_size; /* DSC RC buffer block size in bytes */ }; -#endif struct dc_crtc_timing { uint32_t h_total; uint32_t h_border_left; @@ -755,13 +735,9 @@ struct dc_crtc_timing { enum scanning_type scan_type; struct dc_crtc_timing_flags flags; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT struct dc_dsc_config dsc_cfg; -#endif }; -#ifndef AMD_EDID_UTILITY - enum trigger_delay { TRIGGER_DELAY_NEXT_PIXEL = 0, TRIGGER_DELAY_NEXT_LINE, @@ -796,7 +772,6 @@ enum vram_type { VIDEO_MEMORY_TYPE_GDDR6 = 6, }; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 enum dwb_cnv_out_bpc { DWB_CNV_OUT_BPC_8BPC = 0, DWB_CNV_OUT_BPC_10BPC = 1, @@ -847,7 +822,6 @@ struct mcif_buf_params { unsigned int swlock; }; -#endif #define MAX_TG_COLOR_VALUE 0x3FF struct tg_color { @@ -857,7 +831,5 @@ struct tg_color { uint16_t color_b_cb; }; -#endif /* AMD_EDID_UTILITY */ - #endif /* DC_HW_TYPES_H */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index f24fd19ed93d71389ca8634173cd456f80bcc470..1ff79f703734090ce5ffdba22e65e55ae7717acc 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -29,13 +29,11 @@ #include "dc_types.h" #include "grph_object_defs.h" -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT enum dc_link_fec_state { dc_link_fec_not_ready, dc_link_fec_ready, dc_link_fec_enabled }; -#endif struct dc_link_status { bool link_active; struct dpcd_caps *dpcd_caps; @@ -85,6 +83,7 @@ struct dc_link { bool link_state_valid; bool aux_access_disabled; bool sync_lt_in_progress; + bool is_lttpr_mode_transparent; /* caps is the same as reported_link_cap. link_traing use * reported_link_cap. Will clean up. TODO @@ -95,6 +94,7 @@ struct dc_link { struct dc_lane_settings cur_lane_setting; struct dc_link_settings preferred_link_setting; struct dc_link_training_overrides preferred_training_settings; + struct dp_audio_test_data audio_test_data; uint8_t ddc_hw_inst; @@ -140,9 +140,7 @@ struct dc_link { struct link_trace link_trace; struct gpio *hpd_gpio; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT enum dc_link_fec_state fec_state; -#endif }; const struct dc_link_status *dc_link_get_status(const struct dc_link *dc_link); @@ -259,6 +257,7 @@ void dc_link_dp_disable_hpd(const struct dc_link *link); bool dc_link_dp_set_test_pattern( struct dc_link *link, enum dp_test_pattern test_pattern, + enum dp_test_pattern_color_space test_pattern_color_space, const struct link_training_settings *p_link_settings, const unsigned char *p_custom_pattern, unsigned int cust_pattern_size); @@ -290,6 +289,7 @@ void dc_link_enable_hpd(const struct dc_link *link); void dc_link_disable_hpd(const struct dc_link *link); void dc_link_set_test_pattern(struct dc_link *link, enum dp_test_pattern test_pattern, + enum dp_test_pattern_color_space test_pattern_color_space, const struct link_training_settings *p_link_settings, const unsigned char *p_custom_pattern, unsigned int cust_pattern_size); @@ -305,6 +305,10 @@ bool dc_submit_i2c( uint32_t link_index, struct i2c_command *cmd); +bool dc_submit_i2c_oem( + struct dc *dc, + struct i2c_command *cmd); + uint32_t dc_bandwidth_in_kbps_from_timing( const struct dc_crtc_timing *timing); #endif /* DC_LINK_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index fdb6adc37857a1654fbe5e33a95d5bb027a38aa8..3ea54321b04581da8405157c05e752a992a96c84 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -52,7 +52,6 @@ struct freesync_context { bool dummy; }; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) enum hubp_dmdata_mode { DMDATA_SW_MODE, DMDATA_HW_MODE @@ -82,9 +81,7 @@ struct dc_dmdata_attributes { /* An unbounded array of uint32s, represents software dmdata to be loaded */ uint32_t *dmdata_sw_data; }; -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct dc_writeback_info { bool wb_enabled; int dwb_pipe_inst; @@ -96,7 +93,6 @@ struct dc_writeback_update { unsigned int num_wb_info; struct dc_writeback_info writeback_info[MAX_DWB_PIPES]; }; -#endif enum vertical_interrupt_ref_point { START_V_UPDATE = 0, @@ -121,9 +117,7 @@ union stream_update_flags { uint32_t abm_level:1; uint32_t dpms_off:1; uint32_t gamut_remap:1; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) uint32_t wb_update:1; -#endif } bits; uint32_t raw; @@ -164,6 +158,7 @@ struct dc_stream_state { enum view_3d_format view_format; + bool use_vsc_sdp_for_colorimetry; bool ignore_msa_timing_param; bool converter_disable_audio; uint8_t qs_bit; @@ -203,11 +198,9 @@ struct dc_stream_state { struct crtc_trigger_info triggered_crtc_reset; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) /* writeback */ unsigned int num_wb_info; struct dc_writeback_info writeback_info[MAX_DWB_PIPES]; -#endif /* Computed state bits */ bool mode_changed : 1; @@ -226,9 +219,7 @@ struct dc_stream_state { bool apply_seamless_boot_optimization; uint32_t stream_id; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT bool is_dsc_enabled; -#endif union stream_update_flags update_flags; }; @@ -251,6 +242,7 @@ struct dc_stream_update { struct dc_info_packet *vsp_infopacket; bool *dpms_off; + bool integer_scaling_update; struct colorspace_transform *gamut_remap; enum dc_color_space *output_color_space; @@ -258,12 +250,8 @@ struct dc_stream_update { struct dc_csc_transform *output_csc_transform; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct dc_writeback_update *wb_update; -#endif -#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT) struct dc_dsc_config *dsc_config; -#endif }; bool dc_is_stream_unchanged( @@ -353,7 +341,6 @@ bool dc_add_all_planes_for_stream( int plane_count, struct dc_state *context); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) bool dc_stream_add_writeback(struct dc *dc, struct dc_stream_state *stream, struct dc_writeback_info *wb_info); @@ -364,7 +351,6 @@ bool dc_stream_dmdata_status_done(struct dc *dc, struct dc_stream_state *stream) bool dc_stream_set_dynamic_metadata(struct dc *dc, struct dc_stream_state *stream, struct dc_dmdata_attributes *dmdata_attr); -#endif enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream); diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index d9be8fc3889f7d9f0a7a1fd3d63f036110f445b0..2b92bfa28bde8665eefdbcccbef5229f5e1b27ec 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -25,7 +25,6 @@ #ifndef DC_TYPES_H_ #define DC_TYPES_H_ -#ifndef AMD_EDID_UTILITY /* AND EdidUtility only needs a portion * of this file, including the rest only * causes additional issues. @@ -48,6 +47,7 @@ struct dc_stream_state; struct dc_link; struct dc_sink; struct dal; +struct dc_dmub_srv; /******************************** * Environment definitions @@ -109,6 +109,8 @@ struct dc_context { uint32_t dc_sink_id_count; uint32_t dc_stream_id_count; uint64_t fbc_gpu_addr; + struct dc_dmub_srv *dmub_srv; + #ifdef CONFIG_DRM_AMD_DC_HDCP struct cp_psp cp_psp; #endif @@ -119,6 +121,7 @@ struct dc_context { #define DC_EDID_BLOCK_SIZE 128 #define MAX_SURFACE_NUM 4 #define NUM_PIXEL_FORMATS 10 +#define MAX_REPEATER_CNT 8 #include "dc_ddc_types.h" @@ -402,6 +405,30 @@ enum dpcd_downstream_port_max_bpc { DOWN_STREAM_MAX_12BPC, DOWN_STREAM_MAX_16BPC }; + + +enum link_training_offset { + DPRX = 0, + LTTPR_PHY_REPEATER1 = 1, + LTTPR_PHY_REPEATER2 = 2, + LTTPR_PHY_REPEATER3 = 3, + LTTPR_PHY_REPEATER4 = 4, + LTTPR_PHY_REPEATER5 = 5, + LTTPR_PHY_REPEATER6 = 6, + LTTPR_PHY_REPEATER7 = 7, + LTTPR_PHY_REPEATER8 = 8 +}; + +struct dc_lttpr_caps { + union dpcd_rev revision; + uint8_t mode; + uint8_t max_lane_count; + uint8_t max_link_rate; + uint8_t phy_repeater_cnt; + uint8_t max_ext_timeout; + uint8_t aux_rd_interval[MAX_REPEATER_CNT - 1]; +}; + struct dc_dongle_caps { /* dongle type (DP converter, CV smart dongle) */ enum display_dongle_type dongle_type; @@ -440,7 +467,6 @@ enum display_content_type { DISPLAY_CONTENT_TYPE_GAME = 8 }; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) /* writeback */ struct dwb_stereo_params { bool stereo_enabled; /* false: normal mode, true: 3D stereo */ @@ -471,7 +497,6 @@ struct dc_dwb_params { enum dwb_subsample_position subsample_position; struct dc_transfer_func *out_transfer_func; }; -#endif /* audio*/ @@ -579,9 +604,7 @@ enum dc_infoframe_type { DC_HDMI_INFOFRAME_TYPE_AVI = 0x82, DC_HDMI_INFOFRAME_TYPE_SPD = 0x83, DC_HDMI_INFOFRAME_TYPE_AUDIO = 0x84, -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT DC_DP_INFOFRAME_TYPE_PPS = 0x10, -#endif }; struct dc_info_packet { @@ -757,10 +780,6 @@ struct dc_clock_config { uint32_t current_clock_khz;/*current clock in use*/ }; -#endif /*AMD_EDID_UTILITY*/ -//AMD EDID UTILITY does not need any of the above structures - -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT /* DSC DPCD capabilities */ union dsc_slice_caps1 { struct { @@ -830,6 +849,5 @@ struct dsc_dec_dpcd_caps { uint32_t branch_overall_throughput_1_mps; /* In MPs */ uint32_t branch_max_line_width; }; -#endif #endif /* DC_TYPES_H_ */ 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 7ba7e6f722f6162106ea7deeaee7b118af6d6ce7..ba0caaffa24bf37add2e3b654388dfc5df6d40c7 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.h @@ -67,7 +67,6 @@ SRI(DC_ABM1_HGLS_REG_READ_PROGRESS, ABM, id), \ NBIO_SR(BIOS_SCRATCH_2) -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define ABM_DCN20_REG_LIST() \ ABM_COMMON_REG_LIST_DCE_BASE(), \ SR(DC_ABM1_HG_SAMPLE_RATE), \ @@ -81,7 +80,6 @@ SR(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES), \ SR(DC_ABM1_HGLS_REG_READ_PROGRESS), \ NBIO_SR(BIOS_SCRATCH_2) -#endif #define ABM_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -163,9 +161,7 @@ ABM_SF(ABM0_DC_ABM1_HGLS_REG_READ_PROGRESS, \ ABM1_BL_REG_READ_MISSED_FRAME_CLEAR, mask_sh) -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define ABM_MASK_SH_LIST_DCN20(mask_sh) ABM_MASK_SH_LIST_DCE110(mask_sh) -#endif #define ABM_REG_FIELD_LIST(type) \ type ABM1_HG_NUM_OF_BINS_SEL; \ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c index e472608faf3351ba112a1968792be6f6e4aa207a..f1a5d2c6aa37874577fa6e804cad2c5a43b8c6b8 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c @@ -60,12 +60,14 @@ enum { AUX_DEFER_RETRY_COUNTER = 6 }; -#define TIME_OUT_INCREMENT 1016 -#define TIME_OUT_MULTIPLIER_8 8 -#define TIME_OUT_MULTIPLIER_16 16 -#define TIME_OUT_MULTIPLIER_32 32 -#define TIME_OUT_MULTIPLIER_64 64 -#define MAX_TIMEOUT_LENGTH 127 +#define TIME_OUT_INCREMENT 1016 +#define TIME_OUT_MULTIPLIER_8 8 +#define TIME_OUT_MULTIPLIER_16 16 +#define TIME_OUT_MULTIPLIER_32 32 +#define TIME_OUT_MULTIPLIER_64 64 +#define MAX_TIMEOUT_LENGTH 127 +#define DEFAULT_AUX_ENGINE_MULT 0 +#define DEFAULT_AUX_ENGINE_LENGTH 69 static void release_engine( struct dce_aux *engine) @@ -427,11 +429,14 @@ void dce110_engine_destroy(struct dce_aux **engine) } -static bool dce_aux_configure_timeout(struct ddc_service *ddc, +static uint32_t dce_aux_configure_timeout(struct ddc_service *ddc, uint32_t timeout_in_us) { uint32_t multiplier = 0; uint32_t length = 0; + uint32_t prev_length = 0; + uint32_t prev_mult = 0; + uint32_t prev_timeout_val = 0; struct ddc *ddc_pin = ddc->ddc_pin; struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(aux_engine); @@ -440,7 +445,10 @@ static bool dce_aux_configure_timeout(struct ddc_service *ddc, aux110->polling_timeout_period = timeout_in_us * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER; /* 2-Update aux timeout period length and multiplier */ - if (timeout_in_us <= TIME_OUT_INCREMENT) { + if (timeout_in_us == 0) { + multiplier = DEFAULT_AUX_ENGINE_MULT; + length = DEFAULT_AUX_ENGINE_LENGTH; + } else if (timeout_in_us <= TIME_OUT_INCREMENT) { multiplier = 0; length = timeout_in_us/TIME_OUT_MULTIPLIER_8; if (timeout_in_us % TIME_OUT_MULTIPLIER_8 != 0) @@ -464,9 +472,29 @@ static bool dce_aux_configure_timeout(struct ddc_service *ddc, length = (length < MAX_TIMEOUT_LENGTH) ? length : MAX_TIMEOUT_LENGTH; + REG_GET_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, &prev_length, AUX_RX_TIMEOUT_LEN_MUL, &prev_mult); + + switch (prev_mult) { + case 0: + prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_8; + break; + case 1: + prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_16; + break; + case 2: + prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_32; + break; + case 3: + prev_timeout_val = prev_length * TIME_OUT_MULTIPLIER_64; + break; + default: + prev_timeout_val = DEFAULT_AUX_ENGINE_LENGTH * TIME_OUT_MULTIPLIER_8; + break; + } + REG_UPDATE_SEQ_2(AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, length, AUX_RX_TIMEOUT_LEN_MUL, multiplier); - return true; + return prev_timeout_val; } static struct dce_aux_funcs aux_functions = { @@ -583,6 +611,8 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc, uint8_t reply; bool payload_reply = true; enum aux_channel_operation_result operation_result; + bool retry_on_defer = false; + int aux_ack_retries = 0, aux_defer_retries = 0, aux_i2c_defer_retries = 0, @@ -613,8 +643,10 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc, break; case AUX_TRANSACTION_REPLY_AUX_DEFER: - case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_NACK: case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER: + retry_on_defer = true; + /* fall through */ + case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_NACK: if (++aux_defer_retries >= AUX_MAX_DEFER_RETRIES) { goto fail; } else { @@ -647,15 +679,24 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc, break; case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: - if (++aux_timeout_retries >= AUX_MAX_TIMEOUT_RETRIES) - goto fail; - else { - /* - * DP 1.4, 2.8.2: AUX Transaction Response/Reply Timeouts - * According to the DP spec there should be 3 retries total - * with a 400us wait inbetween each. Hardware already waits - * for 550us therefore no wait is required here. - */ + // Check whether a DEFER had occurred before the timeout. + // If so, treat timeout as a DEFER. + if (retry_on_defer) { + if (++aux_defer_retries >= AUX_MAX_DEFER_RETRIES) + goto fail; + else if (payload->defer_delay > 0) + msleep(payload->defer_delay); + } else { + if (++aux_timeout_retries >= AUX_MAX_TIMEOUT_RETRIES) + goto fail; + else { + /* + * DP 1.4, 2.8.2: AUX Transaction Response/Reply Timeouts + * According to the DP spec there should be 3 retries total + * with a 400us wait inbetween each. Hardware already waits + * for 550us therefore no wait is required here. + */ + } } break; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h index b4b2c79a80736351b6faac766381316f8d2d913c..382465862f2972482be42d6fe0935735910c25bc 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h @@ -30,7 +30,6 @@ #include "inc/hw/aux_engine.h" -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 #define AUX_COMMON_REG_LIST0(id)\ SRI(AUX_CONTROL, DP_AUX, id), \ SRI(AUX_ARB_CONTROL, DP_AUX, id), \ @@ -39,7 +38,6 @@ SRI(AUX_INTERRUPT_CONTROL, DP_AUX, id), \ SRI(AUX_DPHY_RX_CONTROL1, DP_AUX, id), \ SRI(AUX_SW_STATUS, DP_AUX, id) -#endif #define AUX_COMMON_REG_LIST(id)\ SRI(AUX_CONTROL, DP_AUX, id), \ @@ -311,7 +309,7 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc, struct aux_payload *cmd); struct dce_aux_funcs { - bool (*configure_timeout) + uint32_t (*configure_timeout) (struct ddc_service *ddc, uint32_t timeout); void (*destroy) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index f787a6b9478121672f69a78a31bdf5844ffbdb05..2e992fbc0d71844f0d0008cf5afc76cc19aef242 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -905,7 +905,7 @@ static bool dce112_program_pix_clk( struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source); struct bp_pixel_clock_parameters bp_pc_params = {0}; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) if (IS_FPGA_MAXIMUS_DC(clock_source->ctx->dce_environment)) { unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0; unsigned dp_dto_ref_100hz = 7000000; @@ -1004,7 +1004,6 @@ static bool get_pixel_clk_frequency_100hz( return false; } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) /* this table is use to find *1.001 and /1.001 pixel rates from non-precise pixel rate */ struct pixel_rate_range_table_entry { @@ -1064,7 +1063,6 @@ static const struct clock_source_funcs dcn20_clk_src_funcs = { .get_pix_clk_dividers = dce112_get_pix_clk_dividers, .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz }; -#endif /*****************************************/ /* Constructor */ @@ -1435,7 +1433,6 @@ bool dce112_clk_src_construct( return true; } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) bool dcn20_clk_src_construct( struct dce110_clk_src *clk_src, struct dc_context *ctx, @@ -1451,4 +1448,3 @@ bool dcn20_clk_src_construct( return ret; } -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h index 43c1bf60b83ca28bbd904565703017d3c08d236b..51bd25079606462d5d1ea816b0bf03d4c6747818 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h @@ -55,7 +55,6 @@ CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_DCCG_DEEP_COLOR_CNTL, mask_sh),\ CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE, mask_sh) -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define CS_COMMON_REG_LIST_DCN2_0(index, pllid) \ SRI(PIXCLK_RESYNC_CNTL, PHYPLL, pllid),\ SRII(PHASE, DP_DTO, 0),\ @@ -76,9 +75,7 @@ SRII(PIXEL_RATE_CNTL, OTG, 3),\ SRII(PIXEL_RATE_CNTL, OTG, 4),\ SRII(PIXEL_RATE_CNTL, OTG, 5) -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) #define CS_COMMON_REG_LIST_DCN2_1(index, pllid) \ SRI(PIXCLK_RESYNC_CNTL, PHYPLL, pllid),\ SRII(PHASE, DP_DTO, 0),\ @@ -93,17 +90,14 @@ SRII(PIXEL_RATE_CNTL, OTG, 1),\ SRII(PIXEL_RATE_CNTL, OTG, 2),\ SRII(PIXEL_RATE_CNTL, OTG, 3) -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define CS_COMMON_MASK_SH_LIST_DCN2_0(mask_sh)\ CS_SF(DP_DTO0_PHASE, DP_DTO0_PHASE, mask_sh),\ CS_SF(DP_DTO0_MODULO, DP_DTO0_MODULO, mask_sh),\ CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_DCCG_DEEP_COLOR_CNTL, mask_sh),\ CS_SF(OTG0_PIXEL_RATE_CNTL, DP_DTO0_ENABLE, mask_sh) -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) #define CS_COMMON_REG_LIST_DCN1_0(index, pllid) \ SRI(PIXCLK_RESYNC_CNTL, PHYPLL, pllid),\ @@ -201,7 +195,6 @@ bool dce112_clk_src_construct( const struct dce110_clk_src_shift *cs_shift, const struct dce110_clk_src_mask *cs_mask); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) bool dcn20_clk_src_construct( struct dce110_clk_src *clk_src, struct dc_context *ctx, @@ -210,6 +203,5 @@ bool dcn20_clk_src_construct( const struct dce110_clk_src_regs *regs, const struct dce110_clk_src_shift *cs_shift, const struct dce110_clk_src_mask *cs_mask); -#endif #endif diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c index ba995d3f23182438b70e4e42a9053ad7698f44b1..e619e67e6b513a2c4183a56da08a2b60e82c1a62 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c @@ -59,6 +59,12 @@ #define MCP_BL_SET_PWM_FRAC 0x6A /* Enable or disable Fractional PWM */ #define MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK 0x00000001L +// PSP FW version +#define mmMP0_SMN_C2PMSG_58 0x1607A + +//Register access policy version +#define mmMP0_SMN_C2PMSG_91 0x1609B + static bool dce_dmcu_init(struct dmcu *dmcu) { // Do nothing @@ -318,7 +324,7 @@ static void dce_get_psr_wait_loop( return; } -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) static void dcn10_get_dmcu_version(struct dmcu *dmcu) { struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); @@ -373,6 +379,7 @@ static bool dcn10_dmcu_init(struct dmcu *dmcu) const struct dc_config *config = &dmcu->ctx->dc->config; bool status = false; + PERF_TRACE(); /* Definition of DC_DMCU_SCRATCH * 0 : firmare not loaded * 1 : PSP load DMCU FW but not initialized @@ -429,9 +436,21 @@ static bool dcn10_dmcu_init(struct dmcu *dmcu) break; } + PERF_TRACE(); return status; } +static bool dcn21_dmcu_init(struct dmcu *dmcu) +{ + struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); + uint32_t dmcub_psp_version = REG_READ(DMCUB_SCRATCH15); + + if (dmcu->auto_load_dmcu && dmcub_psp_version == 0) { + return false; + } + + return dcn10_dmcu_init(dmcu); +} static bool dcn10_dmcu_load_iram(struct dmcu *dmcu, unsigned int start_offset, @@ -727,9 +746,7 @@ static bool dcn10_is_dmcu_initialized(struct dmcu *dmcu) return true; } -#endif //(CONFIG_DRM_AMD_DC_DCN1_0) -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) static bool dcn20_lock_phy(struct dmcu *dmcu) { @@ -777,7 +794,7 @@ static bool dcn20_unlock_phy(struct dmcu *dmcu) return true; } -#endif //(CONFIG_DRM_AMD_DC_DCN2_0) +#endif //(CONFIG_DRM_AMD_DC_DCN) static const struct dmcu_funcs dce_funcs = { .dmcu_init = dce_dmcu_init, @@ -790,7 +807,7 @@ static const struct dmcu_funcs dce_funcs = { .is_dmcu_initialized = dce_is_dmcu_initialized }; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) static const struct dmcu_funcs dcn10_funcs = { .dmcu_init = dcn10_dmcu_init, .load_iram = dcn10_dmcu_load_iram, @@ -801,9 +818,7 @@ static const struct dmcu_funcs dcn10_funcs = { .get_psr_wait_loop = dcn10_get_psr_wait_loop, .is_dmcu_initialized = dcn10_is_dmcu_initialized }; -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) static const struct dmcu_funcs dcn20_funcs = { .dmcu_init = dcn10_dmcu_init, .load_iram = dcn10_dmcu_load_iram, @@ -816,6 +831,19 @@ static const struct dmcu_funcs dcn20_funcs = { .lock_phy = dcn20_lock_phy, .unlock_phy = dcn20_unlock_phy }; + +static const struct dmcu_funcs dcn21_funcs = { + .dmcu_init = dcn21_dmcu_init, + .load_iram = dcn10_dmcu_load_iram, + .set_psr_enable = dcn10_dmcu_set_psr_enable, + .setup_psr = dcn10_dmcu_setup_psr, + .get_psr_state = dcn10_get_dmcu_psr_state, + .set_psr_wait_loop = dcn10_psr_wait_loop, + .get_psr_wait_loop = dcn10_get_psr_wait_loop, + .is_dmcu_initialized = dcn10_is_dmcu_initialized, + .lock_phy = dcn20_lock_phy, + .unlock_phy = dcn20_unlock_phy +}; #endif static void dce_dmcu_construct( @@ -836,6 +864,26 @@ static void dce_dmcu_construct( dmcu_dce->dmcu_mask = dmcu_mask; } +#if defined(CONFIG_DRM_AMD_DC_DCN) +static void dcn21_dmcu_construct( + struct dce_dmcu *dmcu_dce, + struct dc_context *ctx, + const struct dce_dmcu_registers *regs, + const struct dce_dmcu_shift *dmcu_shift, + const struct dce_dmcu_mask *dmcu_mask) +{ + uint32_t psp_version = 0; + + dce_dmcu_construct(dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask); + + if (!IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) { + psp_version = dm_read_reg(ctx, mmMP0_SMN_C2PMSG_58); + dmcu_dce->base.auto_load_dmcu = ((psp_version & 0x00FF00FF) > 0x00110029); + dmcu_dce->base.psp_version = psp_version; + } +} +#endif + struct dmcu *dce_dmcu_create( struct dc_context *ctx, const struct dce_dmcu_registers *regs, @@ -857,7 +905,7 @@ struct dmcu *dce_dmcu_create( return &dmcu_dce->base; } -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) struct dmcu *dcn10_dmcu_create( struct dc_context *ctx, const struct dce_dmcu_registers *regs, @@ -878,9 +926,7 @@ struct dmcu *dcn10_dmcu_create( return &dmcu_dce->base; } -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct dmcu *dcn20_dmcu_create( struct dc_context *ctx, const struct dce_dmcu_registers *regs, @@ -901,6 +947,27 @@ struct dmcu *dcn20_dmcu_create( return &dmcu_dce->base; } + +struct dmcu *dcn21_dmcu_create( + struct dc_context *ctx, + const struct dce_dmcu_registers *regs, + const struct dce_dmcu_shift *dmcu_shift, + const struct dce_dmcu_mask *dmcu_mask) +{ + struct dce_dmcu *dmcu_dce = kzalloc(sizeof(*dmcu_dce), GFP_KERNEL); + + if (dmcu_dce == NULL) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn21_dmcu_construct( + dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask); + + dmcu_dce->base.funcs = &dcn21_funcs; + + return &dmcu_dce->base; +} #endif void dce_dmcu_destroy(struct dmcu **dmcu) 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 cc8587683b4b691117ac345079b2c401d2a26327..5e044c2d3d6d31f001f42648025b689fdc4270cc 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h @@ -71,6 +71,10 @@ DMCU_COMMON_REG_LIST_DCE_BASE(), \ SR(DMU_MEM_PWR_CNTL) +#define DMCU_DCN20_REG_LIST()\ + DMCU_DCN10_REG_LIST(), \ + SR(DMCUB_SCRATCH15) + #define DMCU_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -175,6 +179,7 @@ struct dce_dmcu_registers { uint32_t DMCU_INTERRUPT_TO_UC_EN_MASK; uint32_t SMU_INTERRUPT_CONTROL; uint32_t DC_DMCU_SCRATCH; + uint32_t DMCUB_SCRATCH15; }; struct dce_dmcu { @@ -261,13 +266,17 @@ struct dmcu *dcn10_dmcu_create( const struct dce_dmcu_shift *dmcu_shift, const struct dce_dmcu_mask *dmcu_mask); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct dmcu *dcn20_dmcu_create( struct dc_context *ctx, const struct dce_dmcu_registers *regs, const struct dce_dmcu_shift *dmcu_shift, const struct dce_dmcu_mask *dmcu_mask); -#endif + +struct dmcu *dcn21_dmcu_create( + struct dc_context *ctx, + const struct dce_dmcu_registers *regs, + const struct dce_dmcu_shift *dmcu_shift, + const struct dce_dmcu_mask *dmcu_mask); void dce_dmcu_destroy(struct dmcu **dmcu); 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 0275d6d60da42a26ea2fb97b34178b65e0bd377d..e1c5839a80dcda582e01b38684c735d9a14081ee 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c @@ -25,7 +25,7 @@ #include "dce_hwseq.h" #include "reg_helper.h" -#include "hw_sequencer.h" +#include "hw_sequencer_private.h" #include "core_types.h" #define CTX \ 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 32d145a0d6fce5437b480e97c76970335895c8d4..c5aa1f48593a6eba67b2019b31be21253492bc70 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -25,7 +25,7 @@ #ifndef __DCE_HWSEQ_H__ #define __DCE_HWSEQ_H__ -#include "hw_sequencer.h" +#include "dc_types.h" #define BL_REG_LIST()\ SR(LVTMA_PWRSEQ_CNTL), \ @@ -210,7 +210,6 @@ SR(DC_IP_REQUEST_CNTL), \ BL_REG_LIST() -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define HWSEQ_DCN2_REG_LIST()\ HWSEQ_DCN_REG_LIST(), \ HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 0), \ @@ -276,9 +275,7 @@ SR(D6VGA_CONTROL), \ SR(DC_IP_REQUEST_CNTL), \ BL_REG_LIST() -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) #define HWSEQ_DCN21_REG_LIST()\ HWSEQ_DCN_REG_LIST(), \ HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 0), \ @@ -329,7 +326,6 @@ SR(D6VGA_CONTROL), \ SR(DC_IP_REQUEST_CNTL), \ BL_REG_LIST() -#endif struct dce_hwseq_registers { @@ -577,7 +573,6 @@ struct dce_hwseq_registers { HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_RENDER_START, mask_sh),\ HWSEQ_LVTMA_MASK_SH_LIST(mask_sh) -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define HWSEQ_DCN2_MASK_SH_LIST(mask_sh)\ HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ @@ -637,9 +632,7 @@ struct dce_hwseq_registers { HWS_SF(, DOMAIN21_PG_STATUS, DOMAIN21_PGFSM_PWR_STATUS, mask_sh), \ HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ HWSEQ_LVTMA_MASK_SH_LIST(mask_sh) -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) #define HWSEQ_DCN21_MASK_SH_LIST(mask_sh)\ HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ @@ -682,7 +675,6 @@ struct dce_hwseq_registers { HWSEQ_LVTMA_MASK_SH_LIST(mask_sh), \ HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \ HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) -#endif #define HWSEQ_REG_FIELD_LIST(type) \ type DCFE_CLOCK_ENABLE; \ @@ -800,8 +792,7 @@ struct dce_hwseq_registers { type D2VGA_MODE_ENABLE; \ type D3VGA_MODE_ENABLE; \ type D4VGA_MODE_ENABLE; \ - type AZALIA_AUDIO_DTO_MODULE;\ - type HPO_HDMISTREAMCLK_GATE_DIS; + type AZALIA_AUDIO_DTO_MODULE; struct dce_hwseq_shift { HWSEQ_REG_FIELD_LIST(uint8_t) @@ -820,6 +811,10 @@ enum blnd_mode { BLND_MODE_BLENDING,/* Alpha blending - blend 'current' and 'other' */ }; +struct dce_hwseq; +struct pipe_ctx; +struct clock_source; + void dce_enable_fe_clock(struct dce_hwseq *hwss, unsigned int inst, bool enable); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.c b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.c index 35a75398fcb400b95901796d5964c8819452e2d0..dd41736bb5c4930de31b43898194a86f8e88fd92 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.c @@ -31,7 +31,7 @@ bool dce_i2c_submit_command( struct i2c_command *cmd) { struct dce_i2c_hw *dce_i2c_hw; - struct dce_i2c_sw *dce_i2c_sw; + struct dce_i2c_sw dce_i2c_sw = {0}; if (!ddc) { BREAK_TO_DEBUGGER(); @@ -43,18 +43,15 @@ bool dce_i2c_submit_command( return false; } - /* The software engine is only available on dce8 */ - dce_i2c_sw = dce_i2c_acquire_i2c_sw_engine(pool, ddc); - - if (!dce_i2c_sw) { - dce_i2c_hw = acquire_i2c_hw_engine(pool, ddc); - - if (!dce_i2c_hw) - return false; + dce_i2c_hw = acquire_i2c_hw_engine(pool, ddc); + if (dce_i2c_hw) return dce_i2c_submit_command_hw(pool, ddc, cmd, dce_i2c_hw); - } - return dce_i2c_submit_command_sw(pool, ddc, cmd, dce_i2c_sw); + dce_i2c_sw.ctx = ddc->ctx; + if (dce_i2c_engine_acquire_sw(&dce_i2c_sw, ddc)) { + return dce_i2c_submit_command_sw(pool, ddc, cmd, &dce_i2c_sw); + } + return false; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c index aad7b52165be18cf886f15e1fe6a34138ea9659c..1cd4d8fc361f9ac4e8d2d95fd7878d57fb0f2945 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c @@ -296,9 +296,7 @@ static bool setup_engine( struct dce_i2c_hw *dce_i2c_hw) { uint32_t i2c_setup_limit = I2C_SETUP_TIME_LIMIT_DCE; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) uint32_t reset_length = 0; -#endif /* we have checked I2c not used by DMCU, set SW use I2C REQ to 1 to indicate SW using it*/ REG_UPDATE(DC_I2C_ARBITRATION, DC_I2C_SW_USE_I2C_REG_REQ, 1); @@ -322,14 +320,12 @@ static bool setup_engine( REG_UPDATE_N(SETUP, 2, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT), i2c_setup_limit, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 1); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) } else { reset_length = dce_i2c_hw->send_reset_length; REG_UPDATE_N(SETUP, 3, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT), i2c_setup_limit, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_SEND_RESET_LENGTH), reset_length, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 1); -#endif } /* Program HW priority * set to High - interrupt software I2C at any time @@ -705,7 +701,6 @@ void dcn1_i2c_hw_construct( dce_i2c_hw->setup_limit = I2C_SETUP_TIME_LIMIT_DCN; } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) void dcn2_i2c_hw_construct( struct dce_i2c_hw *dce_i2c_hw, struct dc_context *ctx, @@ -724,4 +719,3 @@ void dcn2_i2c_hw_construct( if (ctx->dc->debug.scl_reset_length10) dce_i2c_hw->send_reset_length = I2C_SEND_RESET_LENGTH_10; } -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h index cb0234e5d597eec046c87acc2c897d193024267e..d4b2037f7d74f10d336b4286a943eb94334cc11f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h @@ -177,9 +177,7 @@ struct dce_i2c_shift { uint8_t DC_I2C_INDEX; uint8_t DC_I2C_INDEX_WRITE; uint8_t XTAL_REF_DIV; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) uint8_t DC_I2C_DDC1_SEND_RESET_LENGTH; -#endif uint8_t DC_I2C_REG_RW_CNTL_STATUS; }; @@ -220,17 +218,13 @@ struct dce_i2c_mask { uint32_t DC_I2C_INDEX; uint32_t DC_I2C_INDEX_WRITE; uint32_t XTAL_REF_DIV; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) uint32_t DC_I2C_DDC1_SEND_RESET_LENGTH; -#endif uint32_t DC_I2C_REG_RW_CNTL_STATUS; }; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define I2C_COMMON_MASK_SH_LIST_DCN2(mask_sh)\ I2C_COMMON_MASK_SH_LIST_DCE110(mask_sh),\ I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_SEND_RESET_LENGTH, mask_sh) -#endif struct dce_i2c_registers { uint32_t SETUP; @@ -312,7 +306,6 @@ void dcn1_i2c_hw_construct( const struct dce_i2c_shift *shifts, const struct dce_i2c_mask *masks); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) void dcn2_i2c_hw_construct( struct dce_i2c_hw *dce_i2c_hw, struct dc_context *ctx, @@ -320,7 +313,6 @@ void dcn2_i2c_hw_construct( const struct dce_i2c_registers *regs, const struct dce_i2c_shift *shifts, const struct dce_i2c_mask *masks); -#endif bool dce_i2c_submit_command_hw( struct resource_pool *pool, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_sw.c b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_sw.c index a5a11c251e257ef120e10e3bd4bbef7628c53d26..87d8428df6c46a19ee1a229626d3be16f66ce17f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_sw.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_sw.c @@ -73,31 +73,6 @@ static void release_engine_dce_sw( dce_i2c_sw->ddc = NULL; } -static bool get_hw_supported_ddc_line( - struct ddc *ddc, - enum gpio_ddc_line *line) -{ - enum gpio_ddc_line line_found; - - *line = GPIO_DDC_LINE_UNKNOWN; - - if (!ddc) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!ddc->hw_info.hw_supported) - return false; - - line_found = dal_ddc_get_line(ddc); - - if (line_found >= GPIO_DDC_LINE_COUNT) - return false; - - *line = line_found; - - return true; -} static bool wait_for_scl_high_sw( struct dc_context *ctx, struct ddc *ddc, @@ -524,21 +499,3 @@ bool dce_i2c_submit_command_sw( return result; } -struct dce_i2c_sw *dce_i2c_acquire_i2c_sw_engine( - struct resource_pool *pool, - struct ddc *ddc) -{ - enum gpio_ddc_line line; - struct dce_i2c_sw *engine = NULL; - - if (get_hw_supported_ddc_line(ddc, &line)) - engine = pool->sw_i2cs[line]; - - if (!engine) - return NULL; - - if (!dce_i2c_engine_acquire_sw(engine, ddc)) - return NULL; - - return engine; -} diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_sw.h b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_sw.h index 5bbcdd455614fce41c0dcd9fc3276b01806f2028..019fc47bb76708f9cfbc7377366ebea61d3b30e8 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_sw.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_sw.h @@ -49,9 +49,9 @@ bool dce_i2c_submit_command_sw( struct i2c_command *cmd, struct dce_i2c_sw *dce_i2c_sw); -struct dce_i2c_sw *dce_i2c_acquire_i2c_sw_engine( - struct resource_pool *pool, - struct ddc *ddc); +bool dce_i2c_engine_acquire_sw( + struct dce_i2c_sw *dce_i2c_sw, + struct ddc *ddc_handle); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c index 6ed922a3c1cd52da9cfad46587a634d85b665356..451574971b9641327742611311ba4ecd9d991ce6 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c @@ -137,7 +137,7 @@ static void dce110_update_generic_info_packet( AFMT_GENERIC0_UPDATE, (packet_index == 0), AFMT_GENERIC2_UPDATE, (packet_index == 2)); } -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) if (REG(AFMT_VBI_PACKET_CONTROL1)) { switch (packet_index) { case 0: @@ -231,7 +231,7 @@ static void dce110_update_hdmi_info_packet( HDMI_GENERIC1_SEND, send, HDMI_GENERIC1_LINE, line); break; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) case 4: if (REG(HDMI_GENERIC_PACKET_CONTROL2)) REG_UPDATE_3(HDMI_GENERIC_PACKET_CONTROL2, @@ -275,9 +275,10 @@ static void dce110_stream_encoder_dp_set_stream_attribute( struct stream_encoder *enc, struct dc_crtc_timing *crtc_timing, enum dc_color_space output_color_space, + bool use_vsc_sdp_for_colorimetry, uint32_t enable_sdp_splitting) { -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) uint32_t h_active_start; uint32_t v_active_start; uint32_t misc0 = 0; @@ -329,7 +330,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( if (enc110->se_mask->DP_VID_M_DOUBLE_VALUE_EN) REG_UPDATE(DP_VID_TIMING, DP_VID_M_DOUBLE_VALUE_EN, 1); -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) if (enc110->se_mask->DP_VID_N_MUL) REG_UPDATE(DP_VID_TIMING, DP_VID_N_MUL, 1); #endif @@ -340,7 +341,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( break; } -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) if (REG(DP_MSA_MISC)) misc1 = REG_READ(DP_MSA_MISC); #endif @@ -374,7 +375,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( /* set dynamic range and YCbCr range */ -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) switch (hw_crtc_timing.display_color_depth) { case COLOR_DEPTH_666: colorimetry_bpc = 0; @@ -454,7 +455,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( DP_DYN_RANGE, dynamic_range_rgb, DP_YCBCR_RANGE, dynamic_range_ycbcr); -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) if (REG(DP_MSA_COLORIMETRY)) REG_SET(DP_MSA_COLORIMETRY, 0, DP_MSA_MISC0, misc0); @@ -489,7 +490,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( hw_crtc_timing.v_front_porch; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) /* start at begining of left border */ if (REG(DP_MSA_TIMING_PARAM2)) REG_SET_2(DP_MSA_TIMING_PARAM2, 0, @@ -786,7 +787,7 @@ static void dce110_stream_encoder_update_hdmi_info_packets( dce110_update_hdmi_info_packet(enc110, 3, &info_frame->hdrsmd); } -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) if (enc110->se_mask->HDMI_DB_DISABLE) { /* for bring up, disable dp double TODO */ if (REG(HDMI_DB_CONTROL)) @@ -824,7 +825,7 @@ static void dce110_stream_encoder_stop_hdmi_info_packets( HDMI_GENERIC1_LINE, 0, HDMI_GENERIC1_SEND, 0); -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) /* stop generic packets 2 & 3 on HDMI */ if (REG(HDMI_GENERIC_PACKET_CONTROL2)) REG_SET_6(HDMI_GENERIC_PACKET_CONTROL2, 0, diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c index 799d36299c9bef133655f8e82d08ce7a6653451a..753cb8edd9962273733dc9c155ab2a04cfaff315 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c @@ -26,7 +26,6 @@ #include "dc.h" #include "core_types.h" #include "clk_mgr.h" -#include "hw_sequencer.h" #include "dce100_hw_sequencer.h" #include "resource.h" @@ -136,7 +135,7 @@ void dce100_hw_sequencer_construct(struct dc *dc) { dce110_hw_sequencer_construct(dc); - dc->hwss.enable_display_power_gating = dce100_enable_display_power_gating; + dc->hwseq->funcs.enable_display_power_gating = dce100_enable_display_power_gating; dc->hwss.prepare_bandwidth = dce100_prepare_bandwidth; dc->hwss.optimize_bandwidth = dce100_optimize_bandwidth; } diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h index a6b80fdaa666a12240b1ddfc0268a31c49aafd61..34518da20009d94ede9c8f725e99c516688704aa 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h @@ -27,6 +27,7 @@ #define __DC_HWSS_DCE100_H__ #include "core_types.h" +#include "hw_sequencer_private.h" struct dc; struct dc_state; diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index a5e122c721ec06d123dd6a6b29f05da4f57bca71..8f78bf9abbca1b070b8af6c217bc6967d1886cd9 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -725,7 +725,7 @@ void dce100_clock_source_destroy(struct clock_source **clk_src) *clk_src = NULL; } -static void destruct(struct dce110_resource_pool *pool) +static void dce100_resource_destruct(struct dce110_resource_pool *pool) { unsigned int i; @@ -885,7 +885,7 @@ static void dce100_destroy_resource_pool(struct resource_pool **pool) { struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); - destruct(dce110_pool); + dce100_resource_destruct(dce110_pool); kfree(dce110_pool); *pool = NULL; } @@ -950,7 +950,7 @@ static const struct resource_funcs dce100_res_pool_funcs = { .find_first_free_match_stream_enc_for_link = dce100_find_first_free_match_stream_enc_for_link }; -static bool construct( +static bool dce100_resource_construct( uint8_t num_virtual_links, struct dc *dc, struct dce110_resource_pool *pool) @@ -1122,7 +1122,7 @@ static bool construct( return true; res_create_fail: - destruct(pool); + dce100_resource_destruct(pool); return false; } @@ -1137,7 +1137,7 @@ struct resource_pool *dce100_create_resource_pool( if (!pool) return NULL; - if (construct(num_virtual_links, dc, pool)) + if (dce100_resource_construct(num_virtual_links, dc, pool)) return &pool->base; kfree(pool); 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 f0e837d140007b47a9bc67feeaaa45c5289e434f..4939cf3b316f29c2fe30cb7be4556df83cde878d 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 @@ -61,6 +61,8 @@ #include "atomfirmware.h" +#define GAMMA_HW_POINTS_NUM 256 + /* * All values are in milliseconds; * For eDP, after power-up/power/down, @@ -268,7 +270,7 @@ static void build_prescale_params(struct ipp_prescale_params *prescale_params, } static bool -dce110_set_input_transfer_func(struct pipe_ctx *pipe_ctx, +dce110_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) { struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; @@ -596,7 +598,7 @@ dce110_translate_regamma_to_hw_format(const struct dc_transfer_func *output_tf, } static bool -dce110_set_output_transfer_func(struct pipe_ctx *pipe_ctx, +dce110_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream) { struct transform *xfm = pipe_ctx->plane_res.xfm; @@ -651,10 +653,9 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) { enum dc_lane_count lane_count = pipe_ctx->stream->link->cur_link_settings.lane_count; - struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; struct dc_link *link = pipe_ctx->stream->link; - + const struct dc *dc = link->dc; uint32_t active_total_with_borders; uint32_t early_control = 0; @@ -667,7 +668,7 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, pipe_ctx->stream_res.stream_enc->id, true); - link->dc->hwss.update_info_frame(pipe_ctx); + dc->hwss.update_info_frame(pipe_ctx); /* enable early control to avoid corruption on DP monitor*/ active_total_with_borders = @@ -943,15 +944,15 @@ void dce110_edp_backlight_control( void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx) { /* notify audio driver for audio modes of monitor */ - struct dc *core_dc; + struct dc *dc; struct clk_mgr *clk_mgr; unsigned int i, num_audio = 1; if (!pipe_ctx->stream) return; - core_dc = pipe_ctx->stream->ctx->dc; - clk_mgr = core_dc->clk_mgr; + dc = pipe_ctx->stream->ctx->dc; + clk_mgr = dc->clk_mgr; if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == true) return; @@ -959,7 +960,7 @@ void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx) if (pipe_ctx->stream_res.audio) { for (i = 0; i < MAX_PIPES; i++) { /*current_state not updated yet*/ - if (core_dc->current_state->res_ctx.pipe_ctx[i].stream_res.audio != NULL) + if (dc->current_state->res_ctx.pipe_ctx[i].stream_res.audio != NULL) num_audio++; } @@ -1047,6 +1048,7 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, struct encoder_unblank_param params = { { 0 } }; struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->link; + struct dce_hwseq *hws = link->dc->hwseq; /* only 3 items below are used by unblank */ params.timing = pipe_ctx->stream->timing; @@ -1056,7 +1058,7 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, ¶ms); if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { - link->dc->hwss.edp_backlight_control(link, true); + hws->funcs.edp_backlight_control(link, true); } } @@ -1064,9 +1066,10 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->link; + struct dce_hwseq *hws = link->dc->hwseq; if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { - link->dc->hwss.edp_backlight_control(link, false); + hws->funcs.edp_backlight_control(link, false); dc_link_set_abm_disable(link); } @@ -1223,7 +1226,7 @@ static void program_scaler(const struct dc *dc, { struct tg_color color = {0}; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) /* TOFPGA */ if (pipe_ctx->plane_res.xfm->funcs->transform_set_pixel_storage_depth == NULL) return; @@ -1322,12 +1325,11 @@ static enum dc_status apply_single_controller_ctx_to_hw( struct dc_stream_state *stream = pipe_ctx->stream; struct drr_params params = {0}; unsigned int event_triggers = 0; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; -#endif + struct dce_hwseq *hws = dc->hwseq; - if (dc->hwss.disable_stream_gating) { - dc->hwss.disable_stream_gating(dc, pipe_ctx); + if (hws->funcs.disable_stream_gating) { + hws->funcs.disable_stream_gating(dc, pipe_ctx); } if (pipe_ctx->stream_res.audio != NULL) { @@ -1357,10 +1359,10 @@ static enum dc_status apply_single_controller_ctx_to_hw( /* */ /* Do not touch stream timing on seamless boot optimization. */ if (!pipe_ctx->stream->apply_seamless_boot_optimization) - dc->hwss.enable_stream_timing(pipe_ctx, context, dc); + hws->funcs.enable_stream_timing(pipe_ctx, context, dc); - if (dc->hwss.setup_vupdate_interrupt) - dc->hwss.setup_vupdate_interrupt(pipe_ctx); + if (hws->funcs.setup_vupdate_interrupt) + hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); params.vertical_total_min = stream->adjust.v_total_min; params.vertical_total_max = stream->adjust.v_total_max; @@ -1390,7 +1392,6 @@ static enum dc_status apply_single_controller_ctx_to_hw( pipe_ctx->stream_res.opp, &stream->bit_depth_params, &stream->clamping); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) while (odm_pipe) { odm_pipe->stream_res.opp->funcs->opp_set_dyn_expansion( odm_pipe->stream_res.opp, @@ -1404,7 +1405,6 @@ static enum dc_status apply_single_controller_ctx_to_hw( &stream->clamping); odm_pipe = odm_pipe->next_odm_pipe; } -#endif if (!stream->dpms_off) core_link_enable_stream(context, pipe_ctx); @@ -1438,6 +1438,9 @@ static void power_down_encoders(struct dc *dc) if (!dc->links[i]->wa_flags.dp_keep_receiver_powered) dp_receiver_power_ctrl(dc->links[i], false); + if (signal != SIGNAL_TYPE_EDP) + signal = SIGNAL_TYPE_NONE; + dc->links[i]->link_enc->funcs->disable_output( dc->links[i]->link_enc, signal); } @@ -1552,9 +1555,10 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) bool can_apply_edp_fast_boot = false; bool can_apply_seamless_boot = false; bool keep_edp_vdd_on = false; + struct dce_hwseq *hws = dc->hwseq; - if (dc->hwss.init_pipes) - dc->hwss.init_pipes(dc, context); + if (hws->funcs.init_pipes) + hws->funcs.init_pipes(dc, context); edp_stream = get_edp_stream(context); @@ -1591,7 +1595,7 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) if (!can_apply_edp_fast_boot && !can_apply_seamless_boot) { if (edp_link_with_sink && !keep_edp_vdd_on) { /*turn off backlight before DP_blank and encoder powered down*/ - dc->hwss.edp_backlight_control(edp_link_with_sink, false); + hws->funcs.edp_backlight_control(edp_link_with_sink, false); } /*resume from S3, no vbios posting, no need to power down again*/ power_down_all_hw_blocks(dc); @@ -2006,13 +2010,14 @@ enum dc_status dce110_apply_ctx_to_hw( struct dc *dc, struct dc_state *context) { + struct dce_hwseq *hws = dc->hwseq; struct dc_bios *dcb = dc->ctx->dc_bios; enum dc_status status; int i; /* Reset old context */ /* look up the targets that have been removed since last commit */ - dc->hwss.reset_hw_ctx_wrap(dc, context); + hws->funcs.reset_hw_ctx_wrap(dc, context); /* Skip applying if no targets */ if (context->stream_count <= 0) @@ -2037,7 +2042,7 @@ enum dc_status dce110_apply_ctx_to_hw( continue; } - dc->hwss.enable_display_power_gating( + hws->funcs.enable_display_power_gating( dc, i, dc->ctx->dc_bios, PIPE_GATING_CONTROL_DISABLE); } @@ -2346,19 +2351,20 @@ static void init_hw(struct dc *dc) struct transform *xfm; struct abm *abm; struct dmcu *dmcu; + struct dce_hwseq *hws = dc->hwseq; bp = dc->ctx->dc_bios; for (i = 0; i < dc->res_pool->pipe_count; i++) { xfm = dc->res_pool->transforms[i]; xfm->funcs->transform_reset(xfm); - dc->hwss.enable_display_power_gating( + hws->funcs.enable_display_power_gating( dc, i, bp, PIPE_GATING_CONTROL_INIT); - dc->hwss.enable_display_power_gating( + hws->funcs.enable_display_power_gating( dc, i, bp, PIPE_GATING_CONTROL_DISABLE); - dc->hwss.enable_display_pipe_clock_gating( + hws->funcs.enable_display_pipe_clock_gating( dc->ctx, true); } @@ -2444,6 +2450,8 @@ static void dce110_program_front_end_for_pipe( 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)); @@ -2502,10 +2510,10 @@ static void dce110_program_front_end_for_pipe( 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) - dc->hwss.set_input_transfer_func(pipe_ctx, pipe_ctx->plane_state); + hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); if (pipe_ctx->plane_state->update_flags.bits.full_update) - dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); + hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); DC_LOG_SURFACE( "Pipe:%d %p: addr hi:0x%x, " @@ -2608,6 +2616,7 @@ static void dce110_apply_ctx_for_surface( static void dce110_power_down_fe(struct dc *dc, struct pipe_ctx *pipe_ctx) { + struct dce_hwseq *hws = dc->hwseq; int fe_idx = pipe_ctx->plane_res.mi ? pipe_ctx->plane_res.mi->inst : pipe_ctx->pipe_idx; @@ -2615,7 +2624,7 @@ static void dce110_power_down_fe(struct dc *dc, struct pipe_ctx *pipe_ctx) if (dc->current_state->res_ctx.pipe_ctx[fe_idx].stream) return; - dc->hwss.enable_display_power_gating( + hws->funcs.enable_display_power_gating( dc, fe_idx, dc->ctx->dc_bios, PIPE_GATING_CONTROL_ENABLE); dc->res_pool->transforms[fe_idx]->funcs->transform_reset( @@ -2704,14 +2713,10 @@ static const struct hw_sequencer_funcs dce110_funcs = { .program_gamut_remap = program_gamut_remap, .program_output_csc = program_output_csc, .init_hw = init_hw, - .init_pipes = init_pipes, .apply_ctx_to_hw = dce110_apply_ctx_to_hw, .apply_ctx_for_surface = dce110_apply_ctx_for_surface, .update_plane_addr = update_plane_addr, .update_pending_status = dce110_update_pending_status, - .set_input_transfer_func = dce110_set_input_transfer_func, - .set_output_transfer_func = dce110_set_output_transfer_func, - .power_down = dce110_power_down, .enable_accelerated_mode = dce110_enable_accelerated_mode, .enable_timing_synchronization = dce110_enable_timing_synchronization, .enable_per_frame_crtc_position_reset = dce110_enable_per_frame_crtc_position_reset, @@ -2722,8 +2727,6 @@ static const struct hw_sequencer_funcs dce110_funcs = { .blank_stream = dce110_blank_stream, .enable_audio_stream = dce110_enable_audio_stream, .disable_audio_stream = dce110_disable_audio_stream, - .enable_display_pipe_clock_gating = enable_display_pipe_clock_gating, - .enable_display_power_gating = dce110_enable_display_power_gating, .disable_plane = dce110_power_down_fe, .pipe_control_lock = dce_pipe_control_lock, .prepare_bandwidth = dce110_prepare_bandwidth, @@ -2731,22 +2734,33 @@ static const struct hw_sequencer_funcs dce110_funcs = { .set_drr = set_drr, .get_position = get_position, .set_static_screen_control = set_static_screen_control, - .reset_hw_ctx_wrap = dce110_reset_hw_ctx_wrap, - .enable_stream_timing = dce110_enable_stream_timing, - .disable_stream_gating = NULL, - .enable_stream_gating = NULL, .setup_stereo = NULL, .set_avmute = dce110_set_avmute, .wait_for_mpcc_disconnect = dce110_wait_for_mpcc_disconnect, - .edp_backlight_control = dce110_edp_backlight_control, .edp_power_control = dce110_edp_power_control, .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, .set_cursor_position = dce110_set_cursor_position, .set_cursor_attribute = dce110_set_cursor_attribute }; +static const struct hwseq_private_funcs dce110_private_funcs = { + .init_pipes = init_pipes, + .update_plane_addr = update_plane_addr, + .set_input_transfer_func = dce110_set_input_transfer_func, + .set_output_transfer_func = dce110_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_pipe_clock_gating = enable_display_pipe_clock_gating, + .enable_display_power_gating = dce110_enable_display_power_gating, + .reset_hw_ctx_wrap = dce110_reset_hw_ctx_wrap, + .enable_stream_timing = dce110_enable_stream_timing, + .disable_stream_gating = NULL, + .enable_stream_gating = NULL, + .edp_backlight_control = dce110_edp_backlight_control, +}; + void dce110_hw_sequencer_construct(struct dc *dc) { dc->hwss = dce110_funcs; + dc->hwseq->funcs = dce110_private_funcs; } diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h index 2f9b7dbdf4157dd3256a6d789696159fd8cf687b..26a9c14a58b1778d86e6bc9ca3ab605589638b3b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h @@ -27,8 +27,8 @@ #define __DC_HWSS_DCE110_H__ #include "core_types.h" +#include "hw_sequencer_private.h" -#define GAMMA_HW_POINTS_NUM 256 struct dc; struct dc_state; struct dm_pp_display_configuration; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index 83a4dbf6d76e9cff8803cc1bbf76cefaa13a68b4..bf14e9ab040ce4083ee6ed9546b354d2de9b644a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -782,7 +782,7 @@ void dce110_clock_source_destroy(struct clock_source **clk_src) *clk_src = NULL; } -static void destruct(struct dce110_resource_pool *pool) +static void dce110_resource_destruct(struct dce110_resource_pool *pool) { unsigned int i; @@ -1097,6 +1097,7 @@ static struct pipe_ctx *dce110_acquire_underlay( struct dc_stream_state *stream) { struct dc *dc = stream->ctx->dc; + struct dce_hwseq *hws = dc->hwseq; struct resource_context *res_ctx = &context->res_ctx; unsigned int underlay_idx = pool->underlay_pipe_index; struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[underlay_idx]; @@ -1117,7 +1118,7 @@ static struct pipe_ctx *dce110_acquire_underlay( struct tg_color black_color = {0}; struct dc_bios *dcb = dc->ctx->dc_bios; - dc->hwss.enable_display_power_gating( + hws->funcs.enable_display_power_gating( dc, pipe_ctx->stream_res.tg->inst, dcb, PIPE_GATING_CONTROL_DISABLE); @@ -1161,7 +1162,7 @@ static void dce110_destroy_resource_pool(struct resource_pool **pool) { struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); - destruct(dce110_pool); + dce110_resource_destruct(dce110_pool); kfree(dce110_pool); *pool = NULL; } @@ -1313,7 +1314,7 @@ const struct resource_caps *dce110_resource_cap( return &carrizo_resource_cap; } -static bool construct( +static bool dce110_resource_construct( uint8_t num_virtual_links, struct dc *dc, struct dce110_resource_pool *pool, @@ -1492,7 +1493,7 @@ static bool construct( return true; res_create_fail: - destruct(pool); + dce110_resource_destruct(pool); return false; } @@ -1507,7 +1508,7 @@ struct resource_pool *dce110_create_resource_pool( if (!pool) return NULL; - if (construct(num_virtual_links, dc, pool, asic_id)) + if (dce110_resource_construct(num_virtual_links, dc, pool, asic_id)) return &pool->base; kfree(pool); diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.c index 1e4a7c13f0edc114f11e4506c98f6225b49ebbcb..19873ee1f78dd72665ad670c13730edc04eaed6e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.c @@ -158,6 +158,6 @@ void dce112_hw_sequencer_construct(struct dc *dc) * structure */ dce110_hw_sequencer_construct(dc); - dc->hwss.enable_display_power_gating = dce112_enable_display_power_gating; + dc->hwseq->funcs.enable_display_power_gating = dce112_enable_display_power_gating; } diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.h index e646f4a37fa2e4705e1a07f3da895811d25ba87d..943f1b2c5b2fc4ddb7d7b34b12b59ed05436c3cc 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.h @@ -27,6 +27,7 @@ #define __DC_HWSS_DCE112_H__ #include "core_types.h" +#include "hw_sequencer_private.h" struct dc; 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 97dcc5d0862b316d4bbfcc6d61b3b586fec0bd29..700ad8b3e54b2910b16905cd46d0d8b0fe2f7391 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -744,7 +744,7 @@ void dce112_clock_source_destroy(struct clock_source **clk_src) *clk_src = NULL; } -static void destruct(struct dce110_resource_pool *pool) +static void dce112_resource_destruct(struct dce110_resource_pool *pool) { unsigned int i; @@ -1013,7 +1013,7 @@ static void dce112_destroy_resource_pool(struct resource_pool **pool) { struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); - destruct(dce110_pool); + dce112_resource_destruct(dce110_pool); kfree(dce110_pool); *pool = NULL; } @@ -1186,7 +1186,7 @@ const struct resource_caps *dce112_resource_cap( return &polaris_10_resource_cap; } -static bool construct( +static bool dce112_resource_construct( uint8_t num_virtual_links, struct dc *dc, struct dce110_resource_pool *pool) @@ -1372,7 +1372,7 @@ static bool construct( return true; res_create_fail: - destruct(pool); + dce112_resource_destruct(pool); return false; } @@ -1386,7 +1386,7 @@ struct resource_pool *dce112_create_resource_pool( if (!pool) return NULL; - if (construct(num_virtual_links, dc, pool)) + if (dce112_resource_construct(num_virtual_links, dc, pool)) return &pool->base; kfree(pool); diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c index 1ca30928025ed9484736a5be70059ac1a28ad964..66a13aa39c951ddcf696e6e44694c022d7b75f7c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c @@ -265,7 +265,7 @@ void dce120_hw_sequencer_construct(struct dc *dc) * structure */ dce110_hw_sequencer_construct(dc); - dc->hwss.enable_display_power_gating = dce120_enable_display_power_gating; + dc->hwseq->funcs.enable_display_power_gating = dce120_enable_display_power_gating; dc->hwss.update_dchub = dce120_update_dchub; } diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h index c51afbd0b0124fcee60efd5838487d2ced7c8df5..bc024534732fb6e350851b5032ddba59d8bf102e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h @@ -27,6 +27,7 @@ #define __DC_HWSS_DCE120_H__ #include "core_types.h" +#include "hw_sequencer_private.h" struct dc; diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c index 63543f6918ffa5a895d80ec53df2c198dea6b139..53ab88ef71f5ee25c0f4940ad7f8b1e1333a0251 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c @@ -63,8 +63,8 @@ #include "soc15_hw_ip.h" #include "vega10_ip_offset.h" #include "nbio/nbio_6_1_offset.h" -#include "mmhub/mmhub_9_4_0_offset.h" -#include "mmhub/mmhub_9_4_0_sh_mask.h" +#include "mmhub/mmhub_1_0_offset.h" +#include "mmhub/mmhub_1_0_sh_mask.h" #include "reg_helper.h" #include "dce100/dce100_resource.h" @@ -587,7 +587,7 @@ static void dce120_transform_destroy(struct transform **xfm) *xfm = NULL; } -static void destruct(struct dce110_resource_pool *pool) +static void dce120_resource_destruct(struct dce110_resource_pool *pool) { unsigned int i; @@ -872,7 +872,7 @@ static void dce120_destroy_resource_pool(struct resource_pool **pool) { struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); - destruct(dce110_pool); + dce120_resource_destruct(dce110_pool); kfree(dce110_pool); *pool = NULL; } @@ -1024,7 +1024,7 @@ static uint32_t read_pipe_fuses(struct dc_context *ctx) return value; } -static bool construct( +static bool dce120_resource_construct( uint8_t num_virtual_links, struct dc *dc, struct dce110_resource_pool *pool) @@ -1237,7 +1237,7 @@ controller_create_fail: clk_src_create_fail: res_create_fail: - destruct(pool); + dce120_resource_destruct(pool); return false; } @@ -1252,7 +1252,7 @@ struct resource_pool *dce120_create_resource_pool( if (!pool) return NULL; - if (construct(num_virtual_links, dc, pool)) + if (dce120_resource_construct(num_virtual_links, dc, pool)) return &pool->base; kfree(pool); diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c index c4543178ba2095a84123dd15c396e216fc27162b..893261c81854b9eac7d1f0803329774169e44823 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c @@ -74,7 +74,7 @@ void dce80_hw_sequencer_construct(struct dc *dc) { dce110_hw_sequencer_construct(dc); - dc->hwss.enable_display_power_gating = dce100_enable_display_power_gating; + dc->hwseq->funcs.enable_display_power_gating = dce100_enable_display_power_gating; dc->hwss.pipe_control_lock = dce_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/dce80/dce80_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.h index 7a1b31def66f3646a4dc6aaab498d45f7b77eec4..e43af832d00cd31be1f741d71702bc754b3c01e4 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.h @@ -27,6 +27,7 @@ #define __DC_HWSS_DCE80_H__ #include "core_types.h" +#include "hw_sequencer_private.h" struct dc; diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index 3e8d4b49f2795be6acccfd100602b0a3b186a3a1..2ad5c28c6e66caf1c08afe847a3a722f8d2cc1d1 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -773,7 +773,7 @@ static struct input_pixel_processor *dce80_ipp_create( return &ipp->base; } -static void destruct(struct dce110_resource_pool *pool) +static void dce80_resource_destruct(struct dce110_resource_pool *pool) { unsigned int i; @@ -901,7 +901,7 @@ static void dce80_destroy_resource_pool(struct resource_pool **pool) { struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); - destruct(dce110_pool); + dce80_resource_destruct(dce110_pool); kfree(dce110_pool); *pool = NULL; } @@ -1093,7 +1093,7 @@ static bool dce80_construct( return true; res_create_fail: - destruct(pool); + dce80_resource_destruct(pool); return false; } @@ -1290,7 +1290,7 @@ static bool dce81_construct( return true; res_create_fail: - destruct(pool); + dce80_resource_destruct(pool); return false; } @@ -1483,7 +1483,7 @@ static bool dce83_construct( return true; res_create_fail: - destruct(pool); + dce80_resource_destruct(pool); return false; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile index 032f872be89c8bd72b38959f773c04d0e988091c..62ad1a11bff9c5623300936bf8f5742f6c814ceb 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile @@ -22,7 +22,8 @@ # # Makefile for DCN. -DCN10 = dcn10_resource.o dcn10_ipp.o dcn10_hw_sequencer.o dcn10_hw_sequencer_debug.o \ +DCN10 = dcn10_init.o dcn10_resource.o dcn10_ipp.o dcn10_hw_sequencer.o \ + dcn10_hw_sequencer_debug.o \ dcn10_dpp.o dcn10_opp.o dcn10_optc.o \ dcn10_hubp.o dcn10_mpc.o \ dcn10_dpp_dscl.o dcn10_dpp_cm.o dcn10_cm_common.o \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c index 997e9582edc7a5174dc7a52fbf5d955aaa3b2235..0e682b5aa3ebe0b6ffc700be5cfc0bec0d12a4df 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -290,12 +290,8 @@ void dpp1_cnv_setup ( enum surface_pixel_format format, enum expansion_mode mode, struct dc_csc_transform input_csc_color_matrix, -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 enum dc_color_space input_color_space, struct cnv_alpha_2bit_lut *alpha_2bit_lut) -#else - enum dc_color_space input_color_space) -#endif { uint32_t pixel_format; uint32_t alpha_en; @@ -542,11 +538,9 @@ static const struct dpp_funcs dcn10_dpp_funcs = { .set_optional_cursor_attributes = dpp1_cnv_set_optional_cursor_attributes, .dpp_dppclk_control = dpp1_dppclk_control, .dpp_set_hdr_multiplier = dpp1_set_hdr_multiplier, -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) .dpp_program_blnd_lut = NULL, .dpp_program_shaper_lut = NULL, .dpp_program_3dlut = NULL -#endif }; static struct dpp_caps dcn10_dpp_cap = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h index 1d4a7d640334020272f529f9228ac673c54229c3..2edf566b3a72a66cbdbe14f6c3c9e579380b321a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h @@ -1486,12 +1486,8 @@ void dpp1_cnv_setup ( enum surface_pixel_format format, enum expansion_mode mode, struct dc_csc_transform input_csc_color_matrix, -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 enum dc_color_space input_color_space, struct cnv_alpha_2bit_lut *alpha_2bit_lut); -#else - enum dc_color_space input_color_space); -#endif void dpp1_full_bypass(struct dpp *dpp_base); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c index aa0c7a7d13a00222e2e9a69ab4cbee42322d6ef8..935c892622a06be6169956851729f0c89e48d931 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c @@ -352,6 +352,8 @@ void dpp1_cm_program_regamma_lut(struct dpp *dpp_base, uint32_t i; struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + REG_SEQ_START(); + for (i = 0 ; i < num; i++) { REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].red_reg); REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].green_reg); @@ -626,10 +628,16 @@ void dpp1_set_degamma( case IPP_DEGAMMA_MODE_HW_xvYCC: REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 2); break; + case IPP_DEGAMMA_MODE_USER_PWL: + REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 3); + break; default: BREAK_TO_DEBUGGER(); break; } + + REG_SEQ_SUBMIT(); + REG_SEQ_WAIT_DONE(); } void dpp1_degamma_ram_select( @@ -731,10 +739,8 @@ void dpp1_full_bypass(struct dpp *dpp_base) /* COLOR_KEYER_CONTROL.COLOR_KEYER_EN = 0 this should be default */ if (dpp->tf_mask->CM_BYPASS_EN) REG_SET(CM_CONTROL, 0, CM_BYPASS_EN, 1); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) else REG_SET(CM_CONTROL, 0, CM_BYPASS, 1); -#endif /* Setting degamma bypass for now */ REG_SET(CM_DGAM_CONTROL, 0, CM_DGAM_LUT_MODE, 0); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c index d67e0abeee938049e3765fac649209a35cd97ef5..fce37c527a0b96f27b65eb96e482f5231d9f5cbf 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c @@ -218,14 +218,12 @@ static void dpp1_dscl_set_lb( INTERLEAVE_EN, lb_params->interleave_en, /* Interleave source enable */ LB_DATA_FORMAT__ALPHA_EN, lb_params->alpha_en); /* Alpha enable */ } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) else { /* DSCL caps: pixel data processed in float format */ REG_SET_2(LB_DATA_FORMAT, 0, INTERLEAVE_EN, lb_params->interleave_en, /* Interleave source enable */ LB_DATA_FORMAT__ALPHA_EN, lb_params->alpha_en); /* Alpha enable */ } -#endif REG_SET_2(LB_MEMORY_CTRL, 0, MEMORY_CONFIG, mem_size_config, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.c index 374cc9acda3b4762f018d68790bc867b5001d6ea..b6391a5ead78d9b8885c7ad4d364db3cd67ca05e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.c @@ -23,7 +23,7 @@ * */ -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) #include "reg_helper.h" #include "resource.h" @@ -109,9 +109,7 @@ const struct dwbc_funcs dcn10_dwbc_funcs = { .update = NULL, .set_stereo = NULL, .set_new_content = NULL, -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) .set_warmup = NULL, -#endif .dwb_set_scaler = NULL, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.h index c175edd0bae766dc1d83242469454f4ae74b10ab..d56ea7c8171eb2af0bc86dd18edb5ff43a553a73 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.h @@ -24,7 +24,7 @@ #ifndef __DC_DWBC_DCN10_H__ #define __DC_DWBC_DCN10_H__ -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) /* DCN */ #define BASE_INNER(seg) \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h index 69d903d68661643854726e8d69a028d7b766597e..af57751253dea06b3768cce241baf494d4e81504 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h @@ -121,7 +121,6 @@ struct dcn_hubbub_registers { uint32_t DCN_VM_AGP_BASE; uint32_t DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB; uint32_t DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB; -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) uint32_t DCHUBBUB_ARB_FRAC_URG_BW_NOM_A; uint32_t DCHUBBUB_ARB_FRAC_URG_BW_NOM_B; uint32_t DCHUBBUB_ARB_FRAC_URG_BW_NOM_C; @@ -140,7 +139,6 @@ struct dcn_hubbub_registers { uint32_t DCHVM_CLK_CTRL; uint32_t DCHVM_RIOMMU_CTRL0; uint32_t DCHVM_RIOMMU_STAT0; -#endif }; /* set field name */ @@ -232,7 +230,6 @@ struct dcn_hubbub_registers { type DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C;\ type DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) #define HUBBUB_HVM_REG_FIELD_LIST(type) \ type DCHUBBUB_ARB_MIN_REQ_OUTSTAND_COMMIT_THRESHOLD;\ type DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_A;\ @@ -278,22 +275,17 @@ struct dcn_hubbub_registers { type HOSTVM_POWERSTATUS; \ type RIOMMU_ACTIVE; \ type HOSTVM_PREFETCH_DONE -#endif struct dcn_hubbub_shift { DCN_HUBBUB_REG_FIELD_LIST(uint8_t); HUBBUB_STUTTER_REG_FIELD_LIST(uint8_t); -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) HUBBUB_HVM_REG_FIELD_LIST(uint8_t); -#endif }; struct dcn_hubbub_mask { DCN_HUBBUB_REG_FIELD_LIST(uint32_t); HUBBUB_STUTTER_REG_FIELD_LIST(uint32_t); -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) HUBBUB_HVM_REG_FIELD_LIST(uint32_t); -#endif }; struct dc; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c index 14d1be6c66e631d57583954189b3e74838b3764b..4d1301e5eaf59a4c76a18673f26f1d037cac3831 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -306,7 +306,6 @@ void hubp1_program_pixel_format( REG_UPDATE(DCSURF_SURFACE_CONFIG, SURFACE_PIXEL_FORMAT, 12); break; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FIX: REG_UPDATE(DCSURF_SURFACE_CONFIG, SURFACE_PIXEL_FORMAT, 112); @@ -327,7 +326,6 @@ void hubp1_program_pixel_format( REG_UPDATE(DCSURF_SURFACE_CONFIG, SURFACE_PIXEL_FORMAT, 119); break; -#endif default: BREAK_TO_DEBUGGER(); break; @@ -812,7 +810,8 @@ static void hubp1_set_vm_context0_settings(struct hubp *hubp, void min_set_viewport( struct hubp *hubp, const struct rect *viewport, - const struct rect *viewport_c) + const struct rect *viewport_c, + enum dc_rotation_angle rotation) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); @@ -1014,6 +1013,9 @@ void hubp1_read_state_common(struct hubp *hubp) HUBP_TTU_DISABLE, &s->ttu_disable, HUBP_UNDERFLOW_STATUS, &s->underflow_status); + REG_GET(HUBP_CLK_CNTL, + HUBP_CLOCK_ENABLE, &s->clock_en); + REG_GET(DCN_GLOBAL_TTU_CNTL, MIN_TTU_VBLANK, &s->min_ttu_vblank); @@ -1248,10 +1250,8 @@ static const struct hubp_funcs dcn10_hubp_funcs = { .hubp_get_underflow_status = hubp1_get_underflow_status, .hubp_init = hubp1_init, -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) .dmdata_set_attributes = NULL, .dmdata_load = NULL, -#endif }; /*****************************************/ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h index ae70d9c0aa1d467bc4514c3351ee38934119298b..e44eaae5033bd2717ddb375ef9c6d8514f766b8e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h @@ -670,6 +670,7 @@ struct dcn_hubp_state { uint32_t sw_mode; uint32_t dcc_en; uint32_t blank_en; + uint32_t clock_en; uint32_t underflow_status; uint32_t ttu_disable; uint32_t min_ttu_vblank; @@ -728,13 +729,11 @@ void hubp1_dcc_control(struct hubp *hubp, bool enable, enum hubp_ind_block_size independent_64b_blks); -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 bool hubp1_program_surface_flip_and_addr( struct hubp *hubp, const struct dc_plane_address *address, bool flip_immediate); -#endif bool hubp1_is_flip_pending(struct hubp *hubp); void hubp1_cursor_set_attributes( @@ -750,7 +749,9 @@ void hubp1_set_blank(struct hubp *hubp, bool blank); void min_set_viewport(struct hubp *hubp, const struct rect *viewport, - const struct rect *viewport_c); + const struct rect *viewport_c, + enum dc_rotation_angle rotation); +/* rotation angle added for use by hubp21_set_viewport */ void hubp1_clk_cntl(struct hubp *hubp, bool enable); void hubp1_vtg_sel(struct hubp *hubp, uint32_t otg_inst); 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 eb91432621abe0f0d8cb91472011e005b4260264..3996fef56948ade484bc8a3019b99766444bb6ca 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 @@ -25,17 +25,18 @@ #include #include "dm_services.h" +#include "basics/dc_common.h" #include "core_types.h" #include "resource.h" #include "custom_float.h" #include "dcn10_hw_sequencer.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dcn10_hw_sequencer_debug.h" #include "dce/dce_hwseq.h" #include "abm.h" #include "dmcu.h" #include "dcn10_optc.h" -#include "dcn10/dcn10_dpp.h" -#include "dcn10/dcn10_mpc.h" +#include "dcn10_dpp.h" +#include "dcn10_mpc.h" #include "timing_generator.h" #include "opp.h" #include "ipp.h" @@ -49,9 +50,7 @@ #include "clk_mgr.h" -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #include "dsc.h" -#endif #define DC_LOGGER_INIT(logger) @@ -68,6 +67,8 @@ #define DTN_INFO_MICRO_SEC(ref_cycle) \ print_microsec(dc_ctx, log_ctx, ref_cycle) +#define GAMMA_HW_POINTS_NUM 256 + void print_microsec(struct dc_context *dc_ctx, struct dc_log_buffer_ctx *log_ctx, uint32_t ref_cycle) @@ -81,6 +82,33 @@ void print_microsec(struct dc_context *dc_ctx, us_x10 % frac); } +static void dcn10_lock_all_pipes(struct dc *dc, + struct dc_state *context, + bool lock) +{ + 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 lock the top pipe's tg to prevent redundant + * (un)locking. 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; + + if (lock) + tg->funcs->lock(tg); + else + tg->funcs->unlock(tg); + } +} + static void log_mpc_crc(struct dc *dc, struct dc_log_buffer_ctx *log_ctx) { @@ -129,9 +157,8 @@ static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx) struct resource_pool *pool = dc->res_pool; int i; - DTN_INFO("HUBP: format addr_hi width height" - " rot mir sw_mode dcc_en blank_en ttu_dis underflow" - " min_ttu_vblank qos_low_wm qos_high_wm\n"); + DTN_INFO( + "HUBP: format addr_hi width height rot mir sw_mode dcc_en blank_en clock_en ttu_dis underflow min_ttu_vblank qos_low_wm qos_high_wm\n"); for (i = 0; i < pool->pipe_count; i++) { struct hubp *hubp = pool->hubps[i]; struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state); @@ -139,8 +166,7 @@ static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx) hubp->funcs->hubp_read_state(hubp); if (!s->blank_en) { - DTN_INFO("[%2d]: %5xh %6xh %5d %6d %2xh %2xh %6xh" - " %6d %8d %7d %8xh", + DTN_INFO("[%2d]: %5xh %6xh %5d %6d %2xh %2xh %6xh %6d %8d %8d %7d %8xh", hubp->inst, s->pixel_format, s->inuse_addr_hi, @@ -151,6 +177,7 @@ static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx) s->sw_mode, s->dcc_en, s->blank_en, + s->clock_en, s->ttu_disable, s->underflow_status); DTN_INFO_MICRO_SEC(s->min_ttu_vblank); @@ -308,21 +335,31 @@ void dcn10_log_hw_state(struct dc *dc, } DTN_INFO("\n"); - DTN_INFO("OTG: v_bs v_be v_ss v_se vpol vmax vmin vmax_sel vmin_sel" - " h_bs h_be h_ss h_se hpol htot vtot underflow\n"); + DTN_INFO("OTG: v_bs v_be v_ss v_se vpol vmax vmin vmax_sel vmin_sel h_bs h_be h_ss h_se hpol htot vtot underflow blank_en\n"); for (i = 0; i < pool->timing_generator_count; i++) { struct timing_generator *tg = pool->timing_generators[i]; struct dcn_otg_state s = {0}; - + /* Read shared OTG state registers for all DCNx */ optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); + /* + * For DCN2 and greater, a register on the OPP is used to + * determine if the CRTC is blanked instead of the OTG. So use + * dpg_is_blanked() if exists, otherwise fallback on otg. + * + * TODO: Implement DCN-specific read_otg_state hooks. + */ + if (pool->opps[i]->funcs->dpg_is_blanked) + s.blank_enabled = pool->opps[i]->funcs->dpg_is_blanked(pool->opps[i]); + else + s.blank_enabled = tg->funcs->is_blanked(tg); + //only print if OTG master is enabled if ((s.otg_enabled & 1) == 0) continue; - DTN_INFO("[%d]: %5d %5d %5d %5d %5d %5d %5d %9d %9d %5d %5d %5d" - " %5d %5d %5d %5d %9d\n", + DTN_INFO("[%d]: %5d %5d %5d %5d %5d %5d %5d %9d %9d %5d %5d %5d %5d %5d %5d %5d %9d %8d\n", tg->inst, s.v_blank_start, s.v_blank_end, @@ -340,7 +377,8 @@ void dcn10_log_hw_state(struct dc *dc, s.h_sync_a_pol, s.h_total, s.v_total, - s.underflow_occurred_status); + s.underflow_occurred_status, + s.blank_enabled); // Clear underflow for debug purposes // We want to keep underflow sticky bit on for the longevity tests outside of test environment. @@ -350,7 +388,6 @@ void dcn10_log_hw_state(struct dc *dc, } DTN_INFO("\n"); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT DTN_INFO("DSC: CLOCK_EN SLICE_WIDTH Bytes_pp\n"); for (i = 0; i < pool->res_cap->num_dsc; i++) { struct display_stream_compressor *dsc = pool->dscs[i]; @@ -387,7 +424,7 @@ void dcn10_log_hw_state(struct dc *dc, } DTN_INFO("\n"); - DTN_INFO("L_ENC: DPHY_FEC_EN DPHY_FEC_READY_SHADOW DPHY_FEC_ACTIVE_STATUS\n"); + DTN_INFO("L_ENC: DPHY_FEC_EN DPHY_FEC_READY_SHADOW DPHY_FEC_ACTIVE_STATUS DP_LINK_TRAINING_COMPLETE\n"); for (i = 0; i < dc->link_count; i++) { struct link_encoder *lenc = dc->links[i]->link_enc; @@ -395,16 +432,16 @@ void dcn10_log_hw_state(struct dc *dc, if (lenc->funcs->read_state) { lenc->funcs->read_state(lenc, &s); - DTN_INFO("[%-3d]: %-12d %-22d %-22d\n", + DTN_INFO("[%-3d]: %-12d %-22d %-22d %-25d\n", i, s.dphy_fec_en, s.dphy_fec_ready_shadow, - s.dphy_fec_active_status); + s.dphy_fec_active_status, + s.dp_link_training_complete); DTN_INFO("\n"); } } DTN_INFO("\n"); -#endif DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d dcfclk_deep_sleep_khz:%d dispclk_khz:%d\n" "dppclk_khz:%d max_supported_dppclk_khz:%d fclk_khz:%d socclk_khz:%d\n\n", @@ -438,7 +475,7 @@ bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx) return false; } -static void dcn10_enable_power_gating_plane( +void dcn10_enable_power_gating_plane( struct dce_hwseq *hws, bool enable) { @@ -460,7 +497,7 @@ static void dcn10_enable_power_gating_plane( REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); } -static void dcn10_disable_vga( +void dcn10_disable_vga( struct dce_hwseq *hws) { unsigned int in_vga1_mode = 0; @@ -493,7 +530,7 @@ static void dcn10_disable_vga( REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1); } -static void dcn10_dpp_pg_control( +void dcn10_dpp_pg_control( struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on) @@ -545,7 +582,7 @@ static void dcn10_dpp_pg_control( } } -static void dcn10_hubp_pg_control( +void dcn10_hubp_pg_control( struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) @@ -605,8 +642,8 @@ static void power_on_plane( if (REG(DC_IP_REQUEST_CNTL)) { REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - hws->ctx->dc->hwss.dpp_pg_control(hws, plane_id, true); - hws->ctx->dc->hwss.hubp_pg_control(hws, plane_id, true); + hws->funcs.dpp_pg_control(hws, plane_id, true); + hws->funcs.hubp_pg_control(hws, plane_id, true); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); DC_LOG_DEBUG( @@ -627,7 +664,7 @@ static void undo_DEGVIDCN10_253_wa(struct dc *dc) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - dc->hwss.hubp_pg_control(hws, 0, false); + hws->funcs.hubp_pg_control(hws, 0, false); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); @@ -656,7 +693,7 @@ static void apply_DEGVIDCN10_253_wa(struct dc *dc) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - dc->hwss.hubp_pg_control(hws, 0, true); + hws->funcs.hubp_pg_control(hws, 0, true); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); @@ -664,16 +701,16 @@ static void apply_DEGVIDCN10_253_wa(struct dc *dc) hws->wa_state.DEGVIDCN10_253_applied = true; } -static void dcn10_bios_golden_init(struct dc *dc) +void dcn10_bios_golden_init(struct dc *dc) { + struct dce_hwseq *hws = dc->hwseq; struct dc_bios *bp = dc->ctx->dc_bios; int i; bool allow_self_fresh_force_enable = true; -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) - if (dc->hwss.s0i3_golden_init_wa && dc->hwss.s0i3_golden_init_wa(dc)) + if (hws->funcs.s0i3_golden_init_wa && hws->funcs.s0i3_golden_init_wa(dc)) return; -#endif + if (dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled) allow_self_fresh_force_enable = dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub); @@ -732,7 +769,7 @@ static void false_optc_underflow_wa( tg->funcs->clear_optc_underflow(tg); } -static enum dc_status dcn10_enable_stream_timing( +enum dc_status dcn10_enable_stream_timing( struct pipe_ctx *pipe_ctx, struct dc_state *context, struct dc *dc) @@ -978,8 +1015,9 @@ void dcn10_verify_allow_pstate_change_high(struct dc *dc) } /* trigger HW to start disconnect plane from stream on the next vsync */ -void hwss1_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn10_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) { + struct dce_hwseq *hws = dc->hwseq; struct hubp *hubp = pipe_ctx->plane_res.hubp; int dpp_id = pipe_ctx->plane_res.dpp->inst; struct mpc *mpc = dc->res_pool->mpc; @@ -1004,10 +1042,10 @@ void hwss1_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) hubp->funcs->hubp_disconnect(hubp); if (dc->debug.sanity_checks) - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } -static void dcn10_plane_atomic_power_down(struct dc *dc, +void dcn10_plane_atomic_power_down(struct dc *dc, struct dpp *dpp, struct hubp *hubp) { @@ -1017,8 +1055,8 @@ static void dcn10_plane_atomic_power_down(struct dc *dc, if (REG(DC_IP_REQUEST_CNTL)) { REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - dc->hwss.dpp_pg_control(hws, dpp->inst, false); - dc->hwss.hubp_pg_control(hws, hubp->inst, false); + hws->funcs.dpp_pg_control(hws, dpp->inst, false); + hws->funcs.hubp_pg_control(hws, hubp->inst, false); dpp->funcs->dpp_reset(dpp); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); @@ -1030,8 +1068,9 @@ static void dcn10_plane_atomic_power_down(struct dc *dc, /* disable HW used by plane. * note: cannot disable until disconnect is complete */ -static void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) { + struct dce_hwseq *hws = dc->hwseq; struct hubp *hubp = pipe_ctx->plane_res.hubp; struct dpp *dpp = pipe_ctx->plane_res.dpp; int opp_id = hubp->opp_id; @@ -1050,7 +1089,7 @@ static void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) hubp->power_gated = true; dc->optimized_required = false; /* We're powering off, no need to optimize */ - dc->hwss.plane_atomic_power_down(dc, + hws->funcs.plane_atomic_power_down(dc, pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp); @@ -1062,14 +1101,15 @@ static void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) pipe_ctx->plane_state = NULL; } -static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) { + struct dce_hwseq *hws = dc->hwseq; DC_LOGGER_INIT(dc->ctx->logger); if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) return; - dc->hwss.plane_atomic_disable(dc, pipe_ctx); + hws->funcs.plane_atomic_disable(dc, pipe_ctx); apply_DEGVIDCN10_253_wa(dc); @@ -1077,9 +1117,10 @@ static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) pipe_ctx->pipe_idx); } -static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) +void dcn10_init_pipes(struct dc *dc, struct dc_state *context) { int i; + struct dce_hwseq *hws = dc->hwseq; bool can_apply_seamless_boot = false; for (i = 0; i < context->stream_count; i++) { @@ -1104,8 +1145,8 @@ static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) * command table. */ if (tg->funcs->is_tg_enabled(tg)) { - if (dc->hwss.init_blank != NULL) { - dc->hwss.init_blank(dc, tg); + if (hws->funcs.init_blank != NULL) { + hws->funcs.init_blank(dc, tg); tg->funcs->lock(tg); } else { tg->funcs->lock(tg); @@ -1162,7 +1203,7 @@ static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; - dc->hwss.plane_atomic_disconnect(dc, pipe_ctx); + hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); if (tg->funcs->is_tg_enabled(tg)) tg->funcs->unlock(tg); @@ -1176,7 +1217,7 @@ static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) } } -static void dcn10_init_hw(struct dc *dc) +void dcn10_init_hw(struct dc *dc) { int i; struct abm *abm = dc->res_pool->abm; @@ -1208,15 +1249,15 @@ static void dcn10_init_hw(struct dc *dc) } //Enable ability to power gate / don't force power on permanently - dc->hwss.enable_power_gating_plane(hws, true); + hws->funcs.enable_power_gating_plane(hws, true); return; } if (!dcb->funcs->is_accelerated_mode(dcb)) - dc->hwss.disable_vga(dc->hwseq); + hws->funcs.disable_vga(dc->hwseq); - dc->hwss.bios_golden_init(dc); + hws->funcs.bios_golden_init(dc); if (dc->ctx->dc_bios->fw_info_valid) { res_pool->ref_clocks.xtalin_clock_inKhz = dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; @@ -1258,11 +1299,9 @@ static void dcn10_init_hw(struct dc *dc) } /* Power gate DSCs */ -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT for (i = 0; i < res_pool->res_cap->num_dsc; i++) - if (dc->hwss.dsc_pg_control != NULL) - dc->hwss.dsc_pg_control(hws, res_pool->dscs[i]->inst, false); -#endif + if (hws->funcs.dsc_pg_control != NULL) + hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false); /* If taking control over from VBIOS, we may want to optimize our first * mode set, so we need to skip powering down pipes until we know which @@ -1271,7 +1310,7 @@ static void dcn10_init_hw(struct dc *dc) * everything down. */ if (dcb->funcs->is_accelerated_mode(dcb) || dc->config.power_down_display_on_boot) { - dc->hwss.init_pipes(dc, dc->current_state); + hws->funcs.init_pipes(dc, dc->current_state); } for (i = 0; i < res_pool->audio_count; i++) { @@ -1285,7 +1324,7 @@ static void dcn10_init_hw(struct dc *dc) abm->funcs->abm_init(abm); } - if (dmcu != NULL) + if (dmcu != NULL && !dmcu->auto_load_dmcu) dmcu->funcs->dmcu_init(dmcu); if (abm != NULL && dmcu != NULL) @@ -1303,18 +1342,19 @@ static void dcn10_init_hw(struct dc *dc) REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); } - dc->hwss.enable_power_gating_plane(dc->hwseq, true); + hws->funcs.enable_power_gating_plane(dc->hwseq, true); if (dc->clk_mgr->funcs->notify_wm_ranges) dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); } -static void dcn10_reset_hw_ctx_wrap( +void dcn10_reset_hw_ctx_wrap( struct dc *dc, struct dc_state *context) { int i; + struct dce_hwseq *hws = dc->hwseq; /* Reset Back End*/ for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { @@ -1333,8 +1373,8 @@ static void dcn10_reset_hw_ctx_wrap( struct clock_source *old_clk = pipe_ctx_old->clock_source; dcn10_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); - if (dc->hwss.enable_stream_gating) - dc->hwss.enable_stream_gating(dc, pipe_ctx); + if (hws->funcs.enable_stream_gating) + hws->funcs.enable_stream_gating(dc, pipe_ctx); if (old_clk) old_clk->funcs->cs_power_down(old_clk); } @@ -1367,9 +1407,7 @@ static bool patch_address_for_sbs_tb_stereo( return false; } - - -static void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) { bool addr_patched = false; PHYSICAL_ADDRESS_LOC addr; @@ -1394,8 +1432,8 @@ static void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_c pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; } -static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state) +bool dcn10_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state) { struct dpp *dpp_base = pipe_ctx->plane_res.dpp; const struct dc_transfer_func *tf = NULL; @@ -1427,6 +1465,11 @@ static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx, dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); break; case TRANSFER_FUNCTION_PQ: + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL); + cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params); + dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params); + result = true; + break; default: result = false; break; @@ -1472,9 +1515,8 @@ static void log_tf(struct dc_context *ctx, } } -static bool -dcn10_set_output_transfer_func(struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream) +bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream) { struct dpp *dpp = pipe_ctx->plane_res.dpp; @@ -1510,11 +1552,13 @@ dcn10_set_output_transfer_func(struct pipe_ctx *pipe_ctx, return true; } -static void dcn10_pipe_control_lock( +void dcn10_pipe_control_lock( struct dc *dc, struct pipe_ctx *pipe, bool lock) { + struct dce_hwseq *hws = dc->hwseq; + /* use TG master update lock to lock everything on the TG * therefore only top pipe need to lock */ @@ -1522,7 +1566,7 @@ static void dcn10_pipe_control_lock( return; if (dc->debug.sanity_checks) - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); if (lock) pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); @@ -1530,7 +1574,7 @@ static void dcn10_pipe_control_lock( pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); if (dc->debug.sanity_checks) - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } static bool wait_for_reset_trigger_to_occur( @@ -1570,7 +1614,7 @@ static bool wait_for_reset_trigger_to_occur( return rc; } -static void dcn10_enable_timing_synchronization( +void dcn10_enable_timing_synchronization( struct dc *dc, int group_index, int group_size, @@ -1600,7 +1644,7 @@ static void dcn10_enable_timing_synchronization( DC_SYNC_INFO("Sync complete\n"); } -static void dcn10_enable_per_frame_crtc_position_reset( +void dcn10_enable_per_frame_crtc_position_reset( struct dc *dc, int group_size, struct pipe_ctx *grouped_pipes[]) @@ -1625,10 +1669,10 @@ static void dcn10_enable_per_frame_crtc_position_reset( } /*static void print_rq_dlg_ttu( - struct dc *core_dc, + struct dc *dc, struct pipe_ctx *pipe_ctx) { - DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, "\n============== DML TTU Output parameters [%d] ==============\n" "qos_level_low_wm: %d, \n" "qos_level_high_wm: %d, \n" @@ -1658,7 +1702,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_c ); - DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, "\n============== DML DLG Output parameters [%d] ==============\n" "refcyc_h_blank_end: %d, \n" "dlg_vblank_end: %d, \n" @@ -1693,7 +1737,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_l ); - DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, "\ndst_y_per_meta_row_nom_l: %d, \n" "refcyc_per_meta_chunk_nom_l: %d, \n" "refcyc_per_line_delivery_pre_l: %d, \n" @@ -1723,7 +1767,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( pipe_ctx->dlg_regs.refcyc_per_line_delivery_c ); - DC_LOG_BANDWIDTH_CALCS(core_dc->ctx->logger, + DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, "\n============== DML RQ Output parameters [%d] ==============\n" "chunk_size: %d \n" "min_chunk_size: %d \n" @@ -1838,7 +1882,7 @@ static void dcn10_enable_plane( struct dce_hwseq *hws = dc->hwseq; if (dc->debug.sanity_checks) { - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } undo_DEGVIDCN10_253_wa(dc); @@ -1895,11 +1939,11 @@ static void dcn10_enable_plane( dcn10_program_pte_vm(hws, pipe_ctx->plane_res.hubp); if (dc->debug.sanity_checks) { - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } } -static void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx) +void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx) { int i = 0; struct dpp_grph_csc_adjustment adjust; @@ -1947,7 +1991,7 @@ static void dcn10_set_csc_adjustment_rgb_mpo_fix(struct pipe_ctx *pipe_ctx, uint matrix[11] = rgb_bias; } -static void dcn10_program_output_csc(struct dc *dc, +void dcn10_program_output_csc(struct dc *dc, struct pipe_ctx *pipe_ctx, enum dc_color_space colorspace, uint16_t *matrix, @@ -1979,57 +2023,6 @@ static void dcn10_program_output_csc(struct dc *dc, } } -bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx) -{ - if (pipe_ctx->plane_state && pipe_ctx->plane_state->visible) - return true; - if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe)) - return true; - return false; -} - -bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx) -{ - if (pipe_ctx->plane_state && pipe_ctx->plane_state->visible) - return true; - if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe)) - return true; - return false; -} - -bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx) -{ - if (pipe_ctx->plane_state && pipe_ctx->plane_state->visible) - return true; - if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe)) - return true; - if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe)) - return true; - return false; -} - -bool is_rgb_cspace(enum dc_color_space output_color_space) -{ - switch (output_color_space) { - case COLOR_SPACE_SRGB: - case COLOR_SPACE_SRGB_LIMITED: - case COLOR_SPACE_2020_RGB_FULLRANGE: - case COLOR_SPACE_2020_RGB_LIMITEDRANGE: - case COLOR_SPACE_ADOBERGB: - return true; - case COLOR_SPACE_YCBCR601: - case COLOR_SPACE_YCBCR709: - case COLOR_SPACE_YCBCR601_LIMITED: - case COLOR_SPACE_YCBCR709_LIMITED: - case COLOR_SPACE_2020_YCBCR: - return false; - default: - /* Add a case to switch */ - BREAK_TO_DEBUGGER(); - return false; - } -} - void dcn10_get_surface_visual_confirm_color( const struct pipe_ctx *pipe_ctx, struct tg_color *color) @@ -2103,70 +2096,7 @@ void dcn10_get_hdr_visual_confirm_color( } } -static uint16_t fixed_point_to_int_frac( - struct fixed31_32 arg, - uint8_t integer_bits, - uint8_t fractional_bits) -{ - int32_t numerator; - int32_t divisor = 1 << fractional_bits; - - uint16_t result; - - uint16_t d = (uint16_t)dc_fixpt_floor( - dc_fixpt_abs( - arg)); - - if (d <= (uint16_t)(1 << integer_bits) - (1 / (uint16_t)divisor)) - numerator = (uint16_t)dc_fixpt_floor( - dc_fixpt_mul_int( - arg, - divisor)); - else { - numerator = dc_fixpt_floor( - dc_fixpt_sub( - dc_fixpt_from_int( - 1LL << integer_bits), - dc_fixpt_recip( - dc_fixpt_from_int( - divisor)))); - } - - if (numerator >= 0) - result = (uint16_t)numerator; - else - result = (uint16_t)( - (1 << (integer_bits + fractional_bits + 1)) + numerator); - - if ((result != 0) && dc_fixpt_lt( - arg, dc_fixpt_zero)) - result |= 1 << (integer_bits + fractional_bits); - - return result; -} - -void dcn10_build_prescale_params(struct dc_bias_and_scale *bias_and_scale, - const struct dc_plane_state *plane_state) -{ - if (plane_state->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN - && plane_state->format != SURFACE_PIXEL_FORMAT_INVALID - && plane_state->input_csc_color_matrix.enable_adjustment - && plane_state->coeff_reduction_factor.value != 0) { - bias_and_scale->scale_blue = fixed_point_to_int_frac( - dc_fixpt_mul(plane_state->coeff_reduction_factor, - dc_fixpt_from_fraction(256, 255)), - 2, - 13); - bias_and_scale->scale_red = bias_and_scale->scale_blue; - bias_and_scale->scale_green = bias_and_scale->scale_blue; - } else { - bias_and_scale->scale_blue = 0x2000; - bias_and_scale->scale_red = 0x2000; - bias_and_scale->scale_green = 0x2000; - } -} - -static void update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) +static void dcn10_update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) { struct dc_bias_and_scale bns_params = {0}; @@ -2175,21 +2105,18 @@ static void update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) plane_state->format, EXPANSION_MODE_ZERO, plane_state->input_csc_color_matrix, -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 plane_state->color_space, NULL); -#else - plane_state->color_space); -#endif //set scale and bias registers - dcn10_build_prescale_params(&bns_params, plane_state); + build_prescale_params(&bns_params, plane_state); if (dpp->funcs->dpp_program_bias_and_scale) dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); } -static void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) { + struct dce_hwseq *hws = dc->hwseq; struct hubp *hubp = pipe_ctx->plane_res.hubp; struct mpcc_blnd_cfg blnd_cfg = {{0}}; bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; @@ -2199,10 +2126,10 @@ static void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) { - dcn10_get_hdr_visual_confirm_color( + hws->funcs.get_hdr_visual_confirm_color( pipe_ctx, &blnd_cfg.black_color); } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) { - dcn10_get_surface_visual_confirm_color( + hws->funcs.get_surface_visual_confirm_color( pipe_ctx, &blnd_cfg.black_color); } else { color_space_to_black_color( @@ -2284,11 +2211,12 @@ static void update_scaler(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); } -void update_dchubp_dpp( +static void dcn10_update_dchubp_dpp( struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_state *context) { + struct dce_hwseq *hws = dc->hwseq; struct hubp *hubp = pipe_ctx->plane_res.hubp; struct dpp *dpp = pipe_ctx->plane_res.dpp; struct dc_plane_state *plane_state = pipe_ctx->plane_state; @@ -2342,12 +2270,12 @@ void update_dchubp_dpp( if (plane_state->update_flags.bits.full_update || plane_state->update_flags.bits.bpp_change) - update_dpp(dpp, plane_state); + dcn10_update_dpp(dpp, plane_state); if (plane_state->update_flags.bits.full_update || plane_state->update_flags.bits.per_pixel_alpha_change || plane_state->update_flags.bits.global_alpha_change) - dc->hwss.update_mpcc(dc, pipe_ctx); + hws->funcs.update_mpcc(dc, pipe_ctx); if (plane_state->update_flags.bits.full_update || plane_state->update_flags.bits.per_pixel_alpha_change || @@ -2363,7 +2291,8 @@ void update_dchubp_dpp( hubp->funcs->mem_program_viewport( hubp, &pipe_ctx->plane_res.scl_data.viewport, - &pipe_ctx->plane_res.scl_data.viewport_c); + &pipe_ctx->plane_res.scl_data.viewport_c, + plane_state->rotation); } if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { @@ -2407,13 +2336,13 @@ void update_dchubp_dpp( hubp->power_gated = false; - dc->hwss.update_plane_addr(dc, pipe_ctx); + hws->funcs.update_plane_addr(dc, pipe_ctx); if (is_pipe_tree_visible(pipe_ctx)) hubp->funcs->set_blank(hubp, false); } -static void dcn10_blank_pixel_data( +void dcn10_blank_pixel_data( struct dc *dc, struct pipe_ctx *pipe_ctx, bool blank) @@ -2456,10 +2385,9 @@ static void dcn10_blank_pixel_data( } } -void set_hdr_multiplier(struct pipe_ctx *pipe_ctx) +void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx) { - struct fixed31_32 multiplier = dc_fixpt_from_fraction( - pipe_ctx->plane_state->sdr_white_level, 80); + struct fixed31_32 multiplier = pipe_ctx->plane_state->hdr_mult; uint32_t hw_mult = 0x1f000; // 1.0 default multiplier struct custom_float_format fmt; @@ -2467,7 +2395,8 @@ void set_hdr_multiplier(struct pipe_ctx *pipe_ctx) fmt.mantissa_bits = 12; fmt.sign = true; - if (pipe_ctx->plane_state->sdr_white_level > 80) + + if (!dc_fixpt_eq(multiplier, dc_fixpt_from_int(0))) // check != 0 convert_to_custom_float_format(multiplier, &fmt, &hw_mult); pipe_ctx->plane_res.dpp->funcs->dpp_set_hdr_multiplier( @@ -2479,17 +2408,19 @@ void dcn10_program_pipe( struct pipe_ctx *pipe_ctx, struct dc_state *context) { + struct dce_hwseq *hws = dc->hwseq; + if (pipe_ctx->plane_state->update_flags.bits.full_update) dcn10_enable_plane(dc, pipe_ctx, context); - update_dchubp_dpp(dc, pipe_ctx, context); + dcn10_update_dchubp_dpp(dc, pipe_ctx, context); - set_hdr_multiplier(pipe_ctx); + hws->funcs.set_hdr_multiplier(pipe_ctx); 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) - dc->hwss.set_input_transfer_func(pipe_ctx, pipe_ctx->plane_state); + hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); /* dcn10_translate_regamma_to_hw_format takes 750us to finish * only do gamma programming for full update. @@ -2498,14 +2429,16 @@ void dcn10_program_pipe( * doing heavy calculation and programming */ if (pipe_ctx->plane_state->update_flags.bits.full_update) - dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); + hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); } -static void program_all_pipe_in_tree( +static void dcn10_program_all_pipe_in_tree( struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_state *context) { + struct dce_hwseq *hws = dc->hwseq; + if (pipe_ctx->top_pipe == NULL) { bool blank = !is_pipe_tree_visible(pipe_ctx); @@ -2519,20 +2452,20 @@ static void program_all_pipe_in_tree( pipe_ctx->stream_res.tg->funcs->set_vtg_params( pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); - if (dc->hwss.setup_vupdate_interrupt) - dc->hwss.setup_vupdate_interrupt(pipe_ctx); + if (hws->funcs.setup_vupdate_interrupt) + hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); - dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); + hws->funcs.blank_pixel_data(dc, pipe_ctx, blank); } if (pipe_ctx->plane_state != NULL) - dcn10_program_pipe(dc, pipe_ctx, context); + hws->funcs.program_pipe(dc, pipe_ctx, context); if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) - program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); + dcn10_program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); } -struct pipe_ctx *find_top_pipe_for_stream( +static struct pipe_ctx *dcn10_find_top_pipe_for_stream( struct dc *dc, struct dc_state *context, const struct dc_stream_state *stream) @@ -2556,19 +2489,20 @@ struct pipe_ctx *find_top_pipe_for_stream( return NULL; } -static void dcn10_apply_ctx_for_surface( +void dcn10_apply_ctx_for_surface( struct dc *dc, const struct dc_stream_state *stream, int num_planes, struct dc_state *context) { + struct dce_hwseq *hws = dc->hwseq; int i; struct timing_generator *tg; uint32_t underflow_check_delay_us; bool removed_pipe[4] = { false }; bool interdependent_update = false; struct pipe_ctx *top_pipe_to_program = - find_top_pipe_for_stream(dc, context, stream); + dcn10_find_top_pipe_for_stream(dc, context, stream); DC_LOGGER_INIT(dc->ctx->logger); if (!top_pipe_to_program) @@ -2581,23 +2515,23 @@ static void dcn10_apply_ctx_for_surface( underflow_check_delay_us = dc->debug.underflow_assert_delay_us; - if (underflow_check_delay_us != 0xFFFFFFFF && dc->hwss.did_underflow_occur) - ASSERT(dc->hwss.did_underflow_occur(dc, top_pipe_to_program)); + if (underflow_check_delay_us != 0xFFFFFFFF && hws->funcs.did_underflow_occur) + ASSERT(hws->funcs.did_underflow_occur(dc, top_pipe_to_program)); if (interdependent_update) - lock_all_pipes(dc, context, true); + dcn10_lock_all_pipes(dc, context, true); else dcn10_pipe_control_lock(dc, top_pipe_to_program, true); if (underflow_check_delay_us != 0xFFFFFFFF) udelay(underflow_check_delay_us); - if (underflow_check_delay_us != 0xFFFFFFFF && dc->hwss.did_underflow_occur) - ASSERT(dc->hwss.did_underflow_occur(dc, top_pipe_to_program)); + if (underflow_check_delay_us != 0xFFFFFFFF && hws->funcs.did_underflow_occur) + ASSERT(hws->funcs.did_underflow_occur(dc, top_pipe_to_program)); if (num_planes == 0) { /* OTG blank before remove all front end */ - dc->hwss.blank_pixel_data(dc, top_pipe_to_program, true); + hws->funcs.blank_pixel_data(dc, top_pipe_to_program, true); } /* Disconnect unused mpcc */ @@ -2623,7 +2557,7 @@ static void dcn10_apply_ctx_for_surface( old_pipe_ctx->plane_state && old_pipe_ctx->stream_res.tg == tg) { - dc->hwss.plane_atomic_disconnect(dc, old_pipe_ctx); + hws->funcs.plane_atomic_disconnect(dc, old_pipe_ctx); removed_pipe[i] = true; DC_LOG_DC("Reset mpcc for pipe %d\n", @@ -2632,13 +2566,11 @@ static void dcn10_apply_ctx_for_surface( } if (num_planes > 0) - program_all_pipe_in_tree(dc, top_pipe_to_program, context); + dcn10_program_all_pipe_in_tree(dc, top_pipe_to_program, context); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) /* Program secondary blending tree and writeback pipes */ - if ((stream->num_wb_info > 0) && (dc->hwss.program_all_writeback_pipes_in_tree)) - dc->hwss.program_all_writeback_pipes_in_tree(dc, stream, context); -#endif + if ((stream->num_wb_info > 0) && (hws->funcs.program_all_writeback_pipes_in_tree)) + hws->funcs.program_all_writeback_pipes_in_tree(dc, stream, context); if (interdependent_update) for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; @@ -2654,7 +2586,7 @@ static void dcn10_apply_ctx_for_surface( } if (interdependent_update) - lock_all_pipes(dc, context, false); + dcn10_lock_all_pipes(dc, context, false); else dcn10_pipe_control_lock(dc, top_pipe_to_program, false); @@ -2691,14 +2623,15 @@ static void dcn10_stereo_hw_frame_pack_wa(struct dc *dc, struct dc_state *contex } } -static void dcn10_prepare_bandwidth( +void dcn10_prepare_bandwidth( struct dc *dc, struct dc_state *context) { + struct dce_hwseq *hws = dc->hwseq; struct hubbub *hubbub = dc->res_pool->hubbub; if (dc->debug.sanity_checks) - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { if (context->stream_count == 0) @@ -2720,17 +2653,18 @@ static void dcn10_prepare_bandwidth( dcn_bw_notify_pplib_of_wm_ranges(dc); if (dc->debug.sanity_checks) - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } -static void dcn10_optimize_bandwidth( +void dcn10_optimize_bandwidth( struct dc *dc, struct dc_state *context) { + struct dce_hwseq *hws = dc->hwseq; struct hubbub *hubbub = dc->res_pool->hubbub; if (dc->debug.sanity_checks) - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { if (context->stream_count == 0) @@ -2752,10 +2686,10 @@ static void dcn10_optimize_bandwidth( dcn_bw_notify_pplib_of_wm_ranges(dc); if (dc->debug.sanity_checks) - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } -static void dcn10_set_drr(struct pipe_ctx **pipe_ctx, +void dcn10_set_drr(struct pipe_ctx **pipe_ctx, int num_pipes, unsigned int vmin, unsigned int vmax, unsigned int vmid, unsigned int vmid_frame_number) { @@ -2783,7 +2717,7 @@ static void dcn10_set_drr(struct pipe_ctx **pipe_ctx, } } -static void dcn10_get_position(struct pipe_ctx **pipe_ctx, +void dcn10_get_position(struct pipe_ctx **pipe_ctx, int num_pipes, struct crtc_position *position) { @@ -2795,7 +2729,7 @@ static void dcn10_get_position(struct pipe_ctx **pipe_ctx, pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position); } -static void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx, +void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx, int num_pipes, const struct dc_static_screen_events *events) { unsigned int i; @@ -2850,7 +2784,7 @@ static void dcn10_config_stereo_parameters( return; } -static void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) +void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) { struct crtc_stereo_flags flags = { 0 }; struct dc_stream_state *stream = pipe_ctx->stream; @@ -2889,15 +2823,16 @@ static struct hubp *get_hubp_by_inst(struct resource_pool *res_pool, int mpcc_in return NULL; } -static void dcn10_wait_for_mpcc_disconnect( +void dcn10_wait_for_mpcc_disconnect( struct dc *dc, struct resource_pool *res_pool, struct pipe_ctx *pipe_ctx) { + struct dce_hwseq *hws = dc->hwseq; int mpcc_inst; if (dc->debug.sanity_checks) { - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } if (!pipe_ctx->stream_res.opp) @@ -2914,12 +2849,12 @@ static void dcn10_wait_for_mpcc_disconnect( } if (dc->debug.sanity_checks) { - dcn10_verify_allow_pstate_change_high(dc); + hws->funcs.verify_allow_pstate_change_high(dc); } } -static bool dcn10_dummy_display_power_gating( +bool dcn10_dummy_display_power_gating( struct dc *dc, uint8_t controller_id, struct dc_bios *dcb, @@ -2928,7 +2863,7 @@ static bool dcn10_dummy_display_power_gating( return true; } -static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) +void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) { struct dc_plane_state *plane_state = pipe_ctx->plane_state; struct timing_generator *tg = pipe_ctx->stream_res.tg; @@ -2952,7 +2887,7 @@ static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) } } -static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) +void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) { struct hubbub *hubbub = hws->ctx->dc->res_pool->hubbub; @@ -2960,7 +2895,7 @@ static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh hubbub->funcs->update_dchub(hubbub, dh_data); } -static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) +void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) { struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; struct hubp *hubp = pipe_ctx->plane_res.hubp; @@ -2974,15 +2909,30 @@ static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) .rotation = pipe_ctx->plane_state->rotation, .mirror = pipe_ctx->plane_state->horizontal_mirror }; - uint32_t x_plane = pipe_ctx->plane_state->dst_rect.x; - uint32_t y_plane = pipe_ctx->plane_state->dst_rect.y; - uint32_t x_offset = min(x_plane, pos_cpy.x); - uint32_t y_offset = min(y_plane, pos_cpy.y); - pos_cpy.x -= x_offset; - pos_cpy.y -= y_offset; - pos_cpy.x_hotspot += (x_plane - x_offset); - pos_cpy.y_hotspot += (y_plane - y_offset); + int x_plane = pipe_ctx->plane_state->dst_rect.x; + int y_plane = pipe_ctx->plane_state->dst_rect.y; + int x_pos = pos_cpy.x; + int y_pos = pos_cpy.y; + + // translate cursor from stream space to plane space + x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.width / + pipe_ctx->plane_state->dst_rect.width; + y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.height / + pipe_ctx->plane_state->dst_rect.height; + + if (x_pos < 0) { + pos_cpy.x_hotspot -= x_pos; + x_pos = 0; + } + + if (y_pos < 0) { + pos_cpy.y_hotspot -= y_pos; + y_pos = 0; + } + + pos_cpy.x = (uint32_t)x_pos; + pos_cpy.y = (uint32_t)y_pos; if (pipe_ctx->plane_state->address.type == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) @@ -3026,7 +2976,7 @@ static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width, hubp->curs_attr.height); } -static void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) +void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) { struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; @@ -3036,7 +2986,7 @@ static void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.dpp, attributes); } -static void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) +void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) { uint32_t sdr_white_level = pipe_ctx->stream->cursor_attributes.sdr_white_level; struct fixed31_32 multiplier; @@ -3063,12 +3013,12 @@ static void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.dpp, &opt_attr); } -/** -* apply_front_porch_workaround TODO FPGA still need? -* -* This is a workaround for a bug that has existed since R5xx and has not been -* fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive. -*/ +/* + * apply_front_porch_workaround TODO FPGA still need? + * + * This is a workaround for a bug that has existed since R5xx and has not been + * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive. + */ static void apply_front_porch_workaround( struct dc_crtc_timing *timing) { @@ -3081,7 +3031,7 @@ static void apply_front_porch_workaround( } } -int get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx) +int dcn10_get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx) { const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing; struct dc_crtc_timing patched_crtc_timing; @@ -3110,34 +3060,8 @@ int get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx) return vertical_line_start; } -void lock_all_pipes(struct dc *dc, - struct dc_state *context, - bool lock) -{ - 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 lock the top pipe's tg to prevent redundant - * (un)locking. 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; - - if (lock) - tg->funcs->lock(tg); - else - tg->funcs->unlock(tg); - } -} - -static void calc_vupdate_position( +static void dcn10_calc_vupdate_position( + struct dc *dc, struct pipe_ctx *pipe_ctx, uint32_t *start_line, uint32_t *end_line) @@ -3145,7 +3069,7 @@ static void calc_vupdate_position( const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing; int vline_int_offset_from_vupdate = pipe_ctx->stream->periodic_interrupt0.lines_offset; - int vupdate_offset_from_vsync = get_vupdate_offset_from_vsync(pipe_ctx); + int vupdate_offset_from_vsync = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); int start_position; if (vline_int_offset_from_vupdate > 0) @@ -3166,7 +3090,8 @@ static void calc_vupdate_position( *end_line = 2; } -static void cal_vline_position( +static void dcn10_cal_vline_position( + struct dc *dc, struct pipe_ctx *pipe_ctx, enum vline_select vline, uint32_t *start_line, @@ -3181,7 +3106,8 @@ static void cal_vline_position( switch (ref_point) { case START_V_UPDATE: - calc_vupdate_position( + dcn10_calc_vupdate_position( + dc, pipe_ctx, start_line, end_line); @@ -3195,7 +3121,8 @@ static void cal_vline_position( } } -static void dcn10_setup_periodic_interrupt( +void dcn10_setup_periodic_interrupt( + struct dc *dc, struct pipe_ctx *pipe_ctx, enum vline_select vline) { @@ -3205,7 +3132,7 @@ static void dcn10_setup_periodic_interrupt( uint32_t start_line = 0; uint32_t end_line = 0; - cal_vline_position(pipe_ctx, vline, &start_line, &end_line); + dcn10_cal_vline_position(dc, pipe_ctx, vline, &start_line, &end_line); tg->funcs->setup_vertical_interrupt0(tg, start_line, end_line); @@ -3216,10 +3143,10 @@ static void dcn10_setup_periodic_interrupt( } } -static void dcn10_setup_vupdate_interrupt(struct pipe_ctx *pipe_ctx) +void dcn10_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx) { struct timing_generator *tg = pipe_ctx->stream_res.tg; - int start_line = get_vupdate_offset_from_vsync(pipe_ctx); + int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); if (start_line < 0) { ASSERT(0); @@ -3230,12 +3157,13 @@ static void dcn10_setup_vupdate_interrupt(struct pipe_ctx *pipe_ctx) tg->funcs->setup_vertical_interrupt2(tg, start_line); } -static void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, +void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, struct dc_link_settings *link_settings) { struct encoder_unblank_param params = { { 0 } }; struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->link; + struct dce_hwseq *hws = link->dc->hwseq; /* only 3 items below are used by unblank */ params.timing = pipe_ctx->stream->timing; @@ -3249,11 +3177,11 @@ static void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, } if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { - link->dc->hwss.edp_backlight_control(link, true); + hws->funcs.edp_backlight_control(link, true); } } -static void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, +void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, const uint8_t *custom_sdp_message, unsigned int sdp_message_size) { @@ -3264,7 +3192,7 @@ static void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, sdp_message_size); } } -static enum dc_status dcn10_set_clock(struct dc *dc, +enum dc_status dcn10_set_clock(struct dc *dc, enum dc_clock_type clock_type, uint32_t clk_khz, uint32_t stepping) @@ -3304,7 +3232,7 @@ static enum dc_status dcn10_set_clock(struct dc *dc, } -static void dcn10_get_clock(struct dc *dc, +void dcn10_get_clock(struct dc *dc, enum dc_clock_type clock_type, struct dc_clock_config *clock_cfg) { @@ -3314,77 +3242,3 @@ static void dcn10_get_clock(struct dc *dc, dc->clk_mgr->funcs->get_clock(dc->clk_mgr, context, clock_type, clock_cfg); } - -static const struct hw_sequencer_funcs dcn10_funcs = { - .program_gamut_remap = dcn10_program_gamut_remap, - .init_hw = dcn10_init_hw, - .init_pipes = dcn10_init_pipes, - .apply_ctx_to_hw = dce110_apply_ctx_to_hw, - .apply_ctx_for_surface = dcn10_apply_ctx_for_surface, - .update_plane_addr = dcn10_update_plane_addr, - .plane_atomic_disconnect = hwss1_plane_atomic_disconnect, - .update_dchub = dcn10_update_dchub, - .update_mpcc = dcn10_update_mpcc, - .update_pending_status = dcn10_update_pending_status, - .set_input_transfer_func = dcn10_set_input_transfer_func, - .set_output_transfer_func = dcn10_set_output_transfer_func, - .program_output_csc = dcn10_program_output_csc, - .power_down = dce110_power_down, - .enable_accelerated_mode = dce110_enable_accelerated_mode, - .enable_timing_synchronization = dcn10_enable_timing_synchronization, - .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, - .update_info_frame = dce110_update_info_frame, - .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, - .enable_stream = dce110_enable_stream, - .disable_stream = dce110_disable_stream, - .unblank_stream = dcn10_unblank_stream, - .blank_stream = dce110_blank_stream, - .enable_audio_stream = dce110_enable_audio_stream, - .disable_audio_stream = dce110_disable_audio_stream, - .enable_display_power_gating = dcn10_dummy_display_power_gating, - .disable_plane = dcn10_disable_plane, - .blank_pixel_data = dcn10_blank_pixel_data, - .pipe_control_lock = dcn10_pipe_control_lock, - .prepare_bandwidth = dcn10_prepare_bandwidth, - .optimize_bandwidth = dcn10_optimize_bandwidth, - .reset_hw_ctx_wrap = dcn10_reset_hw_ctx_wrap, - .enable_stream_timing = dcn10_enable_stream_timing, - .set_drr = dcn10_set_drr, - .get_position = dcn10_get_position, - .set_static_screen_control = dcn10_set_static_screen_control, - .setup_stereo = dcn10_setup_stereo, - .set_avmute = dce110_set_avmute, - .log_hw_state = dcn10_log_hw_state, - .get_hw_state = dcn10_get_hw_state, - .clear_status_bits = dcn10_clear_status_bits, - .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, - .edp_backlight_control = dce110_edp_backlight_control, - .edp_power_control = dce110_edp_power_control, - .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, - .set_cursor_position = dcn10_set_cursor_position, - .set_cursor_attribute = dcn10_set_cursor_attribute, - .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, - .disable_stream_gating = NULL, - .enable_stream_gating = NULL, - .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, - .setup_vupdate_interrupt = dcn10_setup_vupdate_interrupt, - .set_clock = dcn10_set_clock, - .get_clock = dcn10_get_clock, - .did_underflow_occur = dcn10_did_underflow_occur, - .init_blank = NULL, - .disable_vga = dcn10_disable_vga, - .bios_golden_init = dcn10_bios_golden_init, - .plane_atomic_disable = dcn10_plane_atomic_disable, - .plane_atomic_power_down = dcn10_plane_atomic_power_down, - .enable_power_gating_plane = dcn10_enable_power_gating_plane, - .dpp_pg_control = dcn10_dpp_pg_control, - .hubp_pg_control = dcn10_hubp_pg_control, - .dsc_pg_control = NULL, -}; - - -void dcn10_hw_sequencer_construct(struct dc *dc) -{ - dc->hwss = dcn10_funcs; -} - 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 d3616b1948cc7be67e7ae0d5a39e4ae3a7a6ee71..55b8f3b2fc4edea35c0c6d22ba7e796b710a3b55 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 @@ -27,68 +27,160 @@ #define __DC_HWSS_DCN10_H__ #include "core_types.h" +#include "hw_sequencer_private.h" struct dc; void dcn10_hw_sequencer_construct(struct dc *dc); -extern void fill_display_configs( - const struct dc_state *context, - struct dm_pp_display_configuration *pp_display_cfg); - -bool is_rgb_cspace(enum dc_color_space output_color_space); - -void hwss1_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx); - -void dcn10_verify_allow_pstate_change_high(struct dc *dc); +int dcn10_get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx); +void dcn10_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx); +enum dc_status dcn10_enable_stream_timing( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, + struct dc *dc); +void dcn10_optimize_bandwidth( + struct dc *dc, + struct dc_state *context); +void dcn10_prepare_bandwidth( + struct dc *dc, + struct dc_state *context); +void dcn10_pipe_control_lock( + struct dc *dc, + struct pipe_ctx *pipe, + bool lock); +void dcn10_blank_pixel_data( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool blank); +void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, + struct dc_link_settings *link_settings); +void dcn10_program_output_csc(struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum dc_color_space colorspace, + uint16_t *matrix, + int opp_id); +bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream); +bool dcn10_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); +void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn10_reset_hw_ctx_wrap( + struct dc *dc, + struct dc_state *context); +void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn10_apply_ctx_for_surface( + struct dc *dc, + const struct dc_stream_state *stream, + int num_planes, + struct dc_state *context); +void dcn10_hubp_pg_control( + struct dce_hwseq *hws, + unsigned int hubp_inst, + bool power_on); +void dcn10_dpp_pg_control( + struct dce_hwseq *hws, + unsigned int dpp_inst, + bool power_on); +void dcn10_enable_power_gating_plane( + struct dce_hwseq *hws, + bool enable); +void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn10_disable_vga( + struct dce_hwseq *hws); void dcn10_program_pipe( struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_state *context); - -void dcn10_get_hw_state( +void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx); +void dcn10_init_hw(struct dc *dc); +void dcn10_init_pipes(struct dc *dc, struct dc_state *context); +enum dc_status dce110_apply_ctx_to_hw( + struct dc *dc, + struct dc_state *context); +void dcn10_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data); +void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx); +void dce110_power_down(struct dc *dc); +void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context); +void dcn10_enable_timing_synchronization( + struct dc *dc, + int group_index, + int group_size, + struct pipe_ctx *grouped_pipes[]); +void dcn10_enable_per_frame_crtc_position_reset( + struct dc *dc, + int group_size, + struct pipe_ctx *grouped_pipes[]); +void dce110_update_info_frame(struct pipe_ctx *pipe_ctx); +void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, + const uint8_t *custom_sdp_message, + unsigned int sdp_message_size); +void dce110_blank_stream(struct pipe_ctx *pipe_ctx); +void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx); +void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx); +bool dcn10_dummy_display_power_gating( struct dc *dc, - char *pBuf, unsigned int bufSize, + uint8_t controller_id, + struct dc_bios *dcb, + enum pipe_gating_control power_gating); +void dcn10_set_drr(struct pipe_ctx **pipe_ctx, + int num_pipes, unsigned int vmin, unsigned int vmax, + unsigned int vmid, unsigned int vmid_frame_number); +void dcn10_get_position(struct pipe_ctx **pipe_ctx, + int num_pipes, + struct crtc_position *position); +void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx, + int num_pipes, const struct dc_static_screen_events *events); +void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc); +void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable); +void dcn10_log_hw_state(struct dc *dc, + struct dc_log_buffer_ctx *log_ctx); +void dcn10_get_hw_state(struct dc *dc, + char *pBuf, + unsigned int bufSize, unsigned int mask); - void dcn10_clear_status_bits(struct dc *dc, unsigned int mask); - -bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx); - -bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx); - -bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx); - -void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp); - -void set_hdr_multiplier(struct pipe_ctx *pipe_ctx); - +void dcn10_wait_for_mpcc_disconnect( + struct dc *dc, + struct resource_pool *res_pool, + struct pipe_ctx *pipe_ctx); +void dce110_edp_backlight_control( + struct dc_link *link, + bool enable); +void dce110_edp_power_control( + struct dc_link *link, + bool power_up); +void dce110_edp_wait_for_hpd_ready( + struct dc_link *link, + bool power_up); +void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx); +void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx); +void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx); +void dcn10_setup_periodic_interrupt( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum vline_select vline); +enum dc_status dcn10_set_clock(struct dc *dc, + enum dc_clock_type clock_type, + uint32_t clk_khz, + uint32_t stepping); +void dcn10_get_clock(struct dc *dc, + enum dc_clock_type clock_type, + struct dc_clock_config *clock_cfg); +bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn10_bios_golden_init(struct dc *dc); +void dcn10_plane_atomic_power_down(struct dc *dc, + struct dpp *dpp, + struct hubp *hubp); void dcn10_get_surface_visual_confirm_color( const struct pipe_ctx *pipe_ctx, struct tg_color *color); - void dcn10_get_hdr_visual_confirm_color( struct pipe_ctx *pipe_ctx, struct tg_color *color); - -bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx); - -void update_dchubp_dpp( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context); - -struct pipe_ctx *find_top_pipe_for_stream( - struct dc *dc, - struct dc_state *context, - const struct dc_stream_state *stream); - -int get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx); - -void dcn10_build_prescale_params(struct dc_bias_and_scale *bias_and_scale, - const struct dc_plane_state *plane_state); -void lock_all_pipes(struct dc *dc, - struct dc_state *context, - bool lock); +void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx); +void dcn10_verify_allow_pstate_change_high(struct dc *dc); #endif /* __DC_HWSS_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..596f95c22e85b07f94bafa559573dff501171b20 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.h @@ -0,0 +1,43 @@ +/* + * Copyright 2016 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: AMD + * + */ + +#ifndef __DC_HWSS_DCN10_DEBUG_H__ +#define __DC_HWSS_DCN10_DEBUG_H__ + +#include "core_types.h" + +struct dc; + +void dcn10_clear_status_bits(struct dc *dc, unsigned int mask); + +void dcn10_log_hw_state(struct dc *dc, + struct dc_log_buffer_ctx *log_ctx); + +void dcn10_get_hw_state(struct dc *dc, + char *pBuf, + unsigned int bufSize, + unsigned int mask); + +#endif /* __DC_HWSS_DCN10_DEBUG_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c new file mode 100644 index 0000000000000000000000000000000000000000..e7e5352ec424b36aa64a62dd79c631cc611e17be --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c @@ -0,0 +1,111 @@ +/* + * Copyright 2016 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: AMD + * + */ + +#include "hw_sequencer_private.h" +#include "dce110/dce110_hw_sequencer.h" +#include "dcn10_hw_sequencer.h" + +static const struct hw_sequencer_funcs dcn10_funcs = { + .program_gamut_remap = dcn10_program_gamut_remap, + .init_hw = dcn10_init_hw, + .apply_ctx_to_hw = dce110_apply_ctx_to_hw, + .apply_ctx_for_surface = dcn10_apply_ctx_for_surface, + .update_plane_addr = dcn10_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .program_output_csc = dcn10_program_output_csc, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dce110_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, + .enable_stream = dce110_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dcn10_unblank_stream, + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dcn10_disable_plane, + .pipe_control_lock = dcn10_pipe_control_lock, + .prepare_bandwidth = dcn10_prepare_bandwidth, + .optimize_bandwidth = dcn10_optimize_bandwidth, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn10_set_static_screen_control, + .setup_stereo = dcn10_setup_stereo, + .set_avmute = dce110_set_avmute, + .log_hw_state = dcn10_log_hw_state, + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, +}; + +static const struct hwseq_private_funcs dcn10_private_funcs = { + .init_pipes = dcn10_init_pipes, + .update_plane_addr = dcn10_update_plane_addr, + .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, + .program_pipe = dcn10_program_pipe, + .update_mpcc = dcn10_update_mpcc, + .set_input_transfer_func = dcn10_set_input_transfer_func, + .set_output_transfer_func = dcn10_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .blank_pixel_data = dcn10_blank_pixel_data, + .reset_hw_ctx_wrap = dcn10_reset_hw_ctx_wrap, + .enable_stream_timing = dcn10_enable_stream_timing, + .edp_backlight_control = dce110_edp_backlight_control, + .disable_stream_gating = NULL, + .enable_stream_gating = NULL, + .setup_vupdate_interrupt = dcn10_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = NULL, + .disable_vga = dcn10_disable_vga, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn10_plane_atomic_disable, + .plane_atomic_power_down = dcn10_plane_atomic_power_down, + .enable_power_gating_plane = dcn10_enable_power_gating_plane, + .dpp_pg_control = dcn10_dpp_pg_control, + .hubp_pg_control = dcn10_hubp_pg_control, + .dsc_pg_control = NULL, + .get_surface_visual_confirm_color = dcn10_get_surface_visual_confirm_color, + .get_hdr_visual_confirm_color = dcn10_get_hdr_visual_confirm_color, + .set_hdr_multiplier = dcn10_set_hdr_multiplier, + .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, +}; + +void dcn10_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dcn10_funcs; + dc->hwseq->funcs = dcn10_private_funcs; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.h new file mode 100644 index 0000000000000000000000000000000000000000..8c6fd7b844a4d74a70f6257e727ce862e5f5dc4b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.h @@ -0,0 +1,33 @@ +/* + * Copyright 2016 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: AMD + * + */ + +#ifndef __DC_DCN10_INIT_H__ +#define __DC_DCN10_INIT_H__ + +struct dc; + +void dcn10_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN10_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c index 0fb9e440cb9def8afa028cefea2a73879f866507..f05371c1fc3656565ac131e6a74728b7e0c1ac4d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c @@ -53,11 +53,9 @@ static const struct ipp_funcs dcn10_ipp_funcs = { .ipp_destroy = dcn10_ipp_destroy }; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) static const struct ipp_funcs dcn20_ipp_funcs = { .ipp_destroy = dcn10_ipp_destroy }; -#endif void dcn10_ipp_construct( struct dcn10_ipp *ippn10, @@ -76,7 +74,6 @@ void dcn10_ipp_construct( ippn10->ipp_mask = ipp_mask; } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) void dcn20_ipp_construct( struct dcn10_ipp *ippn10, struct dc_context *ctx, @@ -93,4 +90,3 @@ void dcn20_ipp_construct( ippn10->ipp_shift = ipp_shift; ippn10->ipp_mask = ipp_mask; } -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h index cfa24459242b47504947f09418e6d9d1d60dcbff..f0e0d07b031122a79dcf19df68b364dd3c2bb874 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h @@ -49,7 +49,6 @@ SRI(CURSOR_HOT_SPOT, CURSOR, id), \ SRI(CURSOR_DST_OFFSET, CURSOR, id) -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define IPP_REG_LIST_DCN20(id) \ IPP_REG_LIST_DCN(id), \ SRI(CURSOR_SETTINGS, HUBPREQ, id), \ @@ -60,7 +59,6 @@ SRI(CURSOR_POSITION, CURSOR0_, id), \ SRI(CURSOR_HOT_SPOT, CURSOR0_, id), \ SRI(CURSOR_DST_OFFSET, CURSOR0_, id) -#endif #define CURSOR0_CURSOR_CONTROL__CURSOR_2X_MAGNIFY__SHIFT 0x4 #define CURSOR0_CURSOR_CONTROL__CURSOR_2X_MAGNIFY_MASK 0x00000010L @@ -105,7 +103,6 @@ IPP_SF(CURSOR0_CURSOR_DST_OFFSET, CURSOR_DST_X_OFFSET, mask_sh), \ IPP_SF(CNVC_CFG0_FORMAT_CONTROL, OUTPUT_FP, mask_sh) -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define IPP_MASK_SH_LIST_DCN20(mask_sh) \ IPP_MASK_SH_LIST_DCN(mask_sh), \ IPP_SF(HUBPREQ0_CURSOR_SETTINGS, CURSOR0_DST_Y_OFFSET, mask_sh), \ @@ -124,7 +121,6 @@ IPP_SF(CURSOR0_0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_X, mask_sh), \ IPP_SF(CURSOR0_0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_Y, mask_sh), \ IPP_SF(CURSOR0_0_CURSOR_DST_OFFSET, CURSOR_DST_X_OFFSET, mask_sh) -#endif #define IPP_DCN10_REG_FIELD_LIST(type) \ type CNVC_SURFACE_PIXEL_FORMAT; \ @@ -196,13 +192,11 @@ void dcn10_ipp_construct(struct dcn10_ipp *ippn10, const struct dcn10_ipp_shift *ipp_shift, const struct dcn10_ipp_mask *ipp_mask); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) void dcn20_ipp_construct(struct dcn10_ipp *ippn10, struct dc_context *ctx, int inst, const struct dcn10_ipp_registers *regs, const struct dcn10_ipp_shift *ipp_shift, const struct dcn10_ipp_mask *ipp_mask); -#endif #endif /* _DCN10_IPP_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h index 88fcc395adf52475672479147d6a1075e84db052..7493a630f4dcdf2250f4ca547550748e9947270a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h @@ -72,9 +72,7 @@ struct dcn10_link_enc_aux_registers { uint32_t AUX_CONTROL; uint32_t AUX_DPHY_RX_CONTROL0; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 uint32_t AUX_DPHY_TX_CONTROL; -#endif }; struct dcn10_link_enc_hpd_registers { @@ -106,7 +104,6 @@ struct dcn10_link_enc_registers { uint32_t DP_DPHY_HBR2_PATTERN_CONTROL; uint32_t DP_SEC_CNTL1; uint32_t TMDS_CTL_BITS; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) /* DCCG */ uint32_t CLOCK_ENABLE; /* DIG */ @@ -136,7 +133,6 @@ struct dcn10_link_enc_registers { uint32_t RAWLANE2_DIG_PCS_XF_RX_OVRD_IN_3; uint32_t RAWLANE3_DIG_PCS_XF_RX_OVRD_IN_2; uint32_t RAWLANE3_DIG_PCS_XF_RX_OVRD_IN_3; -#endif }; #define LE_SF(reg_name, field_name, post_fix)\ @@ -242,7 +238,6 @@ struct dcn10_link_enc_registers { type AUX_LS_READ_EN;\ type AUX_RX_RECEIVE_WINDOW -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define DCN20_LINK_ENCODER_DPCS_REG_FIELD_LIST(type) \ type RDPCS_PHY_DP_TX0_DATA_EN;\ @@ -423,20 +418,15 @@ struct dcn10_link_enc_registers { type AUX_TX_PRECHARGE_SYMBOLS; \ type AUX_MODE_DET_CHECK_DELAY;\ type DPCS_DBG_CBUS_DIS -#endif struct dcn10_link_enc_shift { DCN_LINK_ENCODER_REG_FIELD_LIST(uint8_t); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) DCN20_LINK_ENCODER_REG_FIELD_LIST(uint8_t); -#endif }; struct dcn10_link_enc_mask { DCN_LINK_ENCODER_REG_FIELD_LIST(uint32_t); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) DCN20_LINK_ENCODER_REG_FIELD_LIST(uint32_t); -#endif }; struct dcn10_link_encoder { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c index 8b2f29f6dabd202ca3cdfcf73fb6593904721021..04f863499cfb75352ef0a2b6a69fe165f645dabd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c @@ -42,20 +42,27 @@ void mpc1_set_bg_color(struct mpc *mpc, int mpcc_id) { struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc); + struct mpcc *bottommost_mpcc = mpc1_get_mpcc(mpc, mpcc_id); + uint32_t bg_r_cr, bg_g_y, bg_b_cb; + + /* find bottommost mpcc. */ + while (bottommost_mpcc->mpcc_bot) { + bottommost_mpcc = bottommost_mpcc->mpcc_bot; + } /* mpc color is 12 bit. tg_color is 10 bit */ /* todo: might want to use 16 bit to represent color and have each * hw block translate to correct color depth. */ - uint32_t bg_r_cr = bg_color->color_r_cr << 2; - uint32_t bg_g_y = bg_color->color_g_y << 2; - uint32_t bg_b_cb = bg_color->color_b_cb << 2; + bg_r_cr = bg_color->color_r_cr << 2; + bg_g_y = bg_color->color_g_y << 2; + bg_b_cb = bg_color->color_b_cb << 2; - REG_SET(MPCC_BG_R_CR[mpcc_id], 0, + REG_SET(MPCC_BG_R_CR[bottommost_mpcc->mpcc_id], 0, MPCC_BG_R_CR, bg_r_cr); - REG_SET(MPCC_BG_G_Y[mpcc_id], 0, + REG_SET(MPCC_BG_G_Y[bottommost_mpcc->mpcc_id], 0, MPCC_BG_G_Y, bg_g_y); - REG_SET(MPCC_BG_B_CB[mpcc_id], 0, + REG_SET(MPCC_BG_B_CB[bottommost_mpcc->mpcc_id], 0, MPCC_BG_B_CB, bg_b_cb); } @@ -457,12 +464,10 @@ static const struct mpc_funcs dcn10_mpc_funcs = { .assert_mpcc_idle_before_connect = mpc1_assert_mpcc_idle_before_connect, .init_mpcc_list_from_hw = mpc1_init_mpcc_list_from_hw, .update_blending = mpc1_update_blending, -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) .set_denorm = NULL, .set_denorm_clamp = NULL, .set_output_csc = NULL, .set_output_gamma = NULL, -#endif }; void dcn10_mpc_construct(struct dcn10_mpc *mpc10, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c index 0a9ad692f541af3c821abdb5cb9c92d74c518832..d79718fde5a65ae9a501c2745ef845a744719507 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c @@ -373,11 +373,9 @@ void opp1_program_oppbuf( */ REG_UPDATE(OPPBUF_CONTROL, OPPBUF_PIXEL_REPETITION, oppbuf->pixel_repetition); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) /* Controls the number of padded pixels at the end of a segment */ if (REG(OPPBUF_CONTROL1)) REG_UPDATE(OPPBUF_CONTROL1, OPPBUF_NUM_SEGMENT_PADDED_PIXELS, oppbuf->num_segment_padded_pixels); -#endif } void opp1_pipe_clock_control(struct output_pixel_processor *opp, bool enable) @@ -404,9 +402,8 @@ static const struct opp_funcs dcn10_opp_funcs = { .opp_program_bit_depth_reduction = opp1_program_bit_depth_reduction, .opp_program_stereo = opp1_program_stereo, .opp_pipe_clock_control = opp1_pipe_clock_control, -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) .opp_set_disp_pattern_generator = NULL, -#endif + .dpg_is_blanked = NULL, .opp_destroy = opp1_destroy }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index dabccbd49ad4aa53239075c7f2ec5a33365b51cd..cd7412dc42d1a23401703bea6814ce53352454ac 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -457,11 +457,16 @@ static bool optc1_enable_crtc(struct timing_generator *optc) REG_UPDATE(CONTROL, VTG0_ENABLE, 1); + REG_SEQ_START(); + /* Enable CRTC */ REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 3, OTG_MASTER_EN, 1); + REG_SEQ_SUBMIT(); + REG_SEQ_WAIT_DONE(); + return true; } @@ -1497,7 +1502,6 @@ void dcn10_timing_generator_init(struct optc *optc1) optc1->min_v_sync_width = 1; } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT /* "Containter" vs. "pixel" is a concept within HW blocks, mostly those closer to the back-end. It works like this: * * - In most of the formats (RGB or YCbCr 4:4:4, 4:2:2 uncompressed and DSC 4:2:2 Simple) pixel rate is the same as @@ -1510,15 +1514,12 @@ void dcn10_timing_generator_init(struct optc *optc1) * to it) and has to be treated the same as 4:2:0, i.e. target containter rate has to be halved in this case as well. * */ -#endif bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) { bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422 && !timing->dsc_cfg.ycbcr422_simple); -#endif return two_pix; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h index c8d795b335baff92c3add378e1ead404dcea0cb4..3afeb1a30f214da63c6c173a68fd023525863915 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -165,13 +165,11 @@ struct dcn_optc_registers { uint32_t OTG_CRC0_WINDOWB_X_CONTROL; uint32_t OTG_CRC0_WINDOWB_Y_CONTROL; uint32_t GSL_SOURCE_SELECT; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 uint32_t DWB_SOURCE_SELECT; uint32_t OTG_DSC_START_POSITION; uint32_t OPTC_DATA_FORMAT_CONTROL; uint32_t OPTC_BYTES_PER_PIXEL; uint32_t OPTC_WIDTH_CONTROL; -#endif }; #define TG_COMMON_MASK_SH_LIST_DCN(mask_sh)\ @@ -456,7 +454,6 @@ struct dcn_optc_registers { type MANUAL_FLOW_CONTROL;\ type MANUAL_FLOW_CONTROL_SEL; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 #define TG_REG_FIELD_LIST(type) \ TG_REG_FIELD_LIST_DCN1_0(type)\ @@ -479,12 +476,6 @@ struct dcn_optc_registers { type OPTC_DWB0_SOURCE_SELECT;\ type OPTC_DWB1_SOURCE_SELECT; -#else - -#define TG_REG_FIELD_LIST(type) \ - TG_REG_FIELD_LIST_DCN1_0(type) - -#endif struct dcn_optc_shift { @@ -542,6 +533,7 @@ struct dcn_otg_state { uint32_t h_total; uint32_t underflow_occurred_status; uint32_t otg_enabled; + uint32_t blank_enabled; }; void optc1_read_otg_state(struct optc *optc1, 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 15640aedd664d09994bdd4abd333ec87e3ebf54c..3b71898e859e598caee54fbe4657b9d7826479a6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -28,6 +28,8 @@ #include "dm_services.h" #include "dc.h" +#include "dcn10_init.h" + #include "resource.h" #include "include/irq_service_interface.h" #include "dcn10_resource.h" @@ -919,7 +921,7 @@ static struct pp_smu_funcs *dcn10_pp_smu_create(struct dc_context *ctx) return pp_smu; } -static void destruct(struct dcn10_resource_pool *pool) +static void dcn10_resource_destruct(struct dcn10_resource_pool *pool) { unsigned int i; @@ -1166,7 +1168,7 @@ static void dcn10_destroy_resource_pool(struct resource_pool **pool) { struct dcn10_resource_pool *dcn10_pool = TO_DCN10_RES_POOL(*pool); - destruct(dcn10_pool); + dcn10_resource_destruct(dcn10_pool); kfree(dcn10_pool); *pool = NULL; } @@ -1305,7 +1307,7 @@ static uint32_t read_pipe_fuses(struct dc_context *ctx) return value; } -static bool construct( +static bool dcn10_resource_construct( uint8_t num_virtual_links, struct dc *dc, struct dcn10_resource_pool *pool) @@ -1592,7 +1594,7 @@ static bool construct( fail: - destruct(pool); + dcn10_resource_destruct(pool); return false; } @@ -1607,7 +1609,7 @@ struct resource_pool *dcn10_create_resource_pool( if (!pool) return NULL; - if (construct(init_data->num_virtual_links, dc, pool)) + if (dcn10_resource_construct(init_data->num_virtual_links, dc, pool)) return &pool->base; kfree(pool); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c index 06e5bbb4545cd5512baa310c12dcc42bc2d4b80e..376c4264d295b5f9fe808e14ed44389093c66581 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c @@ -247,6 +247,7 @@ void enc1_stream_encoder_dp_set_stream_attribute( struct stream_encoder *enc, struct dc_crtc_timing *crtc_timing, enum dc_color_space output_color_space, + bool use_vsc_sdp_for_colorimetry, uint32_t enable_sdp_splitting) { uint32_t h_active_start; @@ -312,10 +313,7 @@ void enc1_stream_encoder_dp_set_stream_attribute( * Pixel Encoding/Colorimetry Format and that a Sink device shall ignore MISC1, bit 7, * and MISC0, bits 7:1 (MISC1, bit 7, and MISC0, bits 7:1, become "don't care"). */ - if ((hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) || - (output_color_space == COLOR_SPACE_2020_YCBCR) || - (output_color_space == COLOR_SPACE_2020_RGB_FULLRANGE) || - (output_color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE)) + if (use_vsc_sdp_for_colorimetry) misc1 = misc1 | 0x40; else misc1 = misc1 & ~0x40; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h index c9cbc21d121e8a519a4a813aa5809732f0d67867..f9b9e221c698b5bc692a4ab25d498b30f6b0b591 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h @@ -163,14 +163,12 @@ struct dcn10_stream_enc_registers { uint32_t DP_MSA_TIMING_PARAM3; uint32_t DP_MSA_TIMING_PARAM4; uint32_t HDMI_DB_CONTROL; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) uint32_t DP_DSC_CNTL; uint32_t DP_DSC_BYTES_PER_PIXEL; uint32_t DME_CONTROL; uint32_t DP_SEC_METADATA_TRANSMISSION; uint32_t HDMI_METADATA_PACKET_CONTROL; uint32_t DP_SEC_FRAMING4; -#endif uint32_t DIG_CLOCK_PATTERN; }; @@ -466,7 +464,6 @@ struct dcn10_stream_enc_registers { type DIG_SOURCE_SELECT;\ type DIG_CLOCK_PATTERN -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define SE_REG_FIELD_LIST_DCN2_0(type) \ type DP_DSC_MODE;\ type DP_DSC_SLICE_WIDTH;\ @@ -485,20 +482,15 @@ struct dcn10_stream_enc_registers { type DOLBY_VISION_EN;\ type DP_PIXEL_COMBINE;\ type DP_SST_SDP_SPLITTING -#endif struct dcn10_stream_encoder_shift { SE_REG_FIELD_LIST_DCN1_0(uint8_t); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) SE_REG_FIELD_LIST_DCN2_0(uint8_t); -#endif }; struct dcn10_stream_encoder_mask { SE_REG_FIELD_LIST_DCN1_0(uint32_t); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) SE_REG_FIELD_LIST_DCN2_0(uint32_t); -#endif }; struct dcn10_stream_encoder { @@ -526,6 +518,7 @@ void enc1_stream_encoder_dp_set_stream_attribute( struct stream_encoder *enc, struct dc_crtc_timing *crtc_timing, enum dc_color_space output_color_space, + bool use_vsc_sdp_for_colorimetry, uint32_t enable_sdp_splitting); void enc1_stream_encoder_hdmi_set_stream_attribute( diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile index 63f3bddba7daaa50ab93dbd9a42fc13327208d84..fd52862d6624b793957e43eb79fc90b0db5d1b1d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile @@ -1,14 +1,13 @@ +# SPDX-License-Identifier: MIT # # Makefile for DCN. -DCN20 = dcn20_resource.o dcn20_hwseq.o dcn20_dpp.o dcn20_dpp_cm.o dcn20_hubp.o \ +DCN20 = dcn20_resource.o dcn20_init.o dcn20_hwseq.o dcn20_dpp.o dcn20_dpp_cm.o dcn20_hubp.o \ dcn20_mpc.o dcn20_opp.o dcn20_hubbub.o dcn20_optc.o dcn20_mmhubbub.o \ dcn20_stream_encoder.o dcn20_link_encoder.o dcn20_dccg.o \ dcn20_vmid.o dcn20_dwb.o dcn20_dwb_scl.o -ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT DCN20 += dcn20_dsc.o -endif CFLAGS_$(AMDDALPATH)/dc/dcn20/dcn20_resource.o := -mhard-float -msse diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c index 2d112c316424f535d2312e02fc76f1c45be6ed39..05a3e7f97ef05eb78ae3e6244f86b0a8344e6851 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c @@ -149,6 +149,9 @@ void dpp2_set_degamma( case IPP_DEGAMMA_MODE_HW_xvYCC: REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 2); break; + case IPP_DEGAMMA_MODE_USER_PWL: + REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 3); + break; default: BREAK_TO_DEBUGGER(); break; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c index 63eb377ed9c03fcc9e0dfbafd09977394147f65a..0111545dac75d9035044dcd5d39732f9f7e54969 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c @@ -23,7 +23,6 @@ * */ -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #include "reg_helper.h" #include "dcn20_dsc.h" #include "dsc/dscc_types.h" @@ -222,9 +221,18 @@ static bool dsc2_get_packed_pps(struct display_stream_compressor *dsc, const str static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe) { struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + int dsc_clock_en; + int dsc_fw_config; + int enabled_opp_pipe; - /* TODO Check if DSC alreay in use? */ - DC_LOG_DSC("enable DSC at opp pipe %d", opp_pipe); + DC_LOG_DSC("enable DSC %d at opp pipe %d", dsc->inst, opp_pipe); + + REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &dsc_clock_en); + REG_GET_2(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, &dsc_fw_config, DSCRM_DSC_OPP_PIPE_SOURCE, &enabled_opp_pipe); + if ((dsc_clock_en || dsc_fw_config) && enabled_opp_pipe != opp_pipe) { + DC_LOG_DSC("ERROR: DSC %d at opp pipe %d already enabled!", dsc->inst, enabled_opp_pipe); + ASSERT(0); + } REG_UPDATE(DSC_TOP_CONTROL, DSC_CLOCK_EN, 1); @@ -238,8 +246,18 @@ static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe) static void dsc2_disable(struct display_stream_compressor *dsc) { struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + int dsc_clock_en; + int dsc_fw_config; + int enabled_opp_pipe; - DC_LOG_DSC("disable DSC"); + DC_LOG_DSC("disable DSC %d", dsc->inst); + + REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &dsc_clock_en); + REG_GET_2(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, &dsc_fw_config, DSCRM_DSC_OPP_PIPE_SOURCE, &enabled_opp_pipe); + if (!dsc_clock_en || !dsc_fw_config) { + DC_LOG_DSC("ERROR: DSC %d at opp pipe %d already disabled!", dsc->inst, enabled_opp_pipe); + ASSERT(0); + } REG_UPDATE(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, 0); @@ -715,4 +733,3 @@ static void dsc_write_to_registers(struct display_stream_compressor *dsc, const } } -#endif 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 4e2fb38390a46544f6935c8092c7f02e4b2fbde4..9855a7ed0387a7cdd8949b1cae8feb0d5db94090 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h @@ -21,7 +21,6 @@ * Authors: AMD * */ -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #ifndef __DCN20_DSC_H__ #define __DCN20_DSC_H__ @@ -572,4 +571,3 @@ void dsc2_construct(struct dcn20_dsc *dsc, #endif -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c index 69e2aae4239475e274290174915c8a66e757a336..84d7ac5dd2060abd2f653185c6db51c82d6948e0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c @@ -30,6 +30,8 @@ #include "reg_helper.h" #include "basics/conversion.h" +#define DC_LOGGER_INIT(logger) + #define REG(reg)\ hubp2->hubp_regs->reg @@ -483,7 +485,6 @@ void hubp2_program_pixel_format( REG_UPDATE(DCSURF_SURFACE_CONFIG, SURFACE_PIXEL_FORMAT, 12); break; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FIX: REG_UPDATE(DCSURF_SURFACE_CONFIG, SURFACE_PIXEL_FORMAT, 112); @@ -504,7 +505,6 @@ void hubp2_program_pixel_format( REG_UPDATE(DCSURF_SURFACE_CONFIG, SURFACE_PIXEL_FORMAT, 119); break; -#endif default: BREAK_TO_DEBUGGER(); break; @@ -1204,6 +1204,9 @@ void hubp2_read_state_common(struct hubp *hubp) HUBP_TTU_DISABLE, &s->ttu_disable, HUBP_UNDERFLOW_STATUS, &s->underflow_status); + REG_GET(HUBP_CLK_CNTL, + HUBP_CLOCK_ENABLE, &s->clock_en); + REG_GET(DCN_GLOBAL_TTU_CNTL, MIN_TTU_VBLANK, &s->min_ttu_vblank); @@ -1243,6 +1246,314 @@ void hubp2_read_state(struct hubp *hubp) } +void hubp2_validate_dml_output(struct hubp *hubp, + struct dc_context *ctx, + struct _vcs_dpi_display_rq_regs_st *dml_rq_regs, + struct _vcs_dpi_display_dlg_regs_st *dml_dlg_attr, + struct _vcs_dpi_display_ttu_regs_st *dml_ttu_attr) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + struct _vcs_dpi_display_rq_regs_st rq_regs = {0}; + struct _vcs_dpi_display_dlg_regs_st dlg_attr = {0}; + struct _vcs_dpi_display_ttu_regs_st ttu_attr = {0}; + DC_LOGGER_INIT(ctx->logger); + DC_LOG_DEBUG("DML Validation | Running Validation"); + + /* Requestor Regs */ + REG_GET(HUBPRET_CONTROL, + DET_BUF_PLANE1_BASE_ADDRESS, &rq_regs.plane1_base_address); + REG_GET_4(DCN_EXPANSION_MODE, + DRQ_EXPANSION_MODE, &rq_regs.drq_expansion_mode, + PRQ_EXPANSION_MODE, &rq_regs.prq_expansion_mode, + MRQ_EXPANSION_MODE, &rq_regs.mrq_expansion_mode, + CRQ_EXPANSION_MODE, &rq_regs.crq_expansion_mode); + REG_GET_8(DCHUBP_REQ_SIZE_CONFIG, + CHUNK_SIZE, &rq_regs.rq_regs_l.chunk_size, + MIN_CHUNK_SIZE, &rq_regs.rq_regs_l.min_chunk_size, + META_CHUNK_SIZE, &rq_regs.rq_regs_l.meta_chunk_size, + MIN_META_CHUNK_SIZE, &rq_regs.rq_regs_l.min_meta_chunk_size, + DPTE_GROUP_SIZE, &rq_regs.rq_regs_l.dpte_group_size, + MPTE_GROUP_SIZE, &rq_regs.rq_regs_l.mpte_group_size, + SWATH_HEIGHT, &rq_regs.rq_regs_l.swath_height, + PTE_ROW_HEIGHT_LINEAR, &rq_regs.rq_regs_l.pte_row_height_linear); + REG_GET_8(DCHUBP_REQ_SIZE_CONFIG_C, + CHUNK_SIZE_C, &rq_regs.rq_regs_c.chunk_size, + MIN_CHUNK_SIZE_C, &rq_regs.rq_regs_c.min_chunk_size, + META_CHUNK_SIZE_C, &rq_regs.rq_regs_c.meta_chunk_size, + MIN_META_CHUNK_SIZE_C, &rq_regs.rq_regs_c.min_meta_chunk_size, + DPTE_GROUP_SIZE_C, &rq_regs.rq_regs_c.dpte_group_size, + MPTE_GROUP_SIZE_C, &rq_regs.rq_regs_c.mpte_group_size, + SWATH_HEIGHT_C, &rq_regs.rq_regs_c.swath_height, + PTE_ROW_HEIGHT_LINEAR_C, &rq_regs.rq_regs_c.pte_row_height_linear); + + if (rq_regs.plane1_base_address != dml_rq_regs->plane1_base_address) + DC_LOG_DEBUG("DML Validation | HUBPRET_CONTROL:DET_BUF_PLANE1_BASE_ADDRESS - Expected: %u Actual: %u\n", + dml_rq_regs->plane1_base_address, rq_regs.plane1_base_address); + if (rq_regs.drq_expansion_mode != dml_rq_regs->drq_expansion_mode) + DC_LOG_DEBUG("DML Validation | DCN_EXPANSION_MODE:DRQ_EXPANSION_MODE - Expected: %u Actual: %u\n", + dml_rq_regs->drq_expansion_mode, rq_regs.drq_expansion_mode); + if (rq_regs.prq_expansion_mode != dml_rq_regs->prq_expansion_mode) + DC_LOG_DEBUG("DML Validation | DCN_EXPANSION_MODE:MRQ_EXPANSION_MODE - Expected: %u Actual: %u\n", + dml_rq_regs->prq_expansion_mode, rq_regs.prq_expansion_mode); + if (rq_regs.mrq_expansion_mode != dml_rq_regs->mrq_expansion_mode) + DC_LOG_DEBUG("DML Validation | DCN_EXPANSION_MODE:DET_BUF_PLANE1_BASE_ADDRESS - Expected: %u Actual: %u\n", + dml_rq_regs->mrq_expansion_mode, rq_regs.mrq_expansion_mode); + if (rq_regs.crq_expansion_mode != dml_rq_regs->crq_expansion_mode) + DC_LOG_DEBUG("DML Validation | DCN_EXPANSION_MODE:CRQ_EXPANSION_MODE - Expected: %u Actual: %u\n", + dml_rq_regs->crq_expansion_mode, rq_regs.crq_expansion_mode); + + if (rq_regs.rq_regs_l.chunk_size != dml_rq_regs->rq_regs_l.chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:CHUNK_SIZE - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.chunk_size, rq_regs.rq_regs_l.chunk_size); + if (rq_regs.rq_regs_l.min_chunk_size != dml_rq_regs->rq_regs_l.min_chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:MIN_CHUNK_SIZE - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.min_chunk_size, rq_regs.rq_regs_l.min_chunk_size); + if (rq_regs.rq_regs_l.meta_chunk_size != dml_rq_regs->rq_regs_l.meta_chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:META_CHUNK_SIZE - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.meta_chunk_size, rq_regs.rq_regs_l.meta_chunk_size); + if (rq_regs.rq_regs_l.min_meta_chunk_size != dml_rq_regs->rq_regs_l.min_meta_chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:MIN_META_CHUNK_SIZE - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.min_meta_chunk_size, rq_regs.rq_regs_l.min_meta_chunk_size); + if (rq_regs.rq_regs_l.dpte_group_size != dml_rq_regs->rq_regs_l.dpte_group_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:DPTE_GROUP_SIZE - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.dpte_group_size, rq_regs.rq_regs_l.dpte_group_size); + if (rq_regs.rq_regs_l.mpte_group_size != dml_rq_regs->rq_regs_l.mpte_group_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:MPTE_GROUP_SIZE - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.mpte_group_size, rq_regs.rq_regs_l.mpte_group_size); + if (rq_regs.rq_regs_l.swath_height != dml_rq_regs->rq_regs_l.swath_height) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:SWATH_HEIGHT - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.swath_height, rq_regs.rq_regs_l.swath_height); + if (rq_regs.rq_regs_l.pte_row_height_linear != dml_rq_regs->rq_regs_l.pte_row_height_linear) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:PTE_ROW_HEIGHT_LINEAR - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.pte_row_height_linear, rq_regs.rq_regs_l.pte_row_height_linear); + + if (rq_regs.rq_regs_c.chunk_size != dml_rq_regs->rq_regs_c.chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG:CHUNK_SIZE_C - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_c.chunk_size, rq_regs.rq_regs_c.chunk_size); + if (rq_regs.rq_regs_c.min_chunk_size != dml_rq_regs->rq_regs_c.min_chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG:MIN_CHUNK_SIZE_C - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_c.min_chunk_size, rq_regs.rq_regs_c.min_chunk_size); + if (rq_regs.rq_regs_c.meta_chunk_size != dml_rq_regs->rq_regs_c.meta_chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG:META_CHUNK_SIZE_C - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_c.meta_chunk_size, rq_regs.rq_regs_c.meta_chunk_size); + if (rq_regs.rq_regs_c.min_meta_chunk_size != dml_rq_regs->rq_regs_c.min_meta_chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG:MIN_META_CHUNK_SIZE_C - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_c.min_meta_chunk_size, rq_regs.rq_regs_c.min_meta_chunk_size); + if (rq_regs.rq_regs_c.dpte_group_size != dml_rq_regs->rq_regs_c.dpte_group_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG:DPTE_GROUP_SIZE_C - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_c.dpte_group_size, rq_regs.rq_regs_c.dpte_group_size); + if (rq_regs.rq_regs_c.mpte_group_size != dml_rq_regs->rq_regs_c.mpte_group_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG:MPTE_GROUP_SIZE_C - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_c.mpte_group_size, rq_regs.rq_regs_c.mpte_group_size); + if (rq_regs.rq_regs_c.swath_height != dml_rq_regs->rq_regs_c.swath_height) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG:SWATH_HEIGHT_C - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_c.swath_height, rq_regs.rq_regs_c.swath_height); + if (rq_regs.rq_regs_c.pte_row_height_linear != dml_rq_regs->rq_regs_c.pte_row_height_linear) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG:PTE_ROW_HEIGHT_LINEAR_C - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_c.pte_row_height_linear, rq_regs.rq_regs_c.pte_row_height_linear); + + /* DLG - Per hubp */ + REG_GET_2(BLANK_OFFSET_0, + REFCYC_H_BLANK_END, &dlg_attr.refcyc_h_blank_end, + DLG_V_BLANK_END, &dlg_attr.dlg_vblank_end); + REG_GET(BLANK_OFFSET_1, + MIN_DST_Y_NEXT_START, &dlg_attr.min_dst_y_next_start); + REG_GET(DST_DIMENSIONS, + REFCYC_PER_HTOTAL, &dlg_attr.refcyc_per_htotal); + REG_GET_2(DST_AFTER_SCALER, + REFCYC_X_AFTER_SCALER, &dlg_attr.refcyc_x_after_scaler, + DST_Y_AFTER_SCALER, &dlg_attr.dst_y_after_scaler); + REG_GET(REF_FREQ_TO_PIX_FREQ, + REF_FREQ_TO_PIX_FREQ, &dlg_attr.ref_freq_to_pix_freq); + + if (dlg_attr.refcyc_h_blank_end != dml_dlg_attr->refcyc_h_blank_end) + DC_LOG_DEBUG("DML Validation | BLANK_OFFSET_0:REFCYC_H_BLANK_END - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_h_blank_end, dlg_attr.refcyc_h_blank_end); + if (dlg_attr.dlg_vblank_end != dml_dlg_attr->dlg_vblank_end) + DC_LOG_DEBUG("DML Validation | BLANK_OFFSET_0:DLG_V_BLANK_END - Expected: %u Actual: %u\n", + dml_dlg_attr->dlg_vblank_end, dlg_attr.dlg_vblank_end); + if (dlg_attr.min_dst_y_next_start != dml_dlg_attr->min_dst_y_next_start) + DC_LOG_DEBUG("DML Validation | BLANK_OFFSET_1:MIN_DST_Y_NEXT_START - Expected: %u Actual: %u\n", + dml_dlg_attr->min_dst_y_next_start, dlg_attr.min_dst_y_next_start); + if (dlg_attr.refcyc_per_htotal != dml_dlg_attr->refcyc_per_htotal) + DC_LOG_DEBUG("DML Validation | DST_DIMENSIONS:REFCYC_PER_HTOTAL - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_htotal, dlg_attr.refcyc_per_htotal); + if (dlg_attr.refcyc_x_after_scaler != dml_dlg_attr->refcyc_x_after_scaler) + DC_LOG_DEBUG("DML Validation | DST_AFTER_SCALER:REFCYC_X_AFTER_SCALER - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_x_after_scaler, dlg_attr.refcyc_x_after_scaler); + if (dlg_attr.dst_y_after_scaler != dml_dlg_attr->dst_y_after_scaler) + DC_LOG_DEBUG("DML Validation | DST_AFTER_SCALER:DST_Y_AFTER_SCALER - Expected: %u Actual: %u\n", + dml_dlg_attr->dst_y_after_scaler, dlg_attr.dst_y_after_scaler); + if (dlg_attr.ref_freq_to_pix_freq != dml_dlg_attr->ref_freq_to_pix_freq) + DC_LOG_DEBUG("DML Validation | REF_FREQ_TO_PIX_FREQ:REF_FREQ_TO_PIX_FREQ - Expected: %u Actual: %u\n", + dml_dlg_attr->ref_freq_to_pix_freq, dlg_attr.ref_freq_to_pix_freq); + + /* DLG - Per luma/chroma */ + REG_GET(VBLANK_PARAMETERS_1, + REFCYC_PER_PTE_GROUP_VBLANK_L, &dlg_attr.refcyc_per_pte_group_vblank_l); + if (REG(NOM_PARAMETERS_0)) + REG_GET(NOM_PARAMETERS_0, + DST_Y_PER_PTE_ROW_NOM_L, &dlg_attr.dst_y_per_pte_row_nom_l); + if (REG(NOM_PARAMETERS_1)) + REG_GET(NOM_PARAMETERS_1, + REFCYC_PER_PTE_GROUP_NOM_L, &dlg_attr.refcyc_per_pte_group_nom_l); + REG_GET(NOM_PARAMETERS_4, + DST_Y_PER_META_ROW_NOM_L, &dlg_attr.dst_y_per_meta_row_nom_l); + REG_GET(NOM_PARAMETERS_5, + REFCYC_PER_META_CHUNK_NOM_L, &dlg_attr.refcyc_per_meta_chunk_nom_l); + REG_GET_2(PER_LINE_DELIVERY, + REFCYC_PER_LINE_DELIVERY_L, &dlg_attr.refcyc_per_line_delivery_l, + REFCYC_PER_LINE_DELIVERY_C, &dlg_attr.refcyc_per_line_delivery_c); + REG_GET_2(PER_LINE_DELIVERY_PRE, + REFCYC_PER_LINE_DELIVERY_PRE_L, &dlg_attr.refcyc_per_line_delivery_pre_l, + REFCYC_PER_LINE_DELIVERY_PRE_C, &dlg_attr.refcyc_per_line_delivery_pre_c); + REG_GET(VBLANK_PARAMETERS_2, + REFCYC_PER_PTE_GROUP_VBLANK_C, &dlg_attr.refcyc_per_pte_group_vblank_c); + if (REG(NOM_PARAMETERS_2)) + REG_GET(NOM_PARAMETERS_2, + DST_Y_PER_PTE_ROW_NOM_C, &dlg_attr.dst_y_per_pte_row_nom_c); + if (REG(NOM_PARAMETERS_3)) + REG_GET(NOM_PARAMETERS_3, + REFCYC_PER_PTE_GROUP_NOM_C, &dlg_attr.refcyc_per_pte_group_nom_c); + REG_GET(NOM_PARAMETERS_6, + DST_Y_PER_META_ROW_NOM_C, &dlg_attr.dst_y_per_meta_row_nom_c); + REG_GET(NOM_PARAMETERS_7, + REFCYC_PER_META_CHUNK_NOM_C, &dlg_attr.refcyc_per_meta_chunk_nom_c); + REG_GET(VBLANK_PARAMETERS_3, + REFCYC_PER_META_CHUNK_VBLANK_L, &dlg_attr.refcyc_per_meta_chunk_vblank_l); + REG_GET(VBLANK_PARAMETERS_4, + REFCYC_PER_META_CHUNK_VBLANK_C, &dlg_attr.refcyc_per_meta_chunk_vblank_c); + + if (dlg_attr.refcyc_per_pte_group_vblank_l != dml_dlg_attr->refcyc_per_pte_group_vblank_l) + DC_LOG_DEBUG("DML Validation | VBLANK_PARAMETERS_1:REFCYC_PER_PTE_GROUP_VBLANK_L - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_pte_group_vblank_l, dlg_attr.refcyc_per_pte_group_vblank_l); + if (dlg_attr.dst_y_per_pte_row_nom_l != dml_dlg_attr->dst_y_per_pte_row_nom_l) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_0:DST_Y_PER_PTE_ROW_NOM_L - Expected: %u Actual: %u\n", + dml_dlg_attr->dst_y_per_pte_row_nom_l, dlg_attr.dst_y_per_pte_row_nom_l); + if (dlg_attr.refcyc_per_pte_group_nom_l != dml_dlg_attr->refcyc_per_pte_group_nom_l) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_1:REFCYC_PER_PTE_GROUP_NOM_L - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_pte_group_nom_l, dlg_attr.refcyc_per_pte_group_nom_l); + if (dlg_attr.dst_y_per_meta_row_nom_l != dml_dlg_attr->dst_y_per_meta_row_nom_l) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_4:DST_Y_PER_META_ROW_NOM_L - Expected: %u Actual: %u\n", + dml_dlg_attr->dst_y_per_meta_row_nom_l, dlg_attr.dst_y_per_meta_row_nom_l); + if (dlg_attr.refcyc_per_meta_chunk_nom_l != dml_dlg_attr->refcyc_per_meta_chunk_nom_l) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_5:REFCYC_PER_META_CHUNK_NOM_L - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_meta_chunk_nom_l, dlg_attr.refcyc_per_meta_chunk_nom_l); + if (dlg_attr.refcyc_per_line_delivery_l != dml_dlg_attr->refcyc_per_line_delivery_l) + DC_LOG_DEBUG("DML Validation | PER_LINE_DELIVERY:REFCYC_PER_LINE_DELIVERY_L - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_line_delivery_l, dlg_attr.refcyc_per_line_delivery_l); + if (dlg_attr.refcyc_per_line_delivery_c != dml_dlg_attr->refcyc_per_line_delivery_c) + DC_LOG_DEBUG("DML Validation | PER_LINE_DELIVERY:REFCYC_PER_LINE_DELIVERY_C - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_line_delivery_c, dlg_attr.refcyc_per_line_delivery_c); + if (dlg_attr.refcyc_per_pte_group_vblank_c != dml_dlg_attr->refcyc_per_pte_group_vblank_c) + DC_LOG_DEBUG("DML Validation | VBLANK_PARAMETERS_2:REFCYC_PER_PTE_GROUP_VBLANK_C - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_pte_group_vblank_c, dlg_attr.refcyc_per_pte_group_vblank_c); + if (dlg_attr.dst_y_per_pte_row_nom_c != dml_dlg_attr->dst_y_per_pte_row_nom_c) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_2:DST_Y_PER_PTE_ROW_NOM_C - Expected: %u Actual: %u\n", + dml_dlg_attr->dst_y_per_pte_row_nom_c, dlg_attr.dst_y_per_pte_row_nom_c); + if (dlg_attr.refcyc_per_pte_group_nom_c != dml_dlg_attr->refcyc_per_pte_group_nom_c) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_3:REFCYC_PER_PTE_GROUP_NOM_C - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_pte_group_nom_c, dlg_attr.refcyc_per_pte_group_nom_c); + if (dlg_attr.dst_y_per_meta_row_nom_c != dml_dlg_attr->dst_y_per_meta_row_nom_c) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_6:DST_Y_PER_META_ROW_NOM_C - Expected: %u Actual: %u\n", + dml_dlg_attr->dst_y_per_meta_row_nom_c, dlg_attr.dst_y_per_meta_row_nom_c); + if (dlg_attr.refcyc_per_meta_chunk_nom_c != dml_dlg_attr->refcyc_per_meta_chunk_nom_c) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_7:REFCYC_PER_META_CHUNK_NOM_C - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_meta_chunk_nom_c, dlg_attr.refcyc_per_meta_chunk_nom_c); + if (dlg_attr.refcyc_per_line_delivery_pre_l != dml_dlg_attr->refcyc_per_line_delivery_pre_l) + DC_LOG_DEBUG("DML Validation | PER_LINE_DELIVERY_PRE:REFCYC_PER_LINE_DELIVERY_PRE_L - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_line_delivery_pre_l, dlg_attr.refcyc_per_line_delivery_pre_l); + if (dlg_attr.refcyc_per_line_delivery_pre_c != dml_dlg_attr->refcyc_per_line_delivery_pre_c) + DC_LOG_DEBUG("DML Validation | PER_LINE_DELIVERY_PRE:REFCYC_PER_LINE_DELIVERY_PRE_C - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_line_delivery_pre_c, dlg_attr.refcyc_per_line_delivery_pre_c); + if (dlg_attr.refcyc_per_meta_chunk_vblank_l != dml_dlg_attr->refcyc_per_meta_chunk_vblank_l) + DC_LOG_DEBUG("DML Validation | VBLANK_PARAMETERS_3:REFCYC_PER_META_CHUNK_VBLANK_L - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_meta_chunk_vblank_l, dlg_attr.refcyc_per_meta_chunk_vblank_l); + if (dlg_attr.refcyc_per_meta_chunk_vblank_c != dml_dlg_attr->refcyc_per_meta_chunk_vblank_c) + DC_LOG_DEBUG("DML Validation | VBLANK_PARAMETERS_4:REFCYC_PER_META_CHUNK_VBLANK_C - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_meta_chunk_vblank_c, dlg_attr.refcyc_per_meta_chunk_vblank_c); + + /* TTU - per hubp */ + REG_GET_2(DCN_TTU_QOS_WM, + QoS_LEVEL_LOW_WM, &ttu_attr.qos_level_low_wm, + QoS_LEVEL_HIGH_WM, &ttu_attr.qos_level_high_wm); + + if (ttu_attr.qos_level_low_wm != dml_ttu_attr->qos_level_low_wm) + DC_LOG_DEBUG("DML Validation | DCN_TTU_QOS_WM:QoS_LEVEL_LOW_WM - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_level_low_wm, ttu_attr.qos_level_low_wm); + if (ttu_attr.qos_level_high_wm != dml_ttu_attr->qos_level_high_wm) + DC_LOG_DEBUG("DML Validation | DCN_TTU_QOS_WM:QoS_LEVEL_HIGH_WM - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_level_high_wm, ttu_attr.qos_level_high_wm); + + /* TTU - per luma/chroma */ + /* Assumed surf0 is luma and 1 is chroma */ + REG_GET_3(DCN_SURF0_TTU_CNTL0, + REFCYC_PER_REQ_DELIVERY, &ttu_attr.refcyc_per_req_delivery_l, + QoS_LEVEL_FIXED, &ttu_attr.qos_level_fixed_l, + QoS_RAMP_DISABLE, &ttu_attr.qos_ramp_disable_l); + REG_GET_3(DCN_SURF1_TTU_CNTL0, + REFCYC_PER_REQ_DELIVERY, &ttu_attr.refcyc_per_req_delivery_c, + QoS_LEVEL_FIXED, &ttu_attr.qos_level_fixed_c, + QoS_RAMP_DISABLE, &ttu_attr.qos_ramp_disable_c); + REG_GET_3(DCN_CUR0_TTU_CNTL0, + REFCYC_PER_REQ_DELIVERY, &ttu_attr.refcyc_per_req_delivery_cur0, + QoS_LEVEL_FIXED, &ttu_attr.qos_level_fixed_cur0, + QoS_RAMP_DISABLE, &ttu_attr.qos_ramp_disable_cur0); + REG_GET(FLIP_PARAMETERS_1, + REFCYC_PER_PTE_GROUP_FLIP_L, &dlg_attr.refcyc_per_pte_group_flip_l); + REG_GET(DCN_CUR0_TTU_CNTL1, + REFCYC_PER_REQ_DELIVERY_PRE, &ttu_attr.refcyc_per_req_delivery_pre_cur0); + REG_GET(DCN_CUR1_TTU_CNTL1, + REFCYC_PER_REQ_DELIVERY_PRE, &ttu_attr.refcyc_per_req_delivery_pre_cur1); + REG_GET(DCN_SURF0_TTU_CNTL1, + REFCYC_PER_REQ_DELIVERY_PRE, &ttu_attr.refcyc_per_req_delivery_pre_l); + REG_GET(DCN_SURF1_TTU_CNTL1, + REFCYC_PER_REQ_DELIVERY_PRE, &ttu_attr.refcyc_per_req_delivery_pre_c); + + if (ttu_attr.refcyc_per_req_delivery_l != dml_ttu_attr->refcyc_per_req_delivery_l) + DC_LOG_DEBUG("DML Validation | DCN_SURF0_TTU_CNTL0:REFCYC_PER_REQ_DELIVERY - Expected: %u Actual: %u\n", + dml_ttu_attr->refcyc_per_req_delivery_l, ttu_attr.refcyc_per_req_delivery_l); + if (ttu_attr.qos_level_fixed_l != dml_ttu_attr->qos_level_fixed_l) + DC_LOG_DEBUG("DML Validation | DCN_SURF0_TTU_CNTL0:QoS_LEVEL_FIXED - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_level_fixed_l, ttu_attr.qos_level_fixed_l); + if (ttu_attr.qos_ramp_disable_l != dml_ttu_attr->qos_ramp_disable_l) + DC_LOG_DEBUG("DML Validation | DCN_SURF0_TTU_CNTL0:QoS_RAMP_DISABLE - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_ramp_disable_l, ttu_attr.qos_ramp_disable_l); + if (ttu_attr.refcyc_per_req_delivery_c != dml_ttu_attr->refcyc_per_req_delivery_c) + DC_LOG_DEBUG("DML Validation | DCN_SURF1_TTU_CNTL0:REFCYC_PER_REQ_DELIVERY - Expected: %u Actual: %u\n", + dml_ttu_attr->refcyc_per_req_delivery_c, ttu_attr.refcyc_per_req_delivery_c); + if (ttu_attr.qos_level_fixed_c != dml_ttu_attr->qos_level_fixed_c) + DC_LOG_DEBUG("DML Validation | DCN_SURF1_TTU_CNTL0:QoS_LEVEL_FIXED - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_level_fixed_c, ttu_attr.qos_level_fixed_c); + if (ttu_attr.qos_ramp_disable_c != dml_ttu_attr->qos_ramp_disable_c) + DC_LOG_DEBUG("DML Validation | DCN_SURF1_TTU_CNTL0:QoS_RAMP_DISABLE - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_ramp_disable_c, ttu_attr.qos_ramp_disable_c); + if (ttu_attr.refcyc_per_req_delivery_cur0 != dml_ttu_attr->refcyc_per_req_delivery_cur0) + DC_LOG_DEBUG("DML Validation | DCN_CUR0_TTU_CNTL0:REFCYC_PER_REQ_DELIVERY - Expected: %u Actual: %u\n", + dml_ttu_attr->refcyc_per_req_delivery_cur0, ttu_attr.refcyc_per_req_delivery_cur0); + if (ttu_attr.qos_level_fixed_cur0 != dml_ttu_attr->qos_level_fixed_cur0) + DC_LOG_DEBUG("DML Validation | DCN_CUR0_TTU_CNTL0:QoS_LEVEL_FIXED - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_level_fixed_cur0, ttu_attr.qos_level_fixed_cur0); + if (ttu_attr.qos_ramp_disable_cur0 != dml_ttu_attr->qos_ramp_disable_cur0) + DC_LOG_DEBUG("DML Validation | DCN_CUR0_TTU_CNTL0:QoS_RAMP_DISABLE - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_ramp_disable_cur0, ttu_attr.qos_ramp_disable_cur0); + if (dlg_attr.refcyc_per_pte_group_flip_l != dml_dlg_attr->refcyc_per_pte_group_flip_l) + DC_LOG_DEBUG("DML Validation | FLIP_PARAMETERS_1:REFCYC_PER_PTE_GROUP_FLIP_L - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_pte_group_flip_l, dlg_attr.refcyc_per_pte_group_flip_l); + if (ttu_attr.refcyc_per_req_delivery_pre_cur0 != dml_ttu_attr->refcyc_per_req_delivery_pre_cur0) + DC_LOG_DEBUG("DML Validation | DCN_CUR0_TTU_CNTL1:REFCYC_PER_REQ_DELIVERY_PRE - Expected: %u Actual: %u\n", + dml_ttu_attr->refcyc_per_req_delivery_pre_cur0, ttu_attr.refcyc_per_req_delivery_pre_cur0); + if (ttu_attr.refcyc_per_req_delivery_pre_cur1 != dml_ttu_attr->refcyc_per_req_delivery_pre_cur1) + DC_LOG_DEBUG("DML Validation | DCN_CUR1_TTU_CNTL1:REFCYC_PER_REQ_DELIVERY_PRE - Expected: %u Actual: %u\n", + dml_ttu_attr->refcyc_per_req_delivery_pre_cur1, ttu_attr.refcyc_per_req_delivery_pre_cur1); + if (ttu_attr.refcyc_per_req_delivery_pre_l != dml_ttu_attr->refcyc_per_req_delivery_pre_l) + DC_LOG_DEBUG("DML Validation | DCN_SURF0_TTU_CNTL1:REFCYC_PER_REQ_DELIVERY_PRE - Expected: %u Actual: %u\n", + dml_ttu_attr->refcyc_per_req_delivery_pre_l, ttu_attr.refcyc_per_req_delivery_pre_l); + if (ttu_attr.refcyc_per_req_delivery_pre_c != dml_ttu_attr->refcyc_per_req_delivery_pre_c) + DC_LOG_DEBUG("DML Validation | DCN_SURF1_TTU_CNTL1:REFCYC_PER_REQ_DELIVERY_PRE - Expected: %u Actual: %u\n", + dml_ttu_attr->refcyc_per_req_delivery_pre_c, ttu_attr.refcyc_per_req_delivery_pre_c); +} + static struct hubp_funcs dcn20_hubp_funcs = { .hubp_enable_tripleBuffer = hubp2_enable_triplebuffer, .hubp_is_triplebuffer_enabled = hubp2_is_triplebuffer_enabled, @@ -1266,6 +1577,7 @@ static struct hubp_funcs dcn20_hubp_funcs = { .hubp_clear_underflow = hubp2_clear_underflow, .hubp_set_flip_control_surface_gsl = hubp2_set_flip_control_surface_gsl, .hubp_init = hubp1_init, + .validate_dml_output = hubp2_validate_dml_output, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h index d5c8615af45ef2a55df6ecfbd3d1e3d4e2f37537..8c04a3606a5423e4335ba535b3e0df7b6516d580 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h @@ -148,7 +148,6 @@ uint32_t VMID_SETTINGS_0 -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) #define DCN21_HUBP_REG_COMMON_VARIABLE_LIST \ DCN2_HUBP_REG_COMMON_VARIABLE_LIST; \ uint32_t FLIP_PARAMETERS_3;\ @@ -157,7 +156,6 @@ uint32_t FLIP_PARAMETERS_6;\ uint32_t VBLANK_PARAMETERS_5;\ uint32_t VBLANK_PARAMETERS_6 -#endif #define DCN2_HUBP_REG_FIELD_VARIABLE_LIST(type) \ DCN_HUBP_REG_FIELD_BASE_LIST(type); \ @@ -184,7 +182,6 @@ type SURFACE_TRIPLE_BUFFER_ENABLE;\ type VMID -#ifdef CONFIG_DRM_AMD_DC_DCN2_1 #define DCN21_HUBP_REG_FIELD_VARIABLE_LIST(type) \ DCN2_HUBP_REG_FIELD_VARIABLE_LIST(type);\ type REFCYC_PER_VM_GROUP_FLIP;\ @@ -194,31 +191,18 @@ type REFCYC_PER_PTE_GROUP_FLIP_C; \ type REFCYC_PER_META_CHUNK_FLIP_C; \ type VM_GROUP_SIZE -#endif struct dcn_hubp2_registers { -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) DCN21_HUBP_REG_COMMON_VARIABLE_LIST; -#else - DCN2_HUBP_REG_COMMON_VARIABLE_LIST; -#endif }; struct dcn_hubp2_shift { -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) DCN21_HUBP_REG_FIELD_VARIABLE_LIST(uint8_t); -#else - DCN2_HUBP_REG_FIELD_VARIABLE_LIST(uint8_t); -#endif }; struct dcn_hubp2_mask { -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) DCN21_HUBP_REG_FIELD_VARIABLE_LIST(uint32_t); -#else - DCN2_HUBP_REG_FIELD_VARIABLE_LIST(uint32_t); -#endif }; struct dcn20_hubp { diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index ac8c18fadefce30d922fd7d10c710290285d4a44..32878a65bdd7cbb1c1ddc1b7ef97ce4f416434cf 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -25,17 +25,15 @@ #include #include "dm_services.h" +#include "basics/dc_common.h" #include "dm_helpers.h" #include "core_types.h" #include "resource.h" -#include "dcn20/dcn20_resource.h" -#include "dce110/dce110_hw_sequencer.h" -#include "dcn10/dcn10_hw_sequencer.h" +#include "dcn20_resource.h" #include "dcn20_hwseq.h" #include "dce/dce_hwseq.h" -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT -#include "dcn20/dcn20_dsc.h" -#endif +#include "dcn20_dsc.h" +#include "dcn20_optc.h" #include "abm.h" #include "clk_mgr.h" #include "dmcu.h" @@ -45,10 +43,9 @@ #include "ipp.h" #include "mpc.h" #include "mcif_wb.h" +#include "dchubbub.h" #include "reg_helper.h" #include "dcn10/dcn10_cm_common.h" -#include "dcn10/dcn10_hubbub.h" -#include "dcn10/dcn10_optc.h" #include "dc_link_dp.h" #include "vm_helper.h" #include "dccg.h" @@ -64,7 +61,125 @@ #define FN(reg_name, field_name) \ hws->shifts->field_name, hws->masks->field_name -static void dcn20_enable_power_gating_plane( +static int find_free_gsl_group(const struct dc *dc) +{ + if (dc->res_pool->gsl_groups.gsl_0 == 0) + return 1; + if (dc->res_pool->gsl_groups.gsl_1 == 0) + return 2; + if (dc->res_pool->gsl_groups.gsl_2 == 0) + return 3; + + return 0; +} + +/* NOTE: This is not a generic setup_gsl function (hence the suffix as_lock) + * This is only used to lock pipes in pipe splitting case with immediate flip + * Ordinary MPC/OTG locks suppress VUPDATE which doesn't help with immediate, + * so we get tearing with freesync since we cannot flip multiple pipes + * atomically. + * We use GSL for this: + * - immediate flip: find first available GSL group if not already assigned + * program gsl with that group, set current OTG as master + * and always us 0x4 = AND of flip_ready from all pipes + * - vsync flip: disable GSL if used + * + * Groups in stream_res are stored as +1 from HW registers, i.e. + * gsl_0 <=> pipe_ctx->stream_res.gsl_group == 1 + * Using a magic value like -1 would require tracking all inits/resets + */ +static void dcn20_setup_gsl_group_as_lock( + const struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool enable) +{ + struct gsl_params gsl; + int group_idx; + + memset(&gsl, 0, sizeof(struct gsl_params)); + + if (enable) { + /* return if group already assigned since GSL was set up + * for vsync flip, we would unassign so it can't be "left over" + */ + if (pipe_ctx->stream_res.gsl_group > 0) + return; + + group_idx = find_free_gsl_group(dc); + ASSERT(group_idx != 0); + pipe_ctx->stream_res.gsl_group = group_idx; + + /* set gsl group reg field and mark resource used */ + switch (group_idx) { + case 1: + gsl.gsl0_en = 1; + dc->res_pool->gsl_groups.gsl_0 = 1; + break; + case 2: + gsl.gsl1_en = 1; + dc->res_pool->gsl_groups.gsl_1 = 1; + break; + case 3: + gsl.gsl2_en = 1; + dc->res_pool->gsl_groups.gsl_2 = 1; + break; + default: + BREAK_TO_DEBUGGER(); + return; // invalid case + } + gsl.gsl_master_en = 1; + } else { + group_idx = pipe_ctx->stream_res.gsl_group; + if (group_idx == 0) + return; // if not in use, just return + + pipe_ctx->stream_res.gsl_group = 0; + + /* unset gsl group reg field and mark resource free */ + switch (group_idx) { + case 1: + gsl.gsl0_en = 0; + dc->res_pool->gsl_groups.gsl_0 = 0; + break; + case 2: + gsl.gsl1_en = 0; + dc->res_pool->gsl_groups.gsl_1 = 0; + break; + case 3: + gsl.gsl2_en = 0; + dc->res_pool->gsl_groups.gsl_2 = 0; + break; + default: + BREAK_TO_DEBUGGER(); + return; + } + gsl.gsl_master_en = 0; + } + + /* at this point we want to program whether it's to enable or disable */ + if (pipe_ctx->stream_res.tg->funcs->set_gsl != NULL && + pipe_ctx->stream_res.tg->funcs->set_gsl_source_select != NULL) { + pipe_ctx->stream_res.tg->funcs->set_gsl( + pipe_ctx->stream_res.tg, + &gsl); + + pipe_ctx->stream_res.tg->funcs->set_gsl_source_select( + pipe_ctx->stream_res.tg, group_idx, enable ? 4 : 0); + } else + BREAK_TO_DEBUGGER(); +} + +void dcn20_set_flip_control_gsl( + struct pipe_ctx *pipe_ctx, + bool flip_immediate) +{ + if (pipe_ctx && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl) + pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl( + pipe_ctx->plane_res.hubp, flip_immediate); + +} + +void dcn20_enable_power_gating_plane( struct dce_hwseq *hws, bool enable) { @@ -128,44 +243,6 @@ void dcn20_dccg_init(struct dce_hwseq *hws) /* This value is dependent on the hardware pipeline delay so set once per SOC */ REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0x801003c); } -void dcn20_display_init(struct dc *dc) -{ - struct dce_hwseq *hws = dc->hwseq; - - /* RBBMIF - * disable RBBMIF timeout detection for all clients - * Ensure RBBMIF does not drop register accesses due to the per-client timeout - */ - REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF); - REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF); - - /* DCCG */ - dcn20_dccg_init(hws); - - REG_UPDATE(DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, 0); - - /* DCHUB/MMHUBBUB - * set global timer refclk divider - * 100Mhz refclk -> 2 - * 27Mhz refclk -> 1 - * 48Mhz refclk -> 1 - */ - REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2); - REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); - REG_WRITE(REFCLK_CNTL, 0); - - /* OPTC - * OTG_CONTROL.OTG_DISABLE_POINT_CNTL = 0x3; will be set during optc2_enable_crtc - */ - - /* AZ - * default value is 0x64 for 100Mhz ref clock, if the ref clock is 100Mhz, no need to program this regiser, - * if not, it should be programmed according to the ref clock - */ - REG_UPDATE(AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, 0x64); - /* Enable controller clock gating */ - REG_WRITE(AZALIA_CONTROLLER_CLOCK_GATING, 0x1); -} void dcn20_disable_vga( struct dce_hwseq *hws) @@ -178,15 +255,15 @@ void dcn20_disable_vga( REG_WRITE(D6VGA_CONTROL, 0); } -void dcn20_program_tripleBuffer( +void dcn20_program_triple_buffer( const struct dc *dc, struct pipe_ctx *pipe_ctx, - bool enableTripleBuffer) + bool enable_triple_buffer) { if (pipe_ctx->plane_res.hubp && pipe_ctx->plane_res.hubp->funcs) { pipe_ctx->plane_res.hubp->funcs->hubp_enable_tripleBuffer( pipe_ctx->plane_res.hubp, - enableTripleBuffer); + enable_triple_buffer); } } @@ -195,6 +272,7 @@ void dcn20_init_blank( struct dc *dc, struct timing_generator *tg) { + struct dce_hwseq *hws = dc->hwseq; enum dc_color_space color_space; struct tg_color black_color = {0}; struct output_pixel_processor *opp = NULL; @@ -225,6 +303,7 @@ void dcn20_init_blank( opp->funcs->opp_set_disp_pattern_generator( opp, CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, + CONTROLLER_DP_COLOR_SPACE_UDEFINED, COLOR_DEPTH_UNDEFINED, &black_color, otg_active_width, @@ -234,17 +313,17 @@ void dcn20_init_blank( bottom_opp->funcs->opp_set_disp_pattern_generator( bottom_opp, CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, + CONTROLLER_DP_COLOR_SPACE_UDEFINED, COLOR_DEPTH_UNDEFINED, &black_color, otg_active_width, otg_active_height); } - dcn20_hwss_wait_for_blank_complete(opp); + hws->funcs.wait_for_blank_complete(opp); } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT -static void dcn20_dsc_pg_control( +void dcn20_dsc_pg_control( struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on) @@ -320,9 +399,8 @@ static void dcn20_dsc_pg_control( if (org_ip_request_cntl == 0) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); } -#endif -static void dcn20_dpp_pg_control( +void dcn20_dpp_pg_control( struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on) @@ -396,7 +474,7 @@ static void dcn20_dpp_pg_control( } -static void dcn20_hubp_pg_control( +void dcn20_hubp_pg_control( struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) @@ -473,8 +551,9 @@ static void dcn20_hubp_pg_control( /* disable HW used by plane. * note: cannot disable until disconnect is complete */ -static void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) { + struct dce_hwseq *hws = dc->hwseq; struct hubp *hubp = pipe_ctx->plane_res.hubp; struct dpp *dpp = pipe_ctx->plane_res.dpp; @@ -495,7 +574,7 @@ static void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) hubp->power_gated = true; dc->optimized_required = false; /* We're powering off, no need to optimize */ - dc->hwss.plane_atomic_power_down(dc, + hws->funcs.plane_atomic_power_down(dc, pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp); @@ -526,6 +605,7 @@ enum dc_status dcn20_enable_stream_timing( struct dc_state *context, struct dc *dc) { + struct dce_hwseq *hws = dc->hwseq; struct dc_stream_state *stream = pipe_ctx->stream; struct drr_params params = {0}; unsigned int event_triggers = 0; @@ -585,7 +665,7 @@ enum dc_status dcn20_enable_stream_timing( pipe_ctx->stream_res.opp, true); - dc->hwss.blank_pixel_data(dc, pipe_ctx, true); + hws->funcs.blank_pixel_data(dc, pipe_ctx, true); /* VTG is within DCHUB command block. DCFCLK is always on */ if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) { @@ -593,7 +673,7 @@ enum dc_status dcn20_enable_stream_timing( return DC_ERROR_UNEXPECTED; } - dcn20_hwss_wait_for_blank_complete(pipe_ctx->stream_res.opp); + hws->funcs.wait_for_blank_complete(pipe_ctx->stream_res.opp); params.vertical_total_min = stream->adjust.v_total_min; params.vertical_total_max = stream->adjust.v_total_max; @@ -649,7 +729,7 @@ void dcn20_program_output_csc(struct dc *dc, } } -bool dcn20_set_output_transfer_func(struct pipe_ctx *pipe_ctx, +bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream) { int mpcc_id = pipe_ctx->plane_res.hubp->inst; @@ -736,20 +816,14 @@ bool dcn20_set_shaper_3dlut( else result = dpp_base->funcs->dpp_program_3dlut(dpp_base, NULL); - if (plane_state->lut3d_func && - plane_state->lut3d_func->state.bits.initialized == 1 && - plane_state->lut3d_func->hdr_multiplier != 0) - dpp_base->funcs->dpp_set_hdr_multiplier(dpp_base, - plane_state->lut3d_func->hdr_multiplier); - else - dpp_base->funcs->dpp_set_hdr_multiplier(dpp_base, 0x1f000); - return result; } -bool dcn20_set_input_transfer_func(struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state) +bool dcn20_set_input_transfer_func(struct dc *dc, + struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state) { + struct dce_hwseq *hws = dc->hwseq; struct dpp *dpp_base = pipe_ctx->plane_res.dpp; const struct dc_transfer_func *tf = NULL; bool result = true; @@ -758,8 +832,8 @@ bool dcn20_set_input_transfer_func(struct pipe_ctx *pipe_ctx, if (dpp_base == NULL || plane_state == NULL) return false; - dcn20_set_shaper_3dlut(pipe_ctx, plane_state); - dcn20_set_blend_lut(pipe_ctx, plane_state); + hws->funcs.set_shaper_3dlut(pipe_ctx, plane_state); + hws->funcs.set_blend_lut(pipe_ctx, plane_state); if (plane_state->in_transfer_func) tf = plane_state->in_transfer_func; @@ -804,6 +878,11 @@ bool dcn20_set_input_transfer_func(struct pipe_ctx *pipe_ctx, IPP_DEGAMMA_MODE_BYPASS); break; case TRANSFER_FUNCTION_PQ: + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL); + cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params); + dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params); + result = true; + break; default: result = false; break; @@ -824,7 +903,7 @@ bool dcn20_set_input_transfer_func(struct pipe_ctx *pipe_ctx, return result; } -static void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) +void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) { struct pipe_ctx *odm_pipe; int opp_cnt = 1; @@ -855,6 +934,7 @@ void dcn20_blank_pixel_data( struct dc_stream_state *stream = pipe_ctx->stream; enum dc_color_space color_space = stream->output_color_space; enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR; + enum controller_dp_color_space test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED; struct pipe_ctx *odm_pipe; int odm_cnt = 1; @@ -873,8 +953,10 @@ void dcn20_blank_pixel_data( if (stream_res->abm) stream_res->abm->funcs->set_abm_immediate_disable(stream_res->abm); - if (dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) + if (dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) { test_pattern = CONTROLLER_DP_TEST_PATTERN_COLORSQUARES; + test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_RGB; + } } else { test_pattern = CONTROLLER_DP_TEST_PATTERN_VIDEOMODE; } @@ -882,6 +964,7 @@ void dcn20_blank_pixel_data( stream_res->opp->funcs->opp_set_disp_pattern_generator( stream_res->opp, test_pattern, + test_pattern_color_space, stream->timing.display_color_depth, &black_color, width, @@ -892,6 +975,7 @@ void dcn20_blank_pixel_data( odm_pipe->stream_res.opp, dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE && blank ? CONTROLLER_DP_TEST_PATTERN_COLORRAMP : test_pattern, + test_pattern_color_space, stream->timing.display_color_depth, &black_color, width, @@ -1217,6 +1301,7 @@ static void dcn20_update_dchubp_dpp( struct pipe_ctx *pipe_ctx, struct dc_state *context) { + struct dce_hwseq *hws = dc->hwseq; struct hubp *hubp = pipe_ctx->plane_res.hubp; struct dpp *dpp = pipe_ctx->plane_res.dpp; struct dc_plane_state *plane_state = pipe_ctx->plane_state; @@ -1261,7 +1346,7 @@ static void dcn20_update_dchubp_dpp( if (dpp->funcs->dpp_program_bias_and_scale) { //TODO :for CNVC set scale and bias registers if necessary - dcn10_build_prescale_params(&bns_params, plane_state); + build_prescale_params(&bns_params, plane_state); dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); } } @@ -1269,19 +1354,19 @@ static void dcn20_update_dchubp_dpp( if (pipe_ctx->update_flags.bits.mpcc || plane_state->update_flags.bits.global_alpha_change || plane_state->update_flags.bits.per_pixel_alpha_change) { - /* Need mpcc to be idle if changing opp */ - if (pipe_ctx->update_flags.bits.opp_changed) { - struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx]; - int mpcc_inst; - - for (mpcc_inst = 0; mpcc_inst < MAX_PIPES; mpcc_inst++) { - if (!old_pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) - continue; + // MPCC inst is equal to pipe index in practice + int mpcc_inst = pipe_ctx->pipe_idx; + int opp_inst; + int opp_count = dc->res_pool->res_cap->num_opp; + + for (opp_inst = 0; opp_inst < opp_count; opp_inst++) { + if (dc->res_pool->opps[opp_inst]->mpcc_disconnect_pending[mpcc_inst]) { dc->res_pool->mpc->funcs->wait_for_idle(dc->res_pool->mpc, mpcc_inst); - old_pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false; + dc->res_pool->opps[opp_inst]->mpcc_disconnect_pending[mpcc_inst] = false; + break; } } - dc->hwss.update_mpcc(dc, pipe_ctx); + hws->funcs.update_mpcc(dc, pipe_ctx); } if (pipe_ctx->update_flags.bits.scaler || @@ -1302,7 +1387,8 @@ static void dcn20_update_dchubp_dpp( hubp->funcs->mem_program_viewport( hubp, &pipe_ctx->plane_res.scl_data.viewport, - &pipe_ctx->plane_res.scl_data.viewport_c); + &pipe_ctx->plane_res.scl_data.viewport_c, + plane_state->rotation); /* Any updates are handled in dc interface, just need to apply existing for plane enable */ if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed) @@ -1356,7 +1442,7 @@ static void dcn20_update_dchubp_dpp( } if (pipe_ctx->update_flags.bits.enable || plane_state->update_flags.bits.addr_update) - dc->hwss.update_plane_addr(dc, pipe_ctx); + hws->funcs.update_plane_addr(dc, pipe_ctx); if (pipe_ctx->update_flags.bits.enable) hubp->funcs->set_blank(hubp, false); @@ -1368,10 +1454,11 @@ static void dcn20_program_pipe( struct pipe_ctx *pipe_ctx, struct dc_state *context) { + struct dce_hwseq *hws = dc->hwseq; /* Only need to unblank on top pipe */ if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->stream->update_flags.bits.abm_level) && !pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe) - dc->hwss.blank_pixel_data(dc, pipe_ctx, !pipe_ctx->plane_state->visible); + hws->funcs.blank_pixel_data(dc, pipe_ctx, !pipe_ctx->plane_state->visible); if (pipe_ctx->update_flags.bits.global_sync) { pipe_ctx->stream_res.tg->funcs->program_global_sync( @@ -1384,12 +1471,12 @@ static void dcn20_program_pipe( pipe_ctx->stream_res.tg->funcs->set_vtg_params( pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); - if (dc->hwss.setup_vupdate_interrupt) - dc->hwss.setup_vupdate_interrupt(pipe_ctx); + if (hws->funcs.setup_vupdate_interrupt) + hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); } if (pipe_ctx->update_flags.bits.odm) - dc->hwss.update_odm(dc, context, pipe_ctx); + hws->funcs.update_odm(dc, context, pipe_ctx); if (pipe_ctx->update_flags.bits.enable) dcn20_enable_plane(dc, pipe_ctx, context); @@ -1398,20 +1485,20 @@ static void dcn20_program_pipe( dcn20_update_dchubp_dpp(dc, pipe_ctx, context); if (pipe_ctx->update_flags.bits.enable - || pipe_ctx->plane_state->update_flags.bits.sdr_white_level) - set_hdr_multiplier(pipe_ctx); + || pipe_ctx->plane_state->update_flags.bits.hdr_mult) + hws->funcs.set_hdr_multiplier(pipe_ctx); if (pipe_ctx->update_flags.bits.enable || pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || pipe_ctx->plane_state->update_flags.bits.gamma_change) - dc->hwss.set_input_transfer_func(pipe_ctx, pipe_ctx->plane_state); + hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); /* dcn10_translate_regamma_to_hw_format takes 750us to finish * only do gamma programming for powering on, internal memcmp to avoid * updating on slave planes */ if (pipe_ctx->update_flags.bits.enable || pipe_ctx->stream->update_flags.bits.out_tf) - dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); + hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); /* If the pipe has been enabled or has a different opp, we * should reprogram the fmt. This deals with cases where @@ -1445,12 +1532,13 @@ static bool does_pipe_need_lock(struct pipe_ctx *pipe) return false; } -static void dcn20_program_front_end_for_ctx( +void dcn20_program_front_end_for_ctx( struct dc *dc, struct dc_state *context) { const unsigned int TIMEOUT_FOR_PIPE_ENABLE_MS = 100; int i; + struct dce_hwseq *hws = dc->hwseq; bool pipe_locked[MAX_PIPES] = {false}; DC_LOGGER_INIT(dc->ctx->logger); @@ -1482,13 +1570,13 @@ static void dcn20_program_front_end_for_ctx( && !context->res_ctx.pipe_ctx[i].top_pipe && !context->res_ctx.pipe_ctx[i].prev_odm_pipe && context->res_ctx.pipe_ctx[i].stream) - dc->hwss.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true); + hws->funcs.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true); /* Disconnect mpcc */ for (i = 0; i < dc->res_pool->pipe_count; i++) if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable || context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) { - dc->hwss.plane_atomic_disconnect(dc, &dc->current_state->res_ctx.pipe_ctx[i]); + 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); } @@ -1508,8 +1596,8 @@ static void dcn20_program_front_end_for_ctx( pipe = &context->res_ctx.pipe_ctx[i]; if (!pipe->prev_odm_pipe && pipe->stream->num_wb_info > 0 && (pipe->update_flags.raw || pipe->plane_state->update_flags.raw || pipe->stream->update_flags.raw) - && dc->hwss.program_all_writeback_pipes_in_tree) - dc->hwss.program_all_writeback_pipes_in_tree(dc, pipe->stream, context); + && hws->funcs.program_all_writeback_pipes_in_tree) + hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context); } } @@ -1594,6 +1682,7 @@ bool dcn20_update_bandwidth( struct dc_state *context) { int i; + struct dce_hwseq *hws = dc->hwseq; /* recalculate DML parameters */ if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) @@ -1623,10 +1712,10 @@ bool dcn20_update_bandwidth( pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); if (pipe_ctx->prev_odm_pipe == NULL) - dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); + hws->funcs.blank_pixel_data(dc, pipe_ctx, blank); - if (dc->hwss.setup_vupdate_interrupt) - dc->hwss.setup_vupdate_interrupt(pipe_ctx); + if (hws->funcs.setup_vupdate_interrupt) + hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); } pipe_ctx->plane_res.hubp->funcs->hubp_setup( @@ -1640,7 +1729,7 @@ bool dcn20_update_bandwidth( return true; } -static void dcn20_enable_writeback( +void dcn20_enable_writeback( struct dc *dc, const struct dc_stream_status *stream_status, struct dc_writeback_info *wb_info, @@ -1684,7 +1773,7 @@ void dcn20_disable_writeback( mcif_wb->funcs->disable_mcif(mcif_wb); } -bool dcn20_hwss_wait_for_blank_complete( +bool dcn20_wait_for_blank_complete( struct output_pixel_processor *opp) { int counter; @@ -1713,9 +1802,8 @@ bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx) return hubp->funcs->dmdata_status_done(hubp); } -static void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx) { -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT struct dce_hwseq *hws = dc->hwseq; if (pipe_ctx->stream_res.dsc) { @@ -1727,12 +1815,10 @@ static void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx odm_pipe = odm_pipe->next_odm_pipe; } } -#endif } -static void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx) { -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT struct dce_hwseq *hws = dc->hwseq; if (pipe_ctx->stream_res.dsc) { @@ -1744,7 +1830,6 @@ static void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx) odm_pipe = odm_pipe->next_odm_pipe; } } -#endif } void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx) @@ -1767,12 +1852,7 @@ void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx) hubp->funcs->dmdata_set_attributes(hubp, &attr); } -void dcn20_disable_stream(struct pipe_ctx *pipe_ctx) -{ - dce110_disable_stream(pipe_ctx); -} - -static void dcn20_init_vm_ctx( +void dcn20_init_vm_ctx( struct dce_hwseq *hws, struct dc *dc, struct dc_virtual_addr_space_config *va_config, @@ -1794,7 +1874,7 @@ static void dcn20_init_vm_ctx( dc->res_pool->hubbub->funcs->init_vm_ctx(dc->res_pool->hubbub, &config, vmid); } -static int dcn20_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) +int dcn20_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) { struct dcn_hubbub_phys_addr_config config; @@ -1838,8 +1918,7 @@ static bool patch_address_for_sbs_tb_stereo( return false; } - -static void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) { bool addr_patched = false; PHYSICAL_ADDRESS_LOC addr; @@ -1873,6 +1952,7 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, struct encoder_unblank_param params = { { 0 } }; struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->link; + struct dce_hwseq *hws = link->dc->hwseq; struct pipe_ctx *odm_pipe; params.opp_cnt = 1; @@ -1885,7 +1965,7 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, params.link_settings.link_rate = link_settings->link_rate; if (dc_is_dp_signal(pipe_ctx->stream->signal)) { - if (optc1_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1) + if (optc2_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1) params.timing.pix_clk_100hz /= 2; pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine( pipe_ctx->stream_res.stream_enc, params.opp_cnt > 1); @@ -1893,14 +1973,14 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, } if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { - link->dc->hwss.edp_backlight_control(link, true); + hws->funcs.edp_backlight_control(link, true); } } -void dcn20_setup_vupdate_interrupt(struct pipe_ctx *pipe_ctx) +void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx) { struct timing_generator *tg = pipe_ctx->stream_res.tg; - int start_line = get_vupdate_offset_from_vsync(pipe_ctx); + int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); if (start_line < 0) start_line = 0; @@ -1943,11 +2023,9 @@ static void dcn20_reset_back_end_for_pipe( } } } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT else if (pipe_ctx->stream_res.dsc) { dp_set_dsc_enable(pipe_ctx, false); } -#endif /* by upper caller loop, parent pipe: pipe0, will be reset last. * back end share by all pipes and will be disable only when disable @@ -1978,11 +2056,12 @@ static void dcn20_reset_back_end_for_pipe( pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); } -static void dcn20_reset_hw_ctx_wrap( +void dcn20_reset_hw_ctx_wrap( struct dc *dc, struct dc_state *context) { int i; + struct dce_hwseq *hws = dc->hwseq; /* Reset Back End*/ for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { @@ -2001,8 +2080,8 @@ static void dcn20_reset_hw_ctx_wrap( struct clock_source *old_clk = pipe_ctx_old->clock_source; dcn20_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); - if (dc->hwss.enable_stream_gating) - dc->hwss.enable_stream_gating(dc, pipe_ctx); + if (hws->funcs.enable_stream_gating) + hws->funcs.enable_stream_gating(dc, pipe_ctx); if (old_clk) old_clk->funcs->cs_power_down(old_clk); } @@ -2031,8 +2110,9 @@ void dcn20_get_mpctree_visual_confirm_color( *color = pipe_colors[top_pipe->pipe_idx]; } -static void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) { + struct dce_hwseq *hws = dc->hwseq; struct hubp *hubp = pipe_ctx->plane_res.hubp; struct mpcc_blnd_cfg blnd_cfg = { {0} }; bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha; @@ -2043,10 +2123,10 @@ static void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) // input to MPCC is always RGB, by default leave black_color at 0 if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) { - dcn10_get_hdr_visual_confirm_color( + hws->funcs.get_hdr_visual_confirm_color( pipe_ctx, &blnd_cfg.black_color); } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) { - dcn10_get_surface_visual_confirm_color( + hws->funcs.get_surface_visual_confirm_color( pipe_ctx, &blnd_cfg.black_color); } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_MPCTREE) { dcn20_get_mpctree_visual_confirm_color( @@ -2083,12 +2163,6 @@ static void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) */ mpcc_id = hubp->inst; - /* If there is no full update, don't need to touch MPC tree*/ - if (!pipe_ctx->plane_state->update_flags.bits.full_update) { - mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); - return; - } - /* check if this MPCC is already being used */ new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id); /* remove MPCC if being used */ @@ -2113,125 +2187,7 @@ static void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) hubp->mpcc_id = mpcc_id; } -static int find_free_gsl_group(const struct dc *dc) -{ - if (dc->res_pool->gsl_groups.gsl_0 == 0) - return 1; - if (dc->res_pool->gsl_groups.gsl_1 == 0) - return 2; - if (dc->res_pool->gsl_groups.gsl_2 == 0) - return 3; - - return 0; -} - -/* NOTE: This is not a generic setup_gsl function (hence the suffix as_lock) - * This is only used to lock pipes in pipe splitting case with immediate flip - * Ordinary MPC/OTG locks suppress VUPDATE which doesn't help with immediate, - * so we get tearing with freesync since we cannot flip multiple pipes - * atomically. - * We use GSL for this: - * - immediate flip: find first available GSL group if not already assigned - * program gsl with that group, set current OTG as master - * and always us 0x4 = AND of flip_ready from all pipes - * - vsync flip: disable GSL if used - * - * Groups in stream_res are stored as +1 from HW registers, i.e. - * gsl_0 <=> pipe_ctx->stream_res.gsl_group == 1 - * Using a magic value like -1 would require tracking all inits/resets - */ -void dcn20_setup_gsl_group_as_lock( - const struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool enable) -{ - struct gsl_params gsl; - int group_idx; - - memset(&gsl, 0, sizeof(struct gsl_params)); - - if (enable) { - /* return if group already assigned since GSL was set up - * for vsync flip, we would unassign so it can't be "left over" - */ - if (pipe_ctx->stream_res.gsl_group > 0) - return; - - group_idx = find_free_gsl_group(dc); - ASSERT(group_idx != 0); - pipe_ctx->stream_res.gsl_group = group_idx; - - /* set gsl group reg field and mark resource used */ - switch (group_idx) { - case 1: - gsl.gsl0_en = 1; - dc->res_pool->gsl_groups.gsl_0 = 1; - break; - case 2: - gsl.gsl1_en = 1; - dc->res_pool->gsl_groups.gsl_1 = 1; - break; - case 3: - gsl.gsl2_en = 1; - dc->res_pool->gsl_groups.gsl_2 = 1; - break; - default: - BREAK_TO_DEBUGGER(); - return; // invalid case - } - gsl.gsl_master_en = 1; - } else { - group_idx = pipe_ctx->stream_res.gsl_group; - if (group_idx == 0) - return; // if not in use, just return - - pipe_ctx->stream_res.gsl_group = 0; - - /* unset gsl group reg field and mark resource free */ - switch (group_idx) { - case 1: - gsl.gsl0_en = 0; - dc->res_pool->gsl_groups.gsl_0 = 0; - break; - case 2: - gsl.gsl1_en = 0; - dc->res_pool->gsl_groups.gsl_1 = 0; - break; - case 3: - gsl.gsl2_en = 0; - dc->res_pool->gsl_groups.gsl_2 = 0; - break; - default: - BREAK_TO_DEBUGGER(); - return; - } - gsl.gsl_master_en = 0; - } - - /* at this point we want to program whether it's to enable or disable */ - if (pipe_ctx->stream_res.tg->funcs->set_gsl != NULL && - pipe_ctx->stream_res.tg->funcs->set_gsl_source_select != NULL) { - pipe_ctx->stream_res.tg->funcs->set_gsl( - pipe_ctx->stream_res.tg, - &gsl); - - pipe_ctx->stream_res.tg->funcs->set_gsl_source_select( - pipe_ctx->stream_res.tg, group_idx, enable ? 4 : 0); - } else - BREAK_TO_DEBUGGER(); -} - -static void dcn20_set_flip_control_gsl( - struct pipe_ctx *pipe_ctx, - bool flip_immediate) -{ - if (pipe_ctx && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl) - pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl( - pipe_ctx->plane_res.hubp, flip_immediate); - -} - -static void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) +void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) { enum dc_lane_count lane_count = pipe_ctx->stream->link->cur_link_settings.lane_count; @@ -2279,7 +2235,7 @@ static void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) } } -static void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx) +void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; struct hubp *hubp = pipe_ctx->plane_res.hubp; @@ -2305,7 +2261,7 @@ static void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx) hubp->inst, mode); } -static void dcn20_fpga_init_hw(struct dc *dc) +void dcn20_fpga_init_hw(struct dc *dc) { int i, j; struct dce_hwseq *hws = dc->hwseq; @@ -2320,13 +2276,13 @@ static void dcn20_fpga_init_hw(struct dc *dc) res_pool->dccg->funcs->dccg_init(res_pool->dccg); //Enable ability to power gate / don't force power on permanently - dc->hwss.enable_power_gating_plane(hws, true); + hws->funcs.enable_power_gating_plane(hws, true); // Specific to FPGA dccg and registers REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF); REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF); - dcn20_dccg_init(hws); + hws->funcs.dccg_init(hws); REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2); REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); @@ -2390,7 +2346,7 @@ static void dcn20_fpga_init_hw(struct dc *dc) dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; /*to do*/ - hwss1_plane_atomic_disconnect(dc, pipe_ctx); + hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); } /* initialize DWB pointer to MCIF_WB */ @@ -2419,57 +2375,3 @@ static void dcn20_fpga_init_hw(struct dc *dc) tg->funcs->tg_init(tg); } } - -void dcn20_hw_sequencer_construct(struct dc *dc) -{ - dcn10_hw_sequencer_construct(dc); - dc->hwss.unblank_stream = dcn20_unblank_stream; - dc->hwss.update_plane_addr = dcn20_update_plane_addr; - dc->hwss.enable_stream_timing = dcn20_enable_stream_timing; - dc->hwss.program_triplebuffer = dcn20_program_tripleBuffer; - dc->hwss.set_input_transfer_func = dcn20_set_input_transfer_func; - dc->hwss.set_output_transfer_func = dcn20_set_output_transfer_func; - dc->hwss.apply_ctx_for_surface = NULL; - dc->hwss.program_front_end_for_ctx = dcn20_program_front_end_for_ctx; - dc->hwss.pipe_control_lock = dcn20_pipe_control_lock; - dc->hwss.pipe_control_lock_global = dcn20_pipe_control_lock_global; - dc->hwss.optimize_bandwidth = dcn20_optimize_bandwidth; - dc->hwss.prepare_bandwidth = dcn20_prepare_bandwidth; - dc->hwss.update_bandwidth = dcn20_update_bandwidth; - dc->hwss.enable_writeback = dcn20_enable_writeback; - dc->hwss.disable_writeback = dcn20_disable_writeback; - dc->hwss.program_output_csc = dcn20_program_output_csc; - dc->hwss.update_odm = dcn20_update_odm; - dc->hwss.blank_pixel_data = dcn20_blank_pixel_data; - dc->hwss.dmdata_status_done = dcn20_dmdata_status_done; - dc->hwss.program_dmdata_engine = dcn20_program_dmdata_engine; - dc->hwss.enable_stream = dcn20_enable_stream; - dc->hwss.disable_stream = dcn20_disable_stream; - dc->hwss.init_sys_ctx = dcn20_init_sys_ctx; - dc->hwss.init_vm_ctx = dcn20_init_vm_ctx; - dc->hwss.disable_stream_gating = dcn20_disable_stream_gating; - dc->hwss.enable_stream_gating = dcn20_enable_stream_gating; - dc->hwss.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt; - dc->hwss.reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap; - dc->hwss.update_mpcc = dcn20_update_mpcc; - dc->hwss.set_flip_control_gsl = dcn20_set_flip_control_gsl; - dc->hwss.init_blank = dcn20_init_blank; - dc->hwss.disable_plane = dcn20_disable_plane; - dc->hwss.plane_atomic_disable = dcn20_plane_atomic_disable; - dc->hwss.enable_power_gating_plane = dcn20_enable_power_gating_plane; - dc->hwss.dpp_pg_control = dcn20_dpp_pg_control; - dc->hwss.hubp_pg_control = dcn20_hubp_pg_control; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT - dc->hwss.dsc_pg_control = dcn20_dsc_pg_control; -#else - dc->hwss.dsc_pg_control = NULL; -#endif - dc->hwss.disable_vga = dcn20_disable_vga; - - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { - dc->hwss.init_hw = dcn20_fpga_init_hw; - dc->hwss.init_pipes = NULL; - } - - -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h index 3098f1049ed799ba1b968937fde64db3c9ab2e7e..eecd7a26ec4c41556b06df516ff97475adecf262 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h @@ -26,90 +26,113 @@ #ifndef __DC_HWSS_DCN20_H__ #define __DC_HWSS_DCN20_H__ -struct dc; +#include "hw_sequencer_private.h" -void dcn20_hw_sequencer_construct(struct dc *dc); - -enum dc_status dcn20_enable_stream_timing( - struct pipe_ctx *pipe_ctx, - struct dc_state *context, - struct dc *dc); - -void dcn20_blank_pixel_data( +bool dcn20_set_blend_lut( + struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state); +bool dcn20_set_shaper_3dlut( + struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state); +void dcn20_program_front_end_for_ctx( struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool blank); - + struct dc_state *context); +void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx); +bool dcn20_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); +bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream); void dcn20_program_output_csc(struct dc *dc, struct pipe_ctx *pipe_ctx, enum dc_color_space colorspace, uint16_t *matrix, int opp_id); - +void dcn20_enable_stream(struct pipe_ctx *pipe_ctx); +void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, + struct dc_link_settings *link_settings); +void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn20_blank_pixel_data( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool blank); +void dcn20_pipe_control_lock( + struct dc *dc, + struct pipe_ctx *pipe, + bool lock); +void dcn20_pipe_control_lock_global( + struct dc *dc, + struct pipe_ctx *pipe, + bool lock); void dcn20_prepare_bandwidth( struct dc *dc, struct dc_state *context); - void dcn20_optimize_bandwidth( struct dc *dc, struct dc_state *context); - bool dcn20_update_bandwidth( struct dc *dc, struct dc_state *context); - +void dcn20_reset_hw_ctx_wrap( + struct dc *dc, + struct dc_state *context); +enum dc_status dcn20_enable_stream_timing( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, + struct dc *dc); +void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn20_init_blank( + struct dc *dc, + struct timing_generator *tg); +void dcn20_disable_vga( + struct dce_hwseq *hws); +void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn20_enable_power_gating_plane( + struct dce_hwseq *hws, + bool enable); +void dcn20_dpp_pg_control( + struct dce_hwseq *hws, + unsigned int dpp_inst, + bool power_on); +void dcn20_hubp_pg_control( + struct dce_hwseq *hws, + unsigned int hubp_inst, + bool power_on); +void dcn20_program_triple_buffer( + const struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool enable_triple_buffer); +void dcn20_enable_writeback( + struct dc *dc, + const struct dc_stream_status *stream_status, + struct dc_writeback_info *wb_info, + struct dc_state *context); void dcn20_disable_writeback( struct dc *dc, unsigned int dwb_pipe_inst); - -bool dcn20_hwss_wait_for_blank_complete( - struct output_pixel_processor *opp); - -bool dcn20_set_output_transfer_func(struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream); - -bool dcn20_set_input_transfer_func(struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state); - +void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx); - +void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx); void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx); - -void dcn20_disable_stream(struct pipe_ctx *pipe_ctx); - -void dcn20_program_tripleBuffer( - const struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool enableTripleBuffer); - -void dcn20_setup_vupdate_interrupt(struct pipe_ctx *pipe_ctx); - -void dcn20_pipe_control_lock_global( +void dcn20_init_vm_ctx( + struct dce_hwseq *hws, struct dc *dc, - struct pipe_ctx *pipe, - bool lock); -void dcn20_setup_gsl_group_as_lock(const struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool enable); -void dcn20_dccg_init(struct dce_hwseq *hws); -void dcn20_init_blank( - struct dc *dc, - struct timing_generator *tg); -void dcn20_display_init(struct dc *dc); -void dcn20_pipe_control_lock( - struct dc *dc, - struct pipe_ctx *pipe, - bool lock); -void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn20_enable_plane( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context); -bool dcn20_set_blend_lut( - struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state); -bool dcn20_set_shaper_3dlut( - struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state); -void dcn20_get_mpctree_visual_confirm_color( + struct dc_virtual_addr_space_config *va_config, + int vmid); +void dcn20_set_flip_control_gsl( struct pipe_ctx *pipe_ctx, - struct tg_color *color); + bool flip_immediate); +void dcn20_dsc_pg_control( + struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on); +void dcn20_fpga_init_hw(struct dc *dc); +bool dcn20_wait_for_blank_complete( + struct output_pixel_processor *opp); +void dcn20_dccg_init(struct dce_hwseq *hws); +int dcn20_init_sys_ctx(struct dce_hwseq *hws, + struct dc *dc, + struct dc_phy_addr_space_config *pa_config); + #endif /* __DC_HWSS_DCN20_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c new file mode 100644 index 0000000000000000000000000000000000000000..d51e02fdab4d3eb427e310dbde23122b5b162d86 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c @@ -0,0 +1,133 @@ +/* + * Copyright 2016 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: AMD + * + */ + +#include "dce110/dce110_hw_sequencer.h" +#include "dcn10/dcn10_hw_sequencer.h" +#include "dcn20_hwseq.h" + +static const struct hw_sequencer_funcs dcn20_funcs = { + .program_gamut_remap = dcn10_program_gamut_remap, + .init_hw = dcn10_init_hw, + .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, + .update_plane_addr = dcn20_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .program_output_csc = dcn20_program_output_csc, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dce110_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, + .enable_stream = dcn20_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dcn20_unblank_stream, + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dcn20_disable_plane, + .pipe_control_lock = dcn20_pipe_control_lock, + .pipe_control_lock_global = dcn20_pipe_control_lock_global, + .prepare_bandwidth = dcn20_prepare_bandwidth, + .optimize_bandwidth = dcn20_optimize_bandwidth, + .update_bandwidth = dcn20_update_bandwidth, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn10_set_static_screen_control, + .setup_stereo = dcn10_setup_stereo, + .set_avmute = dce110_set_avmute, + .log_hw_state = dcn10_log_hw_state, + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .program_triplebuffer = dcn20_program_triple_buffer, + .enable_writeback = dcn20_enable_writeback, + .disable_writeback = dcn20_disable_writeback, + .dmdata_status_done = dcn20_dmdata_status_done, + .program_dmdata_engine = dcn20_program_dmdata_engine, + .set_dmdata_attributes = dcn20_set_dmdata_attributes, + .init_sys_ctx = dcn20_init_sys_ctx, + .init_vm_ctx = dcn20_init_vm_ctx, + .set_flip_control_gsl = dcn20_set_flip_control_gsl, + .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, +}; + +static const struct hwseq_private_funcs dcn20_private_funcs = { + .init_pipes = dcn10_init_pipes, + .update_plane_addr = dcn20_update_plane_addr, + .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, + .update_mpcc = dcn20_update_mpcc, + .set_input_transfer_func = dcn20_set_input_transfer_func, + .set_output_transfer_func = dcn20_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .blank_pixel_data = dcn20_blank_pixel_data, + .reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap, + .enable_stream_timing = dcn20_enable_stream_timing, + .edp_backlight_control = dce110_edp_backlight_control, + .disable_stream_gating = dcn20_disable_stream_gating, + .enable_stream_gating = dcn20_enable_stream_gating, + .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = dcn20_init_blank, + .disable_vga = dcn20_disable_vga, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn20_plane_atomic_disable, + .plane_atomic_power_down = dcn10_plane_atomic_power_down, + .enable_power_gating_plane = dcn20_enable_power_gating_plane, + .dpp_pg_control = dcn20_dpp_pg_control, + .hubp_pg_control = dcn20_hubp_pg_control, + .dsc_pg_control = NULL, + .update_odm = dcn20_update_odm, + .dsc_pg_control = dcn20_dsc_pg_control, + .get_surface_visual_confirm_color = dcn10_get_surface_visual_confirm_color, + .get_hdr_visual_confirm_color = dcn10_get_hdr_visual_confirm_color, + .set_hdr_multiplier = dcn10_set_hdr_multiplier, + .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, + .wait_for_blank_complete = dcn20_wait_for_blank_complete, + .dccg_init = dcn20_dccg_init, + .set_blend_lut = dcn20_set_blend_lut, + .set_shaper_3dlut = dcn20_set_shaper_3dlut, +}; + +void dcn20_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dcn20_funcs; + dc->hwseq->funcs = dcn20_private_funcs; + + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + dc->hwss.init_hw = dcn20_fpga_init_hw; + dc->hwseq->funcs.init_pipes = NULL; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.h new file mode 100644 index 0000000000000000000000000000000000000000..12277797cd7106ec2e406a50c66a875292c99a52 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.h @@ -0,0 +1,33 @@ +/* + * Copyright 2016 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: AMD + * + */ + +#ifndef __DC_DCN20_INIT_H__ +#define __DC_DCN20_INIT_H__ + +struct dc; + +void dcn20_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN20_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c index e476f27aa3a9a917a8f9b665e6ec5e05f4a95705..e4ac73035c84a4522e2781ee44ac176157d2b46b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c @@ -168,10 +168,8 @@ static struct mpll_cfg dcn2_mpll_cfg[] = { void enc2_fec_set_enable(struct link_encoder *enc, bool enable) { struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT DC_LOG_DSC("%s FEC at link encoder inst %d", enable ? "Enabling" : "Disabling", enc->id.enum_id); -#endif REG_UPDATE(DP_DPHY_CNTL, DPHY_FEC_EN, enable); } @@ -192,7 +190,6 @@ bool enc2_fec_is_active(struct link_encoder *enc) return (active != 0); } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT /* this function reads dsc related register fields to be logged later in dcn10_log_hw_state * into a dcn_dsc_state struct. */ @@ -203,8 +200,8 @@ void link_enc2_read_state(struct link_encoder *enc, struct link_enc_state *s) REG_GET(DP_DPHY_CNTL, DPHY_FEC_EN, &s->dphy_fec_en); REG_GET(DP_DPHY_CNTL, DPHY_FEC_READY_SHADOW, &s->dphy_fec_ready_shadow); REG_GET(DP_DPHY_CNTL, DPHY_FEC_ACTIVE_STATUS, &s->dphy_fec_active_status); + REG_GET(DP_LINK_CNTL, DP_LINK_TRAINING_COMPLETE, &s->dp_link_training_complete); } -#endif static bool update_cfg_data( struct dcn10_link_encoder *enc10, @@ -315,9 +312,7 @@ void enc2_hw_init(struct link_encoder *enc) } static const struct link_encoder_funcs dcn20_link_enc_funcs = { -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT .read_state = link_enc2_read_state, -#endif .validate_output_with_stream = dcn10_link_encoder_validate_output_with_stream, .hw_init = enc2_hw_init, 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 0c98a0bbbd14f0cea11cbbd9ebeda7e0396333f1..62dfd34c69f184fabeb4acc6de11c7d108700ab9 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 @@ -158,9 +158,7 @@ void enc2_fec_set_ready(struct link_encoder *enc, bool ready); bool enc2_fec_is_active(struct link_encoder *enc); void enc2_hw_init(struct link_encoder *enc); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT void link_enc2_read_state(struct link_encoder *enc, struct link_enc_state *s); -#endif void dcn20_link_encoder_enable_dp_output( struct link_encoder *enc, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c index 5a188b2bc033c92a340cdd2ae374f0a957d0e6d3..f90031ed58a640c344d6b2489057fe05ec9eb768 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c @@ -345,6 +345,9 @@ static void mpc20_program_ogam_pwl( uint32_t i; struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + PERF_TRACE(); + REG_SEQ_START(); + for (i = 0 ; i < num; i++) { REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0, MPCC_OGAM_LUT_DATA, rgb[i].red_reg); REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0, MPCC_OGAM_LUT_DATA, rgb[i].green_reg); @@ -463,6 +466,11 @@ void mpc2_assert_mpcc_idle_before_connect(struct mpc *mpc, int mpcc_id) ASSERT(!mpc_disabled); ASSERT(!mpc_idle); } + + REG_SEQ_SUBMIT(); + PERF_TRACE(); + REG_SEQ_WAIT_DONE(); + PERF_TRACE(); } static void mpc2_init_mpcc(struct mpcc *mpcc, int mpcc_inst) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c index 40164ed015ea5de34bea1f54ee6a8e713a3d810e..023cc71fad0f55f02232b88a5cd0c3875993c398 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c @@ -41,6 +41,7 @@ void opp2_set_disp_pattern_generator( struct output_pixel_processor *opp, enum controller_dp_test_pattern test_pattern, + enum controller_dp_color_space color_space, enum dc_color_depth color_depth, const struct tg_color *solid_color, int width, @@ -100,9 +101,22 @@ void opp2_set_disp_pattern_generator( TEST_PATTERN_DYN_RANGE_CEA : TEST_PATTERN_DYN_RANGE_VESA); + switch (color_space) { + case CONTROLLER_DP_COLOR_SPACE_YCBCR601: + mode = TEST_PATTERN_MODE_COLORSQUARES_YCBCR601; + break; + case CONTROLLER_DP_COLOR_SPACE_YCBCR709: + mode = TEST_PATTERN_MODE_COLORSQUARES_YCBCR709; + break; + case CONTROLLER_DP_COLOR_SPACE_RGB: + default: + mode = TEST_PATTERN_MODE_COLORSQUARES_RGB; + break; + } + REG_UPDATE_6(DPG_CONTROL, DPG_EN, 1, - DPG_MODE, TEST_PATTERN_MODE_COLORSQUARES_RGB, + DPG_MODE, mode, DPG_DYNAMIC_RANGE, dyn_range, DPG_BIT_DEPTH, bit_depth, DPG_VRES, 6, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.h index abd8de9a78f8b0662fab3b03c7d742cc67642eb4..4093bec172c181479a31aaf276349ae2975f3bf0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.h @@ -140,6 +140,7 @@ void dcn20_opp_construct(struct dcn20_opp *oppn20, void opp2_set_disp_pattern_generator( struct output_pixel_processor *opp, enum controller_dp_test_pattern test_pattern, + enum controller_dp_color_space color_space, enum dc_color_depth color_depth, const struct tg_color *solid_color, int width, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c index 3b613fb93ef8041dd4f5846ad072ea4887684ad5..673c83e2afd40dc58e4d12513f25f20e47fa0a48 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c @@ -59,11 +59,16 @@ bool optc2_enable_crtc(struct timing_generator *optc) REG_UPDATE(CONTROL, VTG0_ENABLE, 1); + REG_SEQ_START(); + /* Enable CRTC */ REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 3, OTG_MASTER_EN, 1); + REG_SEQ_SUBMIT(); + REG_SEQ_WAIT_DONE(); + return true; } @@ -167,7 +172,6 @@ void optc2_set_gsl_source_select( } } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT /* DSC encoder frame start controls: x = h position, line_num = # of lines from vstartup */ void optc2_set_dsc_encoder_frame_start(struct timing_generator *optc, int x_position, @@ -201,13 +205,12 @@ void optc2_set_dsc_config(struct timing_generator *optc, REG_UPDATE(OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, dsc_slice_width); } -#endif -/** - * PTI i think is already done somewhere else for 2ka - * (opp?, please double check. - * OPTC side only has 1 register to set for PTI_ENABLE) - */ +/*TEMP: Need to figure out inheritance model here.*/ +bool optc2_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) +{ + return optc1_is_two_pixels_per_containter(timing); +} void optc2_set_odm_bypass(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing) @@ -221,7 +224,7 @@ void optc2_set_odm_bypass(struct timing_generator *optc, OPTC_SEG1_SRC_SEL, 0xf); REG_WRITE(OTG_H_TIMING_CNTL, 0); - h_div_2 = optc1_is_two_pixels_per_containter(dc_crtc_timing); + h_div_2 = optc2_is_two_pixels_per_containter(dc_crtc_timing); REG_UPDATE(OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_BY2, h_div_2); REG_SET(OPTC_MEMORY_CONFIG, 0, @@ -448,9 +451,7 @@ static struct timing_generator_funcs dcn20_tg_funcs = { .setup_global_swap_lock = NULL, .get_crc = optc1_get_crc, .configure_crc = optc1_configure_crc, -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT .set_dsc_config = optc2_set_dsc_config, -#endif .set_dwb_source = optc2_set_dwb_source, .set_odm_bypass = optc2_set_odm_bypass, .set_odm_combine = optc2_set_odm_combine, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h index 32a58431fd0909c227b17e1369cd65e421cbff0d..ac93fbfaee03adadf8555eaa065a1fe1df896698 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h @@ -86,12 +86,10 @@ void optc2_set_gsl_source_select(struct timing_generator *optc, int group_idx, uint32_t gsl_ready_signal); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT void optc2_set_dsc_config(struct timing_generator *optc, enum optc_dsc_mode dsc_mode, uint32_t dsc_bytes_per_pixel, uint32_t dsc_slice_width); -#endif void optc2_set_odm_bypass(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing); @@ -109,5 +107,5 @@ void optc2_triplebuffer_unlock(struct timing_generator *optc); void optc2_lock_doublebuffer_disable(struct timing_generator *optc); void optc2_lock_doublebuffer_enable(struct timing_generator *optc); void optc2_program_manual_trigger(struct timing_generator *optc); - +bool optc2_is_two_pixels_per_containter(const struct dc_crtc_timing *timing); #endif /* __DC_OPTC_DCN20_H__ */ 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 09793336d84f6944b44092fbce09e8f5d74b2283..cfc69919ef9e45c725e071ae576e3cad3418a63a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -28,6 +28,8 @@ #include "dm_services.h" #include "dc.h" +#include "dcn20_init.h" + #include "resource.h" #include "include/irq_service_interface.h" #include "dcn20/dcn20_resource.h" @@ -45,9 +47,7 @@ #include "dcn10/dcn10_resource.h" #include "dcn20_opp.h" -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #include "dcn20_dsc.h" -#endif #include "dcn20_link_encoder.h" #include "dcn20_stream_encoder.h" @@ -59,6 +59,7 @@ #include "dml/display_mode_vba.h" #include "dcn20_dccg.h" #include "dcn20_vmid.h" +#include "dc_link_ddc.h" #include "navi10_ip_offset.h" @@ -82,8 +83,6 @@ #include "amdgpu_socbb.h" -/* NV12 SOC BB is currently in FW, mark SW bounding box invalid. */ -#define SOC_BOUNDING_BOX_VALID false #define DC_LOGGER_INIT(logger) struct _vcs_dpi_ip_params_st dcn2_0_ip = { @@ -94,11 +93,7 @@ struct _vcs_dpi_ip_params_st dcn2_0_ip = { .hostvm_max_page_table_levels = 4, .hostvm_cached_page_table_levels = 0, .pte_group_size_bytes = 2048, -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT .num_dsc = 6, -#else - .num_dsc = 0, -#endif .rob_buffer_size_kbytes = 168, .det_buffer_size_kbytes = 164, .dpte_buffer_size_in_pte_reqs_luma = 84, @@ -838,7 +833,6 @@ static int map_transmitter_id_to_phy_instance( } } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #define dsc_regsDCN20(id)\ [id] = {\ DSC_REG_LIST_DCN20(id)\ @@ -860,7 +854,6 @@ static const struct dcn20_dsc_shift dsc_shift = { static const struct dcn20_dsc_mask dsc_mask = { DSC_REG_LIST_SH_MASK_DCN20(_MASK) }; -#endif static const struct dccg_registers dccg_regs = { DCCG_REG_LIST_DCN2() @@ -884,9 +877,7 @@ static const struct resource_caps res_cap_nv10 = { .num_dwb = 1, .num_ddc = 6, .num_vmid = 16, -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT .num_dsc = 6, -#endif }; static const struct dc_plane_cap plane_cap = { @@ -1282,7 +1273,6 @@ void dcn20_clock_source_destroy(struct clock_source **clk_src) *clk_src = NULL; } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT struct display_stream_compressor *dcn20_dsc_create( struct dc_context *ctx, uint32_t inst) @@ -1305,9 +1295,8 @@ void dcn20_dsc_destroy(struct display_stream_compressor **dsc) *dsc = NULL; } -#endif -static void destruct(struct dcn20_resource_pool *pool) +static void dcn20_resource_destruct(struct dcn20_resource_pool *pool) { unsigned int i; @@ -1318,12 +1307,10 @@ static void destruct(struct dcn20_resource_pool *pool) } } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT for (i = 0; i < pool->base.res_cap->num_dsc; i++) { if (pool->base.dscs[i] != NULL) dcn20_dsc_destroy(&pool->base.dscs[i]); } -#endif if (pool->base.mpc != NULL) { kfree(TO_DCN20_MPC(pool->base.mpc)); @@ -1416,6 +1403,8 @@ static void destruct(struct dcn20_resource_pool *pool) if (pool->base.pp_smu != NULL) dcn20_pp_smu_destroy(&pool->base.pp_smu); + if (pool->base.oem_device != NULL) + dal_ddc_service_destroy(&pool->base.oem_device); } struct hubp *dcn20_hubp_create( @@ -1466,7 +1455,7 @@ static void get_pixel_clock_parameters( if (opp_cnt == 4) pixel_clk_params->requested_pix_clk_100hz /= 4; - else if (optc1_is_two_pixels_per_containter(&stream->timing) || opp_cnt == 2) + else if (optc2_is_two_pixels_per_containter(&stream->timing) || opp_cnt == 2) pixel_clk_params->requested_pix_clk_100hz /= 2; if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) @@ -1532,17 +1521,23 @@ enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state return status; } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT static void acquire_dsc(struct resource_context *res_ctx, const struct resource_pool *pool, - struct display_stream_compressor **dsc) + struct display_stream_compressor **dsc, + int pipe_idx) { int i; ASSERT(*dsc == NULL); *dsc = NULL; + if (pool->res_cap->num_dsc == pool->res_cap->num_opp) { + *dsc = pool->dscs[pipe_idx]; + res_ctx->is_dsc_acquired[pipe_idx] = true; + return; + } + /* Find first free DSC */ for (i = 0; i < pool->res_cap->num_dsc; i++) if (!res_ctx->is_dsc_acquired[i]) { @@ -1566,10 +1561,8 @@ static void release_dsc(struct resource_context *res_ctx, } } -#endif -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT static enum dc_status add_dsc_to_stream_resource(struct dc *dc, struct dc_state *dc_ctx, struct dc_stream_state *dc_stream) @@ -1585,11 +1578,10 @@ static enum dc_status add_dsc_to_stream_resource(struct dc *dc, if (pipe_ctx->stream != dc_stream) continue; - acquire_dsc(&dc_ctx->res_ctx, pool, &pipe_ctx->stream_res.dsc); + acquire_dsc(&dc_ctx->res_ctx, pool, &pipe_ctx->stream_res.dsc, i); /* The number of DSCs can be less than the number of pipes */ if (!pipe_ctx->stream_res.dsc) { - dm_output_to_console("No DSCs available\n"); result = DC_NO_DSC_RESOURCE; } @@ -1621,7 +1613,6 @@ static enum dc_status remove_dsc_from_stream_resource(struct dc *dc, else return DC_OK; } -#endif enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream) @@ -1633,11 +1624,9 @@ enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, if (result == DC_OK) result = resource_map_phy_clock_resources(dc, new_ctx, dc_stream); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT /* Get a DSC if required and available */ if (result == DC_OK && dc_stream->timing.flags.DSC) result = add_dsc_to_stream_resource(dc, new_ctx, dc_stream); -#endif if (result == DC_OK) result = dcn20_build_mapped_resource(dc, new_ctx, dc_stream); @@ -1650,9 +1639,7 @@ enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_ { enum dc_status result = DC_OK; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT result = remove_dsc_from_stream_resource(dc, new_ctx, dc_stream); -#endif return result; } @@ -1735,9 +1722,7 @@ bool dcn20_split_stream_for_odm( next_odm_pipe->plane_res.xfm = pool->transforms[next_odm_pipe->pipe_idx]; next_odm_pipe->plane_res.dpp = pool->dpps[next_odm_pipe->pipe_idx]; next_odm_pipe->plane_res.mpcc_inst = pool->dpps[next_odm_pipe->pipe_idx]->inst; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT next_odm_pipe->stream_res.dsc = NULL; -#endif if (prev_odm_pipe->next_odm_pipe && prev_odm_pipe->next_odm_pipe != next_odm_pipe) { next_odm_pipe->next_odm_pipe = prev_odm_pipe->next_odm_pipe; next_odm_pipe->next_odm_pipe->prev_odm_pipe = next_odm_pipe; @@ -1783,14 +1768,12 @@ bool dcn20_split_stream_for_odm( sd->recout.x = 0; } next_odm_pipe->stream_res.opp = pool->opps[next_odm_pipe->pipe_idx]; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT if (next_odm_pipe->stream->timing.flags.DSC == 1) { - acquire_dsc(res_ctx, pool, &next_odm_pipe->stream_res.dsc); + acquire_dsc(res_ctx, pool, &next_odm_pipe->stream_res.dsc, next_odm_pipe->pipe_idx); ASSERT(next_odm_pipe->stream_res.dsc); if (next_odm_pipe->stream_res.dsc == NULL) return false; } -#endif return true; } @@ -1814,9 +1797,7 @@ void dcn20_split_stream_for_mpc( secondary_pipe->plane_res.xfm = pool->transforms[secondary_pipe->pipe_idx]; secondary_pipe->plane_res.dpp = pool->dpps[secondary_pipe->pipe_idx]; secondary_pipe->plane_res.mpcc_inst = pool->dpps[secondary_pipe->pipe_idx]->inst; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT secondary_pipe->stream_res.dsc = NULL; -#endif if (primary_pipe->bottom_pipe && primary_pipe->bottom_pipe != secondary_pipe) { ASSERT(!secondary_pipe->bottom_pipe); secondary_pipe->bottom_pipe = primary_pipe->bottom_pipe; @@ -1868,10 +1849,11 @@ void dcn20_populate_dml_writeback_from_context( } int dcn20_populate_dml_pipes_from_context( - struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes) + struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes) { int pipe_cnt, i; bool synchronized_vblank = true; + struct resource_context *res_ctx = &context->res_ctx; for (i = 0, pipe_cnt = -1; i < dc->res_pool->pipe_count; i++) { if (!res_ctx->pipe_ctx[i].stream) @@ -1891,25 +1873,26 @@ int dcn20_populate_dml_pipes_from_context( for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { struct dc_crtc_timing *timing = &res_ctx->pipe_ctx[i].stream->timing; + unsigned int v_total; int output_bpc; if (!res_ctx->pipe_ctx[i].stream) continue; + + v_total = timing->v_total; /* todo: pipes[pipe_cnt].pipe.src.dynamic_metadata_enable = 0; pipes[pipe_cnt].pipe.src.dcc = 0; pipes[pipe_cnt].pipe.src.vm = 0;*/ -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT pipes[pipe_cnt].dout.dsc_enable = res_ctx->pipe_ctx[i].stream->timing.flags.DSC; /* todo: rotation?*/ pipes[pipe_cnt].dout.dsc_slices = res_ctx->pipe_ctx[i].stream->timing.dsc_cfg.num_slices_h; -#endif if (res_ctx->pipe_ctx[i].stream->use_dynamic_meta) { pipes[pipe_cnt].pipe.src.dynamic_metadata_enable = true; /* 1/2 vblank */ pipes[pipe_cnt].pipe.src.dynamic_metadata_lines_before_active = - (timing->v_total - timing->v_addressable + (v_total - timing->v_addressable - timing->v_border_top - timing->v_border_bottom) / 2; /* 36 bytes dp, 32 hdmi */ pipes[pipe_cnt].pipe.src.dynamic_metadata_xmit_bytes = @@ -1923,13 +1906,13 @@ int dcn20_populate_dml_pipes_from_context( - timing->h_addressable - timing->h_border_left - timing->h_border_right; - pipes[pipe_cnt].pipe.dest.vblank_start = timing->v_total - timing->v_front_porch; + pipes[pipe_cnt].pipe.dest.vblank_start = v_total - timing->v_front_porch; pipes[pipe_cnt].pipe.dest.vblank_end = pipes[pipe_cnt].pipe.dest.vblank_start - timing->v_addressable - timing->v_border_top - timing->v_border_bottom; pipes[pipe_cnt].pipe.dest.htotal = timing->h_total; - pipes[pipe_cnt].pipe.dest.vtotal = timing->v_total; + pipes[pipe_cnt].pipe.dest.vtotal = v_total; pipes[pipe_cnt].pipe.dest.hactive = timing->h_addressable; pipes[pipe_cnt].pipe.dest.vactive = timing->v_addressable; pipes[pipe_cnt].pipe.dest.interlaced = timing->flags.INTERLACE; @@ -1992,14 +1975,12 @@ int dcn20_populate_dml_pipes_from_context( case COLOR_DEPTH_161616: output_bpc = 16; break; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 case COLOR_DEPTH_999: output_bpc = 9; break; case COLOR_DEPTH_111111: output_bpc = 11; break; -#endif default: output_bpc = 8; break; @@ -2027,10 +2008,8 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].dout.output_bpp = output_bpc * 3; } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT if (res_ctx->pipe_ctx[i].stream->timing.flags.DSC) pipes[pipe_cnt].dout.output_bpp = res_ctx->pipe_ctx[i].stream->timing.dsc_cfg.bits_per_pixel / 16.0; -#endif /* todo: default max for now, until there is logic reflecting this in dc*/ pipes[pipe_cnt].dout.output_bpc = 12; @@ -2054,6 +2033,7 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].pipe.src.viewport_height = timing->v_addressable; if (pipes[pipe_cnt].pipe.src.viewport_height > 1080) pipes[pipe_cnt].pipe.src.viewport_height = 1080; + pipes[pipe_cnt].pipe.src.surface_height_y = pipes[pipe_cnt].pipe.src.viewport_height; pipes[pipe_cnt].pipe.src.data_pitch = ((pipes[pipe_cnt].pipe.src.viewport_width + 63) / 64) * 64; /* linear sw only */ pipes[pipe_cnt].pipe.src.source_format = dm_444_32; pipes[pipe_cnt].pipe.dest.recout_width = pipes[pipe_cnt].pipe.src.viewport_width; /*vp_width/hratio*/ @@ -2068,8 +2048,8 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].pipe.scale_taps.vtaps = 1; pipes[pipe_cnt].pipe.src.is_hsplit = 0; pipes[pipe_cnt].pipe.dest.odm_combine = 0; - pipes[pipe_cnt].pipe.dest.vtotal_min = timing->v_total; - pipes[pipe_cnt].pipe.dest.vtotal_max = timing->v_total; + pipes[pipe_cnt].pipe.dest.vtotal_min = v_total; + pipes[pipe_cnt].pipe.dest.vtotal_max = v_total; } else { struct dc_plane_state *pln = res_ctx->pipe_ctx[i].plane_state; struct scaler_data *scl = &res_ctx->pipe_ctx[i].plane_res.scl_data; @@ -2087,6 +2067,7 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].pipe.src.viewport_width_c = scl->viewport_c.width; pipes[pipe_cnt].pipe.src.viewport_height = scl->viewport.height; pipes[pipe_cnt].pipe.src.viewport_height_c = scl->viewport_c.height; + pipes[pipe_cnt].pipe.src.surface_height_y = pln->plane_size.surface_size.height; if (pln->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { pipes[pipe_cnt].pipe.src.data_pitch = pln->plane_size.surface_pitch; pipes[pipe_cnt].pipe.src.data_pitch_c = pln->plane_size.chroma_pitch; @@ -2252,7 +2233,6 @@ void dcn20_set_mcif_arb_params( } } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx) { int i; @@ -2286,7 +2266,6 @@ bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx) } return true; } -#endif struct pipe_ctx *dcn20_find_secondary_pipe(struct dc *dc, struct resource_context *res_ctx, @@ -2389,10 +2368,8 @@ void dcn20_merge_pipes_for_validate( odm_pipe->bottom_pipe = NULL; odm_pipe->prev_odm_pipe = NULL; odm_pipe->next_odm_pipe = NULL; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT if (odm_pipe->stream_res.dsc) release_dsc(&context->res_ctx, dc->res_pool, &odm_pipe->stream_res.dsc); -#endif /* Clear plane_res and stream_res */ memset(&odm_pipe->plane_res, 0, sizeof(odm_pipe->plane_res)); memset(&odm_pipe->stream_res, 0, sizeof(odm_pipe->stream_res)); @@ -2535,7 +2512,7 @@ bool dcn20_fast_validate_bw( dcn20_merge_pipes_for_validate(dc, context); - pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, &context->res_ctx, pipes); + pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes); *pipe_cnt_out = pipe_cnt; @@ -2612,14 +2589,12 @@ bool dcn20_fast_validate_bw( ASSERT(0); } } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT /* Actual dsc count per stream dsc validation*/ if (!dcn20_validate_dsc(dc, context)) { context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states] = DML_FAIL_DSC_VALIDATION_FAILURE; goto validate_fail; } -#endif *vlevel_out = vlevel; @@ -2683,10 +2658,10 @@ static void dcn20_calculate_wm( if (pipe_cnt != pipe_idx) { if (dc->res_pool->funcs->populate_dml_pipes) pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, - &context->res_ctx, pipes); + context, pipes); else pipe_cnt = dcn20_populate_dml_pipes_from_context(dc, - &context->res_ctx, pipes); + context, pipes); } *out_pipe_cnt = pipe_cnt; @@ -2706,11 +2681,9 @@ static void dcn20_calculate_wm( context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.b.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.b.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; -#endif if (vlevel < 2) { pipes[0].clks_cfg.voltage = 2; @@ -2722,10 +2695,8 @@ static void dcn20_calculate_wm( context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.c.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; -#endif if (vlevel < 3) { pipes[0].clks_cfg.voltage = 3; @@ -2737,10 +2708,8 @@ static void dcn20_calculate_wm( context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.d.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; -#endif pipes[0].clks_cfg.voltage = vlevel; pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].dcfclk_mhz; @@ -2750,10 +2719,8 @@ static void dcn20_calculate_wm( context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.a.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; -#endif } void dcn20_calculate_dlg_params( @@ -2920,6 +2887,7 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, bool full_pstate_supported = false; bool dummy_pstate_supported = false; double p_state_latency_us = context->bw_ctx.dml.soc.dram_clock_change_latency_us; + context->bw_ctx.dml.soc.disable_dram_clock_change_vactive_support = dc->debug.disable_dram_clock_change_vactive_support; if (fast_validate) return dcn20_validate_bandwidth_internal(dc, context, true); @@ -2996,7 +2964,7 @@ static void dcn20_destroy_resource_pool(struct resource_pool **pool) { struct dcn20_resource_pool *dcn20_pool = TO_DCN20_RES_POOL(*pool); - destruct(dcn20_pool); + dcn20_resource_destruct(dcn20_pool); kfree(dcn20_pool); *pool = NULL; } @@ -3309,12 +3277,13 @@ static bool init_soc_bounding_box(struct dc *dc, DC_LOGGER_INIT(dc->ctx->logger); - if (!bb && !SOC_BOUNDING_BOX_VALID) { + /* TODO: upstream NV12 bounding box when its launched */ + if (!bb && ASICREV_IS_NAVI12_P(dc->ctx->asic_id.hw_internal_rev)) { DC_LOG_ERROR("%s: not valid soc bounding box/n", __func__); return false; } - if (bb && !SOC_BOUNDING_BOX_VALID) { + if (bb && ASICREV_IS_NAVI12_P(dc->ctx->asic_id.hw_internal_rev)) { int i; dcn2_0_nv12_soc.sr_exit_time_us = @@ -3456,7 +3425,7 @@ static bool init_soc_bounding_box(struct dc *dc, return true; } -static bool construct( +static bool dcn20_resource_construct( uint8_t num_virtual_links, struct dc *dc, struct dcn20_resource_pool *pool) @@ -3464,6 +3433,7 @@ static bool construct( int i; struct dc_context *ctx = dc->ctx; struct irq_service_init_data init_data; + struct ddc_service_init_data ddc_init_data; struct _vcs_dpi_soc_bounding_box_st *loaded_bb = get_asic_rev_soc_bb(ctx->asic_id.hw_internal_rev); struct _vcs_dpi_ip_params_st *loaded_ip = @@ -3723,7 +3693,6 @@ static bool construct( goto create_fail; } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT for (i = 0; i < pool->base.res_cap->num_dsc; i++) { pool->base.dscs[i] = dcn20_dsc_create(ctx, i); if (pool->base.dscs[i] == NULL) { @@ -3732,7 +3701,6 @@ static bool construct( goto create_fail; } } -#endif if (!dcn20_dwbc_create(ctx, &pool->base)) { BREAK_TO_DEBUGGER(); @@ -3759,11 +3727,22 @@ static bool construct( dc->cap_funcs = cap_funcs; + if (dc->ctx->dc_bios->fw_info.oem_i2c_present) { + ddc_init_data.ctx = dc->ctx; + ddc_init_data.link = NULL; + ddc_init_data.id.id = dc->ctx->dc_bios->fw_info.oem_i2c_obj_id; + ddc_init_data.id.enum_id = 0; + ddc_init_data.id.type = OBJECT_TYPE_GENERIC; + pool->base.oem_device = dal_ddc_service_create(&ddc_init_data); + } else { + pool->base.oem_device = NULL; + } + return true; create_fail: - destruct(pool); + dcn20_resource_destruct(pool); return false; } @@ -3778,7 +3757,7 @@ struct resource_pool *dcn20_create_resource_pool( if (!pool) return NULL; - if (construct(init_data->num_virtual_links, dc, pool)) + if (dcn20_resource_construct(init_data->num_virtual_links, dc, pool)) return &pool->base; BREAK_TO_DEBUGGER(); 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 fef473d68a4ae5dc893c9487410ea99abed1553d..840ca66c34e12edb921358492cd8d4654bd78673 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h @@ -50,7 +50,7 @@ unsigned int dcn20_calc_max_scaled_time( enum mmhubbub_wbif_mode mode, unsigned int urgent_watermark); int dcn20_populate_dml_pipes_from_context( - struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes); + struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes); struct pipe_ctx *dcn20_acquire_idle_pipe_for_layer( struct dc_state *state, const struct resource_pool *pool, @@ -127,9 +127,7 @@ int dcn20_validate_apply_pipe_split_flags( struct dc_state *context, int vlevel, bool *split); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx); -#endif void dcn20_split_stream_for_mpc( struct resource_context *res_ctx, const struct resource_pool *pool, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c index 4b34016164348706e8be44aca42ef24d0aa89b13..9b70a1e7b962b87f1a4b20e918471dea7f2e3306 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c @@ -205,7 +205,6 @@ static void enc2_stream_encoder_stop_hdmi_info_packets( HDMI_GENERIC7_LINE, 0); } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT /* Update GSP7 SDP 128 byte long */ static void enc2_update_gsp7_128_info_packet( @@ -360,7 +359,6 @@ static void enc2_read_state(struct stream_encoder *enc, struct enc_state *s) REG_GET(DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, &s->sec_stream_enable); } } -#endif /* Set Dynamic Metadata-configuration. * enable_dme: TRUE: enables Dynamic Metadata Enfine, FALSE: disables DME @@ -440,10 +438,8 @@ static bool is_two_pixels_per_containter(const struct dc_crtc_timing *timing) { bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422 && !timing->dsc_cfg.ycbcr422_simple); -#endif return two_pix; } @@ -492,15 +488,23 @@ void enc2_stream_encoder_dp_unblank( DP_VID_N_MUL, n_multiply); } - /* set DIG_START to 0x1 to reset FIFO */ + /* make sure stream is disabled before resetting steer fifo */ + REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, false); + REG_WAIT(DP_VID_STREAM_CNTL, DP_VID_STREAM_STATUS, 0, 10, 5000); + /* set DIG_START to 0x1 to reset FIFO */ REG_UPDATE(DIG_FE_CNTL, DIG_START, 1); + udelay(1); /* write 0 to take the FIFO out of reset */ REG_UPDATE(DIG_FE_CNTL, DIG_START, 0); - /* switch DP encoder to CRTC data */ + /* switch DP encoder to CRTC data, but reset it the fifo first. It may happen + * that it overflows during mode transition, and sometimes doesn't recover. + */ + REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, 1); + udelay(10); REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, 0); @@ -533,11 +537,16 @@ void enc2_stream_encoder_dp_set_stream_attribute( struct stream_encoder *enc, struct dc_crtc_timing *crtc_timing, enum dc_color_space output_color_space, + bool use_vsc_sdp_for_colorimetry, uint32_t enable_sdp_splitting) { struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); - enc1_stream_encoder_dp_set_stream_attribute(enc, crtc_timing, output_color_space, enable_sdp_splitting); + enc1_stream_encoder_dp_set_stream_attribute(enc, + crtc_timing, + output_color_space, + use_vsc_sdp_for_colorimetry, + enable_sdp_splitting); REG_UPDATE(DP_SEC_FRAMING4, DP_SST_SDP_SPLITTING, enable_sdp_splitting); @@ -560,6 +569,8 @@ static const struct stream_encoder_funcs dcn20_str_enc_funcs = { enc2_stream_encoder_stop_hdmi_info_packets, .update_dp_info_packets = enc2_stream_encoder_update_dp_info_packets, + .send_immediate_sdp_message = + enc1_stream_encoder_send_immediate_sdp_message, .stop_dp_info_packets = enc1_stream_encoder_stop_dp_info_packets, .dp_blank = @@ -582,11 +593,9 @@ static const struct stream_encoder_funcs dcn20_str_enc_funcs = { .dp_get_pixel_format = enc1_stream_encoder_dp_get_pixel_format, -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT .enc_read_state = enc2_read_state, .dp_set_dsc_config = enc2_dp_set_dsc_config, .dp_set_dsc_pps_info_packet = enc2_dp_set_dsc_pps_info_packet, -#endif .set_dynamic_metadata = enc2_set_dynamic_metadata, .hdmi_reset_stream_attribute = enc1_reset_hdmi_stream_attribute, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h index 3f94a9f13c4a7a91938ee6e1051d55158205882f..d2a805bd457342443791008c3d8eb7f74e7a3bde 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h @@ -98,6 +98,7 @@ void enc2_stream_encoder_dp_set_stream_attribute( struct stream_encoder *enc, struct dc_crtc_timing *crtc_timing, enum dc_color_space output_color_space, + bool use_vsc_sdp_for_colorimetry, uint32_t enable_sdp_splitting); void enc2_stream_encoder_dp_unblank( diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/Makefile b/drivers/gpu/drm/amd/display/dc/dcn21/Makefile index 14113ccf498d27c6d9eb48790cc83821fabb989e..4763721fb1c9a2a29d64550b51e5dab620292b1d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn21/Makefile @@ -1,7 +1,9 @@ +# SPDX-License-Identifier: MIT # # Makefile for DCN21. -DCN21 = dcn21_hubp.o dcn21_hubbub.o dcn21_resource.o dcn21_hwseq.o dcn21_link_encoder.o +DCN21 = dcn21_init.o dcn21_hubp.o dcn21_hubbub.o dcn21_resource.o \ + dcn21_hwseq.o dcn21_link_encoder.o CFLAGS_$(AMDDALPATH)/dc/dcn21/dcn21_resource.o := -mhard-float -msse diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.c index 2f5a5867e6749318b65f30a8f80b3b8983659484..332bf3d3a66450aac74daf4db721ce13ac773008 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.c @@ -29,6 +29,8 @@ #include "dm_services.h" #include "reg_helper.h" +#define DC_LOGGER_INIT(logger) + #define REG(reg)\ hubp21->hubp_regs->reg @@ -164,6 +166,72 @@ static void hubp21_setup( } +void hubp21_set_viewport( + struct hubp *hubp, + const struct rect *viewport, + const struct rect *viewport_c, + enum dc_rotation_angle rotation) +{ + struct dcn21_hubp *hubp21 = TO_DCN21_HUBP(hubp); + int patched_viewport_height = 0; + struct dc_debug_options *debug = &hubp->ctx->dc->debug; + + REG_SET_2(DCSURF_PRI_VIEWPORT_DIMENSION, 0, + PRI_VIEWPORT_WIDTH, viewport->width, + PRI_VIEWPORT_HEIGHT, viewport->height); + + REG_SET_2(DCSURF_PRI_VIEWPORT_START, 0, + PRI_VIEWPORT_X_START, viewport->x, + PRI_VIEWPORT_Y_START, viewport->y); + + /*for stereo*/ + REG_SET_2(DCSURF_SEC_VIEWPORT_DIMENSION, 0, + SEC_VIEWPORT_WIDTH, viewport->width, + SEC_VIEWPORT_HEIGHT, viewport->height); + + REG_SET_2(DCSURF_SEC_VIEWPORT_START, 0, + SEC_VIEWPORT_X_START, viewport->x, + SEC_VIEWPORT_Y_START, viewport->y); + + /* + * Work around for underflow issue with NV12 + rIOMMU translation + * + immediate flip. This will cause hubp underflow, but will not + * be user visible since underflow is in blank region + * Disable w/a when rotated 180 degrees, causes vertical chroma offset + */ + patched_viewport_height = viewport_c->height; + if (debug->nv12_iflip_vm_wa && viewport_c->height > 512 && + rotation != ROTATION_ANGLE_180) { + int pte_row_height = 0; + int pte_rows = 0; + + REG_GET(DCHUBP_REQ_SIZE_CONFIG_C, + PTE_ROW_HEIGHT_LINEAR_C, &pte_row_height); + + pte_row_height = 1 << (pte_row_height + 3); + pte_rows = (viewport_c->height / pte_row_height) + 1; + patched_viewport_height = pte_rows * pte_row_height + 1; + } + + + /* DC supports NV12 only at the moment */ + REG_SET_2(DCSURF_PRI_VIEWPORT_DIMENSION_C, 0, + PRI_VIEWPORT_WIDTH_C, viewport_c->width, + PRI_VIEWPORT_HEIGHT_C, patched_viewport_height); + + REG_SET_2(DCSURF_PRI_VIEWPORT_START_C, 0, + PRI_VIEWPORT_X_START_C, viewport_c->x, + PRI_VIEWPORT_Y_START_C, viewport_c->y); + + REG_SET_2(DCSURF_SEC_VIEWPORT_DIMENSION_C, 0, + SEC_VIEWPORT_WIDTH_C, viewport_c->width, + SEC_VIEWPORT_HEIGHT_C, patched_viewport_height); + + REG_SET_2(DCSURF_SEC_VIEWPORT_START_C, 0, + SEC_VIEWPORT_X_START_C, viewport_c->x, + SEC_VIEWPORT_Y_START_C, viewport_c->y); +} + void hubp21_set_vm_system_aperture_settings(struct hubp *hubp, struct vm_system_aperture_param *apt) { @@ -191,6 +259,349 @@ void hubp21_set_vm_system_aperture_settings(struct hubp *hubp, SYSTEM_ACCESS_MODE, 0x3); } +void hubp21_validate_dml_output(struct hubp *hubp, + struct dc_context *ctx, + struct _vcs_dpi_display_rq_regs_st *dml_rq_regs, + struct _vcs_dpi_display_dlg_regs_st *dml_dlg_attr, + struct _vcs_dpi_display_ttu_regs_st *dml_ttu_attr) +{ + struct dcn21_hubp *hubp21 = TO_DCN21_HUBP(hubp); + struct _vcs_dpi_display_rq_regs_st rq_regs = {0}; + struct _vcs_dpi_display_dlg_regs_st dlg_attr = {0}; + struct _vcs_dpi_display_ttu_regs_st ttu_attr = {0}; + DC_LOGGER_INIT(ctx->logger); + DC_LOG_DEBUG("DML Validation | Running Validation"); + + /* Requester - Per hubp */ + REG_GET(HUBPRET_CONTROL, + DET_BUF_PLANE1_BASE_ADDRESS, &rq_regs.plane1_base_address); + REG_GET_4(DCN_EXPANSION_MODE, + DRQ_EXPANSION_MODE, &rq_regs.drq_expansion_mode, + PRQ_EXPANSION_MODE, &rq_regs.prq_expansion_mode, + MRQ_EXPANSION_MODE, &rq_regs.mrq_expansion_mode, + CRQ_EXPANSION_MODE, &rq_regs.crq_expansion_mode); + REG_GET_8(DCHUBP_REQ_SIZE_CONFIG, + CHUNK_SIZE, &rq_regs.rq_regs_l.chunk_size, + MIN_CHUNK_SIZE, &rq_regs.rq_regs_l.min_chunk_size, + META_CHUNK_SIZE, &rq_regs.rq_regs_l.meta_chunk_size, + MIN_META_CHUNK_SIZE, &rq_regs.rq_regs_l.min_meta_chunk_size, + DPTE_GROUP_SIZE, &rq_regs.rq_regs_l.dpte_group_size, + VM_GROUP_SIZE, &rq_regs.rq_regs_l.mpte_group_size, + SWATH_HEIGHT, &rq_regs.rq_regs_l.swath_height, + PTE_ROW_HEIGHT_LINEAR, &rq_regs.rq_regs_l.pte_row_height_linear); + REG_GET_7(DCHUBP_REQ_SIZE_CONFIG_C, + CHUNK_SIZE_C, &rq_regs.rq_regs_c.chunk_size, + MIN_CHUNK_SIZE_C, &rq_regs.rq_regs_c.min_chunk_size, + META_CHUNK_SIZE_C, &rq_regs.rq_regs_c.meta_chunk_size, + MIN_META_CHUNK_SIZE_C, &rq_regs.rq_regs_c.min_meta_chunk_size, + DPTE_GROUP_SIZE_C, &rq_regs.rq_regs_c.dpte_group_size, + SWATH_HEIGHT_C, &rq_regs.rq_regs_c.swath_height, + PTE_ROW_HEIGHT_LINEAR_C, &rq_regs.rq_regs_c.pte_row_height_linear); + + if (rq_regs.plane1_base_address != dml_rq_regs->plane1_base_address) + DC_LOG_DEBUG("DML Validation | HUBPRET_CONTROL:DET_BUF_PLANE1_BASE_ADDRESS - Expected: %u Actual: %u\n", + dml_rq_regs->plane1_base_address, rq_regs.plane1_base_address); + if (rq_regs.drq_expansion_mode != dml_rq_regs->drq_expansion_mode) + DC_LOG_DEBUG("DML Validation | DCN_EXPANSION_MODE:DRQ_EXPANSION_MODE - Expected: %u Actual: %u\n", + dml_rq_regs->drq_expansion_mode, rq_regs.drq_expansion_mode); + if (rq_regs.prq_expansion_mode != dml_rq_regs->prq_expansion_mode) + DC_LOG_DEBUG("DML Validation | DCN_EXPANSION_MODE:MRQ_EXPANSION_MODE - Expected: %u Actual: %u\n", + dml_rq_regs->prq_expansion_mode, rq_regs.prq_expansion_mode); + if (rq_regs.mrq_expansion_mode != dml_rq_regs->mrq_expansion_mode) + DC_LOG_DEBUG("DML Validation | DCN_EXPANSION_MODE:DET_BUF_PLANE1_BASE_ADDRESS - Expected: %u Actual: %u\n", + dml_rq_regs->mrq_expansion_mode, rq_regs.mrq_expansion_mode); + if (rq_regs.crq_expansion_mode != dml_rq_regs->crq_expansion_mode) + DC_LOG_DEBUG("DML Validation | DCN_EXPANSION_MODE:CRQ_EXPANSION_MODE - Expected: %u Actual: %u\n", + dml_rq_regs->crq_expansion_mode, rq_regs.crq_expansion_mode); + + if (rq_regs.rq_regs_l.chunk_size != dml_rq_regs->rq_regs_l.chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:CHUNK_SIZE - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.chunk_size, rq_regs.rq_regs_l.chunk_size); + if (rq_regs.rq_regs_l.min_chunk_size != dml_rq_regs->rq_regs_l.min_chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:MIN_CHUNK_SIZE - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.min_chunk_size, rq_regs.rq_regs_l.min_chunk_size); + if (rq_regs.rq_regs_l.meta_chunk_size != dml_rq_regs->rq_regs_l.meta_chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:META_CHUNK_SIZE - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.meta_chunk_size, rq_regs.rq_regs_l.meta_chunk_size); + if (rq_regs.rq_regs_l.min_meta_chunk_size != dml_rq_regs->rq_regs_l.min_meta_chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:MIN_META_CHUNK_SIZE - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.min_meta_chunk_size, rq_regs.rq_regs_l.min_meta_chunk_size); + if (rq_regs.rq_regs_l.dpte_group_size != dml_rq_regs->rq_regs_l.dpte_group_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:DPTE_GROUP_SIZE - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.dpte_group_size, rq_regs.rq_regs_l.dpte_group_size); + if (rq_regs.rq_regs_l.mpte_group_size != dml_rq_regs->rq_regs_l.mpte_group_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:VM_GROUP_SIZE - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.mpte_group_size, rq_regs.rq_regs_l.mpte_group_size); + if (rq_regs.rq_regs_l.swath_height != dml_rq_regs->rq_regs_l.swath_height) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:SWATH_HEIGHT - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.swath_height, rq_regs.rq_regs_l.swath_height); + if (rq_regs.rq_regs_l.pte_row_height_linear != dml_rq_regs->rq_regs_l.pte_row_height_linear) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG_C:PTE_ROW_HEIGHT_LINEAR - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_l.pte_row_height_linear, rq_regs.rq_regs_l.pte_row_height_linear); + + if (rq_regs.rq_regs_c.chunk_size != dml_rq_regs->rq_regs_c.chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG:CHUNK_SIZE_C - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_c.chunk_size, rq_regs.rq_regs_c.chunk_size); + if (rq_regs.rq_regs_c.min_chunk_size != dml_rq_regs->rq_regs_c.min_chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG:MIN_CHUNK_SIZE_C - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_c.min_chunk_size, rq_regs.rq_regs_c.min_chunk_size); + if (rq_regs.rq_regs_c.meta_chunk_size != dml_rq_regs->rq_regs_c.meta_chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG:META_CHUNK_SIZE_C - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_c.meta_chunk_size, rq_regs.rq_regs_c.meta_chunk_size); + if (rq_regs.rq_regs_c.min_meta_chunk_size != dml_rq_regs->rq_regs_c.min_meta_chunk_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG:MIN_META_CHUNK_SIZE_C - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_c.min_meta_chunk_size, rq_regs.rq_regs_c.min_meta_chunk_size); + if (rq_regs.rq_regs_c.dpte_group_size != dml_rq_regs->rq_regs_c.dpte_group_size) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG:DPTE_GROUP_SIZE_C - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_c.dpte_group_size, rq_regs.rq_regs_c.dpte_group_size); + if (rq_regs.rq_regs_c.swath_height != dml_rq_regs->rq_regs_c.swath_height) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG:SWATH_HEIGHT_C - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_c.swath_height, rq_regs.rq_regs_c.swath_height); + if (rq_regs.rq_regs_c.pte_row_height_linear != dml_rq_regs->rq_regs_c.pte_row_height_linear) + DC_LOG_DEBUG("DML Validation | DCHUBP_REQ_SIZE_CONFIG:PTE_ROW_HEIGHT_LINEAR_C - Expected: %u Actual: %u\n", + dml_rq_regs->rq_regs_c.pte_row_height_linear, rq_regs.rq_regs_c.pte_row_height_linear); + + + /* DLG - Per hubp */ + REG_GET_2(BLANK_OFFSET_0, + REFCYC_H_BLANK_END, &dlg_attr.refcyc_h_blank_end, + DLG_V_BLANK_END, &dlg_attr.dlg_vblank_end); + REG_GET(BLANK_OFFSET_1, + MIN_DST_Y_NEXT_START, &dlg_attr.min_dst_y_next_start); + REG_GET(DST_DIMENSIONS, + REFCYC_PER_HTOTAL, &dlg_attr.refcyc_per_htotal); + REG_GET_2(DST_AFTER_SCALER, + REFCYC_X_AFTER_SCALER, &dlg_attr.refcyc_x_after_scaler, + DST_Y_AFTER_SCALER, &dlg_attr.dst_y_after_scaler); + REG_GET(REF_FREQ_TO_PIX_FREQ, + REF_FREQ_TO_PIX_FREQ, &dlg_attr.ref_freq_to_pix_freq); + + if (dlg_attr.refcyc_h_blank_end != dml_dlg_attr->refcyc_h_blank_end) + DC_LOG_DEBUG("DML Validation | BLANK_OFFSET_0:REFCYC_H_BLANK_END - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_h_blank_end, dlg_attr.refcyc_h_blank_end); + if (dlg_attr.dlg_vblank_end != dml_dlg_attr->dlg_vblank_end) + DC_LOG_DEBUG("DML Validation | BLANK_OFFSET_0:DLG_V_BLANK_END - Expected: %u Actual: %u\n", + dml_dlg_attr->dlg_vblank_end, dlg_attr.dlg_vblank_end); + if (dlg_attr.min_dst_y_next_start != dml_dlg_attr->min_dst_y_next_start) + DC_LOG_DEBUG("DML Validation | BLANK_OFFSET_1:MIN_DST_Y_NEXT_START - Expected: %u Actual: %u\n", + dml_dlg_attr->min_dst_y_next_start, dlg_attr.min_dst_y_next_start); + if (dlg_attr.refcyc_per_htotal != dml_dlg_attr->refcyc_per_htotal) + DC_LOG_DEBUG("DML Validation | DST_DIMENSIONS:REFCYC_PER_HTOTAL - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_htotal, dlg_attr.refcyc_per_htotal); + if (dlg_attr.refcyc_x_after_scaler != dml_dlg_attr->refcyc_x_after_scaler) + DC_LOG_DEBUG("DML Validation | DST_AFTER_SCALER:REFCYC_X_AFTER_SCALER - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_x_after_scaler, dlg_attr.refcyc_x_after_scaler); + if (dlg_attr.dst_y_after_scaler != dml_dlg_attr->dst_y_after_scaler) + DC_LOG_DEBUG("DML Validation | DST_AFTER_SCALER:DST_Y_AFTER_SCALER - Expected: %u Actual: %u\n", + dml_dlg_attr->dst_y_after_scaler, dlg_attr.dst_y_after_scaler); + if (dlg_attr.ref_freq_to_pix_freq != dml_dlg_attr->ref_freq_to_pix_freq) + DC_LOG_DEBUG("DML Validation | REF_FREQ_TO_PIX_FREQ:REF_FREQ_TO_PIX_FREQ - Expected: %u Actual: %u\n", + dml_dlg_attr->ref_freq_to_pix_freq, dlg_attr.ref_freq_to_pix_freq); + + /* DLG - Per luma/chroma */ + REG_GET(VBLANK_PARAMETERS_1, + REFCYC_PER_PTE_GROUP_VBLANK_L, &dlg_attr.refcyc_per_pte_group_vblank_l); + if (REG(NOM_PARAMETERS_0)) + REG_GET(NOM_PARAMETERS_0, + DST_Y_PER_PTE_ROW_NOM_L, &dlg_attr.dst_y_per_pte_row_nom_l); + if (REG(NOM_PARAMETERS_1)) + REG_GET(NOM_PARAMETERS_1, + REFCYC_PER_PTE_GROUP_NOM_L, &dlg_attr.refcyc_per_pte_group_nom_l); + REG_GET(NOM_PARAMETERS_4, + DST_Y_PER_META_ROW_NOM_L, &dlg_attr.dst_y_per_meta_row_nom_l); + REG_GET(NOM_PARAMETERS_5, + REFCYC_PER_META_CHUNK_NOM_L, &dlg_attr.refcyc_per_meta_chunk_nom_l); + REG_GET_2(PER_LINE_DELIVERY, + REFCYC_PER_LINE_DELIVERY_L, &dlg_attr.refcyc_per_line_delivery_l, + REFCYC_PER_LINE_DELIVERY_C, &dlg_attr.refcyc_per_line_delivery_c); + REG_GET_2(PER_LINE_DELIVERY_PRE, + REFCYC_PER_LINE_DELIVERY_PRE_L, &dlg_attr.refcyc_per_line_delivery_pre_l, + REFCYC_PER_LINE_DELIVERY_PRE_C, &dlg_attr.refcyc_per_line_delivery_pre_c); + REG_GET(VBLANK_PARAMETERS_2, + REFCYC_PER_PTE_GROUP_VBLANK_C, &dlg_attr.refcyc_per_pte_group_vblank_c); + if (REG(NOM_PARAMETERS_2)) + REG_GET(NOM_PARAMETERS_2, + DST_Y_PER_PTE_ROW_NOM_C, &dlg_attr.dst_y_per_pte_row_nom_c); + if (REG(NOM_PARAMETERS_3)) + REG_GET(NOM_PARAMETERS_3, + REFCYC_PER_PTE_GROUP_NOM_C, &dlg_attr.refcyc_per_pte_group_nom_c); + REG_GET(NOM_PARAMETERS_6, + DST_Y_PER_META_ROW_NOM_C, &dlg_attr.dst_y_per_meta_row_nom_c); + REG_GET(NOM_PARAMETERS_7, + REFCYC_PER_META_CHUNK_NOM_C, &dlg_attr.refcyc_per_meta_chunk_nom_c); + REG_GET(VBLANK_PARAMETERS_3, + REFCYC_PER_META_CHUNK_VBLANK_L, &dlg_attr.refcyc_per_meta_chunk_vblank_l); + REG_GET(VBLANK_PARAMETERS_4, + REFCYC_PER_META_CHUNK_VBLANK_C, &dlg_attr.refcyc_per_meta_chunk_vblank_c); + + if (dlg_attr.refcyc_per_pte_group_vblank_l != dml_dlg_attr->refcyc_per_pte_group_vblank_l) + DC_LOG_DEBUG("DML Validation | VBLANK_PARAMETERS_1:REFCYC_PER_PTE_GROUP_VBLANK_L - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_pte_group_vblank_l, dlg_attr.refcyc_per_pte_group_vblank_l); + if (dlg_attr.dst_y_per_pte_row_nom_l != dml_dlg_attr->dst_y_per_pte_row_nom_l) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_0:DST_Y_PER_PTE_ROW_NOM_L - Expected: %u Actual: %u\n", + dml_dlg_attr->dst_y_per_pte_row_nom_l, dlg_attr.dst_y_per_pte_row_nom_l); + if (dlg_attr.refcyc_per_pte_group_nom_l != dml_dlg_attr->refcyc_per_pte_group_nom_l) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_1:REFCYC_PER_PTE_GROUP_NOM_L - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_pte_group_nom_l, dlg_attr.refcyc_per_pte_group_nom_l); + if (dlg_attr.dst_y_per_meta_row_nom_l != dml_dlg_attr->dst_y_per_meta_row_nom_l) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_4:DST_Y_PER_META_ROW_NOM_L - Expected: %u Actual: %u\n", + dml_dlg_attr->dst_y_per_meta_row_nom_l, dlg_attr.dst_y_per_meta_row_nom_l); + if (dlg_attr.refcyc_per_meta_chunk_nom_l != dml_dlg_attr->refcyc_per_meta_chunk_nom_l) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_5:REFCYC_PER_META_CHUNK_NOM_L - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_meta_chunk_nom_l, dlg_attr.refcyc_per_meta_chunk_nom_l); + if (dlg_attr.refcyc_per_line_delivery_l != dml_dlg_attr->refcyc_per_line_delivery_l) + DC_LOG_DEBUG("DML Validation | PER_LINE_DELIVERY:REFCYC_PER_LINE_DELIVERY_L - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_line_delivery_l, dlg_attr.refcyc_per_line_delivery_l); + if (dlg_attr.refcyc_per_line_delivery_c != dml_dlg_attr->refcyc_per_line_delivery_c) + DC_LOG_DEBUG("DML Validation | PER_LINE_DELIVERY:REFCYC_PER_LINE_DELIVERY_C - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_line_delivery_c, dlg_attr.refcyc_per_line_delivery_c); + if (dlg_attr.refcyc_per_pte_group_vblank_c != dml_dlg_attr->refcyc_per_pte_group_vblank_c) + DC_LOG_DEBUG("DML Validation | VBLANK_PARAMETERS_2:REFCYC_PER_PTE_GROUP_VBLANK_C - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_pte_group_vblank_c, dlg_attr.refcyc_per_pte_group_vblank_c); + if (dlg_attr.dst_y_per_pte_row_nom_c != dml_dlg_attr->dst_y_per_pte_row_nom_c) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_2:DST_Y_PER_PTE_ROW_NOM_C - Expected: %u Actual: %u\n", + dml_dlg_attr->dst_y_per_pte_row_nom_c, dlg_attr.dst_y_per_pte_row_nom_c); + if (dlg_attr.refcyc_per_pte_group_nom_c != dml_dlg_attr->refcyc_per_pte_group_nom_c) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_3:REFCYC_PER_PTE_GROUP_NOM_C - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_pte_group_nom_c, dlg_attr.refcyc_per_pte_group_nom_c); + if (dlg_attr.dst_y_per_meta_row_nom_c != dml_dlg_attr->dst_y_per_meta_row_nom_c) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_6:DST_Y_PER_META_ROW_NOM_C - Expected: %u Actual: %u\n", + dml_dlg_attr->dst_y_per_meta_row_nom_c, dlg_attr.dst_y_per_meta_row_nom_c); + if (dlg_attr.refcyc_per_meta_chunk_nom_c != dml_dlg_attr->refcyc_per_meta_chunk_nom_c) + DC_LOG_DEBUG("DML Validation | NOM_PARAMETERS_7:REFCYC_PER_META_CHUNK_NOM_C - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_meta_chunk_nom_c, dlg_attr.refcyc_per_meta_chunk_nom_c); + if (dlg_attr.refcyc_per_line_delivery_pre_l != dml_dlg_attr->refcyc_per_line_delivery_pre_l) + DC_LOG_DEBUG("DML Validation | PER_LINE_DELIVERY_PRE:REFCYC_PER_LINE_DELIVERY_PRE_L - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_line_delivery_pre_l, dlg_attr.refcyc_per_line_delivery_pre_l); + if (dlg_attr.refcyc_per_line_delivery_pre_c != dml_dlg_attr->refcyc_per_line_delivery_pre_c) + DC_LOG_DEBUG("DML Validation | PER_LINE_DELIVERY_PRE:REFCYC_PER_LINE_DELIVERY_PRE_C - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_line_delivery_pre_c, dlg_attr.refcyc_per_line_delivery_pre_c); + if (dlg_attr.refcyc_per_meta_chunk_vblank_l != dml_dlg_attr->refcyc_per_meta_chunk_vblank_l) + DC_LOG_DEBUG("DML Validation | VBLANK_PARAMETERS_3:REFCYC_PER_META_CHUNK_VBLANK_L - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_meta_chunk_vblank_l, dlg_attr.refcyc_per_meta_chunk_vblank_l); + if (dlg_attr.refcyc_per_meta_chunk_vblank_c != dml_dlg_attr->refcyc_per_meta_chunk_vblank_c) + DC_LOG_DEBUG("DML Validation | VBLANK_PARAMETERS_4:REFCYC_PER_META_CHUNK_VBLANK_C - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_meta_chunk_vblank_c, dlg_attr.refcyc_per_meta_chunk_vblank_c); + + /* TTU - per hubp */ + REG_GET_2(DCN_TTU_QOS_WM, + QoS_LEVEL_LOW_WM, &ttu_attr.qos_level_low_wm, + QoS_LEVEL_HIGH_WM, &ttu_attr.qos_level_high_wm); + + if (ttu_attr.qos_level_low_wm != dml_ttu_attr->qos_level_low_wm) + DC_LOG_DEBUG("DML Validation | DCN_TTU_QOS_WM:QoS_LEVEL_LOW_WM - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_level_low_wm, ttu_attr.qos_level_low_wm); + if (ttu_attr.qos_level_high_wm != dml_ttu_attr->qos_level_high_wm) + DC_LOG_DEBUG("DML Validation | DCN_TTU_QOS_WM:QoS_LEVEL_HIGH_WM - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_level_high_wm, ttu_attr.qos_level_high_wm); + + /* TTU - per luma/chroma */ + /* Assumed surf0 is luma and 1 is chroma */ + REG_GET_3(DCN_SURF0_TTU_CNTL0, + REFCYC_PER_REQ_DELIVERY, &ttu_attr.refcyc_per_req_delivery_l, + QoS_LEVEL_FIXED, &ttu_attr.qos_level_fixed_l, + QoS_RAMP_DISABLE, &ttu_attr.qos_ramp_disable_l); + REG_GET_3(DCN_SURF1_TTU_CNTL0, + REFCYC_PER_REQ_DELIVERY, &ttu_attr.refcyc_per_req_delivery_c, + QoS_LEVEL_FIXED, &ttu_attr.qos_level_fixed_c, + QoS_RAMP_DISABLE, &ttu_attr.qos_ramp_disable_c); + REG_GET_3(DCN_CUR0_TTU_CNTL0, + REFCYC_PER_REQ_DELIVERY, &ttu_attr.refcyc_per_req_delivery_cur0, + QoS_LEVEL_FIXED, &ttu_attr.qos_level_fixed_cur0, + QoS_RAMP_DISABLE, &ttu_attr.qos_ramp_disable_cur0); + REG_GET(FLIP_PARAMETERS_1, + REFCYC_PER_PTE_GROUP_FLIP_L, &dlg_attr.refcyc_per_pte_group_flip_l); + REG_GET(DCN_CUR0_TTU_CNTL1, + REFCYC_PER_REQ_DELIVERY_PRE, &ttu_attr.refcyc_per_req_delivery_pre_cur0); + REG_GET(DCN_CUR1_TTU_CNTL1, + REFCYC_PER_REQ_DELIVERY_PRE, &ttu_attr.refcyc_per_req_delivery_pre_cur1); + REG_GET(DCN_SURF0_TTU_CNTL1, + REFCYC_PER_REQ_DELIVERY_PRE, &ttu_attr.refcyc_per_req_delivery_pre_l); + REG_GET(DCN_SURF1_TTU_CNTL1, + REFCYC_PER_REQ_DELIVERY_PRE, &ttu_attr.refcyc_per_req_delivery_pre_c); + + if (ttu_attr.refcyc_per_req_delivery_l != dml_ttu_attr->refcyc_per_req_delivery_l) + DC_LOG_DEBUG("DML Validation | DCN_SURF0_TTU_CNTL0:REFCYC_PER_REQ_DELIVERY - Expected: %u Actual: %u\n", + dml_ttu_attr->refcyc_per_req_delivery_l, ttu_attr.refcyc_per_req_delivery_l); + if (ttu_attr.qos_level_fixed_l != dml_ttu_attr->qos_level_fixed_l) + DC_LOG_DEBUG("DML Validation | DCN_SURF0_TTU_CNTL0:QoS_LEVEL_FIXED - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_level_fixed_l, ttu_attr.qos_level_fixed_l); + if (ttu_attr.qos_ramp_disable_l != dml_ttu_attr->qos_ramp_disable_l) + DC_LOG_DEBUG("DML Validation | DCN_SURF0_TTU_CNTL0:QoS_RAMP_DISABLE - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_ramp_disable_l, ttu_attr.qos_ramp_disable_l); + if (ttu_attr.refcyc_per_req_delivery_c != dml_ttu_attr->refcyc_per_req_delivery_c) + DC_LOG_DEBUG("DML Validation | DCN_SURF1_TTU_CNTL0:REFCYC_PER_REQ_DELIVERY - Expected: %u Actual: %u\n", + dml_ttu_attr->refcyc_per_req_delivery_c, ttu_attr.refcyc_per_req_delivery_c); + if (ttu_attr.qos_level_fixed_c != dml_ttu_attr->qos_level_fixed_c) + DC_LOG_DEBUG("DML Validation | DCN_SURF1_TTU_CNTL0:QoS_LEVEL_FIXED - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_level_fixed_c, ttu_attr.qos_level_fixed_c); + if (ttu_attr.qos_ramp_disable_c != dml_ttu_attr->qos_ramp_disable_c) + DC_LOG_DEBUG("DML Validation | DCN_SURF1_TTU_CNTL0:QoS_RAMP_DISABLE - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_ramp_disable_c, ttu_attr.qos_ramp_disable_c); + if (ttu_attr.refcyc_per_req_delivery_cur0 != dml_ttu_attr->refcyc_per_req_delivery_cur0) + DC_LOG_DEBUG("DML Validation | DCN_CUR0_TTU_CNTL0:REFCYC_PER_REQ_DELIVERY - Expected: %u Actual: %u\n", + dml_ttu_attr->refcyc_per_req_delivery_cur0, ttu_attr.refcyc_per_req_delivery_cur0); + if (ttu_attr.qos_level_fixed_cur0 != dml_ttu_attr->qos_level_fixed_cur0) + DC_LOG_DEBUG("DML Validation | DCN_CUR0_TTU_CNTL0:QoS_LEVEL_FIXED - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_level_fixed_cur0, ttu_attr.qos_level_fixed_cur0); + if (ttu_attr.qos_ramp_disable_cur0 != dml_ttu_attr->qos_ramp_disable_cur0) + DC_LOG_DEBUG("DML Validation | DCN_CUR0_TTU_CNTL0:QoS_RAMP_DISABLE - Expected: %u Actual: %u\n", + dml_ttu_attr->qos_ramp_disable_cur0, ttu_attr.qos_ramp_disable_cur0); + if (dlg_attr.refcyc_per_pte_group_flip_l != dml_dlg_attr->refcyc_per_pte_group_flip_l) + DC_LOG_DEBUG("DML Validation | FLIP_PARAMETERS_1:REFCYC_PER_PTE_GROUP_FLIP_L - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_pte_group_flip_l, dlg_attr.refcyc_per_pte_group_flip_l); + if (ttu_attr.refcyc_per_req_delivery_pre_cur0 != dml_ttu_attr->refcyc_per_req_delivery_pre_cur0) + DC_LOG_DEBUG("DML Validation | DCN_CUR0_TTU_CNTL1:REFCYC_PER_REQ_DELIVERY_PRE - Expected: %u Actual: %u\n", + dml_ttu_attr->refcyc_per_req_delivery_pre_cur0, ttu_attr.refcyc_per_req_delivery_pre_cur0); + if (ttu_attr.refcyc_per_req_delivery_pre_cur1 != dml_ttu_attr->refcyc_per_req_delivery_pre_cur1) + DC_LOG_DEBUG("DML Validation | DCN_CUR1_TTU_CNTL1:REFCYC_PER_REQ_DELIVERY_PRE - Expected: %u Actual: %u\n", + dml_ttu_attr->refcyc_per_req_delivery_pre_cur1, ttu_attr.refcyc_per_req_delivery_pre_cur1); + if (ttu_attr.refcyc_per_req_delivery_pre_l != dml_ttu_attr->refcyc_per_req_delivery_pre_l) + DC_LOG_DEBUG("DML Validation | DCN_SURF0_TTU_CNTL1:REFCYC_PER_REQ_DELIVERY_PRE - Expected: %u Actual: %u\n", + dml_ttu_attr->refcyc_per_req_delivery_pre_l, ttu_attr.refcyc_per_req_delivery_pre_l); + if (ttu_attr.refcyc_per_req_delivery_pre_c != dml_ttu_attr->refcyc_per_req_delivery_pre_c) + DC_LOG_DEBUG("DML Validation | DCN_SURF1_TTU_CNTL1:REFCYC_PER_REQ_DELIVERY_PRE - Expected: %u Actual: %u\n", + dml_ttu_attr->refcyc_per_req_delivery_pre_c, ttu_attr.refcyc_per_req_delivery_pre_c); + + /* Host VM deadline regs */ + REG_GET(VBLANK_PARAMETERS_5, + REFCYC_PER_VM_GROUP_VBLANK, &dlg_attr.refcyc_per_vm_group_vblank); + REG_GET(VBLANK_PARAMETERS_6, + REFCYC_PER_VM_REQ_VBLANK, &dlg_attr.refcyc_per_vm_req_vblank); + REG_GET(FLIP_PARAMETERS_3, + REFCYC_PER_VM_GROUP_FLIP, &dlg_attr.refcyc_per_vm_group_flip); + REG_GET(FLIP_PARAMETERS_4, + REFCYC_PER_VM_REQ_FLIP, &dlg_attr.refcyc_per_vm_req_flip); + REG_GET(FLIP_PARAMETERS_5, + REFCYC_PER_PTE_GROUP_FLIP_C, &dlg_attr.refcyc_per_pte_group_flip_c); + REG_GET(FLIP_PARAMETERS_6, + REFCYC_PER_META_CHUNK_FLIP_C, &dlg_attr.refcyc_per_meta_chunk_flip_c); + REG_GET(FLIP_PARAMETERS_2, + REFCYC_PER_META_CHUNK_FLIP_L, &dlg_attr.refcyc_per_meta_chunk_flip_l); + + if (dlg_attr.refcyc_per_vm_group_vblank != dml_dlg_attr->refcyc_per_vm_group_vblank) + DC_LOG_DEBUG("DML Validation | VBLANK_PARAMETERS_5:REFCYC_PER_VM_GROUP_VBLANK - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_vm_group_vblank, dlg_attr.refcyc_per_vm_group_vblank); + if (dlg_attr.refcyc_per_vm_req_vblank != dml_dlg_attr->refcyc_per_vm_req_vblank) + DC_LOG_DEBUG("DML Validation | VBLANK_PARAMETERS_6:REFCYC_PER_VM_REQ_VBLANK - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_vm_req_vblank, dlg_attr.refcyc_per_vm_req_vblank); + if (dlg_attr.refcyc_per_vm_group_flip != dml_dlg_attr->refcyc_per_vm_group_flip) + DC_LOG_DEBUG("DML Validation | FLIP_PARAMETERS_3:REFCYC_PER_VM_GROUP_FLIP - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_vm_group_flip, dlg_attr.refcyc_per_vm_group_flip); + if (dlg_attr.refcyc_per_vm_req_flip != dml_dlg_attr->refcyc_per_vm_req_flip) + DC_LOG_DEBUG("DML Validation | FLIP_PARAMETERS_4:REFCYC_PER_VM_REQ_FLIP - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_vm_req_flip, dlg_attr.refcyc_per_vm_req_flip); + if (dlg_attr.refcyc_per_pte_group_flip_c != dml_dlg_attr->refcyc_per_pte_group_flip_c) + DC_LOG_DEBUG("DML Validation | FLIP_PARAMETERS_5:REFCYC_PER_PTE_GROUP_FLIP_C - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_pte_group_flip_c, dlg_attr.refcyc_per_pte_group_flip_c); + if (dlg_attr.refcyc_per_meta_chunk_flip_c != dml_dlg_attr->refcyc_per_meta_chunk_flip_c) + DC_LOG_DEBUG("DML Validation | FLIP_PARAMETERS_6:REFCYC_PER_META_CHUNK_FLIP_C - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_meta_chunk_flip_c, dlg_attr.refcyc_per_meta_chunk_flip_c); + if (dlg_attr.refcyc_per_meta_chunk_flip_l != dml_dlg_attr->refcyc_per_meta_chunk_flip_l) + DC_LOG_DEBUG("DML Validation | FLIP_PARAMETERS_2:REFCYC_PER_META_CHUNK_FLIP_L - Expected: %u Actual: %u\n", + dml_dlg_attr->refcyc_per_meta_chunk_flip_l, dlg_attr.refcyc_per_meta_chunk_flip_l); +} + void hubp21_init(struct hubp *hubp) { // DEDCN21-133: Inconsistent row starting line for flip between DPTE and Meta @@ -211,7 +622,7 @@ static struct hubp_funcs dcn21_hubp_funcs = { .hubp_set_vm_system_aperture_settings = hubp21_set_vm_system_aperture_settings, .set_blank = hubp1_set_blank, .dcc_control = hubp1_dcc_control, - .mem_program_viewport = min_set_viewport, + .mem_program_viewport = hubp21_set_viewport, .set_cursor_attributes = hubp2_cursor_set_attributes, .set_cursor_position = hubp1_cursor_set_position, .hubp_clk_cntl = hubp1_clk_cntl, @@ -223,6 +634,7 @@ static struct hubp_funcs dcn21_hubp_funcs = { .hubp_clear_underflow = hubp1_clear_underflow, .hubp_set_flip_control_surface_gsl = hubp2_set_flip_control_surface_gsl, .hubp_init = hubp21_init, + .validate_dml_output = hubp21_validate_dml_output, }; bool hubp21_construct( diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c index b25215cadf853cb910f560ed06e568ff5493322b..081ad8e43d581519a0be5ed86aafd67c40eb6ad0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c @@ -28,7 +28,7 @@ #include "core_types.h" #include "resource.h" #include "dce/dce_hwseq.h" -#include "dcn20/dcn20_hwseq.h" +#include "dcn21_hwseq.h" #include "vmid.h" #include "reg_helper.h" #include "hw/clk_mgr.h" @@ -61,7 +61,7 @@ static void mmhub_update_page_table_config(struct dcn_hubbub_phys_addr_config *c } -static int dcn21_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) +int dcn21_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) { struct dcn_hubbub_phys_addr_config config; @@ -82,7 +82,7 @@ static int dcn21_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_ph // work around for Renoir s0i3, if register is programmed, bypass golden init. -static bool dcn21_s0i3_golden_init_wa(struct dc *dc) +bool dcn21_s0i3_golden_init_wa(struct dc *dc) { struct dce_hwseq *hws = dc->hwseq; uint32_t value = 0; @@ -112,11 +112,3 @@ void dcn21_optimize_pwr_state( true); } -void dcn21_hw_sequencer_construct(struct dc *dc) -{ - dcn20_hw_sequencer_construct(dc); - dc->hwss.init_sys_ctx = dcn21_init_sys_ctx; - dc->hwss.s0i3_golden_init_wa = dcn21_s0i3_golden_init_wa; - dc->hwss.optimize_pwr_state = dcn21_optimize_pwr_state; - dc->hwss.exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.h index be67b62e6fb1c7c3abde3f455052d1beca04a3c7..18273609612316308f41c31116b8a95e2e698908 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.h @@ -26,8 +26,22 @@ #ifndef __DC_HWSS_DCN21_H__ #define __DC_HWSS_DCN21_H__ +#include "hw_sequencer_private.h" + struct dc; -void dcn21_hw_sequencer_construct(struct dc *dc); +int dcn21_init_sys_ctx(struct dce_hwseq *hws, + struct dc *dc, + struct dc_phy_addr_space_config *pa_config); + +bool dcn21_s0i3_golden_init_wa(struct dc *dc); + +void dcn21_exit_optimized_pwr_state( + const struct dc *dc, + struct dc_state *context); + +void dcn21_optimize_pwr_state( + const struct dc *dc, + struct dc_state *context); #endif /* __DC_HWSS_DCN21_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c new file mode 100644 index 0000000000000000000000000000000000000000..4861aa5c59aefd4ba3962d14b68d0bd0ff5c88b5 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c @@ -0,0 +1,142 @@ +/* + * Copyright 2016 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: AMD + * + */ + +#include "dce110/dce110_hw_sequencer.h" +#include "dcn10/dcn10_hw_sequencer.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn21_hwseq.h" + +static const struct hw_sequencer_funcs dcn21_funcs = { + .program_gamut_remap = dcn10_program_gamut_remap, + .init_hw = dcn10_init_hw, + .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, + .update_plane_addr = dcn20_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .program_output_csc = dcn20_program_output_csc, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dce110_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, + .enable_stream = dcn20_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dcn20_unblank_stream, + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dcn20_disable_plane, + .pipe_control_lock = dcn20_pipe_control_lock, + .pipe_control_lock_global = dcn20_pipe_control_lock_global, + .prepare_bandwidth = dcn20_prepare_bandwidth, + .optimize_bandwidth = dcn20_optimize_bandwidth, + .update_bandwidth = dcn20_update_bandwidth, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn10_set_static_screen_control, + .setup_stereo = dcn10_setup_stereo, + .set_avmute = dce110_set_avmute, + .log_hw_state = dcn10_log_hw_state, + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .program_triplebuffer = dcn20_program_triple_buffer, + .enable_writeback = dcn20_enable_writeback, + .disable_writeback = dcn20_disable_writeback, + .dmdata_status_done = dcn20_dmdata_status_done, + .program_dmdata_engine = dcn20_program_dmdata_engine, + .set_dmdata_attributes = dcn20_set_dmdata_attributes, + .init_sys_ctx = dcn21_init_sys_ctx, + .init_vm_ctx = dcn20_init_vm_ctx, + .set_flip_control_gsl = dcn20_set_flip_control_gsl, + .optimize_pwr_state = dcn21_optimize_pwr_state, + .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, + .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .optimize_pwr_state = dcn21_optimize_pwr_state, + .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, +}; + +static const struct hwseq_private_funcs dcn21_private_funcs = { + .init_pipes = dcn10_init_pipes, + .update_plane_addr = dcn20_update_plane_addr, + .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, + .update_mpcc = dcn20_update_mpcc, + .set_input_transfer_func = dcn20_set_input_transfer_func, + .set_output_transfer_func = dcn20_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .blank_pixel_data = dcn20_blank_pixel_data, + .reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap, + .enable_stream_timing = dcn20_enable_stream_timing, + .edp_backlight_control = dce110_edp_backlight_control, + .disable_stream_gating = dcn20_disable_stream_gating, + .enable_stream_gating = dcn20_enable_stream_gating, + .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = dcn20_init_blank, + .disable_vga = dcn20_disable_vga, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn20_plane_atomic_disable, + .plane_atomic_power_down = dcn10_plane_atomic_power_down, + .enable_power_gating_plane = dcn20_enable_power_gating_plane, + .dpp_pg_control = dcn20_dpp_pg_control, + .hubp_pg_control = dcn20_hubp_pg_control, + .dsc_pg_control = NULL, + .update_odm = dcn20_update_odm, + .dsc_pg_control = dcn20_dsc_pg_control, + .get_surface_visual_confirm_color = dcn10_get_surface_visual_confirm_color, + .get_hdr_visual_confirm_color = dcn10_get_hdr_visual_confirm_color, + .set_hdr_multiplier = dcn10_set_hdr_multiplier, + .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, + .s0i3_golden_init_wa = dcn21_s0i3_golden_init_wa, + .wait_for_blank_complete = dcn20_wait_for_blank_complete, + .dccg_init = dcn20_dccg_init, + .set_blend_lut = dcn20_set_blend_lut, + .set_shaper_3dlut = dcn20_set_shaper_3dlut, +}; + +void dcn21_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dcn21_funcs; + dc->hwseq->funcs = dcn21_private_funcs; + + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + dc->hwss.init_hw = dcn20_fpga_init_hw; + dc->hwseq->funcs.init_pipes = NULL; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.h b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.h new file mode 100644 index 0000000000000000000000000000000000000000..3ed24292648a4f59b80ea09c0f2b9f0fe432fa99 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.h @@ -0,0 +1,33 @@ +/* + * Copyright 2016 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: AMD + * + */ + +#ifndef __DC_DCN21_INIT_H__ +#define __DC_DCN21_INIT_H__ + +struct dc; + +void dcn21_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN20_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_link_encoder.c index e8a504ca5890163c23b5d73d67b20a0dcbdf9ea6..e45683ac871a2ba86d898bab5175ad10393db0cd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_link_encoder.c @@ -323,9 +323,7 @@ void dcn21_link_encoder_disable_output( static const struct link_encoder_funcs dcn21_link_enc_funcs = { -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT .read_state = link_enc2_read_state, -#endif .validate_output_with_stream = dcn10_link_encoder_validate_output_with_stream, .hw_init = enc2_hw_init, 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 459bd9a5caed54dbdb1cffcbe2ea7dc8ba70ff7c..c865b95d5c0e82cf9b3b484f1aa9dd05fd0f3cfc 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c @@ -23,9 +23,13 @@ * */ +#include + #include "dm_services.h" #include "dc.h" +#include "dcn21_init.h" + #include "resource.h" #include "include/irq_service_interface.h" #include "dcn20/dcn20_resource.h" @@ -88,11 +92,7 @@ struct _vcs_dpi_ip_params_st dcn2_1_ip = { .gpuvm_max_page_table_levels = 1, .hostvm_max_page_table_levels = 4, .hostvm_cached_page_table_levels = 2, -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT .num_dsc = 3, -#else - .num_dsc = 0, -#endif .rob_buffer_size_kbytes = 168, .det_buffer_size_kbytes = 164, .dpte_buffer_size_in_pte_reqs_luma = 44, @@ -257,7 +257,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn2_1_soc = { .vmm_page_size_bytes = 4096, .dram_clock_change_latency_us = 23.84, .return_bus_width_bytes = 64, - .dispclk_dppclk_vco_speed_mhz = 3550, + .dispclk_dppclk_vco_speed_mhz = 3600, .xfc_bus_transport_time_us = 4, .xfc_xbuf_latency_tolerance_us = 4, .use_urgent_burst_bw = 1, @@ -350,7 +350,7 @@ static const struct bios_registers bios_regs = { }; static const struct dce_dmcu_registers dmcu_regs = { - DMCU_DCN10_REG_LIST() + DMCU_DCN20_REG_LIST() }; static const struct dce_dmcu_shift dmcu_shift = { @@ -373,20 +373,6 @@ static const struct dce_abm_mask abm_mask = { ABM_MASK_SH_LIST_DCN20(_MASK) }; -#ifdef CONFIG_DRM_AMD_DC_DMUB -static const struct dcn21_dmcub_registers dmcub_regs = { - DMCUB_REG_LIST_DCN() -}; - -static const struct dcn21_dmcub_shift dmcub_shift = { - DMCUB_COMMON_MASK_SH_LIST_BASE(__SHIFT) -}; - -static const struct dcn21_dmcub_mask dmcub_mask = { - DMCUB_COMMON_MASK_SH_LIST_BASE(_MASK) -}; -#endif - #define audio_regs(id)\ [id] = {\ AUD_COMMON_REG_LIST(id)\ @@ -552,7 +538,6 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #define dsc_regsDCN20(id)\ [id] = {\ DSC_REG_LIST_DCN20(id)\ @@ -574,7 +559,6 @@ static const struct dcn20_dsc_shift dsc_shift = { static const struct dcn20_dsc_mask dsc_mask = { DSC_REG_LIST_SH_MASK_DCN20(_MASK) }; -#endif #define ipp_regs(id)\ [id] = {\ @@ -670,7 +654,7 @@ static const struct dcn10_stream_encoder_mask se_mask = { static void dcn21_pp_smu_destroy(struct pp_smu_funcs **pp_smu); static int dcn21_populate_dml_pipes_from_context( - struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes); + struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes); static struct input_pixel_processor *dcn21_ipp_create( struct dc_context *ctx, uint32_t inst) @@ -771,9 +755,7 @@ static const struct resource_caps res_cap_rn = { .num_dwb = 1, .num_ddc = 5, .num_vmid = 1, -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT .num_dsc = 3, -#endif }; #ifdef DIAGS_BUILD @@ -798,9 +780,7 @@ static const struct resource_caps res_cap_rn_FPGA_2pipe_dsc = { .num_pll = 4, .num_dwb = 1, .num_ddc = 4, -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT .num_dsc = 2, -#endif }; #endif @@ -845,6 +825,7 @@ static const struct dc_debug_options debug_defaults_drv = { .scl_reset_length10 = true, .sanity_checks = true, .disable_48mhz_pwrdwn = false, + .nv12_iflip_vm_wa = true }; static const struct dc_debug_options debug_defaults_diags = { @@ -867,7 +848,7 @@ enum dcn20_clk_src_array_id { DCN20_CLK_SRC_TOTAL_DCN21 }; -static void destruct(struct dcn21_resource_pool *pool) +static void dcn21_resource_destruct(struct dcn21_resource_pool *pool) { unsigned int i; @@ -878,12 +859,10 @@ static void destruct(struct dcn21_resource_pool *pool) } } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT for (i = 0; i < pool->base.res_cap->num_dsc; i++) { if (pool->base.dscs[i] != NULL) dcn20_dsc_destroy(&pool->base.dscs[i]); } -#endif if (pool->base.mpc != NULL) { kfree(TO_DCN20_MPC(pool->base.mpc)); @@ -970,11 +949,6 @@ static void destruct(struct dcn21_resource_pool *pool) if (pool->base.dmcu != NULL) dce_dmcu_destroy(&pool->base.dmcu); -#ifdef CONFIG_DRM_AMD_DC_DMUB - if (pool->base.dmcub != NULL) - dcn21_dmcub_destroy(&pool->base.dmcub); -#endif - if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); @@ -1000,31 +974,38 @@ static void calculate_wm_set_for_vlevel( pipes[0].clks_cfg.socclk_mhz = dml->soc.clock_limits[vlevel].socclk_mhz; dml->soc.dram_clock_change_latency_us = table_entry->pstate_latency_us; + dml->soc.sr_exit_time_us = table_entry->sr_exit_time_us; + dml->soc.sr_enter_plus_exit_time_us = table_entry->sr_enter_plus_exit_time_us; wm_set->urgent_ns = get_wm_urgent(dml, pipes, pipe_cnt) * 1000; wm_set->cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(dml, pipes, pipe_cnt) * 1000; wm_set->cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(dml, pipes, pipe_cnt) * 1000; wm_set->cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(dml, pipes, pipe_cnt) * 1000; wm_set->pte_meta_urgent_ns = get_wm_memory_trip(dml, pipes, pipe_cnt) * 1000; -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) wm_set->frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(dml, pipes, pipe_cnt) * 1000; wm_set->frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(dml, pipes, pipe_cnt) * 1000; wm_set->urgent_latency_ns = get_urgent_latency(dml, pipes, pipe_cnt) * 1000; -#endif dml->soc.dram_clock_change_latency_us = dram_clock_change_latency_cached; } static void patch_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *bb) { + int i; + kernel_fpu_begin(); if (dc->bb_overrides.sr_exit_time_ns) { - bb->sr_exit_time_us = dc->bb_overrides.sr_exit_time_ns / 1000.0; + for (i = 0; i < WM_SET_COUNT; i++) { + dc->clk_mgr->bw_params->wm_table.entries[i].sr_exit_time_us = + dc->bb_overrides.sr_exit_time_ns / 1000.0; + } } if (dc->bb_overrides.sr_enter_plus_exit_time_ns) { - bb->sr_enter_plus_exit_time_us = - dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0; + for (i = 0; i < WM_SET_COUNT; i++) { + dc->clk_mgr->bw_params->wm_table.entries[i].sr_enter_plus_exit_time_us = + dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0; + } } if (dc->bb_overrides.urgent_latency_ns) { @@ -1032,9 +1013,12 @@ static void patch_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_s } if (dc->bb_overrides.dram_clock_change_latency_ns) { - bb->dram_clock_change_latency_us = + for (i = 0; i < WM_SET_COUNT; i++) { + dc->clk_mgr->bw_params->wm_table.entries[i].pstate_latency_us = dc->bb_overrides.dram_clock_change_latency_ns / 1000.0; + } } + kernel_fpu_end(); } @@ -1085,10 +1069,10 @@ void dcn21_calculate_wm( if (pipe_cnt != pipe_idx) { if (dc->res_pool->funcs->populate_dml_pipes) pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, - &context->res_ctx, pipes); + context, pipes); else pipe_cnt = dcn21_populate_dml_pipes_from_context(dc, - &context->res_ctx, pipes); + context, pipes); } *out_pipe_cnt = pipe_cnt; @@ -1178,7 +1162,7 @@ static void dcn21_destroy_resource_pool(struct resource_pool **pool) { struct dcn21_resource_pool *dcn21_pool = TO_DCN21_RES_POOL(*pool); - destruct(dcn21_pool); + dcn21_resource_destruct(dcn21_pool); kfree(dcn21_pool); *pool = NULL; } @@ -1317,7 +1301,6 @@ static void read_dce_straps( } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT struct display_stream_compressor *dcn21_dsc_create( struct dc_context *ctx, uint32_t inst) @@ -1333,7 +1316,6 @@ struct display_stream_compressor *dcn21_dsc_create( dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); return &dsc->base; } -#endif static void update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) { @@ -1625,10 +1607,11 @@ static uint32_t read_pipe_fuses(struct dc_context *ctx) } static int dcn21_populate_dml_pipes_from_context( - struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes) + struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes) { - uint32_t pipe_cnt = dcn20_populate_dml_pipes_from_context(dc, res_ctx, pipes); + uint32_t pipe_cnt = dcn20_populate_dml_pipes_from_context(dc, context, pipes); int i; + struct resource_context *res_ctx = &context->res_ctx; for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -1657,7 +1640,7 @@ static struct resource_funcs dcn21_res_pool_funcs = { .update_bw_bounding_box = update_bw_bounding_box }; -static bool construct( +static bool dcn21_resource_construct( uint8_t num_virtual_links, struct dc *dc, struct dcn21_resource_pool *pool) @@ -1697,6 +1680,7 @@ static bool construct( dc->caps.post_blend_color_processing = true; dc->caps.force_dp_tps4_for_cp2520 = true; dc->caps.extended_aux_timeout_support = true; + dc->caps.dmcub_support = true; if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) dc->debug = debug_defaults_drv; @@ -1746,7 +1730,7 @@ static bool construct( goto create_fail; } - pool->base.dmcu = dcn20_dmcu_create(ctx, + pool->base.dmcu = dcn21_dmcu_create(ctx, &dmcu_regs, &dmcu_shift, &dmcu_mask); @@ -1766,18 +1750,6 @@ static bool construct( goto create_fail; } -#ifdef CONFIG_DRM_AMD_DC_DMUB - pool->base.dmcub = dcn21_dmcub_create(ctx, - &dmcub_regs, - &dmcub_shift, - &dmcub_mask); - if (pool->base.dmcub == NULL) { - dm_error("DC: failed to create dmcub!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } -#endif - pool->base.pp_smu = dcn21_pp_smu_create(ctx); num_pipes = dcn2_1_ip.max_num_dpp; @@ -1882,7 +1854,6 @@ static bool construct( goto create_fail; } -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT for (i = 0; i < pool->base.res_cap->num_dsc; i++) { pool->base.dscs[i] = dcn21_dsc_create(ctx, i); if (pool->base.dscs[i] == NULL) { @@ -1891,7 +1862,6 @@ static bool construct( goto create_fail; } } -#endif if (!dcn20_dwbc_create(ctx, &pool->base)) { BREAK_TO_DEBUGGER(); @@ -1922,7 +1892,7 @@ static bool construct( create_fail: - destruct(pool); + dcn21_resource_destruct(pool); return false; } @@ -1937,7 +1907,7 @@ struct resource_pool *dcn21_create_resource_pool( if (!pool) return NULL; - if (construct(init_data->num_virtual_links, dc, pool)) + if (dcn21_resource_construct(init_data->num_virtual_links, dc, pool)) return &pool->base; BREAK_TO_DEBUGGER(); diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h index 94b75e9426074ebd345b702161de4e7e2ac0b930..8bde1d688f2e6f81d5f1ec9df2b85f296dd6a37c 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h +++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h @@ -118,13 +118,11 @@ bool dm_helpers_submit_i2c( const struct dc_link *link, struct i2c_command *cmd); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT bool dm_helpers_dp_write_dsc_enable( struct dc_context *ctx, const struct dc_stream_state *stream, bool enable ); -#endif bool dm_helpers_is_dp_sink_present( struct dc_link *link); diff --git a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h index ef7df9ef6d7ecca72dbba56dce77ee2745c26485..ae608c329366d5acc56e9a0971ef3159d440d972 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h +++ b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h @@ -41,12 +41,8 @@ enum pp_smu_ver { */ PP_SMU_UNSUPPORTED, PP_SMU_VER_RV, -#ifndef CONFIG_TRIM_DRM_AMD_DC_DCN2_0 PP_SMU_VER_NV, -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) PP_SMU_VER_RN, -#endif PP_SMU_VER_MAX }; @@ -143,7 +139,6 @@ struct pp_smu_funcs_rv { void (*set_pme_wa_enable)(struct pp_smu *pp); }; -#ifndef CONFIG_TRIM_DRM_AMD_DC_DCN2_0 /* Used by pp_smu_funcs_nv.set_voltage_by_freq * */ @@ -247,7 +242,6 @@ struct pp_smu_funcs_nv { enum pp_smu_status (*set_pstate_handshake_support)(struct pp_smu *pp, BOOLEAN pstate_handshake_supported); }; -#endif #define PP_SMU_NUM_SOCCLK_DPM_LEVELS 8 #define PP_SMU_NUM_DCFCLK_DPM_LEVELS 8 @@ -291,12 +285,8 @@ struct pp_smu_funcs { struct pp_smu ctx; union { struct pp_smu_funcs_rv rv_funcs; -#ifndef CONFIG_TRIM_DRM_AMD_DC_DCN2_0 struct pp_smu_funcs_nv nv_funcs; -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) struct pp_smu_funcs_rn rn_funcs; -#endif }; }; diff --git a/drivers/gpu/drm/amd/display/dc/dm_services.h b/drivers/gpu/drm/amd/display/dc/dm_services.h index 1a0429744630475252521373a40aa2ec922c6b25..968ff1fef486d76274fed8973b5b74844c85df9c 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_services.h +++ b/drivers/gpu/drm/amd/display/dc/dm_services.h @@ -40,6 +40,9 @@ #undef DEPRECATED +struct dmub_srv; +struct dc_dmub_srv; + irq_handler_idx dm_register_interrupt( struct dc_context *ctx, struct dc_interrupt_params *int_params, @@ -139,6 +142,13 @@ uint32_t generic_reg_update_ex(const struct dc_context *ctx, uint32_t addr, int n, uint8_t shift1, uint32_t mask1, uint32_t field_value1, ...); +struct dc_dmub_srv *dc_dmub_srv_create(struct dc *dc, struct dmub_srv *dmub); +void dc_dmub_srv_destroy(struct dc_dmub_srv **dmub_srv); + +void reg_sequence_start_gather(const struct dc_context *ctx); +void reg_sequence_start_execute(const struct dc_context *ctx); +void reg_sequence_wait_done(const struct dc_context *ctx); + #define FD(reg_field) reg_field ## __SHIFT, \ reg_field ## _MASK diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index 8df251626e22bf10fd3e8924bea490850b04b228..fb6358036be8d4562ddec35938f9e3742a84b4be 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -43,14 +43,12 @@ endif CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags) -ifdef CONFIG_DRM_AMD_DC_DCN2_0 +ifdef CONFIG_DRM_AMD_DC_DCN CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_rq_dlg_calc_20.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20v2.o := $(dml_ccflags) CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_rq_dlg_calc_20v2.o := $(dml_ccflags) -endif -ifdef CONFIG_DRM_AMD_DC_DCN2_1 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) endif @@ -61,11 +59,9 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dml_common_defs.o := $(dml_ccflags) DML = display_mode_lib.o display_rq_dlg_helpers.o dml1_display_rq_dlg_calc.o \ dml_common_defs.o -ifdef CONFIG_DRM_AMD_DC_DCN2_0 +ifdef CONFIG_DRM_AMD_DC_DCN DML += display_mode_vba.o dcn20/display_rq_dlg_calc_20.o dcn20/display_mode_vba_20.o DML += dcn20/display_rq_dlg_calc_20v2.o dcn20/display_mode_vba_20v2.o -endif -ifdef CONFIG_DRM_AMD_DC_DCN2_1 DML += dcn21/display_rq_dlg_calc_21.o dcn21/display_mode_vba_21.o endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c index 6c6c486b774a4ea8d043ba8cae61a4ac6a36cbd9..3b224b155e8cf09b1a21a138fdf4a0fbc170d88d 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c @@ -2577,7 +2577,8 @@ static void dml20_DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPer mode_lib->vba.MinActiveDRAMClockChangeMargin + mode_lib->vba.DRAMClockChangeLatency; - if (mode_lib->vba.MinActiveDRAMClockChangeMargin > 50) { + if (mode_lib->vba.DRAMClockChangeSupportsVActive && + mode_lib->vba.MinActiveDRAMClockChangeMargin > 60) { mode_lib->vba.DRAMClockChangeWatermark += 25; mode_lib->vba.DRAMClockChangeSupport[0][0] = dm_dram_clock_change_vactive; } else { diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c index 3c70dd577292158b4c59f2e34493140702d8fbd7..6482d7b99bae19769212d92dc4ddad5e01377239 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c @@ -2611,9 +2611,13 @@ static void dml20v2_DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndP mode_lib->vba.MinActiveDRAMClockChangeMargin + mode_lib->vba.DRAMClockChangeLatency; - if (mode_lib->vba.MinActiveDRAMClockChangeMargin > 50) { + if (mode_lib->vba.DRAMClockChangeSupportsVActive && + mode_lib->vba.MinActiveDRAMClockChangeMargin > 60) { mode_lib->vba.DRAMClockChangeWatermark += 25; mode_lib->vba.DRAMClockChangeSupport[0][0] = dm_dram_clock_change_vactive; + } else if (mode_lib->vba.DummyPStateCheck && + mode_lib->vba.MinActiveDRAMClockChangeMargin > 0) { + mode_lib->vba.DRAMClockChangeSupport[0][0] = dm_dram_clock_change_vactive; } else { if (mode_lib->vba.SynchronizedVBlank || mode_lib->vba.NumberOfActivePlanes == 1) { mode_lib->vba.DRAMClockChangeSupport[0][0] = dm_dram_clock_change_vblank; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c index 2c7455e22a65569884f8c86740f49c17e0293508..9df24ececcecb080dceed8d66d9f91baa8fea437 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c @@ -929,8 +929,7 @@ static void dml20_rq_dlg_get_dlg_params(struct display_mode_lib *mode_lib, min_dst_y_ttu_vblank = min_ttu_vblank * pclk_freq_in_mhz / (double) htotal; dlg_vblank_start = interlaced ? (vblank_start / 2) : vblank_start; - disp_dlg_regs->min_dst_y_next_start = (unsigned int) (((double) dlg_vblank_start - + min_dst_y_ttu_vblank) * dml_pow(2, 2)); + disp_dlg_regs->min_dst_y_next_start = (unsigned int) ((double) dlg_vblank_start * dml_pow(2, 2)); ASSERT(disp_dlg_regs->min_dst_y_next_start < (unsigned int) dml_pow(2, 18)); dml_print("DML_DLG: %s: min_dcfclk_mhz = %3.2f\n", diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c index ba77957aefe38361c4d19fb0bfcd4453a16d8b56..945291d5ad985762652d90bad39ab01a251a4d9c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c @@ -23,7 +23,6 @@ * */ -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 #include "../display_mode_lib.h" #include "../dml_inline_defs.h" @@ -6126,4 +6125,3 @@ static double CalculateExtraLatency( return CalculateExtraLatency; } -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c index a1f207cbb96688f776f77d9af4eb08520303192a..e60af383b4db92408d44bcb3630d21be66a2f63e 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c @@ -23,7 +23,6 @@ * */ -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 #include "../display_mode_lib.h" #include "../display_mode_vba.h" @@ -1523,8 +1522,8 @@ static void dml_rq_dlg_get_dlg_params( disp_dlg_regs->refcyc_per_vm_group_vblank = get_refcyc_per_vm_group_vblank(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; disp_dlg_regs->refcyc_per_vm_group_flip = get_refcyc_per_vm_group_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; - disp_dlg_regs->refcyc_per_vm_req_vblank = get_refcyc_per_vm_req_vblank(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz;; - disp_dlg_regs->refcyc_per_vm_req_flip = get_refcyc_per_vm_req_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz;; + disp_dlg_regs->refcyc_per_vm_req_vblank = get_refcyc_per_vm_req_vblank(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; + disp_dlg_regs->refcyc_per_vm_req_flip = get_refcyc_per_vm_req_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // Clamp to max for now if (disp_dlg_regs->refcyc_per_vm_group_vblank >= (unsigned int)dml_pow(2, 23)) @@ -1820,4 +1819,3 @@ static void calculate_ttu_cursor( } } -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h index 1c97083b8d0b7718cbddfcb858ec36201f11b7ac..55d4cb23a073a141ebe72d70a31471358ee213ac 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h @@ -135,9 +135,7 @@ enum dm_validation_status { DML_FAIL_DIO_SUPPORT, DML_FAIL_NOT_ENOUGH_DSC, DML_FAIL_DSC_CLK_REQUIRED, -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT DML_FAIL_DSC_VALIDATION_FAILURE, -#endif DML_FAIL_URGENT_LATENCY, DML_FAIL_REORDERING_BUFFER, DML_FAIL_DISPCLK_DPPCLK, diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c index 704efefdcba8cb84c9236b58dc945f1777b424ee..2689401a03a327a87a8e000bae6a2a5fe91a733f 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c @@ -25,18 +25,13 @@ #include "display_mode_lib.h" #include "dc_features.h" -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "dcn20/display_mode_vba_20.h" #include "dcn20/display_rq_dlg_calc_20.h" #include "dcn20/display_mode_vba_20v2.h" #include "dcn20/display_rq_dlg_calc_20v2.h" -#endif -#ifdef CONFIG_DRM_AMD_DC_DCN2_1 #include "dcn21/display_mode_vba_21.h" #include "dcn21/display_rq_dlg_calc_21.h" -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) const struct dml_funcs dml20_funcs = { .validate = dml20_ModeSupportAndSystemConfigurationFull, .recalculate = dml20_recalculate, @@ -50,16 +45,13 @@ const struct dml_funcs dml20v2_funcs = { .rq_dlg_get_dlg_reg = dml20v2_rq_dlg_get_dlg_reg, .rq_dlg_get_rq_reg = dml20v2_rq_dlg_get_rq_reg }; -#endif -#ifdef CONFIG_DRM_AMD_DC_DCN2_1 const struct dml_funcs dml21_funcs = { .validate = dml21_ModeSupportAndSystemConfigurationFull, .recalculate = dml21_recalculate, .rq_dlg_get_dlg_reg = dml21_rq_dlg_get_dlg_reg, .rq_dlg_get_rq_reg = dml21_rq_dlg_get_rq_reg }; -#endif void dml_init_instance(struct display_mode_lib *lib, const struct _vcs_dpi_soc_bounding_box_st *soc_bb, @@ -70,19 +62,15 @@ void dml_init_instance(struct display_mode_lib *lib, lib->ip = *ip_params; lib->project = project; switch (project) { -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 case DML_PROJECT_NAVI10: lib->funcs = dml20_funcs; break; case DML_PROJECT_NAVI10v2: lib->funcs = dml20v2_funcs; break; -#endif -#ifdef CONFIG_DRM_AMD_DC_DCN2_1 case DML_PROJECT_DCN21: lib->funcs = dml21_funcs; break; -#endif default: break; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h index d8c59aa356b6426c4a654e6e87f9b03219a4bda0..cf2758ca5b02f0608bf9ecc45588f323efe867e5 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h @@ -27,20 +27,14 @@ #include "dml_common_defs.h" -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 #include "display_mode_vba.h" -#endif enum dml_project { DML_PROJECT_UNDEFINED, DML_PROJECT_RAVEN1, -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 DML_PROJECT_NAVI10, DML_PROJECT_NAVI10v2, -#endif -#ifdef CONFIG_DRM_AMD_DC_DCN2_1 DML_PROJECT_DCN21, -#endif }; struct display_mode_lib; @@ -70,9 +64,7 @@ struct display_mode_lib { struct _vcs_dpi_ip_params_st ip; struct _vcs_dpi_soc_bounding_box_st soc; enum dml_project project; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 struct vba_vars_st vba; -#endif struct dal_logger *logger; struct dml_funcs funcs; }; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h index cfacd602746756a8563a9d476bbd841eae5c78a2..220d5e610f1f5812186040c4965ade41229de988 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h @@ -99,6 +99,7 @@ struct _vcs_dpi_soc_bounding_box_st { unsigned int num_chans; unsigned int vmm_page_size_bytes; unsigned int hostvm_min_page_size_bytes; + unsigned int gpuvm_min_page_size_bytes; double dram_clock_change_latency_us; double dummy_pstate_latency_us; double writeback_dram_clock_change_latency_us; @@ -112,6 +113,7 @@ struct _vcs_dpi_soc_bounding_box_st { bool do_urgent_latency_adjustment; double urgent_latency_adjustment_fabric_clock_component_us; double urgent_latency_adjustment_fabric_clock_reference_mhz; + bool disable_dram_clock_change_vactive_support; }; struct _vcs_dpi_ip_params_st { @@ -145,7 +147,6 @@ struct _vcs_dpi_ip_params_st { unsigned int writeback_interface_buffer_size_kbytes; unsigned int writeback_line_buffer_buffer_size; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 unsigned int writeback_10bpc420_supported; double writeback_max_hscl_ratio; double writeback_max_vscl_ratio; @@ -155,7 +156,6 @@ struct _vcs_dpi_ip_params_st { unsigned int writeback_max_vscl_taps; unsigned int writeback_line_buffer_luma_buffer_size; unsigned int writeback_line_buffer_chroma_buffer_size; -#endif unsigned int max_page_table_levels; unsigned int max_num_dpp; @@ -225,6 +225,7 @@ struct _vcs_dpi_display_pipe_source_params_st { int source_scan; int sw_mode; int macro_tile_size; + unsigned int surface_height_y; unsigned int viewport_width; unsigned int viewport_height; unsigned int viewport_y_y; @@ -401,6 +402,7 @@ struct _vcs_dpi_display_rq_misc_params_st { struct _vcs_dpi_display_rq_params_st { unsigned char yuv420; unsigned char yuv420_10bpc; + unsigned char rgbe_alpha; display_rq_misc_params_st misc; display_rq_sizing_params_st sizing; display_rq_dlg_params_st dlg; 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 7f9a5621922f7d61d42aa480a0ef98ddb4e2a1b2..15b72a8b5174f5759eb892bbb5d04fdfd9371373 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 @@ -23,7 +23,6 @@ * */ -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 #include "display_mode_lib.h" #include "display_mode_vba.h" @@ -222,13 +221,17 @@ static void fetch_socbb_params(struct display_mode_lib *mode_lib) mode_lib->vba.SRExitTime = soc->sr_exit_time_us; mode_lib->vba.SREnterPlusExitTime = soc->sr_enter_plus_exit_time_us; mode_lib->vba.DRAMClockChangeLatency = soc->dram_clock_change_latency_us; + mode_lib->vba.DummyPStateCheck = soc->dram_clock_change_latency_us == soc->dummy_pstate_latency_us; + mode_lib->vba.DRAMClockChangeSupportsVActive = !soc->disable_dram_clock_change_vactive_support || + mode_lib->vba.DummyPStateCheck; + mode_lib->vba.Downspreading = soc->downspread_percent; mode_lib->vba.DRAMChannelWidth = soc->dram_channel_width_bytes; // new! mode_lib->vba.FabricDatapathToDCNDataReturn = soc->fabric_datapath_to_dcn_data_return_bytes; // new! mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading = soc->dcn_downspread_percent; // new mode_lib->vba.DISPCLKDPPCLKVCOSpeed = soc->dispclk_dppclk_vco_speed_mhz; // new mode_lib->vba.VMMPageSize = soc->vmm_page_size_bytes; - mode_lib->vba.GPUVMMinPageSize = soc->vmm_page_size_bytes / 1024; + mode_lib->vba.GPUVMMinPageSize = soc->gpuvm_min_page_size_bytes / 1024; mode_lib->vba.HostVMMinPageSize = soc->hostvm_min_page_size_bytes / 1024; // Set the voltage scaling clocks as the defaults. Most of these will // be set to different values by the test @@ -858,4 +861,3 @@ double CalculateWriteBackDISPCLK( return CalculateWriteBackDISPCLK; } -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h index 1540ffbe3979b91d7415b71243eb6414557559d7..3eb657ed57149641bef11179e81843c8f2e959e0 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h @@ -23,7 +23,6 @@ * */ -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 #ifndef __DML2_DISPLAY_MODE_VBA_H__ #define __DML2_DISPLAY_MODE_VBA_H__ @@ -155,6 +154,8 @@ struct vba_vars_st { double UrgentLatencySupportUsChroma; unsigned int DSCFormatFactor; + bool DummyPStateCheck; + bool DRAMClockChangeSupportsVActive; bool PrefetchModeSupported; enum self_refresh_affinity AllowDRAMSelfRefreshOrDRAMClockChangeInVblank; // Mode Support only double XFCRemoteSurfaceFlipDelay; @@ -870,4 +871,3 @@ double CalculateWriteBackDISPCLK( unsigned int WritebackChromaLineBufferWidth); #endif /* _DML2_DISPLAY_MODE_VBA_H_ */ -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dsc/Makefile b/drivers/gpu/drm/amd/display/dc/dsc/Makefile index 970737217e53a18ee4331e3cc3aa570c63a79780..641ffb7cfaed4dbc739a707176e07baa08b65268 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dsc/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT # # Makefile for the 'dsc' sub-component of DAL. 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 e60f760585e460ff0f4d5c1cc40473cd13463d1c..d2423ad1fac2ef228858d39ad9ae266a62f7926d 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c @@ -22,27 +22,10 @@ * Author: AMD */ -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #include "dc_hw_types.h" #include "dsc.h" #include - -struct dc_dsc_policy { - bool use_min_slices_h; - int max_slices_h; // Maximum available if 0 - int min_sice_height; // Must not be less than 8 - int max_target_bpp; - int min_target_bpp; // Minimum target bits per pixel -}; - -const struct dc_dsc_policy dsc_policy = { - .use_min_slices_h = true, // DSC Policy: Use minimum number of slices that fits the pixel clock - .max_slices_h = 0, // DSC Policy: Use max available slices (in our case 4 for or 8, depending on the mode) - .min_sice_height = 108, // DSC Policy: Use slice height recommended by VESA DSC Spreadsheet user guide - .max_target_bpp = 16, - .min_target_bpp = 8, -}; - +#include "dc.h" /* This module's internal functions */ @@ -237,8 +220,11 @@ static void get_dsc_enc_caps( // This is a static HW query, so we can use any DSC memset(dsc_enc_caps, 0, sizeof(struct dsc_enc_caps)); - if (dsc) + if (dsc) { dsc->funcs->dsc_get_enc_caps(dsc_enc_caps, pixel_clock_100Hz); + if (dsc->ctx->dc->debug.native422_support) + dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 1; + } } /* Returns 'false' if no intersection was found for at least one capablity. @@ -578,9 +564,11 @@ static bool setup_dsc_config( bool is_dsc_possible = false; int pic_height; int slice_height; + struct dc_dsc_policy policy; memset(dsc_cfg, 0, sizeof(struct dc_dsc_config)); + dc_dsc_get_policy_for_timing(timing, &policy); pic_width = timing->h_addressable + timing->h_border_left + timing->h_border_right; pic_height = timing->v_addressable + timing->v_border_top + timing->v_border_bottom; @@ -596,7 +584,12 @@ static bool setup_dsc_config( goto done; if (target_bandwidth_kbps > 0) { - is_dsc_possible = decide_dsc_target_bpp_x16(&dsc_policy, &dsc_common_caps, target_bandwidth_kbps, timing, &target_bpp); + is_dsc_possible = decide_dsc_target_bpp_x16( + &policy, + &dsc_common_caps, + target_bandwidth_kbps, + timing, + &target_bpp); dsc_cfg->bits_per_pixel = target_bpp; } if (!is_dsc_possible) @@ -698,20 +691,20 @@ static bool setup_dsc_config( if (!is_dsc_possible) goto done; - if (dsc_policy.use_min_slices_h) { + if (policy.use_min_slices_h) { if (min_slices_h > 0) num_slices_h = min_slices_h; else if (max_slices_h > 0) { // Fall back to max slices if min slices is not working out - if (dsc_policy.max_slices_h) - num_slices_h = min(dsc_policy.max_slices_h, max_slices_h); + if (policy.max_slices_h) + num_slices_h = min(policy.max_slices_h, max_slices_h); else num_slices_h = max_slices_h; } else is_dsc_possible = false; } else { if (max_slices_h > 0) { - if (dsc_policy.max_slices_h) - num_slices_h = min(dsc_policy.max_slices_h, max_slices_h); + if (policy.max_slices_h) + num_slices_h = min(policy.max_slices_h, max_slices_h); else num_slices_h = max_slices_h; } else if (min_slices_h > 0) // Fall back to min slices if max slices is not possible @@ -733,7 +726,7 @@ static bool setup_dsc_config( // Slice height (i.e. number of slices per column): start with policy and pick the first one that height is divisible by. // For 4:2:0 make sure the slice height is divisible by 2 as well. if (min_slice_height_override == 0) - slice_height = min(dsc_policy.min_sice_height, pic_height); + slice_height = min(policy.min_slice_height, pic_height); else slice_height = min(min_slice_height_override, pic_height); @@ -903,4 +896,62 @@ bool dc_dsc_compute_config( timing, dsc_min_slice_height_override, dsc_cfg); return is_dsc_possible; } -#endif /* CONFIG_DRM_AMD_DC_DSC_SUPPORT */ + +void dc_dsc_get_policy_for_timing(const struct dc_crtc_timing *timing, struct dc_dsc_policy *policy) +{ + uint32_t bpc = 0; + + policy->min_target_bpp = 0; + policy->max_target_bpp = 0; + + /* DSC Policy: Use minimum number of slices that fits the pixel clock */ + policy->use_min_slices_h = true; + + /* DSC Policy: Use max available slices + * (in our case 4 for or 8, depending on the mode) + */ + policy->max_slices_h = 0; + + /* DSC Policy: Use slice height recommended + * by VESA DSC Spreadsheet user guide + */ + policy->min_slice_height = 108; + + /* DSC Policy: follow DP specs with an internal upper limit to 16 bpp + * for better interoperability + */ + switch (timing->display_color_depth) { + case COLOR_DEPTH_888: + bpc = 8; + break; + case COLOR_DEPTH_101010: + bpc = 10; + break; + case COLOR_DEPTH_121212: + bpc = 12; + break; + default: + return; + } + switch (timing->pixel_encoding) { + case PIXEL_ENCODING_RGB: + case PIXEL_ENCODING_YCBCR444: + case PIXEL_ENCODING_YCBCR422: /* assume no YCbCr422 native support */ + /* DP specs limits to 8 */ + policy->min_target_bpp = 8; + /* DP specs limits to 3 x bpc */ + policy->max_target_bpp = 3 * bpc; + break; + case PIXEL_ENCODING_YCBCR420: + /* DP specs limits to 6 */ + policy->min_target_bpp = 6; + /* DP specs limits to 1.5 x bpc assume bpc is an even number */ + policy->max_target_bpp = bpc * 3 / 2; + break; + default: + return; + } + /* internal upper limit to 16 bpp */ + if (policy->max_target_bpp > 16) + policy->max_target_bpp = 16; +} diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h b/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h index 020ad8f685ea5ca0d52f04203c417a00301dde42..9f70e87b3ecb581d4201c0d0d95353586db8a83d 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h @@ -1,4 +1,3 @@ -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) /* * Copyright 2017 Advanced Micro Devices, Inc. @@ -51,4 +50,3 @@ int dscc_compute_dsc_parameters(const struct drm_dsc_config *pps, struct dsc_par #endif -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h b/drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h index f66d006eac5dc5b920678b60f69d818173bbba4b..e5fac9f4181d81b911e5c36eadf2854ede8edd3e 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h +++ b/drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h @@ -1,4 +1,3 @@ -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) /* * Copyright 2017 Advanced Micro Devices, Inc. @@ -703,4 +702,3 @@ const qp_table qp_table_422_8bpc_max = { { 16, { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 4} } }; -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c index 76c4b12d6824b0d5b4db1a3ef6de27605b03d9d3..03ae15946c6d883015ddf80209fd53674efc6e86 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c @@ -1,4 +1,3 @@ -#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT) /* * Copyright 2017 Advanced Micro Devices, Inc. @@ -252,4 +251,3 @@ void calc_rc_params(struct rc_params *rc, enum colour_mode cm, enum bits_per_com rc->rc_buf_thresh[13] = 8064; } -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h index f1d6e793bc610c8295b8dd1e995f28041e93c9c3..b6b1f09c2009c64feab398e59cc8a0be0ac556f8 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h +++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h @@ -1,4 +1,3 @@ -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) /* * Copyright 2017 Advanced Micro Devices, Inc. @@ -82,4 +81,3 @@ void calc_rc_params(struct rc_params *rc, enum colour_mode cm, enum bits_per_com #endif -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c index 73172fd0b529f1ebc27ede703b464b850151223c..1f6e63b71456369723c8b0d5c3beaeea8222b8f8 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c @@ -1,4 +1,3 @@ -#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT) /* * Copyright 2012-17 Advanced Micro Devices, Inc. * @@ -144,4 +143,3 @@ int dscc_compute_dsc_parameters(const struct drm_dsc_config *pps, struct dsc_par return ret; } -#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/Makefile b/drivers/gpu/drm/amd/display/dc/gpio/Makefile index b3062275711e147001b9f0f58d4f9e9652f3bd29..202baa210cc817000f7e4f7bba7ff47de48d2f46 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/Makefile +++ b/drivers/gpu/drm/amd/display/dc/gpio/Makefile @@ -61,26 +61,25 @@ AMD_DISPLAY_FILES += $(AMD_DAL_GPIO_DCE120) ############################################################################### # DCN 1x ############################################################################### -ifdef CONFIG_DRM_AMD_DC_DCN1_0 +ifdef CONFIG_DRM_AMD_DC_DCN GPIO_DCN10 = hw_translate_dcn10.o hw_factory_dcn10.o AMD_DAL_GPIO_DCN10 = $(addprefix $(AMDDALPATH)/dc/gpio/dcn10/,$(GPIO_DCN10)) AMD_DISPLAY_FILES += $(AMD_DAL_GPIO_DCN10) -endif ############################################################################### # DCN 2 ############################################################################### -ifdef CONFIG_DRM_AMD_DC_DCN2_0 GPIO_DCN20 = hw_translate_dcn20.o hw_factory_dcn20.o AMD_DAL_GPIO_DCN20 = $(addprefix $(AMDDALPATH)/dc/gpio/dcn20/,$(GPIO_DCN20)) AMD_DISPLAY_FILES += $(AMD_DAL_GPIO_DCN20) -endif -ifdef CONFIG_DRM_AMD_DC_DCN2_1 +############################################################################### +# DCN 21 +############################################################################### GPIO_DCN21 = hw_translate_dcn21.o hw_factory_dcn21.o AMD_DAL_GPIO_DCN21 = $(addprefix $(AMDDALPATH)/dc/gpio/dcn21/,$(GPIO_DCN21)) diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c index 43a440385b43cb1d72d2441d6849c1095609cb7a..83f798cb8b2107c7a8aace8d45c0b0421f04e50c 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c @@ -22,7 +22,6 @@ * Authors: AMD * */ -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "dm_services.h" #include "include/gpio_types.h" #include "../hw_factory.h" @@ -110,6 +109,12 @@ static const struct ddc_registers ddc_data_regs_dcn[] = { ddc_data_regs_dcn2(4), ddc_data_regs_dcn2(5), ddc_data_regs_dcn2(6), + { + DDC_GPIO_VGA_REG_LIST(DATA), + .ddc_setup = 0, + .phy_aux_cntl = 0, + .dc_gpio_aux_ctrl_5 = 0 + } }; static const struct ddc_registers ddc_clk_regs_dcn[] = { @@ -119,6 +124,12 @@ static const struct ddc_registers ddc_clk_regs_dcn[] = { ddc_clk_regs_dcn2(4), ddc_clk_regs_dcn2(5), ddc_clk_regs_dcn2(6), + { + DDC_GPIO_VGA_REG_LIST(CLK), + .ddc_setup = 0, + .phy_aux_cntl = 0, + .dc_gpio_aux_ctrl_5 = 0 + } }; static const struct ddc_sh_mask ddc_shift[] = { @@ -246,4 +257,3 @@ void dal_hw_factory_dcn20_init(struct hw_factory *factory) factory->funcs = &funcs; } -#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.h b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.h index 43a4ce7aa3bfae34ef2bf334093cfc9e65981488..0fd9b315bd7a83e77991bcf3f8973c9b18ca9cf9 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.h @@ -22,7 +22,6 @@ * Authors: AMD * */ -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #ifndef __DAL_HW_FACTORY_DCN20_H__ #define __DAL_HW_FACTORY_DCN20_H__ @@ -30,4 +29,3 @@ void dal_hw_factory_dcn20_init(struct hw_factory *factory); #endif /* __DAL_HW_FACTORY_DCN20_H__ */ -#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.c index 915e896e0e91bc69b6714fac0f08df179ae62454..52ba62b3b5e41e42a82ac64de6292368b1c413e2 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.c @@ -26,7 +26,6 @@ /* * Pre-requisites: headers required by header of this unit */ -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "hw_translate_dcn20.h" #include "dm_services.h" @@ -379,4 +378,3 @@ void dal_hw_translate_dcn20_init(struct hw_translate *tr) tr->funcs = &funcs; } -#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.h b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.h index 01f52c7bed86c0dcc41afe8e3dc940cdb1b4b193..5f7a35530e26506f6e0584cdff29f00796873a5b 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.h @@ -22,7 +22,6 @@ * Authors: AMD * */ -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #ifndef __DAL_HW_TRANSLATE_DCN20_H__ #define __DAL_HW_TRANSLATE_DCN20_H__ @@ -32,4 +31,3 @@ struct hw_translate; void dal_hw_translate_dcn20_init(struct hw_translate *tr); #endif /* __DAL_HW_TRANSLATE_DCN20_H__ */ -#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_factory_dcn21.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_factory_dcn21.c index 8572678f8d4f459a2ae8fbb6ee93a54869241caf..907c5911eb9e89d4a05c0ff78d4d2e5995bdd3d6 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_factory_dcn21.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_factory_dcn21.c @@ -22,7 +22,6 @@ * Authors: AMD * */ -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "dm_services.h" #include "include/gpio_types.h" #include "../hw_factory.h" @@ -239,4 +238,3 @@ void dal_hw_factory_dcn21_init(struct hw_factory *factory) factory->funcs = &funcs; } -#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_factory_dcn21.h b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_factory_dcn21.h index 2443f9e7afbf8ac66fdc7df5fe39ca46f2f760c8..4949e0c7fa067f3ef87b86fe4335839ed50b9d14 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_factory_dcn21.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_factory_dcn21.h @@ -22,7 +22,6 @@ * Authors: AMD * */ -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) #ifndef __DAL_HW_FACTORY_DCN21_H__ #define __DAL_HW_FACTORY_DCN21_H__ @@ -30,4 +29,3 @@ void dal_hw_factory_dcn21_init(struct hw_factory *factory); #endif /* __DAL_HW_FACTORY_DCN20_H__ */ -#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.c index fbb58fb8c318aecc5c1a173240ad1e3e3a610edc..291966efe63df0ae31123a5610d61da41f4e5589 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.c @@ -26,7 +26,6 @@ /* * Pre-requisites: headers required by header of this unit */ -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "hw_translate_dcn21.h" #include "dm_services.h" @@ -382,4 +381,3 @@ void dal_hw_translate_dcn21_init(struct hw_translate *tr) tr->funcs = &funcs; } -#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.h b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.h index 2bfaac24c5743b052e030597d00353b3e9fc9d86..9462b0a652000c54e551e3f4e63874baa9341afc 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.h @@ -22,7 +22,6 @@ * Authors: AMD * */ -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) #ifndef __DAL_HW_TRANSLATE_DCN21_H__ #define __DAL_HW_TRANSLATE_DCN21_H__ @@ -32,4 +31,3 @@ struct hw_translate; void dal_hw_translate_dcn21_init(struct hw_translate *tr); #endif /* __DAL_HW_TRANSLATE_DCN21_H__ */ -#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h b/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h index f91e85b04956c41a3a81b631f60c0bfc876bb573..308a543178a56fe22cc140fada4ac0f5e5fb4984 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h @@ -48,13 +48,11 @@ DDC_GPIO_REG_LIST(cd,id),\ .ddc_setup = REG(DC_I2C_DDC ## id ## _SETUP) -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define DDC_REG_LIST_DCN2(cd, id) \ DDC_GPIO_REG_LIST(cd, id),\ .ddc_setup = REG(DC_I2C_DDC ## id ## _SETUP),\ .phy_aux_cntl = REG(PHY_AUX_CNTL), \ .dc_gpio_aux_ctrl_5 = REG(DC_GPIO_AUX_CTRL_5) -#endif #define DDC_GPIO_VGA_REG_LIST_ENTRY(type,cd)\ .type ## _reg = REG(DC_GPIO_DDCVGA_ ## type),\ @@ -90,13 +88,11 @@ DDC_GPIO_I2C_REG_LIST(cd),\ .ddc_setup = 0 -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define DDC_I2C_REG_LIST_DCN2(cd) \ DDC_GPIO_I2C_REG_LIST(cd),\ .ddc_setup = 0,\ .phy_aux_cntl = REG(PHY_AUX_CNTL), \ .dc_gpio_aux_ctrl_5 = REG(DC_GPIO_AUX_CTRL_5) -#endif #define DDC_MASK_SH_LIST_COMMON(mask_sh) \ SF_DDC(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE, mask_sh),\ SF_DDC(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_EDID_DETECT_ENABLE, mask_sh),\ @@ -110,22 +106,18 @@ SF_DDC(DC_GPIO_I2CPAD_MASK, DC_GPIO_SDA_PD_DIS, mask_sh),\ SF_DDC(DC_GPIO_I2CPAD_MASK, DC_GPIO_SCL_PD_DIS, mask_sh) -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define DDC_MASK_SH_LIST_DCN2(mask_sh, cd) \ {DDC_MASK_SH_LIST_COMMON(mask_sh),\ 0,\ 0,\ (PHY_AUX_CNTL__AUX## cd ##_PAD_RXSEL## mask_sh),\ (DC_GPIO_AUX_CTRL_5__DDC_PAD## cd ##_I2CMODE## mask_sh)} -#endif struct ddc_registers { struct gpio_registers gpio; uint32_t ddc_setup; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) uint32_t phy_aux_cntl; uint32_t dc_gpio_aux_ctrl_5; -#endif }; struct ddc_sh_mask { @@ -140,11 +132,9 @@ struct ddc_sh_mask { /* i2cpad_mask */ uint32_t DC_GPIO_SDA_PD_DIS; uint32_t DC_GPIO_SCL_PD_DIS; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) //phy_aux_cntl uint32_t AUX_PAD_RXSEL; uint32_t DDC_PAD_I2CMODE; -#endif }; @@ -180,7 +170,6 @@ struct ddc_sh_mask { {\ DDC_I2C_REG_LIST(SCL)\ } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define ddc_data_regs_dcn2(id) \ {\ DDC_REG_LIST_DCN2(DATA, id)\ @@ -200,7 +189,6 @@ struct ddc_sh_mask { {\ DDC_REG_LIST_DCN2(SCL)\ } -#endif #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_GPIO_DDC_REGS_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c index 1c12961f6472f3041185676e54fc07bc489ef078..1ae153eab31d7e02765599ddf0ff6ee0dcf47347 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c @@ -48,18 +48,18 @@ struct gpio; -static void destruct( +static void dal_hw_ddc_destruct( struct hw_ddc *pin) { dal_hw_gpio_destruct(&pin->base); } -static void destroy( +static void dal_hw_ddc_destroy( struct hw_gpio_pin **ptr) { struct hw_ddc *pin = HW_DDC_FROM_BASE(*ptr); - destruct(pin); + dal_hw_ddc_destruct(pin); kfree(pin); @@ -150,7 +150,6 @@ static enum gpio_result set_config( AUX_PAD1_MODE, 0); } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) if (ddc->regs->dc_gpio_aux_ctrl_5 != 0) { REG_UPDATE(dc_gpio_aux_ctrl_5, DDC_PAD_I2CMODE, 1); } @@ -158,7 +157,6 @@ static enum gpio_result set_config( if (ddc->regs->phy_aux_cntl != 0) { REG_UPDATE(phy_aux_cntl, AUX_PAD_RXSEL, 1); } -#endif return GPIO_RESULT_OK; case GPIO_DDC_CONFIG_TYPE_MODE_AUX: /* set the AUX pad mode */ @@ -166,12 +164,10 @@ static enum gpio_result set_config( REG_SET(gpio.MASK_reg, regval, AUX_PAD1_MODE, 1); } -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) if (ddc->regs->dc_gpio_aux_ctrl_5 != 0) { REG_UPDATE(dc_gpio_aux_ctrl_5, DDC_PAD_I2CMODE, 0); } -#endif return GPIO_RESULT_OK; case GPIO_DDC_CONFIG_TYPE_POLL_FOR_CONNECT: @@ -211,7 +207,7 @@ static enum gpio_result set_config( } static const struct hw_gpio_pin_funcs funcs = { - .destroy = destroy, + .destroy = dal_hw_ddc_destroy, .open = dal_hw_gpio_open, .get_value = dal_hw_gpio_get_value, .set_value = dal_hw_gpio_set_value, @@ -220,7 +216,7 @@ static const struct hw_gpio_pin_funcs funcs = { .close = dal_hw_gpio_close, }; -static void construct( +static void dal_hw_ddc_construct( struct hw_ddc *ddc, enum gpio_id id, uint32_t en, @@ -247,7 +243,7 @@ void dal_hw_ddc_init( return; } - construct(*hw_ddc, id, en, ctx); + dal_hw_ddc_construct(*hw_ddc, id, en, ctx); } struct hw_gpio_pin *dal_hw_ddc_get_pin(struct gpio *gpio) 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 fa9f1d055ec8576a04b71eb2546cf385b571606e..d2d36d48caaae549e79a7b9332e8e5cd076ea446 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c @@ -45,15 +45,11 @@ #include "dce80/hw_factory_dce80.h" #include "dce110/hw_factory_dce110.h" #include "dce120/hw_factory_dce120.h" -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) #include "dcn10/hw_factory_dcn10.h" #endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "dcn20/hw_factory_dcn20.h" -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) #include "dcn21/hw_factory_dcn21.h" -#endif #include "diagnostics/hw_factory_diag.h" @@ -90,19 +86,15 @@ bool dal_hw_factory_init( case DCE_VERSION_12_1: dal_hw_factory_dce120_init(factory); return true; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) case DCN_VERSION_1_0: case DCN_VERSION_1_01: dal_hw_factory_dcn10_init(factory); return true; -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) case DCN_VERSION_2_0: dal_hw_factory_dcn20_init(factory); return true; -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) case DCN_VERSION_2_1: dal_hw_factory_dcn21_init(factory); return true; diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.c index 69b899741f6d612a49d1f06198585e3bcbfaa101..f9e847e6555d9b45547903bd1508daaee77df296 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.c @@ -46,22 +46,13 @@ struct gpio; -static void dal_hw_generic_construct( - struct hw_generic *pin, - enum gpio_id id, - uint32_t en, - struct dc_context *ctx) -{ - dal_hw_gpio_construct(&pin->base, id, en, ctx); -} - static void dal_hw_generic_destruct( struct hw_generic *pin) { dal_hw_gpio_destruct(&pin->base); } -static void destroy( +static void dal_hw_generic_destroy( struct hw_gpio_pin **ptr) { struct hw_generic *generic = HW_GENERIC_FROM_BASE(*ptr); @@ -90,7 +81,7 @@ static enum gpio_result set_config( } static const struct hw_gpio_pin_funcs funcs = { - .destroy = destroy, + .destroy = dal_hw_generic_destroy, .open = dal_hw_gpio_open, .get_value = dal_hw_gpio_get_value, .set_value = dal_hw_gpio_set_value, @@ -99,14 +90,14 @@ static const struct hw_gpio_pin_funcs funcs = { .close = dal_hw_gpio_close, }; -static void construct( - struct hw_generic *generic, +static void dal_hw_generic_construct( + struct hw_generic *pin, enum gpio_id id, uint32_t en, struct dc_context *ctx) { - dal_hw_generic_construct(generic, id, en, ctx); - generic->base.base.funcs = &funcs; + dal_hw_gpio_construct(&pin->base, id, en, ctx); + pin->base.base.funcs = &funcs; } void dal_hw_generic_init( @@ -126,7 +117,7 @@ void dal_hw_generic_init( return; } - construct(*hw_generic, id, en, ctx); + dal_hw_generic_construct(*hw_generic, id, en, ctx); } diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c index 00c9bcf660a3646b6575b7ff216b5661fa3d787e..692f29de779701dfac545fe37ead3663de59172f 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c @@ -46,34 +46,18 @@ struct gpio; -static void dal_hw_hpd_construct( - struct hw_hpd *pin, - enum gpio_id id, - uint32_t en, - struct dc_context *ctx) -{ - dal_hw_gpio_construct(&pin->base, id, en, ctx); -} - static void dal_hw_hpd_destruct( struct hw_hpd *pin) { dal_hw_gpio_destruct(&pin->base); } - -static void destruct( - struct hw_hpd *hpd) -{ - dal_hw_hpd_destruct(hpd); -} - -static void destroy( +static void dal_hw_hpd_destroy( struct hw_gpio_pin **ptr) { struct hw_hpd *hpd = HW_HPD_FROM_BASE(*ptr); - destruct(hpd); + dal_hw_hpd_destruct(hpd); kfree(hpd); @@ -120,7 +104,7 @@ static enum gpio_result set_config( } static const struct hw_gpio_pin_funcs funcs = { - .destroy = destroy, + .destroy = dal_hw_hpd_destroy, .open = dal_hw_gpio_open, .get_value = get_value, .set_value = dal_hw_gpio_set_value, @@ -129,14 +113,14 @@ static const struct hw_gpio_pin_funcs funcs = { .close = dal_hw_gpio_close, }; -static void construct( - struct hw_hpd *hpd, +static void dal_hw_hpd_construct( + struct hw_hpd *pin, enum gpio_id id, uint32_t en, struct dc_context *ctx) { - dal_hw_hpd_construct(hpd, id, en, ctx); - hpd->base.base.funcs = &funcs; + dal_hw_gpio_construct(&pin->base, id, en, ctx); + pin->base.base.funcs = &funcs; } void dal_hw_hpd_init( @@ -156,7 +140,7 @@ void dal_hw_hpd_init( return; } - construct(*hw_hpd, id, en, ctx); + dal_hw_hpd_construct(*hw_hpd, id, en, ctx); } struct hw_gpio_pin *dal_hw_hpd_get_pin(struct gpio *gpio) 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 f2046f55d6a85539a5e422235c0e9cc3745f11c9..5d396657a1ee158e5c745bb99cdf9745e992cd61 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c @@ -43,15 +43,11 @@ #include "dce80/hw_translate_dce80.h" #include "dce110/hw_translate_dce110.h" #include "dce120/hw_translate_dce120.h" -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) #include "dcn10/hw_translate_dcn10.h" #endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "dcn20/hw_translate_dcn20.h" -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) #include "dcn21/hw_translate_dcn21.h" -#endif #include "diagnostics/hw_translate_diag.h" @@ -85,19 +81,15 @@ bool dal_hw_translate_init( case DCE_VERSION_12_1: dal_hw_translate_dce120_init(translate); return true; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) case DCN_VERSION_1_0: case DCN_VERSION_1_01: dal_hw_translate_dcn10_init(translate); return true; -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) case DCN_VERSION_2_0: dal_hw_translate_dcn20_init(translate); return true; -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) case DCN_VERSION_2_1: dal_hw_translate_dcn21_init(translate); return true; diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_status.h b/drivers/gpu/drm/amd/display/dc/inc/core_status.h index fd39e2abe2ed652ac43a058b48acd3857bff7f85..4ead89dd7c418eed866cdcce35c019e4a979a2b7 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_status.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_status.h @@ -43,10 +43,8 @@ enum dc_status { DC_FAIL_BANDWIDTH_VALIDATE = 13, /* BW and Watermark validation */ DC_FAIL_SCALING = 14, DC_FAIL_DP_LINK_TRAINING = 15, -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 DC_FAIL_DSC_VALIDATE = 16, DC_NO_DSC_RESOURCE = 17, -#endif DC_FAIL_UNSUPPORTED_1 = 18, DC_FAIL_CLK_EXCEED_MAX = 21, DC_FAIL_CLK_BELOW_MIN = 22, /*THIS IS MIN PER IP*/ diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index a831079607cddfd3ee0ab1c46785f1850684afdb..16f6ef22367b19771d3f7edb5ed33fedf1843156 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -33,13 +33,11 @@ #include "dc_bios_types.h" #include "mem_input.h" #include "hubp.h" -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) #include "mpc.h" #endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "dwb.h" #include "mcif_wb.h" -#endif #define MAX_CLOCK_SOURCES 7 @@ -89,9 +87,7 @@ void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable); struct resource_pool; struct dc_state; struct resource_context; -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) struct clk_bw_params; -#endif struct resource_funcs { void (*destroy)(struct resource_pool **pool); @@ -105,7 +101,7 @@ struct resource_funcs { int (*populate_dml_pipes)( struct dc *dc, - struct resource_context *res_ctx, + struct dc_state *context, display_e2e_pipe_params_st *pipes); enum dc_status (*validate_global)( @@ -135,7 +131,6 @@ struct resource_funcs { struct resource_context *res_ctx, const struct resource_pool *pool, struct dc_stream_state *stream); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) void (*populate_dml_writeback_from_context)( struct dc *dc, struct resource_context *res_ctx, @@ -146,12 +141,9 @@ struct resource_funcs { struct dc_state *context, display_e2e_pipe_params_st *pipes, int pipe_cnt); -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) void (*update_bw_bounding_box)( struct dc *dc, struct clk_bw_params *bw_params); -#endif }; @@ -180,7 +172,6 @@ struct resource_pool { struct dce_i2c_sw *sw_i2cs[MAX_PIPES]; bool i2c_hw_buffer_in_use; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct dwbc *dwbc[MAX_DWB_PIPES]; struct mcif_wb *mcif_wb[MAX_DWB_PIPES]; struct { @@ -188,11 +179,8 @@ struct resource_pool { unsigned int gsl_1:1; unsigned int gsl_2:1; } gsl_groups; -#endif -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT struct display_stream_compressor *dscs[MAX_PIPES]; -#endif unsigned int pipe_count; unsigned int underlay_pipe_index; @@ -206,9 +194,7 @@ struct resource_pool { unsigned int timing_generator_count; unsigned int mpcc_count; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) unsigned int writeback_pipe_count; -#endif /* * reserved clock source for DP */ @@ -229,6 +215,8 @@ struct resource_pool { const struct resource_funcs *funcs; const struct resource_caps *res_cap; + + struct ddc_service *oem_device; }; struct dcn_fe_bandwidth { @@ -238,9 +226,7 @@ struct dcn_fe_bandwidth { struct stream_resource { struct output_pixel_processor *opp; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT struct display_stream_compressor *dsc; -#endif struct timing_generator *tg; struct stream_encoder *stream_enc; struct audio *audio; @@ -249,12 +235,10 @@ struct stream_resource { struct encoder_info_frame encoder_info_frame; struct abm *abm; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) /* There are only (num_pipes+1)/2 groups. 0 means unassigned, * otherwise it's using group number 'gsl_group-1' */ uint8_t gsl_group; -#endif }; struct plane_resource { @@ -306,17 +290,15 @@ struct pipe_ctx { struct pipe_ctx *next_odm_pipe; struct pipe_ctx *prev_odm_pipe; -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_DRM_AMD_DC_DCN struct _vcs_dpi_display_dlg_regs_st dlg_regs; struct _vcs_dpi_display_ttu_regs_st ttu_regs; struct _vcs_dpi_display_rq_regs_st rq_regs; struct _vcs_dpi_display_pipe_dest_params_st pipe_dlg_param; #endif union pipe_update_flags update_flags; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 struct dwbc *dwbc; struct mcif_wb *mcif_wb; -#endif }; struct resource_context { @@ -325,9 +307,7 @@ struct resource_context { bool is_audio_acquired[MAX_PIPES]; uint8_t clock_source_ref_count[MAX_CLOCK_SOURCES]; uint8_t dp_clock_source_ref_count; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 bool is_dsc_acquired[MAX_PIPES]; -#endif }; struct dce_bw_output { @@ -347,18 +327,14 @@ struct dce_bw_output { int blackout_recovery_time_us; }; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct dcn_bw_writeback { struct mcif_arb_params mcif_wb_arb[MAX_DWB_PIPES]; }; -#endif struct dcn_bw_output { struct dc_clocks clk; struct dcn_watermark_set watermarks; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct dcn_bw_writeback bw_writeback; -#endif }; union bw_output { @@ -392,7 +368,7 @@ struct dc_state { /* Note: these are big structures, do *not* put on stack! */ struct dm_pp_display_configuration pp_display_cfg; -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_DRM_AMD_DC_DCN struct dcn_bw_internal_vars dcn_bw_vars; #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h index 14716ba3566257458767a2b41349f3c4ac4060f1..de2d160114db7f696989c646f4490b3ea48c2e95 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h @@ -105,7 +105,7 @@ int dc_link_aux_transfer_raw(struct ddc_service *ddc, bool dc_link_aux_transfer_with_retries(struct ddc_service *ddc, struct aux_payload *payload); -enum dc_status dc_link_aux_configure_timeout(struct ddc_service *ddc, +uint32_t dc_link_aux_configure_timeout(struct ddc_service *ddc, uint32_t timeout); void dal_ddc_service_write_scdc_data( diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h index 045138dbdccb471989f8215defcabe18829b376a..6198bccd61991e021bc7d4698a6ef79da025547d 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h @@ -28,8 +28,8 @@ #define LINK_TRAINING_ATTEMPTS 4 #define LINK_TRAINING_RETRY_DELAY 50 /* ms */ -#define LINK_AUX_DEFAULT_EXTENDED_TIMEOUT_PERIOD 32000 /*us*/ -#define LINK_AUX_DEFAULT_TIMEOUT_PERIOD 400 /*us*/ +#define LINK_AUX_DEFAULT_EXTENDED_TIMEOUT_PERIOD 3200 /*us*/ +#define LINK_AUX_DEFAULT_TIMEOUT_PERIOD 552 /*us*/ struct dc_link; struct dc_stream_state; @@ -57,10 +57,11 @@ void decide_link_settings( struct dc_link_settings *link_setting); bool perform_link_training_with_retries( - struct dc_link *link, const struct dc_link_settings *link_setting, bool skip_video_pattern, - int attempts); + int attempts, + struct pipe_ctx *pipe_ctx, + enum signal_type signal); bool is_mst_supported(struct dc_link *link); @@ -75,13 +76,11 @@ void dp_enable_mst_on_sink(struct dc_link *link, bool enable); enum dp_panel_mode dp_get_panel_mode(struct dc_link *link); void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode); -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT void dp_set_fec_ready(struct dc_link *link, bool ready); void dp_set_fec_enable(struct dc_link *link, bool enable); bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable); bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable); void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable); bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx); -#endif #endif /* __DC_LINK_DP_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h index 4e18e77dcf422d0db1c76319595a897c300976fa..ac530c057ddda6584c5dce8e899e137fbadc5e1e 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h @@ -31,7 +31,6 @@ #define DCN_MINIMUM_DISPCLK_Khz 100000 #define DCN_MINIMUM_DPPCLK_Khz 100000 -#ifdef CONFIG_DRM_AMD_DC_DCN2_1 /* Constants */ #define DDR4_DRAM_WIDTH 64 #define WM_A 0 @@ -39,12 +38,10 @@ #define WM_C 2 #define WM_D 3 #define WM_SET_COUNT 4 -#endif #define DCN_MINIMUM_DISPCLK_Khz 100000 #define DCN_MINIMUM_DPPCLK_Khz 100000 -#ifdef CONFIG_DRM_AMD_DC_DCN2_1 /* Will these bw structures be ASIC specific? */ #define MAX_NUM_DPM_LVL 8 @@ -69,6 +66,8 @@ struct wm_range_table_entry { unsigned int wm_inst; unsigned int wm_type; double pstate_latency_us; + double sr_exit_time_us; + double sr_enter_plus_exit_time_us; bool valid; }; @@ -152,7 +151,6 @@ struct clk_bw_params { struct clk_limit_table clk_table; struct wm_table wm_table; }; -#endif /* Public interfaces */ struct clk_states { @@ -193,9 +191,8 @@ struct clk_mgr { bool psr_allow_active_cache; int dprefclk_khz; // Used by program pixel clock in clock source funcs, need to figureout where this goes int dentist_vco_freq_khz; -#ifdef CONFIG_DRM_AMD_DC_DCN2_1 + struct clk_state_registers_and_bypass boot_snapshot; struct clk_bw_params *bw_params; -#endif }; /* forward declarations */ 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 a17a77192690710d5e8ac41a78650ae2b8ebfeea..862952c0286a4b18f1af2637887bcfbbbe903c8c 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 @@ -96,12 +96,10 @@ enum dentist_divider_range { .MP1_SMN_C2PMSG_83 = mmMP1_SMN_C2PMSG_83, \ .MP1_SMN_C2PMSG_67 = mmMP1_SMN_C2PMSG_67 -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 #define CLK_REG_LIST_NV10() \ SR(DENTIST_DISPCLK_CNTL), \ CLK_SRI(CLK3_CLK_PLL_REQ, CLK3, 0), \ CLK_SRI(CLK3_CLK2_DFS_CNTL, CLK3, 0) -#endif #define CLK_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -120,7 +118,6 @@ enum dentist_divider_range { CLK_SF(MP1_SMN_C2PMSG_83, CONTENT, mask_sh),\ CLK_SF(MP1_SMN_C2PMSG_91, CONTENT, mask_sh), -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 #define CLK_COMMON_MASK_SH_LIST_DCN20_BASE(mask_sh) \ CLK_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh),\ CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, mask_sh),\ @@ -130,7 +127,6 @@ enum dentist_divider_range { CLK_COMMON_MASK_SH_LIST_DCN20_BASE(mask_sh),\ CLK_SF(CLK3_0_CLK3_CLK_PLL_REQ, FbMult_int, mask_sh),\ CLK_SF(CLK3_0_CLK3_CLK_PLL_REQ, FbMult_frac, mask_sh) -#endif #define CLK_REG_FIELD_LIST(type) \ type DPREFCLK_SRC_SEL; \ @@ -143,30 +139,24 @@ enum dentist_divider_range { ****************** Clock Manager Private Structures *********************************** *************************************************************************************** */ -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 #define CLK20_REG_FIELD_LIST(type) \ type DENTIST_DPPCLK_WDIVIDER; \ type DENTIST_DPPCLK_CHG_DONE; \ type FbMult_int; \ type FbMult_frac; -#endif #define VBIOS_SMU_REG_FIELD_LIST(type) \ type CONTENT; struct clk_mgr_shift { CLK_REG_FIELD_LIST(uint8_t) -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 CLK20_REG_FIELD_LIST(uint8_t) -#endif VBIOS_SMU_REG_FIELD_LIST(uint32_t) }; struct clk_mgr_mask { CLK_REG_FIELD_LIST(uint32_t) -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 CLK20_REG_FIELD_LIST(uint32_t) -#endif VBIOS_SMU_REG_FIELD_LIST(uint32_t) }; @@ -174,10 +164,8 @@ struct clk_mgr_registers { uint32_t DPREFCLK_CNTL; uint32_t DENTIST_DISPCLK_CNTL; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 uint32_t CLK3_CLK2_DFS_CNTL; uint32_t CLK3_CLK_PLL_REQ; -#endif uint32_t MP1_SMN_C2PMSG_67; uint32_t MP1_SMN_C2PMSG_83; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h index c81a17aeaa25c5a7988268d1580f41b6ca06a90e..c0dc1d0f5caea9c171f6aea6707e369525c0ff95 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h @@ -52,7 +52,6 @@ struct dcn_hubbub_wm { struct dcn_hubbub_wm_set sets[4]; }; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 enum dcn_hubbub_page_table_depth { DCN_PAGE_TABLE_DEPTH_1_LEVEL, DCN_PAGE_TABLE_DEPTH_2_LEVEL, @@ -101,13 +100,11 @@ struct hubbub_addr_config { } default_addrs; }; -#endif struct hubbub_funcs { void (*update_dchub)( struct hubbub *hubbub, struct dchub_init_data *dh_data); -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 int (*init_dchub_sys_ctx)( struct hubbub *hubbub, struct dcn_hubbub_phys_addr_config *pa_config); @@ -116,7 +113,6 @@ struct hubbub_funcs { struct dcn_hubbub_virt_addr_config *va_config, int vmid); -#endif bool (*get_dcc_compression_cap)(struct hubbub *hubbub, const struct dc_dcc_surface_param *input, struct dc_surface_dcc_cap *output); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h index c68f0ce346c765ad533134a56d8ae9d7c8834a15..5315f1f86b219f904dc07d095741147104ed59b3 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h @@ -52,6 +52,8 @@ struct dmcu { enum dmcu_state dmcu_state; struct dmcu_version dmcu_version; unsigned int cached_wait_loop_number; + uint32_t psp_version; + bool auto_load_dmcu; }; struct dmcu_funcs { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h index 474c7194a9f8d116689c7b802a89e034e1e50b47..125e42dbd3c581727b3221c3cf4fa89b8be36725 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -36,14 +36,10 @@ struct dpp { struct dpp_caps *caps; struct pwl_params regamma_params; struct pwl_params degamma_params; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct dpp_cursor_attributes cur_attr; -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct pwl_params shaper_params; bool cm_bypass_mode; -#endif }; struct dpp_input_csc_matrix { @@ -56,7 +52,6 @@ struct dpp_grph_csc_adjustment { enum graphics_gamut_adjust_type gamut_adjust_type; }; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 struct cnv_color_keyer_params { int color_keyer_en; int color_keyer_mode; @@ -82,7 +77,6 @@ struct cnv_alpha_2bit_lut { int lut2; int lut3; }; -#endif struct dcn_dpp_state { uint32_t is_enabled; @@ -190,12 +184,8 @@ struct dpp_funcs { enum surface_pixel_format format, enum expansion_mode mode, struct dc_csc_transform input_csc_color_matrix, -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 enum dc_color_space input_color_space, struct cnv_alpha_2bit_lut *alpha_2bit_lut); -#else - enum dc_color_space input_color_space); -#endif void (*dpp_full_bypass)(struct dpp *dpp_base); @@ -224,7 +214,6 @@ struct dpp_funcs { bool dppclk_div, bool enable); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) bool (*dpp_program_blnd_lut)( struct dpp *dpp, const struct pwl_params *params); @@ -237,7 +226,6 @@ struct dpp_funcs { void (*dpp_cnv_set_alpha_keyer)( struct dpp *dpp_base, struct cnv_color_keyer_params *color_keyer); -#endif }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h index c6ff3d78b43502b6d4bf7b1d9a291ecad36c4e10..c59740084ebc48881b6769c47f82313e86bf5d37 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h @@ -22,7 +22,6 @@ * Authors: AMD * */ -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #ifndef __DAL_DSC_H__ #define __DAL_DSC_H__ @@ -98,4 +97,3 @@ struct dsc_funcs { }; #endif -#endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h index ff1a07b35c850400195137ba35c675f518156d67..735f41901b88552c83242fd590c0247084ebabc1 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h @@ -51,20 +51,15 @@ enum dwb_source { dwb_src_otg3, /* for DCN1.x/DCN2.x */ }; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) /* DCN1.x, DCN2.x support 2 pipes */ -#else -/* DCN1.x supports 2 pipes */ -#endif enum dwb_pipe { dwb_pipe0 = 0, -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) dwb_pipe1, #endif dwb_pipe_max_num, }; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) enum dwb_frame_capture_enable { DWB_FRAME_CAPTURE_DISABLE = 0, DWB_FRAME_CAPTURE_ENABLE = 1, @@ -77,9 +72,7 @@ enum wbscl_coef_filter_type_sel { WBSCL_COEF_CHROMA_HORZ_FILTER = 3 }; -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct dwb_warmup_params { bool warmup_en; /* false: normal mode, true: enable pattern generator */ bool warmup_mode; /* false: 420, true: 444 */ @@ -88,7 +81,6 @@ struct dwb_warmup_params { int warmup_width; /* Pattern width (pixels) */ int warmup_height; /* Pattern height (lines) */ }; -#endif struct dwb_caps { enum dce_version hw_version; /* DCN engine version. */ @@ -150,13 +142,11 @@ struct dwbc_funcs { struct dwbc *dwbc, bool is_new_content); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) void (*set_warmup)( struct dwbc *dwbc, struct dwb_warmup_params *warmup_params); -#endif bool (*get_dwb_status)( struct dwbc *dwbc); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h index 809b62b51a43620217bca68227d541d14dfddae5..85a34dde8526427cc95b76b791b7ba9634607fbd 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h @@ -38,9 +38,7 @@ enum cursor_pitch { }; enum cursor_lines_per_chunk { -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) CURSOR_LINE_PER_CHUNK_1 = 0, /* new for DCN2 */ -#endif CURSOR_LINE_PER_CHUNK_2 = 1, CURSOR_LINE_PER_CHUNK_4, CURSOR_LINE_PER_CHUNK_8, @@ -84,7 +82,9 @@ struct hubp_funcs { void (*mem_program_viewport)( struct hubp *hubp, const struct rect *viewport, - const struct rect *viewport_c); + const struct rect *viewport_c, + enum dc_rotation_angle rotation); + /* rotation needed for Renoir workaround */ bool (*hubp_program_surface_flip_and_addr)( struct hubp *hubp, @@ -139,7 +139,6 @@ struct hubp_funcs { unsigned int (*hubp_get_underflow_status)(struct hubp *hubp); void (*hubp_init)(struct hubp *hubp); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) void (*dmdata_set_attributes)( struct hubp *hubp, const struct dc_dmdata_attributes *attr); @@ -159,7 +158,13 @@ struct hubp_funcs { void (*hubp_set_flip_control_surface_gsl)( struct hubp *hubp, bool enable); -#endif + + void (*validate_dml_output)( + struct hubp *hubp, + struct dc_context *ctx, + struct _vcs_dpi_display_rq_regs_st *dml_rq_regs, + struct _vcs_dpi_display_dlg_regs_st *dml_dlg_attr, + struct _vcs_dpi_display_ttu_regs_st *dml_ttu_attr); }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h index f82365e2d03cc1aeba035eb6e25c1445756dfd64..75d419081e76ec3ba78baa9636d40f9c50d845f0 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h @@ -36,9 +36,7 @@ #define MAX_AUDIOS 7 #define MAX_PIPES 6 -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define MAX_DWB_PIPES 1 -#endif struct gamma_curve { uint32_t offset; @@ -81,7 +79,6 @@ struct pwl_result_data { uint32_t delta_blue_reg; }; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct dc_rgb { uint32_t red; uint32_t green; @@ -110,7 +107,6 @@ struct tetrahedral_params { bool use_12bits; }; -#endif /* arr_curve_points - regamma regions/segments specification * arr_points - beginning and end point specified separately (only one on DCE) @@ -195,13 +191,11 @@ enum opp_regamma { OPP_REGAMMA_USER }; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT enum optc_dsc_mode { OPTC_DSC_DISABLED = 0, OPTC_DSC_ENABLED_444 = 1, /* 'RGB 444' or 'Simple YCbCr 4:2:2' (4:2:2 upsampled to 4:4:4) */ OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED = 2 /* Native 4:2:2 or 4:2:0 */ }; -#endif struct dc_bias_and_scale { uint16_t scale_red; @@ -224,12 +218,8 @@ enum test_pattern_mode { TEST_PATTERN_MODE_VERTICALBARS, TEST_PATTERN_MODE_HORIZONTALBARS, TEST_PATTERN_MODE_SINGLERAMP_RGB, -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) TEST_PATTERN_MODE_DUALRAMP_RGB, TEST_PATTERN_MODE_XR_BIAS_RGB -#else - TEST_PATTERN_MODE_DUALRAMP_RGB -#endif }; enum test_pattern_color_format { @@ -255,6 +245,13 @@ enum controller_dp_test_pattern { CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR }; +enum controller_dp_color_space { + CONTROLLER_DP_COLOR_SPACE_RGB, + CONTROLLER_DP_COLOR_SPACE_YCBCR601, + CONTROLLER_DP_COLOR_SPACE_YCBCR709, + CONTROLLER_DP_COLOR_SPACE_UDEFINED +}; + enum dc_lut_mode { LUT_BYPASS, LUT_RAM_A, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h index b21909216fb671f28b034d02599fb769fd0e9879..fb748f082c5601431f57005ae33f0fd060c20c07 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h @@ -113,26 +113,21 @@ struct link_encoder { struct encoder_feature_support features; enum transmitter transmitter; enum hpd_source_id hpd_source; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 bool usbc_combo_phy; -#endif }; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT struct link_enc_state { uint32_t dphy_fec_en; uint32_t dphy_fec_ready_shadow; uint32_t dphy_fec_active_status; + uint32_t dp_link_training_complete; }; -#endif struct link_encoder_funcs { -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT void (*read_state)( struct link_encoder *enc, struct link_enc_state *s); -#endif bool (*validate_output_with_stream)( struct link_encoder *enc, const struct dc_stream_state *stream); void (*hw_init)(struct link_encoder *enc); @@ -174,7 +169,6 @@ struct link_encoder_funcs { unsigned int (*get_dig_frontend)(struct link_encoder *enc); void (*destroy)(struct link_encoder **enc); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) void (*fec_set_enable)(struct link_encoder *enc, bool enable); @@ -182,7 +176,6 @@ struct link_encoder_funcs { bool ready); bool (*fec_is_active)(struct link_encoder *enc); -#endif bool (*is_in_alt_mode) (struct link_encoder *enc); void (*get_max_link_cap)(struct link_encoder *enc, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h index 67b610d6d91f0efe503b08f7a075c3c03a057729..2e2310f1901a74c555628fbf4f2cd107763fe21c 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h @@ -40,11 +40,9 @@ struct cstate_pstate_watermarks_st { struct dcn_watermarks { uint32_t pte_meta_urgent_ns; uint32_t urgent_ns; -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) uint32_t frac_urg_bw_nom; uint32_t frac_urg_bw_flip; int32_t urgent_latency_ns; -#endif struct cstate_pstate_watermarks_st cstate_pstate; }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h index 58826be81395c9c1055eb21fa38d1958d1117eb9..094afc4c817310332dd78521ee1ebe56e79094b1 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h @@ -31,9 +31,7 @@ #define MAX_MPCC 6 #define MAX_OPP 6 -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define MAX_DWB 1 -#endif enum mpc_output_csc_mode { MPC_OUTPUT_CSC_DISABLE = 0, @@ -66,14 +64,12 @@ struct mpcc_blnd_cfg { int global_alpha; bool overlap_only; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) /* MPCC top/bottom gain settings */ int bottom_gain_mode; int background_color_bpc; int top_gain; int bottom_inside_gain; int bottom_outside_gain; -#endif }; struct mpcc_sm_cfg { @@ -90,7 +86,6 @@ struct mpcc_sm_cfg { int force_next_field_polarity; }; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct mpc_denorm_clamp { int clamp_max_r_cr; int clamp_min_r_cr; @@ -99,7 +94,6 @@ struct mpc_denorm_clamp { int clamp_max_b_cb; int clamp_min_b_cb; }; -#endif /* * MPCC connection and blending configuration for a single MPCC instance. @@ -126,10 +120,8 @@ struct mpc { struct dc_context *ctx; struct mpcc mpcc_array[MAX_MPCC]; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct pwl_params blender_params; bool cm_bypass_mode; -#endif }; struct mpcc_state { @@ -230,7 +222,6 @@ struct mpc_funcs { struct mpc *mpc, struct mpc_tree *tree); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) void (*set_denorm)(struct mpc *mpc, int opp_id, enum dc_color_depth output_depth); @@ -258,7 +249,6 @@ struct mpc_funcs { struct mpc *mpc, int mpcc_id, bool power_on); -#endif }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h index 18def2b6fafe02ca79f2adb42f93636805012c7a..7575564b2265af7f50ab1c473e361a2eaff9cb55 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h @@ -263,9 +263,7 @@ struct oppbuf_params { enum oppbuf_display_segmentation mso_segmentation; uint32_t mso_overlap_pixel_num; uint32_t pixel_repetition; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) uint32_t num_segment_padded_pixels; -#endif }; struct opp_funcs { @@ -305,10 +303,10 @@ struct opp_funcs { struct output_pixel_processor *opp, bool enable); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) void (*opp_set_disp_pattern_generator)( struct output_pixel_processor *opp, enum controller_dp_test_pattern test_pattern, + enum controller_dp_color_space color_space, enum dc_color_depth color_depth, const struct tg_color *solid_color, int width, @@ -324,7 +322,6 @@ struct opp_funcs { void (*opp_program_left_edge_extra_pixel)( struct output_pixel_processor *opp, bool count); -#endif }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h index 6305e388612a22fb2bc0261ebcd8ba85a5a00a6c..351b387ad606226d89f42dbfa88d91589f85e7ff 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h @@ -65,13 +65,11 @@ struct audio_clock_info { uint32_t cts_48khz; }; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) enum dynamic_metadata_mode { dmdata_dp, dmdata_hdmi, dmdata_dolby_vision }; -#endif struct encoder_info_frame { /* auxiliary video information */ @@ -90,9 +88,7 @@ struct encoder_info_frame { struct encoder_unblank_param { struct dc_link_settings link_settings; struct dc_crtc_timing timing; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 int opp_cnt; -#endif }; struct encoder_set_dp_phy_pattern_param { @@ -109,7 +105,6 @@ struct stream_encoder { enum engine_id id; }; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT struct enc_state { uint32_t dsc_mode; // DISABLED 0; 1 or 2 indicate enabled state. uint32_t dsc_slice_width; @@ -119,13 +114,13 @@ struct enc_state { uint32_t sec_gsp_pps_enable; uint32_t sec_stream_enable; }; -#endif struct stream_encoder_funcs { void (*dp_set_stream_attribute)( struct stream_encoder *enc, struct dc_crtc_timing *crtc_timing, enum dc_color_space output_color_space, + bool use_vsc_sdp_for_colorimetry, uint32_t enable_sdp_splitting); void (*hdmi_set_stream_attribute)( @@ -219,8 +214,6 @@ struct stream_encoder_funcs { enum dc_pixel_encoding *encoding, enum dc_color_depth *depth); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT void (*enc_read_state)(struct stream_encoder *enc, struct enc_state *s); void (*dp_set_dsc_config)( @@ -232,7 +225,6 @@ struct stream_encoder_funcs { void (*dp_set_dsc_pps_info_packet)(struct stream_encoder *enc, bool enable, uint8_t *dsc_packed_pps); -#endif void (*set_dynamic_metadata)(struct stream_encoder *enc, bool enable, @@ -242,7 +234,6 @@ struct stream_encoder_funcs { void (*dp_set_odm_combine)( struct stream_encoder *enc, bool odm_combine); -#endif }; #endif /* STREAM_ENCODER_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index 27c73caf74ee68687da06bc71203d992372f45ef..2d3efd71fa515e7ebc1b32c9d7b0639362c1cf4f 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h @@ -195,10 +195,8 @@ struct timing_generator_funcs { void (*lock)(struct timing_generator *tg); void (*lock_doublebuffer_disable)(struct timing_generator *tg); void (*lock_doublebuffer_enable)(struct timing_generator *tg); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) void(*triplebuffer_unlock)(struct timing_generator *tg); void(*triplebuffer_lock)(struct timing_generator *tg); -#endif void (*enable_reset_trigger)(struct timing_generator *tg, int source_tg_inst); void (*enable_crtc_reset)(struct timing_generator *tg, @@ -235,7 +233,6 @@ struct timing_generator_funcs { bool (*is_optc_underflow_occurred)(struct timing_generator *tg); void (*clear_optc_underflow)(struct timing_generator *tg); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) void (*set_dwb_source)(struct timing_generator *optc, uint32_t dwb_pipe_inst); @@ -243,7 +240,6 @@ struct timing_generator_funcs { uint32_t *num_of_input_segments, uint32_t *seg0_src_sel, uint32_t *seg1_src_sel); -#endif /** * Configure CRCs for the given timing generator. Return false if TG is @@ -267,13 +263,10 @@ struct timing_generator_funcs { void (*set_vtg_params)(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing); -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT void (*set_dsc_config)(struct timing_generator *optc, enum optc_dsc_mode dsc_mode, uint32_t dsc_bytes_per_pixel, uint32_t dsc_slice_width); -#endif void (*set_odm_bypass)(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing); void (*set_odm_combine)(struct timing_generator *optc, int *opp_id, int opp_cnt, struct dc_crtc_timing *timing); @@ -281,7 +274,6 @@ struct timing_generator_funcs { void (*set_gsl_source_select)(struct timing_generator *optc, int group_idx, uint32_t gsl_ready_signal); -#endif }; #endif 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 d39c1e11def56004d6b4cbcf8e6638eebed8593f..e9c6021a5372733f592d78d9f703dd730d2d7b18 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -32,303 +32,122 @@ #include "inc/hw/link_encoder.h" #include "core_status.h" -enum pipe_gating_control { - PIPE_GATING_CONTROL_DISABLE = 0, - PIPE_GATING_CONTROL_ENABLE, - PIPE_GATING_CONTROL_INIT -}; - enum vline_select { VLINE0, VLINE1 }; -struct dce_hwseq_wa { - bool blnd_crtc_trigger; - bool DEGVIDCN10_253; - bool false_optc_underflow; - bool DEGVIDCN10_254; - bool DEGVIDCN21; -}; - -struct hwseq_wa_state { - bool DEGVIDCN10_253_applied; -}; - -struct dce_hwseq { - struct dc_context *ctx; - const struct dce_hwseq_registers *regs; - const struct dce_hwseq_shift *shifts; - const struct dce_hwseq_mask *masks; - struct dce_hwseq_wa wa; - struct hwseq_wa_state wa_state; -}; - struct pipe_ctx; struct dc_state; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct dc_stream_status; struct dc_writeback_info; -#endif struct dchub_init_data; struct dc_static_screen_events; struct resource_pool; -struct resource_context; -struct stream_resource; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 struct dc_phy_addr_space_config; struct dc_virtual_addr_space_config; -#endif -struct hubp; struct dpp; +struct dce_hwseq; struct hw_sequencer_funcs { + /* Embedded Display Related */ + void (*edp_power_control)(struct dc_link *link, bool enable); + void (*edp_wait_for_hpd_ready)(struct dc_link *link, bool power_up); - void (*disable_stream_gating)(struct dc *dc, struct pipe_ctx *pipe_ctx); - - void (*enable_stream_gating)(struct dc *dc, struct pipe_ctx *pipe_ctx); - + /* Pipe Programming Related */ void (*init_hw)(struct dc *dc); - - void (*init_pipes)(struct dc *dc, struct dc_state *context); - - enum dc_status (*apply_ctx_to_hw)( - struct dc *dc, struct dc_state *context); - - void (*reset_hw_ctx_wrap)( - struct dc *dc, struct dc_state *context); - - void (*apply_ctx_for_surface)( - struct dc *dc, + void (*enable_accelerated_mode)(struct dc *dc, + struct dc_state *context); + enum dc_status (*apply_ctx_to_hw)(struct dc *dc, + struct dc_state *context); + void (*disable_plane)(struct dc *dc, struct pipe_ctx *pipe_ctx); + void (*apply_ctx_for_surface)(struct dc *dc, const struct dc_stream_state *stream, - int num_planes, + int num_planes, struct dc_state *context); + void (*program_front_end_for_ctx)(struct dc *dc, struct dc_state *context); - - void (*program_gamut_remap)( + void (*update_plane_addr)(const struct dc *dc, struct pipe_ctx *pipe_ctx); - - void (*program_output_csc)(struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum dc_color_space colorspace, - uint16_t *matrix, - int opp_id); - -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) - void (*program_front_end_for_ctx)( - struct dc *dc, - struct dc_state *context); - void (*program_triplebuffer)( - const struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool enableTripleBuffer); - void (*set_flip_control_gsl)( - struct pipe_ctx *pipe_ctx, - bool flip_immediate); -#endif - - void (*update_plane_addr)( - const struct dc *dc, - struct pipe_ctx *pipe_ctx); - - void (*plane_atomic_disconnect)( - struct dc *dc, - struct pipe_ctx *pipe_ctx); - - void (*update_dchub)( - struct dce_hwseq *hws, - struct dchub_init_data *dh_data); - -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 - int (*init_sys_ctx)( - struct dce_hwseq *hws, - struct dc *dc, - struct dc_phy_addr_space_config *pa_config); - void (*init_vm_ctx)( - struct dce_hwseq *hws, - struct dc *dc, - struct dc_virtual_addr_space_config *va_config, - int vmid); -#endif - void (*update_mpcc)( - struct dc *dc, - struct pipe_ctx *pipe_ctx); - - void (*update_pending_status)( + void (*update_dchub)(struct dce_hwseq *hws, + struct dchub_init_data *dh_data); + void (*wait_for_mpcc_disconnect)(struct dc *dc, + struct resource_pool *res_pool, struct pipe_ctx *pipe_ctx); - - bool (*set_input_transfer_func)( - struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state); - - bool (*set_output_transfer_func)( - struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream); - - void (*power_down)(struct dc *dc); - - void (*enable_accelerated_mode)(struct dc *dc, struct dc_state *context); - - void (*enable_timing_synchronization)( - struct dc *dc, - int group_index, - int group_size, - struct pipe_ctx *grouped_pipes[]); - - void (*enable_per_frame_crtc_position_reset)( - struct dc *dc, - int group_size, + void (*program_triplebuffer)(const struct dc *dc, + struct pipe_ctx *pipe_ctx, bool enableTripleBuffer); + void (*update_pending_status)(struct pipe_ctx *pipe_ctx); + + /* Pipe Lock Related */ + void (*pipe_control_lock_global)(struct dc *dc, + struct pipe_ctx *pipe, bool lock); + void (*pipe_control_lock)(struct dc *dc, + struct pipe_ctx *pipe, bool lock); + void (*set_flip_control_gsl)(struct pipe_ctx *pipe_ctx, + bool flip_immediate); + + /* Timing Related */ + void (*get_position)(struct pipe_ctx **pipe_ctx, int num_pipes, + struct crtc_position *position); + int (*get_vupdate_offset_from_vsync)(struct pipe_ctx *pipe_ctx); + void (*enable_per_frame_crtc_position_reset)(struct dc *dc, + int group_size, struct pipe_ctx *grouped_pipes[]); + void (*enable_timing_synchronization)(struct dc *dc, + int group_index, int group_size, struct pipe_ctx *grouped_pipes[]); + void (*setup_periodic_interrupt)(struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum vline_select vline); + void (*set_drr)(struct pipe_ctx **pipe_ctx, int num_pipes, + unsigned int vmin, unsigned int vmax, + unsigned int vmid, unsigned int vmid_frame_number); + void (*set_static_screen_control)(struct pipe_ctx **pipe_ctx, + int num_pipes, + const struct dc_static_screen_events *events); - void (*enable_display_pipe_clock_gating)( - struct dc_context *ctx, - bool clock_gating); - - bool (*enable_display_power_gating)( - struct dc *dc, - uint8_t controller_id, - struct dc_bios *dcb, - enum pipe_gating_control power_gating); - - void (*disable_plane)(struct dc *dc, struct pipe_ctx *pipe_ctx); - - void (*update_info_frame)(struct pipe_ctx *pipe_ctx); - - void (*send_immediate_sdp_message)( - struct pipe_ctx *pipe_ctx, - const uint8_t *custom_sdp_message, - unsigned int sdp_message_size); - + /* Stream Related */ void (*enable_stream)(struct pipe_ctx *pipe_ctx); - void (*disable_stream)(struct pipe_ctx *pipe_ctx); - + void (*blank_stream)(struct pipe_ctx *pipe_ctx); void (*unblank_stream)(struct pipe_ctx *pipe_ctx, struct dc_link_settings *link_settings); - void (*blank_stream)(struct pipe_ctx *pipe_ctx); - - void (*enable_audio_stream)(struct pipe_ctx *pipe_ctx); - - void (*disable_audio_stream)(struct pipe_ctx *pipe_ctx); - - void (*pipe_control_lock)( - struct dc *dc, - struct pipe_ctx *pipe, - bool lock); + /* Bandwidth Related */ + void (*prepare_bandwidth)(struct dc *dc, struct dc_state *context); + bool (*update_bandwidth)(struct dc *dc, struct dc_state *context); + void (*optimize_bandwidth)(struct dc *dc, struct dc_state *context); - void (*pipe_control_lock_global)( - struct dc *dc, - struct pipe_ctx *pipe, - bool lock); - void (*blank_pixel_data)( - struct dc *dc, + /* Infopacket Related */ + void (*set_avmute)(struct pipe_ctx *pipe_ctx, bool enable); + void (*send_immediate_sdp_message)( struct pipe_ctx *pipe_ctx, - bool blank); - - void (*prepare_bandwidth)( - struct dc *dc, - struct dc_state *context); - void (*optimize_bandwidth)( - struct dc *dc, - struct dc_state *context); - - void (*exit_optimized_pwr_state)( - const struct dc *dc, - struct dc_state *context); - void (*optimize_pwr_state)( - const struct dc *dc, - struct dc_state *context); - -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) - bool (*update_bandwidth)( - struct dc *dc, - struct dc_state *context); + const uint8_t *custom_sdp_message, + unsigned int sdp_message_size); + void (*update_info_frame)(struct pipe_ctx *pipe_ctx); + void (*set_dmdata_attributes)(struct pipe_ctx *pipe); void (*program_dmdata_engine)(struct pipe_ctx *pipe_ctx); bool (*dmdata_status_done)(struct pipe_ctx *pipe_ctx); -#endif - - void (*set_drr)(struct pipe_ctx **pipe_ctx, int num_pipes, - unsigned int vmin, unsigned int vmax, - unsigned int vmid, unsigned int vmid_frame_number); - - void (*get_position)(struct pipe_ctx **pipe_ctx, int num_pipes, - struct crtc_position *position); - - void (*set_static_screen_control)(struct pipe_ctx **pipe_ctx, - int num_pipes, const struct dc_static_screen_events *events); - - enum dc_status (*enable_stream_timing)( - struct pipe_ctx *pipe_ctx, - struct dc_state *context, - struct dc *dc); - - void (*setup_stereo)( - struct pipe_ctx *pipe_ctx, - struct dc *dc); - - void (*set_avmute)(struct pipe_ctx *pipe_ctx, bool enable); - - void (*log_hw_state)(struct dc *dc, - struct dc_log_buffer_ctx *log_ctx); - void (*get_hw_state)(struct dc *dc, char *pBuf, unsigned int bufSize, unsigned int mask); - void (*clear_status_bits)(struct dc *dc, unsigned int mask); - - void (*wait_for_mpcc_disconnect)(struct dc *dc, - struct resource_pool *res_pool, - struct pipe_ctx *pipe_ctx); - - void (*edp_power_control)( - struct dc_link *link, - bool enable); - void (*edp_backlight_control)( - struct dc_link *link, - bool enable); - void (*edp_wait_for_hpd_ready)(struct dc_link *link, bool power_up); + /* Cursor Related */ void (*set_cursor_position)(struct pipe_ctx *pipe); void (*set_cursor_attribute)(struct pipe_ctx *pipe); void (*set_cursor_sdr_white_level)(struct pipe_ctx *pipe); - void (*setup_periodic_interrupt)(struct pipe_ctx *pipe_ctx, enum vline_select vline); - void (*setup_vupdate_interrupt)(struct pipe_ctx *pipe_ctx); - bool (*did_underflow_occur)(struct dc *dc, struct pipe_ctx *pipe_ctx); - - void (*init_blank)(struct dc *dc, struct timing_generator *tg); - void (*disable_vga)(struct dce_hwseq *hws); - void (*bios_golden_init)(struct dc *dc); - void (*plane_atomic_power_down)(struct dc *dc, - struct dpp *dpp, - struct hubp *hubp); - - void (*plane_atomic_disable)( - struct dc *dc, struct pipe_ctx *pipe_ctx); - - void (*enable_power_gating_plane)( - struct dce_hwseq *hws, - bool enable); - - void (*dpp_pg_control)( - struct dce_hwseq *hws, - unsigned int dpp_inst, - bool power_on); - - void (*hubp_pg_control)( - struct dce_hwseq *hws, - unsigned int hubp_inst, - bool power_on); - - void (*dsc_pg_control)( - struct dce_hwseq *hws, - unsigned int dsc_inst, - bool power_on); - + /* Colour Related */ + void (*program_gamut_remap)(struct pipe_ctx *pipe_ctx); + void (*program_output_csc)(struct dc *dc, struct pipe_ctx *pipe_ctx, + enum dc_color_space colorspace, + uint16_t *matrix, int opp_id); -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) - void (*update_odm)(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); - void (*program_all_writeback_pipes_in_tree)( + /* VM Related */ + int (*init_sys_ctx)(struct dce_hwseq *hws, struct dc *dc, - const struct dc_stream_state *stream, - struct dc_state *context); + struct dc_phy_addr_space_config *pa_config); + void (*init_vm_ctx)(struct dce_hwseq *hws, + struct dc *dc, + struct dc_virtual_addr_space_config *va_config, + int vmid); + + /* Writeback Related */ void (*update_writeback)(struct dc *dc, const struct dc_stream_status *stream_status, struct dc_writeback_info *wb_info, @@ -339,19 +158,32 @@ struct hw_sequencer_funcs { struct dc_state *context); void (*disable_writeback)(struct dc *dc, unsigned int dwb_pipe_inst); -#endif - enum dc_status (*set_clock)(struct dc *dc, - enum dc_clock_type clock_type, - uint32_t clk_khz, - uint32_t stepping); - void (*get_clock)(struct dc *dc, + /* Clock Related */ + enum dc_status (*set_clock)(struct dc *dc, enum dc_clock_type clock_type, + uint32_t clk_khz, uint32_t stepping); + void (*get_clock)(struct dc *dc, enum dc_clock_type clock_type, struct dc_clock_config *clock_cfg); + void (*optimize_pwr_state)(const struct dc *dc, + struct dc_state *context); + void (*exit_optimized_pwr_state)(const struct dc *dc, + struct dc_state *context); + + /* Audio Related */ + void (*enable_audio_stream)(struct pipe_ctx *pipe_ctx); + void (*disable_audio_stream)(struct pipe_ctx *pipe_ctx); + + /* Stereo 3D Related */ + void (*setup_stereo)(struct pipe_ctx *pipe_ctx, struct dc *dc); + + /* HW State Logging Related */ + void (*log_hw_state)(struct dc *dc, struct dc_log_buffer_ctx *log_ctx); + void (*get_hw_state)(struct dc *dc, char *pBuf, + unsigned int bufSize, unsigned int mask); + void (*clear_status_bits)(struct dc *dc, unsigned int mask); + -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) - bool (*s0i3_golden_init_wa)(struct dc *dc); -#endif }; void color_space_to_black_color( diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h new file mode 100644 index 0000000000000000000000000000000000000000..8ba06f015975f4404fe7df9cf461112f4b60369e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h @@ -0,0 +1,156 @@ +/* + * Copyright 2015 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: AMD + * + */ + +#ifndef __DC_HW_SEQUENCER_PRIVATE_H__ +#define __DC_HW_SEQUENCER_PRIVATE_H__ + +#include "dc_types.h" + +enum pipe_gating_control { + PIPE_GATING_CONTROL_DISABLE = 0, + PIPE_GATING_CONTROL_ENABLE, + PIPE_GATING_CONTROL_INIT +}; + +struct dce_hwseq_wa { + bool blnd_crtc_trigger; + bool DEGVIDCN10_253; + bool false_optc_underflow; + bool DEGVIDCN10_254; + bool DEGVIDCN21; +}; + +struct hwseq_wa_state { + bool DEGVIDCN10_253_applied; +}; + +struct pipe_ctx; +struct dc_state; +struct dc_stream_status; +struct dc_writeback_info; +struct dchub_init_data; +struct dc_static_screen_events; +struct resource_pool; +struct resource_context; +struct stream_resource; +struct dc_phy_addr_space_config; +struct dc_virtual_addr_space_config; +struct hubp; +struct dpp; +struct dce_hwseq; +struct timing_generator; +struct tg_color; +struct output_pixel_processor; + +struct hwseq_private_funcs { + + void (*disable_stream_gating)(struct dc *dc, struct pipe_ctx *pipe_ctx); + void (*enable_stream_gating)(struct dc *dc, struct pipe_ctx *pipe_ctx); + void (*init_pipes)(struct dc *dc, struct dc_state *context); + void (*reset_hw_ctx_wrap)(struct dc *dc, struct dc_state *context); + void (*update_plane_addr)(const struct dc *dc, + struct pipe_ctx *pipe_ctx); + void (*plane_atomic_disconnect)(struct dc *dc, + struct pipe_ctx *pipe_ctx); + void (*update_mpcc)(struct dc *dc, struct pipe_ctx *pipe_ctx); + bool (*set_input_transfer_func)(struct dc *dc, + struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); + bool (*set_output_transfer_func)(struct dc *dc, + struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream); + void (*power_down)(struct dc *dc); + void (*enable_display_pipe_clock_gating)(struct dc_context *ctx, + bool clock_gating); + bool (*enable_display_power_gating)(struct dc *dc, + uint8_t controller_id, + struct dc_bios *dcb, + enum pipe_gating_control power_gating); + void (*blank_pixel_data)(struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool blank); + enum dc_status (*enable_stream_timing)( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, + struct dc *dc); + void (*edp_backlight_control)(struct dc_link *link, + bool enable); + void (*setup_vupdate_interrupt)(struct dc *dc, + struct pipe_ctx *pipe_ctx); + bool (*did_underflow_occur)(struct dc *dc, struct pipe_ctx *pipe_ctx); + void (*init_blank)(struct dc *dc, struct timing_generator *tg); + void (*disable_vga)(struct dce_hwseq *hws); + void (*bios_golden_init)(struct dc *dc); + void (*plane_atomic_power_down)(struct dc *dc, + struct dpp *dpp, + struct hubp *hubp); + void (*plane_atomic_disable)(struct dc *dc, struct pipe_ctx *pipe_ctx); + void (*enable_power_gating_plane)(struct dce_hwseq *hws, + bool enable); + void (*dpp_pg_control)(struct dce_hwseq *hws, + unsigned int dpp_inst, + bool power_on); + void (*hubp_pg_control)(struct dce_hwseq *hws, + unsigned int hubp_inst, + bool power_on); + void (*dsc_pg_control)(struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on); + void (*update_odm)(struct dc *dc, struct dc_state *context, + struct pipe_ctx *pipe_ctx); + void (*program_all_writeback_pipes_in_tree)(struct dc *dc, + const struct dc_stream_state *stream, + struct dc_state *context); + bool (*s0i3_golden_init_wa)(struct dc *dc); + void (*get_surface_visual_confirm_color)( + const struct pipe_ctx *pipe_ctx, + struct tg_color *color); + void (*get_hdr_visual_confirm_color)(struct pipe_ctx *pipe_ctx, + struct tg_color *color); + void (*set_hdr_multiplier)(struct pipe_ctx *pipe_ctx); + void (*verify_allow_pstate_change_high)(struct dc *dc); + void (*program_pipe)(struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context); + bool (*wait_for_blank_complete)(struct output_pixel_processor *opp); + void (*dccg_init)(struct dce_hwseq *hws); + bool (*set_blend_lut)(struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); + bool (*set_shaper_3dlut)(struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); +}; + +struct dce_hwseq { + struct dc_context *ctx; + const struct dce_hwseq_registers *regs; + const struct dce_hwseq_shift *shifts; + const struct dce_hwseq_mask *masks; + struct dce_hwseq_wa wa; + struct hwseq_wa_state wa_state; + struct hwseq_private_funcs funcs; + +}; + +#endif /* __DC_HW_SEQUENCER_PRIVATE_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h index 4eff5d38a2f910f32370610f9efda94d95d6234c..9af7ee5bc8ee1d6e3603c7675fe49ee69738c14b 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h @@ -60,11 +60,13 @@ void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal); bool dp_set_hw_training_pattern( struct dc_link *link, - enum dc_dp_training_pattern pattern); + enum dc_dp_training_pattern pattern, + uint32_t offset); void dp_set_hw_lane_settings( struct dc_link *link, - const struct link_training_settings *link_settings); + const struct link_training_settings *link_settings, + uint32_t offset); void dp_set_hw_test_pattern( struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h b/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h index 8503d9cc47638ffe049789243efa47dcad8860ba..47e307388581a88424427101ca8f3adfb5df6d68 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h +++ b/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h @@ -485,4 +485,23 @@ uint32_t generic_indirect_reg_update_ex(const struct dc_context *ctx, uint8_t shift1, uint32_t mask1, uint32_t field_value1, ...); +/* register offload macros + * + * instead of MMIO to register directly, in some cases we want + * to gather register sequence and execute the register sequence + * from another thread so we optimize time required for lengthy ops + */ + +/* start gathering register sequence */ +#define REG_SEQ_START() \ + reg_sequence_start_gather(CTX) + +/* start execution of register sequence gathered since REG_SEQ_START */ +#define REG_SEQ_SUBMIT() \ + reg_sequence_start_execute(CTX) + +/* wait for the last REG_SEQ_SUBMIT to finish */ +#define REG_SEQ_WAIT_DONE() \ + reg_sequence_wait_done(CTX) + #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_REG_HELPER_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index bef224bf803ef5f3a79b443a2ef29cf1b559c09f..7a85abc53d054163a4615bb4de365879b9d015a4 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -46,12 +46,8 @@ struct resource_caps { int num_pll; int num_dwb; int num_ddc; -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 int num_vmid; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT int num_dsc; -#endif -#endif }; struct resource_straps { diff --git a/drivers/gpu/drm/amd/display/dc/irq/Makefile b/drivers/gpu/drm/amd/display/dc/irq/Makefile index ea75420fc876fe3e956231f8180f2f5631cac0cc..0f682ac53bb2e09ed607a29c3c332d09231b9d63 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/Makefile +++ b/drivers/gpu/drm/amd/display/dc/irq/Makefile @@ -60,27 +60,23 @@ AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCE12) ############################################################################### # DCN 1x ############################################################################### -ifdef CONFIG_DRM_AMD_DC_DCN1_0 +ifdef CONFIG_DRM_AMD_DC_DCN IRQ_DCN1 = irq_service_dcn10.o AMD_DAL_IRQ_DCN1 = $(addprefix $(AMDDALPATH)/dc/irq/dcn10/,$(IRQ_DCN1)) AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCN1) -endif ############################################################################### # DCN 20 ############################################################################### -ifdef CONFIG_DRM_AMD_DC_DCN2_0 IRQ_DCN2 = irq_service_dcn20.o AMD_DAL_IRQ_DCN2 = $(addprefix $(AMDDALPATH)/dc/irq/dcn20/,$(IRQ_DCN2)) AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCN2) -endif ############################################################################### # DCN 21 ############################################################################### -ifdef CONFIG_DRM_AMD_DC_DCN2_1 IRQ_DCN21 = irq_service_dcn21.o AMD_DAL_IRQ_DCN21= $(addprefix $(AMDDALPATH)/dc/irq/dcn21/,$(IRQ_DCN21)) diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c index 1a581c4643458d95643da3c6bba7cba695dc6b1f..378cc11aa0476dcb78d20fe12562d868c01c9775 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c @@ -204,7 +204,7 @@ bool dce110_vblank_set(struct irq_service *irq_service, bool enable) { struct dc_context *dc_ctx = irq_service->ctx; - struct dc *core_dc = irq_service->ctx->dc; + struct dc *dc = irq_service->ctx->dc; enum dc_irq_source dal_irq_src = dc_interrupt_to_irq_source(irq_service->ctx->dc, info->src_id, @@ -212,7 +212,7 @@ bool dce110_vblank_set(struct irq_service *irq_service, uint8_t pipe_offset = dal_irq_src - IRQ_TYPE_VBLANK; struct timing_generator *tg = - core_dc->current_state->res_ctx.pipe_ctx[pipe_offset].stream_res.tg; + dc->current_state->res_ctx.pipe_ctx[pipe_offset].stream_res.tg; if (enable) { if (!tg || !tg->funcs->arm_vert_intr(tg, 2)) { @@ -403,7 +403,7 @@ static const struct irq_service_funcs irq_service_funcs_dce110 = { .to_dal_irq_source = to_dal_irq_source_dce110 }; -static void construct(struct irq_service *irq_service, +static void dce110_irq_construct(struct irq_service *irq_service, struct irq_service_init_data *init_data) { dal_irq_service_construct(irq_service, init_data); @@ -421,6 +421,6 @@ dal_irq_service_dce110_create(struct irq_service_init_data *init_data) if (!irq_service) return NULL; - construct(irq_service, init_data); + dce110_irq_construct(irq_service, init_data); return irq_service; } diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c b/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c index 15380336cb515b8af615265b0f2c7485e6c7ec7a..2fe4703395f37ada6678c66fb07d2c8974b7b797 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c @@ -273,7 +273,7 @@ static const struct irq_service_funcs irq_service_funcs_dce120 = { .to_dal_irq_source = to_dal_irq_source_dce110 }; -static void construct( +static void dce120_irq_construct( struct irq_service *irq_service, struct irq_service_init_data *init_data) { @@ -292,6 +292,6 @@ struct irq_service *dal_irq_service_dce120_create( if (!irq_service) return NULL; - construct(irq_service, init_data); + dce120_irq_construct(irq_service, init_data); return irq_service; } diff --git a/drivers/gpu/drm/amd/display/dc/irq/dce80/irq_service_dce80.c b/drivers/gpu/drm/amd/display/dc/irq/dce80/irq_service_dce80.c index 281fee8ad1e54cac6885a682650fb48a9b6f3a80..17e426b80a00fd61ac666498dca0ba0b19c9e505 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dce80/irq_service_dce80.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dce80/irq_service_dce80.c @@ -283,7 +283,7 @@ static const struct irq_service_funcs irq_service_funcs_dce80 = { .to_dal_irq_source = to_dal_irq_source_dce110 }; -static void construct( +static void dce80_irq_construct( struct irq_service *irq_service, struct irq_service_init_data *init_data) { @@ -302,7 +302,7 @@ struct irq_service *dal_irq_service_dce80_create( if (!irq_service) return NULL; - construct(irq_service, init_data); + dce80_irq_construct(irq_service, init_data); return irq_service; } diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c b/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c index cc8e7dedccce63ac86aae28762fe2e047d880918..f956b3bde680dfee271115d21587748e945ac4fd 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c @@ -355,7 +355,7 @@ static const struct irq_service_funcs irq_service_funcs_dcn10 = { .to_dal_irq_source = to_dal_irq_source_dcn10 }; -static void construct( +static void dcn10_irq_construct( struct irq_service *irq_service, struct irq_service_init_data *init_data) { @@ -374,6 +374,6 @@ struct irq_service *dal_irq_service_dcn10_create( if (!irq_service) return NULL; - construct(irq_service, init_data); + dcn10_irq_construct(irq_service, init_data); return irq_service; } diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c index 5db29bf582d31b19e2f9fa84604a594ca2bf442e..2a1fea501f8c160c717f4f91ee980049e0b52ff3 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c @@ -359,7 +359,7 @@ static const struct irq_service_funcs irq_service_funcs_dcn20 = { .to_dal_irq_source = to_dal_irq_source_dcn20 }; -static void construct( +static void dcn20_irq_construct( struct irq_service *irq_service, struct irq_service_init_data *init_data) { @@ -378,6 +378,6 @@ struct irq_service *dal_irq_service_dcn20_create( if (!irq_service) return NULL; - construct(irq_service, init_data); + dcn20_irq_construct(irq_service, init_data); return irq_service; } diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c index cbe7818529bbf0edf21c6f4b5cd2fa3986dec48b..1b971265418b6667b60f6ecd9db90b72b9231186 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c @@ -350,7 +350,7 @@ static const struct irq_service_funcs irq_service_funcs_dcn21 = { .to_dal_irq_source = to_dal_irq_source_dcn21 }; -static void construct( +static void dcn21_irq_construct( struct irq_service *irq_service, struct irq_service_init_data *init_data) { @@ -369,6 +369,6 @@ struct irq_service *dal_irq_service_dcn21_create( if (!irq_service) return NULL; - construct(irq_service, init_data); + dcn21_irq_construct(irq_service, init_data); return irq_service; } 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 0878550a8178eb7b8af65ab13428b4a84c8f37d8..33053b9fe6bd1879e79f3206fe790128fe0ea7ed 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c +++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c @@ -38,7 +38,7 @@ #include "dce120/irq_service_dce120.h" -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) #include "dcn10/irq_service_dcn10.h" #endif diff --git a/drivers/gpu/drm/amd/display/dc/os_types.h b/drivers/gpu/drm/amd/display/dc/os_types.h index 30ec80ac6fc8149882dcadd38287e2694405f6f1..13b9a9bb32c86dd31df09c7f0d92abc5de32bbfd 100644 --- a/drivers/gpu/drm/amd/display/dc/os_types.h +++ b/drivers/gpu/drm/amd/display/dc/os_types.h @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -48,7 +49,7 @@ #define dm_error(fmt, ...) DRM_ERROR(fmt, ##__VA_ARGS__) -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN) #include #endif 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 ff664bdb1482883a4a4d3692d32b33c38a3bd010..b8040da94b9db649626d6ca0e7aa4d85d3bad4d7 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 @@ -32,6 +32,7 @@ static void virtual_stream_encoder_dp_set_stream_attribute( struct stream_encoder *enc, struct dc_crtc_timing *crtc_timing, enum dc_color_space output_color_space, + bool use_vsc_sdp_for_colorimetry, uint32_t enable_sdp_splitting) {} static void virtual_stream_encoder_hdmi_set_stream_attribute( @@ -81,22 +82,14 @@ static void virtual_stream_encoder_reset_hdmi_stream_attribute( struct stream_encoder *enc) {} -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT static void virtual_enc_dp_set_odm_combine( struct stream_encoder *enc, bool odm_combine) {} -#endif -#endif static const struct stream_encoder_funcs virtual_str_enc_funcs = { -#ifdef CONFIG_DRM_AMD_DC_DCN2_0 -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT .dp_set_odm_combine = virtual_enc_dp_set_odm_combine, -#endif -#endif .dp_set_stream_attribute = virtual_stream_encoder_dp_set_stream_attribute, .hdmi_set_stream_attribute = diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h new file mode 100644 index 0000000000000000000000000000000000000000..b10728f33f627e6aaafd9019d9340f6e5dad09de --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -0,0 +1,255 @@ +/* + * Copyright 2019 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: AMD + * + */ + +#ifndef _DMUB_CMD_H_ +#define _DMUB_CMD_H_ + +#include "dmub_types.h" +#include "dmub_cmd_dal.h" +#include "dmub_cmd_vbios.h" +#include "atomfirmware.h" + +#define DMUB_RB_CMD_SIZE 64 +#define DMUB_RB_MAX_ENTRY 128 +#define DMUB_RB_SIZE (DMUB_RB_CMD_SIZE * DMUB_RB_MAX_ENTRY) +#define REG_SET_MASK 0xFFFF + +/* + * Command IDs should be treated as stable ABI. + * Do not reuse or modify IDs. + */ + +enum dmub_cmd_type { + DMUB_CMD__NULL = 0, + DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE = 1, + DMUB_CMD__REG_SEQ_FIELD_UPDATE_SEQ = 2, + DMUB_CMD__REG_SEQ_BURST_WRITE = 3, + DMUB_CMD__REG_REG_WAIT = 4, + DMUB_CMD__PSR = 64, + DMUB_CMD__VBIOS = 128, +}; + +#pragma pack(push, 1) + +struct dmub_cmd_header { + unsigned int type : 8; + unsigned int sub_type : 8; + unsigned int reserved0 : 8; + unsigned int payload_bytes : 6; /* up to 60 bytes */ + unsigned int reserved1 : 2; +}; + +/* + * Read modify write + * + * 60 payload bytes can hold up to 5 sets of read modify writes, + * each take 3 dwords. + * + * number of sequences = header.payload_bytes / sizeof(struct dmub_cmd_read_modify_write_sequence) + * + * modify_mask = 0xffff'ffff means all fields are going to be updated. in this case + * command parser will skip the read and we can use modify_mask = 0xffff'ffff as reg write + */ +struct dmub_cmd_read_modify_write_sequence { + uint32_t addr; + uint32_t modify_mask; + uint32_t modify_value; +}; + +#define DMUB_READ_MODIFY_WRITE_SEQ__MAX 5 +struct dmub_rb_cmd_read_modify_write { + struct dmub_cmd_header header; // type = DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE + struct dmub_cmd_read_modify_write_sequence seq[DMUB_READ_MODIFY_WRITE_SEQ__MAX]; +}; + +/* + * Update a register with specified masks and values sequeunce + * + * 60 payload bytes can hold address + up to 7 sets of mask/value combo, each take 2 dword + * + * number of field update sequence = (header.payload_bytes - sizeof(addr)) / sizeof(struct read_modify_write_sequence) + * + * + * USE CASE: + * 1. auto-increment register where additional read would update pointer and produce wrong result + * 2. toggle a bit without read in the middle + */ + +struct dmub_cmd_reg_field_update_sequence { + uint32_t modify_mask; // 0xffff'ffff to skip initial read + uint32_t modify_value; +}; + +#define DMUB_REG_FIELD_UPDATE_SEQ__MAX 7 + +struct dmub_rb_cmd_reg_field_update_sequence { + struct dmub_cmd_header header; + uint32_t addr; + struct dmub_cmd_reg_field_update_sequence seq[DMUB_REG_FIELD_UPDATE_SEQ__MAX]; +}; + + +/* + * Burst write + * + * support use case such as writing out LUTs. + * + * 60 payload bytes can hold up to 14 values to write to given address + * + * number of payload = header.payload_bytes / sizeof(struct read_modify_write_sequence) + */ +#define DMUB_BURST_WRITE_VALUES__MAX 14 +struct dmub_rb_cmd_burst_write { + struct dmub_cmd_header header; // type = DMUB_CMD__REG_SEQ_BURST_WRITE + uint32_t addr; + uint32_t write_values[DMUB_BURST_WRITE_VALUES__MAX]; +}; + + +struct dmub_rb_cmd_common { + struct dmub_cmd_header header; + uint8_t cmd_buffer[DMUB_RB_CMD_SIZE - sizeof(struct dmub_cmd_header)]; +}; + +struct dmub_cmd_reg_wait_data { + uint32_t addr; + uint32_t mask; + uint32_t condition_field_value; + uint32_t time_out_us; +}; + +struct dmub_rb_cmd_reg_wait { + struct dmub_cmd_header header; + struct dmub_cmd_reg_wait_data reg_wait; +}; + +struct dmub_cmd_digx_encoder_control_data { + union dig_encoder_control_parameters_v1_5 dig; +}; + +struct dmub_rb_cmd_digx_encoder_control { + struct dmub_cmd_header header; + struct dmub_cmd_digx_encoder_control_data encoder_control; +}; + +struct dmub_cmd_set_pixel_clock_data { + struct set_pixel_clock_parameter_v1_7 clk; +}; + +struct dmub_rb_cmd_set_pixel_clock { + struct dmub_cmd_header header; + struct dmub_cmd_set_pixel_clock_data pixel_clock; +}; + +struct dmub_cmd_enable_disp_power_gating_data { + struct enable_disp_power_gating_parameters_v2_1 pwr; +}; + +struct dmub_rb_cmd_enable_disp_power_gating { + struct dmub_cmd_header header; + struct dmub_cmd_enable_disp_power_gating_data power_gating; +}; + +struct dmub_cmd_dig1_transmitter_control_data { + struct dig_transmitter_control_parameters_v1_6 dig; +}; + +struct dmub_rb_cmd_dig1_transmitter_control { + struct dmub_cmd_header header; + struct dmub_cmd_dig1_transmitter_control_data transmitter_control; +}; + +struct dmub_rb_cmd_dpphy_init { + struct dmub_cmd_header header; + uint8_t reserved[60]; +}; + +struct dmub_cmd_psr_copy_settings_data { + uint32_t reg1; + uint32_t reg2; + uint32_t reg3; +}; + +struct dmub_rb_cmd_psr_copy_settings { + struct dmub_cmd_header header; + struct dmub_cmd_psr_copy_settings_data psr_copy_settings_data; +}; + +struct dmub_cmd_psr_set_level_data { + uint16_t psr_level; +}; + +struct dmub_rb_cmd_psr_set_level { + struct dmub_cmd_header header; + struct dmub_cmd_psr_set_level_data psr_set_level_data; +}; + +struct dmub_rb_cmd_psr_disable { + struct dmub_cmd_header header; +}; + +struct dmub_rb_cmd_psr_enable { + struct dmub_cmd_header header; +}; + +struct dmub_cmd_psr_notify_vblank_data { + uint32_t vblank_int; // Which vblank interrupt was triggered +}; + +struct dmub_rb_cmd_notify_vblank { + struct dmub_cmd_header header; + struct dmub_cmd_psr_notify_vblank_data psr_notify_vblank_data; +}; + +struct dmub_cmd_psr_notify_static_state_data { + uint32_t ss_int; // Which static screen interrupt was triggered + uint32_t ss_enter; // Enter (1) or exit (0) static screen +}; + +struct dmub_rb_cmd_psr_notify_static_state { + struct dmub_cmd_header header; + struct dmub_cmd_psr_notify_static_state_data psr_notify_static_state_data; +}; + +union dmub_rb_cmd { + struct dmub_rb_cmd_read_modify_write read_modify_write; + struct dmub_rb_cmd_reg_field_update_sequence reg_field_update_seq; + struct dmub_rb_cmd_burst_write burst_write; + struct dmub_rb_cmd_reg_wait reg_wait; + struct dmub_rb_cmd_common cmd_common; + struct dmub_rb_cmd_digx_encoder_control digx_encoder_control; + struct dmub_rb_cmd_set_pixel_clock set_pixel_clock; + struct dmub_rb_cmd_enable_disp_power_gating enable_disp_power_gating; + struct dmub_rb_cmd_dpphy_init dpphy_init; + struct dmub_rb_cmd_dig1_transmitter_control dig1_transmitter_control; + struct dmub_rb_cmd_psr_enable psr_enable; + struct dmub_rb_cmd_psr_disable psr_disable; + struct dmub_rb_cmd_psr_copy_settings psr_copy_settings; + struct dmub_rb_cmd_psr_set_level psr_set_level; +}; + +#pragma pack(pop) + +#endif /* _DMUB_CMD_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd_dal.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd_dal.h new file mode 100644 index 0000000000000000000000000000000000000000..14f13e8a6f3b4fe588150994be9e4fa1808d6fa3 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd_dal.h @@ -0,0 +1,41 @@ +/* + * Copyright 2019 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: AMD + * + */ + +#ifndef _DMUB_CMD_DAL_H_ +#define _DMUB_CMD_DAL_H_ + +/* + * Command IDs should be treated as stable ABI. + * Do not reuse or modify IDs. + */ + +enum dmub_cmd_psr_type { + DMUB_CMD__PSR_ENABLE = 0, + DMUB_CMD__PSR_DISABLE = 1, + DMUB_CMD__PSR_COPY_SETTINGS = 2, + DMUB_CMD__PSR_SET_LEVEL = 3, +}; + +#endif /* _DMUB_CMD_DAL_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd_vbios.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd_vbios.h new file mode 100644 index 0000000000000000000000000000000000000000..b6deb8e2590f6a570bedcd8177d3a2b42f311146 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd_vbios.h @@ -0,0 +1,41 @@ +/* + * Copyright 2019 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: AMD + * + */ + +#ifndef _DMUB_CMD_VBIOS_H_ +#define _DMUB_CMD_VBIOS_H_ + +/* + * Command IDs should be treated as stable ABI. + * Do not reuse or modify IDs. + */ + +enum dmub_cmd_vbios_type { + DMUB_CMD__VBIOS_DIGX_ENCODER_CONTROL = 0, + DMUB_CMD__VBIOS_DIG1_TRANSMITTER_CONTROL = 1, + DMUB_CMD__VBIOS_SET_PIXEL_CLOCK = 2, + DMUB_CMD__VBIOS_ENABLE_DISP_POWER_GATING = 3, +}; + +#endif /* _DMUB_CMD_VBIOS_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_fw_state.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_fw_state.h new file mode 100644 index 0000000000000000000000000000000000000000..c87b1ba7590ee00ca2f27060f84d56e9718bb435 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_fw_state.h @@ -0,0 +1,73 @@ +/* + * Copyright 2019 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: AMD + * + */ + +#ifndef _DMUB_FW_STATE_H_ +#define _DMUB_FW_STATE_H_ + +#include "dmub_types.h" + +#pragma pack(push, 1) + +struct dmub_fw_state { + /** + * @phy_initialized_during_fw_boot: + * + * Detects if VBIOS/VBL has ran before firmware boot. + * A value of 1 will usually mean S0i3 boot. + */ + uint8_t phy_initialized_during_fw_boot; + + /** + * @intialized_phy: + * + * Bit vector of initialized PHY. + */ + uint8_t initialized_phy; + + /** + * @enabled_phy: + * + * Bit vector of enabled PHY for DP alt mode switch tracking. + */ + uint8_t enabled_phy; + + /** + * @dmcu_fw_loaded: + * + * DMCU auto load state. + */ + uint8_t dmcu_fw_loaded; + + /** + * @psr_state: + * + * PSR state tracking. + */ + uint8_t psr_state; +}; + +#pragma pack(pop) + +#endif /* _DMUB_FW_STATE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_rb.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_rb.h new file mode 100644 index 0000000000000000000000000000000000000000..ac22744eaa948742a77e241d39cf9adde093101a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_rb.h @@ -0,0 +1,129 @@ +/* + * Copyright 2019 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: AMD + * + */ + +#ifndef _DMUB_RB_H_ +#define _DMUB_RB_H_ + +#include "dmub_types.h" +#include "dmub_cmd.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +struct dmub_cmd_header; + +struct dmub_rb_init_params { + void *ctx; + void *base_address; + uint32_t capacity; +}; + +struct dmub_rb { + void *base_address; + uint32_t data_count; + uint32_t rptr; + uint32_t wrpt; + uint32_t capacity; + + void *ctx; + void *dmub; +}; + + +static inline bool dmub_rb_empty(struct dmub_rb *rb) +{ + return (rb->wrpt == rb->rptr); +} + +static inline bool dmub_rb_full(struct dmub_rb *rb) +{ + uint32_t data_count; + + if (rb->wrpt >= rb->rptr) + data_count = rb->wrpt - rb->rptr; + else + data_count = rb->capacity - (rb->rptr - rb->wrpt); + + return (data_count == (rb->capacity - DMUB_RB_CMD_SIZE)); +} + +static inline bool dmub_rb_push_front(struct dmub_rb *rb, + const struct dmub_cmd_header *cmd) +{ + uint8_t *wt_ptr = (uint8_t *)(rb->base_address) + rb->wrpt; + + if (dmub_rb_full(rb)) + return false; + + dmub_memcpy(wt_ptr, cmd, DMUB_RB_CMD_SIZE); + rb->wrpt += DMUB_RB_CMD_SIZE; + + if (rb->wrpt >= rb->capacity) + rb->wrpt %= rb->capacity; + + return true; +} + +static inline bool dmub_rb_front(struct dmub_rb *rb, + struct dmub_cmd_header *cmd) +{ + uint8_t *rd_ptr = (uint8_t *)rb->base_address + rb->rptr; + + if (dmub_rb_empty(rb)) + return false; + + dmub_memcpy(cmd, rd_ptr, DMUB_RB_CMD_SIZE); + + return true; +} + +static inline bool dmub_rb_pop_front(struct dmub_rb *rb) +{ + if (dmub_rb_empty(rb)) + return false; + + rb->rptr += DMUB_RB_CMD_SIZE; + + if (rb->rptr >= rb->capacity) + rb->rptr %= rb->capacity; + + return true; +} + +static inline void dmub_rb_init(struct dmub_rb *rb, + struct dmub_rb_init_params *init_params) +{ + rb->base_address = init_params->base_address; + rb->capacity = init_params->capacity; + rb->rptr = 0; + rb->wrpt = 0; +} + +#if defined(__cplusplus) +} +#endif + +#endif /* _DMUB_RB_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_srv.h new file mode 100644 index 0000000000000000000000000000000000000000..528243e35adda60912d39625f2f24de0fd596f17 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_srv.h @@ -0,0 +1,522 @@ +/* + * Copyright 2019 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: AMD + * + */ + +#ifndef _DMUB_SRV_H_ +#define _DMUB_SRV_H_ + +/** + * DOC: DMUB interface and operation + * + * DMUB is the interface to the display DMCUB microcontroller on DCN hardware. + * It delegates hardware initialization and command submission to the + * microcontroller. DMUB is the shortname for DMCUB. + * + * This interface is not thread-safe. Ensure that all access to the interface + * is properly synchronized by the caller. + * + * Initialization and usage of the DMUB service should be done in the + * steps given below: + * + * 1. dmub_srv_create() + * 2. dmub_srv_has_hw_support() + * 3. dmub_srv_calc_region_info() + * 4. dmub_srv_hw_init() + * + * The call to dmub_srv_create() is required to use the server. + * + * The calls to dmub_srv_has_hw_support() and dmub_srv_calc_region_info() + * are helpers to query cache window size and allocate framebuffer(s) + * for the cache windows. + * + * The call to dmub_srv_hw_init() programs the DMCUB registers to prepare + * for command submission. Commands can be queued via dmub_srv_cmd_queue() + * and executed via dmub_srv_cmd_execute(). + * + * If the queue is full the dmub_srv_wait_for_idle() call can be used to + * wait until the queue has been cleared. + * + * Destroying the DMUB service can be done by calling dmub_srv_destroy(). + * This does not clear DMUB hardware state, only software state. + * + * The interface is intended to be standalone and should not depend on any + * other component within DAL. + */ + +#include "dmub_types.h" +#include "dmub_cmd.h" +#include "dmub_rb.h" +#include "dmub_fw_state.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Forward declarations */ +struct dmub_srv; +struct dmub_cmd_header; +struct dmcu; + +/* enum dmub_status - return code for dmcub functions */ +enum dmub_status { + DMUB_STATUS_OK = 0, + DMUB_STATUS_NO_CTX, + DMUB_STATUS_QUEUE_FULL, + DMUB_STATUS_TIMEOUT, + DMUB_STATUS_INVALID, +}; + +/* enum dmub_asic - dmub asic identifier */ +enum dmub_asic { + DMUB_ASIC_NONE = 0, + DMUB_ASIC_DCN20, + DMUB_ASIC_DCN21, + DMUB_ASIC_MAX, +}; + +/* enum dmub_window_id - dmub window identifier */ +enum dmub_window_id { + DMUB_WINDOW_0_INST_CONST = 0, + DMUB_WINDOW_1_STACK, + DMUB_WINDOW_2_BSS_DATA, + DMUB_WINDOW_3_VBIOS, + DMUB_WINDOW_4_MAILBOX, + DMUB_WINDOW_5_TRACEBUFF, + DMUB_WINDOW_6_FW_STATE, + DMUB_WINDOW_7_RESERVED, + DMUB_WINDOW_TOTAL, +}; + +/** + * struct dmub_region - dmub hw memory region + * @base: base address for region, must be 256 byte aligned + * @top: top address for region + */ +struct dmub_region { + uint32_t base; + uint32_t top; +}; + +/** + * struct dmub_window - dmub hw cache window + * @off: offset to the fb memory in gpu address space + * @r: region in uc address space for cache window + */ +struct dmub_window { + union dmub_addr offset; + struct dmub_region region; +}; + +/** + * struct dmub_fb - defines a dmub framebuffer memory region + * @cpu_addr: cpu virtual address for the region, NULL if invalid + * @gpu_addr: gpu virtual address for the region, NULL if invalid + * @size: size of the region in bytes, zero if invalid + */ +struct dmub_fb { + void *cpu_addr; + uint64_t gpu_addr; + uint32_t size; +}; + +/** + * struct dmub_srv_region_params - params used for calculating dmub regions + * @inst_const_size: size of the fw inst const section + * @bss_data_size: size of the fw bss data section + * @vbios_size: size of the vbios data + */ +struct dmub_srv_region_params { + uint32_t inst_const_size; + uint32_t bss_data_size; + uint32_t vbios_size; +}; + +/** + * struct dmub_srv_region_info - output region info from the dmub service + * @fb_size: required minimum fb size for all regions, aligned to 4096 bytes + * @num_regions: number of regions used by the dmub service + * @regions: region info + * + * The regions are aligned such that they can be all placed within the + * same framebuffer but they can also be placed into different framebuffers. + * + * The size of each region can be calculated by the caller: + * size = reg.top - reg.base + * + * Care must be taken when performing custom allocations to ensure that each + * region base address is 256 byte aligned. + */ +struct dmub_srv_region_info { + uint32_t fb_size; + uint8_t num_regions; + struct dmub_region regions[DMUB_WINDOW_TOTAL]; +}; + +/** + * struct dmub_srv_fb_params - parameters used for driver fb setup + * @region_info: region info calculated by dmub service + * @cpu_addr: base cpu address for the framebuffer + * @gpu_addr: base gpu virtual address for the framebuffer + */ +struct dmub_srv_fb_params { + const struct dmub_srv_region_info *region_info; + void *cpu_addr; + uint64_t gpu_addr; +}; + +/** + * struct dmub_srv_fb_info - output fb info from the dmub service + * @num_fbs: number of required dmub framebuffers + * @fbs: fb data for each region + * + * Output from the dmub service helper that can be used by the + * driver to prepare dmub_fb that can be passed into the dmub + * hw init service. + * + * Assumes that all regions are within the same framebuffer + * and have been setup according to the region_info generated + * by the dmub service. + */ +struct dmub_srv_fb_info { + uint8_t num_fb; + struct dmub_fb fb[DMUB_WINDOW_TOTAL]; +}; + +/** + * struct dmub_srv_base_funcs - Driver specific base callbacks + */ +struct dmub_srv_base_funcs { + /** + * @reg_read: + * + * Hook for reading a register. + * + * Return: The 32-bit register value from the given address. + */ + uint32_t (*reg_read)(void *ctx, uint32_t address); + + /** + * @reg_write: + * + * Hook for writing a value to the register specified by address. + */ + void (*reg_write)(void *ctx, uint32_t address, uint32_t value); +}; + +/** + * struct dmub_srv_hw_funcs - hardware sequencer funcs for dmub + */ +struct dmub_srv_hw_funcs { + /* private: internal use only */ + + void (*reset)(struct dmub_srv *dmub); + + void (*reset_release)(struct dmub_srv *dmub); + + void (*backdoor_load)(struct dmub_srv *dmub, + const struct dmub_window *cw0, + const struct dmub_window *cw1); + + void (*setup_windows)(struct dmub_srv *dmub, + const struct dmub_window *cw2, + const struct dmub_window *cw3, + const struct dmub_window *cw4, + const struct dmub_window *cw5, + const struct dmub_window *cw6); + + void (*setup_mailbox)(struct dmub_srv *dmub, + const struct dmub_region *inbox1); + + uint32_t (*get_inbox1_rptr)(struct dmub_srv *dmub); + + void (*set_inbox1_wptr)(struct dmub_srv *dmub, uint32_t wptr_offset); + + bool (*is_supported)(struct dmub_srv *dmub); + + bool (*is_hw_init)(struct dmub_srv *dmub); + + bool (*is_phy_init)(struct dmub_srv *dmub); + + bool (*is_auto_load_done)(struct dmub_srv *dmub); +}; + +/** + * struct dmub_srv_create_params - params for dmub service creation + * @base_funcs: driver supplied base routines + * @hw_funcs: optional overrides for hw funcs + * @user_ctx: context data for callback funcs + * @asic: driver supplied asic + * @is_virtual: false for hw support only + */ +struct dmub_srv_create_params { + struct dmub_srv_base_funcs funcs; + struct dmub_srv_hw_funcs *hw_funcs; + void *user_ctx; + enum dmub_asic asic; + bool is_virtual; +}; + +/* + * struct dmub_srv_hw_params - params for dmub hardware initialization + * @fb: framebuffer info for each region + * @fb_base: base of the framebuffer aperture + * @fb_offset: offset of the framebuffer aperture + * @psp_version: psp version to pass for DMCU init + * @load_inst_const: true if DMUB should load inst const fw + */ +struct dmub_srv_hw_params { + struct dmub_fb *fb[DMUB_WINDOW_TOTAL]; + uint64_t fb_base; + uint64_t fb_offset; + uint32_t psp_version; + bool load_inst_const; +}; + +/** + * struct dmub_srv - software state for dmcub + * @asic: dmub asic identifier + * @user_ctx: user provided context for the dmub_srv + * @is_virtual: false if hardware support only + * @fw_state: dmub firmware state pointer + */ +struct dmub_srv { + enum dmub_asic asic; + void *user_ctx; + bool is_virtual; + volatile const struct dmub_fw_state *fw_state; + + /* private: internal use only */ + struct dmub_srv_base_funcs funcs; + struct dmub_srv_hw_funcs hw_funcs; + struct dmub_rb inbox1_rb; + + bool sw_init; + bool hw_init; + + uint64_t fb_base; + uint64_t fb_offset; + uint32_t psp_version; +}; + +/** + * dmub_srv_create() - creates the DMUB service. + * @dmub: the dmub service + * @params: creation parameters for the service + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_create(struct dmub_srv *dmub, + const struct dmub_srv_create_params *params); + +/** + * dmub_srv_destroy() - destroys the DMUB service. + * @dmub: the dmub service + */ +void dmub_srv_destroy(struct dmub_srv *dmub); + +/** + * dmub_srv_calc_region_info() - retreives region info from the dmub service + * @dmub: the dmub service + * @params: parameters used to calculate region locations + * @info_out: the output region info from dmub + * + * Calculates the base and top address for all relevant dmub regions + * using the parameters given (if any). + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status +dmub_srv_calc_region_info(struct dmub_srv *dmub, + const struct dmub_srv_region_params *params, + struct dmub_srv_region_info *out); + +/** + * dmub_srv_calc_region_info() - retreives fb info from the dmub service + * @dmub: the dmub service + * @params: parameters used to calculate fb locations + * @info_out: the output fb info from dmub + * + * Calculates the base and top address for all relevant dmub regions + * using the parameters given (if any). + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_calc_fb_info(struct dmub_srv *dmub, + const struct dmub_srv_fb_params *params, + struct dmub_srv_fb_info *out); + +/** + * dmub_srv_has_hw_support() - returns hw support state for dmcub + * @dmub: the dmub service + * @is_supported: hw support state + * + * Queries the hardware for DMCUB support and returns the result. + * + * Can be called before dmub_srv_hw_init(). + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_has_hw_support(struct dmub_srv *dmub, + bool *is_supported); + +/** + * dmub_srv_is_hw_init() - returns hardware init state + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_is_hw_init(struct dmub_srv *dmub, bool *is_hw_init); + +/** + * dmub_srv_hw_init() - initializes the underlying DMUB hardware + * @dmub: the dmub service + * @params: params for hardware initialization + * + * Resets the DMUB hardware and performs backdoor loading of the + * required cache regions based on the input framebuffer regions. + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_NO_CTX - dmcub context not initialized + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub, + const struct dmub_srv_hw_params *params); + +/** + * dmub_srv_cmd_queue() - queues a command to the DMUB + * @dmub: the dmub service + * @cmd: the command to queue + * + * Queues a command to the DMUB service but does not begin execution + * immediately. + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_QUEUE_FULL - no remaining room in queue + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_cmd_queue(struct dmub_srv *dmub, + const struct dmub_cmd_header *cmd); + +/** + * dmub_srv_cmd_execute() - Executes a queued sequence to the dmub + * @dmub: the dmub service + * + * Begins execution of queued commands on the dmub. + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_cmd_execute(struct dmub_srv *dmub); + +/** + * dmub_srv_cmd_submit() - submits a command to the DMUB immediately + * @dmub: the dmub service + * @cmd: the command to submit + * @timeout_us: the maximum number of microseconds to wait + * + * Submits a command to the DMUB with an optional timeout. + * If timeout_us is given then the service will attempt to + * resubmit for the given number of microseconds. + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_TIMEOUT - wait for submit timed out + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_cmd_submit(struct dmub_srv *dmub, + const struct dmub_cmd_header *cmd, + uint32_t timeout_us); + +/** + * dmub_srv_wait_for_auto_load() - Waits for firmware auto load to complete + * @dmub: the dmub service + * @timeout_us: the maximum number of microseconds to wait + * + * Waits until firmware has been autoloaded by the DMCUB. The maximum + * wait time is given in microseconds to prevent spinning forever. + * + * On ASICs without firmware autoload support this function will return + * immediately. + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_TIMEOUT - wait for phy init timed out + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_wait_for_auto_load(struct dmub_srv *dmub, + uint32_t timeout_us); + +/** + * dmub_srv_wait_for_phy_init() - Waits for DMUB PHY init to complete + * @dmub: the dmub service + * @timeout_us: the maximum number of microseconds to wait + * + * Waits until the PHY has been initialized by the DMUB. The maximum + * wait time is given in microseconds to prevent spinning forever. + * + * On ASICs without PHY init support this function will return + * immediately. + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_TIMEOUT - wait for phy init timed out + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_wait_for_phy_init(struct dmub_srv *dmub, + uint32_t timeout_us); + +/** + * dmub_srv_wait_for_idle() - Waits for the DMUB to be idle + * @dmub: the dmub service + * @timeout_us: the maximum number of microseconds to wait + * + * Waits until the DMUB buffer is empty and all commands have + * finished processing. The maximum wait time is given in + * microseconds to prevent spinning forever. + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_TIMEOUT - wait for buffer to flush timed out + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_wait_for_idle(struct dmub_srv *dmub, + uint32_t timeout_us); + +#if defined(__cplusplus) +} +#endif + +#endif /* _DMUB_SRV_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_trace_buffer.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_trace_buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..6b3ee42db350cddc601f83ddbaf0085d7b589194 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_trace_buffer.h @@ -0,0 +1,69 @@ +/* + * Copyright 2019 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: AMD + * + */ +#ifndef _DMUB_TRACE_BUFFER_H_ +#define _DMUB_TRACE_BUFFER_H_ + +#include "dmub_types.h" + +#define LOAD_DMCU_FW 1 +#define LOAD_PHY_FW 2 + + +enum dmucb_trace_code { + DMCUB__UNKNOWN, + DMCUB__MAIN_BEGIN, + DMCUB__PHY_INIT_BEGIN, + DMCUB__PHY_FW_SRAM_LOAD_BEGIN, + DMCUB__PHY_FW_SRAM_LOAD_END, + DMCUB__PHY_INIT_POLL_DONE, + DMCUB__PHY_INIT_END, + DMCUB__DMCU_ERAM_LOAD_BEGIN, + DMCUB__DMCU_ERAM_LOAD_END, + DMCUB__DMCU_ISR_LOAD_BEGIN, + DMCUB__DMCU_ISR_LOAD_END, + DMCUB__MAIN_IDLE, + DMCUB__PERF_TRACE, + DMCUB__PG_DONE, +}; + +struct dmcub_trace_buf_entry { + enum dmucb_trace_code trace_code; + uint32_t tick_count; + uint32_t param0; + uint32_t param1; +}; + +#define TRACE_BUF_SIZE (1024) //1 kB +#define PERF_TRACE_MAX_ENTRY ((TRACE_BUF_SIZE - 8)/sizeof(struct dmcub_trace_buf_entry)) + + +struct dmcub_trace_buf { + uint32_t entry_count; + uint32_t clk_freq; + struct dmcub_trace_buf_entry entries[PERF_TRACE_MAX_ENTRY]; +}; + + +#endif /* _DMUB_TRACE_BUFFER_H_ */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_cik.c b/drivers/gpu/drm/amd/display/dmub/inc/dmub_types.h similarity index 55% rename from drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_cik.c rename to drivers/gpu/drm/amd/display/dmub/inc/dmub_types.h index 19e54acb4125c40e0e1d2532267150f06f16d065..41d524b0db2f3dbac64ab45d4f17c7e17486d62b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_cik.c +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_types.h @@ -1,5 +1,5 @@ /* - * Copyright 2014 Advanced Micro Devices, Inc. + * Copyright 2019 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"), @@ -19,35 +19,46 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * + * Authors: AMD + * */ -#include "kfd_kernel_queue.h" +#ifndef _DMUB_TYPES_H_ +#define _DMUB_TYPES_H_ -static bool initialize_cik(struct kernel_queue *kq, struct kfd_dev *dev, - enum kfd_queue_type type, unsigned int queue_size); -static void uninitialize_cik(struct kernel_queue *kq); -static void submit_packet_cik(struct kernel_queue *kq); +/* Basic type definitions. */ +#include +#include +#include +#include +#include -void kernel_queue_init_cik(struct kernel_queue_ops *ops) -{ - ops->initialize = initialize_cik; - ops->uninitialize = uninitialize_cik; - ops->submit_packet = submit_packet_cik; -} +#if defined(__cplusplus) +extern "C" { +#endif -static bool initialize_cik(struct kernel_queue *kq, struct kfd_dev *dev, - enum kfd_queue_type type, unsigned int queue_size) -{ - return true; -} +#ifndef dmub_memcpy +#define dmub_memcpy(dest, source, bytes) memcpy((dest), (source), (bytes)) +#endif -static void uninitialize_cik(struct kernel_queue *kq) -{ -} +#ifndef dmub_memset +#define dmub_memset(dest, val, bytes) memset((dest), (val), (bytes)) +#endif -static void submit_packet_cik(struct kernel_queue *kq) -{ - *kq->wptr_kernel = kq->pending_wptr; - write_kernel_doorbell(kq->queue->properties.doorbell_ptr, - kq->pending_wptr); +#ifndef dmub_udelay +#define dmub_udelay(microseconds) udelay(microseconds) +#endif + +union dmub_addr { + struct { + uint32_t low_part; + uint32_t high_part; + } u; + uint64_t quad_part; +}; + +#if defined(__cplusplus) } +#endif + +#endif /* _DMUB_TYPES_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/Makefile b/drivers/gpu/drm/amd/display/dmub/src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e08dfeea24b06ce7f6af6c84e269866fa3c9ab1d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/Makefile @@ -0,0 +1,27 @@ +# +# Copyright 2019 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. +# + +DMUB = dmub_srv.o dmub_reg.o dmub_dcn20.o dmub_dcn21.o + +AMD_DAL_DMUB = $(addprefix $(AMDDALPATH)/dmub/src/,$(DMUB)) + +AMD_DISPLAY_FILES += $(AMD_DAL_DMUB) diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c new file mode 100644 index 0000000000000000000000000000000000000000..951ea7053c7e3971bec9ab3702679aac17ab468b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c @@ -0,0 +1,152 @@ +/* + * Copyright 2019 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: AMD + * + */ + +#include "../inc/dmub_srv.h" +#include "dmub_reg.h" + +#include "dcn/dcn_2_0_0_offset.h" +#include "dcn/dcn_2_0_0_sh_mask.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" + +#define BASE_INNER(seg) DCN_BASE__INST0_SEG##seg +#define CTX dmub + +void dmub_dcn20_reset(struct dmub_srv *dmub) +{ + REG_UPDATE(DMCUB_CNTL, DMCUB_SOFT_RESET, 1); + REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0); +} + +void dmub_dcn20_reset_release(struct dmub_srv *dmub) +{ + REG_WRITE(DMCUB_SCRATCH15, dmub->psp_version & 0x001100FF); + REG_UPDATE_2(DMCUB_CNTL, DMCUB_ENABLE, 1, DMCUB_TRACEPORT_EN, 1); + REG_UPDATE(DMCUB_CNTL, DMCUB_SOFT_RESET, 0); +} + +void dmub_dcn20_backdoor_load(struct dmub_srv *dmub, struct dmub_window *cw0, + struct dmub_window *cw1) +{ + REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1); + REG_UPDATE_2(DMCUB_MEM_CNTL, DMCUB_MEM_READ_SPACE, 0x4, + DMCUB_MEM_WRITE_SPACE, 0x4); + + REG_WRITE(DMCUB_REGION3_CW0_OFFSET, cw0->offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW0_OFFSET_HIGH, cw0->offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW0_BASE_ADDRESS, cw0->region.base); + REG_SET_2(DMCUB_REGION3_CW0_TOP_ADDRESS, 0, + DMCUB_REGION3_CW0_TOP_ADDRESS, cw0->region.top, + DMCUB_REGION3_CW0_ENABLE, 1); + + REG_WRITE(DMCUB_REGION3_CW1_OFFSET, cw1->offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW1_OFFSET_HIGH, cw1->offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW1_BASE_ADDRESS, cw1->region.base); + REG_SET_2(DMCUB_REGION3_CW1_TOP_ADDRESS, 0, + DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top, + DMCUB_REGION3_CW1_ENABLE, 1); + + REG_UPDATE_2(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, DMCUB_MEM_UNIT_ID, + 0x20); +} + +void dmub_dcn20_setup_windows(struct dmub_srv *dmub, + const struct dmub_window *cw2, + const struct dmub_window *cw3, + const struct dmub_window *cw4, + const struct dmub_window *cw5, + const struct dmub_window *cw6) +{ + REG_WRITE(DMCUB_REGION3_CW2_OFFSET, cw2->offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW2_OFFSET_HIGH, cw2->offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW2_BASE_ADDRESS, cw2->region.base); + REG_SET_2(DMCUB_REGION3_CW2_TOP_ADDRESS, 0, + DMCUB_REGION3_CW2_TOP_ADDRESS, cw2->region.top, + DMCUB_REGION3_CW2_ENABLE, 1); + + REG_WRITE(DMCUB_REGION3_CW3_OFFSET, cw3->offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW3_OFFSET_HIGH, cw3->offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW3_BASE_ADDRESS, cw3->region.base); + REG_SET_2(DMCUB_REGION3_CW3_TOP_ADDRESS, 0, + DMCUB_REGION3_CW3_TOP_ADDRESS, cw3->region.top, + DMCUB_REGION3_CW3_ENABLE, 1); + + /* TODO: Move this to CW4. */ + + REG_WRITE(DMCUB_REGION4_OFFSET, cw4->offset.u.low_part); + REG_WRITE(DMCUB_REGION4_OFFSET_HIGH, cw4->offset.u.high_part); + REG_SET_2(DMCUB_REGION4_TOP_ADDRESS, 0, DMCUB_REGION4_TOP_ADDRESS, + cw4->region.top - cw4->region.base - 1, DMCUB_REGION4_ENABLE, + 1); + + REG_WRITE(DMCUB_REGION3_CW5_OFFSET, cw5->offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW5_OFFSET_HIGH, cw5->offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW5_BASE_ADDRESS, cw5->region.base); + REG_SET_2(DMCUB_REGION3_CW5_TOP_ADDRESS, 0, + DMCUB_REGION3_CW5_TOP_ADDRESS, cw5->region.top, + DMCUB_REGION3_CW5_ENABLE, 1); + + REG_WRITE(DMCUB_REGION3_CW6_OFFSET, cw6->offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW6_OFFSET_HIGH, cw6->offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW6_BASE_ADDRESS, cw6->region.base); + REG_SET_2(DMCUB_REGION3_CW6_TOP_ADDRESS, 0, + DMCUB_REGION3_CW6_TOP_ADDRESS, cw6->region.top, + DMCUB_REGION3_CW6_ENABLE, 1); +} + +void dmub_dcn20_setup_mailbox(struct dmub_srv *dmub, + const struct dmub_region *inbox1) +{ + /* TODO: Use CW4 instead of region 4. */ + + REG_WRITE(DMCUB_INBOX1_BASE_ADDRESS, 0x80000000); + REG_WRITE(DMCUB_INBOX1_SIZE, inbox1->top - inbox1->base); + REG_WRITE(DMCUB_INBOX1_RPTR, 0); + REG_WRITE(DMCUB_INBOX1_WPTR, 0); +} + +uint32_t dmub_dcn20_get_inbox1_rptr(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_INBOX1_RPTR); +} + +void dmub_dcn20_set_inbox1_wptr(struct dmub_srv *dmub, uint32_t wptr_offset) +{ + REG_WRITE(DMCUB_INBOX1_WPTR, wptr_offset); +} + +bool dmub_dcn20_is_hw_init(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_REGION3_CW2_BASE_ADDRESS) != 0; +} + +bool dmub_dcn20_is_supported(struct dmub_srv *dmub) +{ + uint32_t supported = 0; + + REG_GET(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE, &supported); + + return supported; +} diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h new file mode 100644 index 0000000000000000000000000000000000000000..e70a57573467f72445d7c21f0d60f58049a4b288 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h @@ -0,0 +1,63 @@ +/* + * Copyright 2019 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: AMD + * + */ + +#ifndef _DMUB_DCN20_H_ +#define _DMUB_DCN20_H_ + +#include "../inc/dmub_types.h" + +struct dmub_srv; + +/* Hardware functions. */ + +void dmub_dcn20_init(struct dmub_srv *dmub); + +void dmub_dcn20_reset(struct dmub_srv *dmub); + +void dmub_dcn20_reset_release(struct dmub_srv *dmub); + +void dmub_dcn20_backdoor_load(struct dmub_srv *dmub, + const struct dmub_window *cw0, + const struct dmub_window *cw1); + +void dmub_dcn20_setup_windows(struct dmub_srv *dmub, + const struct dmub_window *cw2, + const struct dmub_window *cw3, + const struct dmub_window *cw4, + const struct dmub_window *cw5, + const struct dmub_window *cw6); + +void dmub_dcn20_setup_mailbox(struct dmub_srv *dmub, + const struct dmub_region *inbox1); + +uint32_t dmub_dcn20_get_inbox1_rptr(struct dmub_srv *dmub); + +void dmub_dcn20_set_inbox1_wptr(struct dmub_srv *dmub, uint32_t wptr_offset); + +bool dmub_dcn20_is_hw_init(struct dmub_srv *dmub); + +bool dmub_dcn20_is_supported(struct dmub_srv *dmub); + +#endif /* _DMUB_DCN20_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c new file mode 100644 index 0000000000000000000000000000000000000000..9cea7a2d8dbfd36a0b9934818f5a22e6a90a4cbf --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c @@ -0,0 +1,141 @@ +/* + * Copyright 2019 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: AMD + * + */ + +#include "../inc/dmub_srv.h" +#include "dmub_reg.h" + +#include "dcn/dcn_2_1_0_offset.h" +#include "dcn/dcn_2_1_0_sh_mask.h" +#include "renoir_ip_offset.h" + +#define BASE_INNER(seg) DMU_BASE__INST0_SEG##seg +#define CTX dmub + +static inline void dmub_dcn21_translate_addr(const union dmub_addr *addr_in, + uint64_t fb_base, + uint64_t fb_offset, + union dmub_addr *addr_out) +{ + addr_out->quad_part = addr_in->quad_part - fb_base + fb_offset; +} + +void dmub_dcn21_backdoor_load(struct dmub_srv *dmub, + const struct dmub_window *cw0, + const struct dmub_window *cw1) +{ + union dmub_addr offset; + uint64_t fb_base = dmub->fb_base, fb_offset = dmub->fb_offset; + + REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1); + REG_UPDATE_2(DMCUB_MEM_CNTL, DMCUB_MEM_READ_SPACE, 0x3, + DMCUB_MEM_WRITE_SPACE, 0x3); + + dmub_dcn21_translate_addr(&cw0->offset, fb_base, fb_offset, &offset); + + REG_WRITE(DMCUB_REGION3_CW0_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW0_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW0_BASE_ADDRESS, cw0->region.base); + REG_SET_2(DMCUB_REGION3_CW0_TOP_ADDRESS, 0, + DMCUB_REGION3_CW0_TOP_ADDRESS, cw0->region.top, + DMCUB_REGION3_CW0_ENABLE, 1); + + dmub_dcn21_translate_addr(&cw1->offset, fb_base, fb_offset, &offset); + + REG_WRITE(DMCUB_REGION3_CW1_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW1_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW1_BASE_ADDRESS, cw1->region.base); + REG_SET_2(DMCUB_REGION3_CW1_TOP_ADDRESS, 0, + DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top, + DMCUB_REGION3_CW1_ENABLE, 1); + + REG_UPDATE_2(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, DMCUB_MEM_UNIT_ID, + 0x20); +} + +void dmub_dcn21_setup_windows(struct dmub_srv *dmub, + const struct dmub_window *cw2, + const struct dmub_window *cw3, + const struct dmub_window *cw4, + const struct dmub_window *cw5, + const struct dmub_window *cw6) +{ + union dmub_addr offset; + uint64_t fb_base = dmub->fb_base, fb_offset = dmub->fb_offset; + + dmub_dcn21_translate_addr(&cw2->offset, fb_base, fb_offset, &offset); + + REG_WRITE(DMCUB_REGION3_CW2_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW2_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW2_BASE_ADDRESS, cw2->region.base); + REG_SET_2(DMCUB_REGION3_CW2_TOP_ADDRESS, 0, + DMCUB_REGION3_CW2_TOP_ADDRESS, cw2->region.top, + DMCUB_REGION3_CW2_ENABLE, 1); + + dmub_dcn21_translate_addr(&cw3->offset, fb_base, fb_offset, &offset); + + REG_WRITE(DMCUB_REGION3_CW3_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW3_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW3_BASE_ADDRESS, cw3->region.base); + REG_SET_2(DMCUB_REGION3_CW3_TOP_ADDRESS, 0, + DMCUB_REGION3_CW3_TOP_ADDRESS, cw3->region.top, + DMCUB_REGION3_CW3_ENABLE, 1); + + /* TODO: Move this to CW4. */ + dmub_dcn21_translate_addr(&cw4->offset, fb_base, fb_offset, &offset); + + REG_WRITE(DMCUB_REGION4_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION4_OFFSET_HIGH, offset.u.high_part); + REG_SET_2(DMCUB_REGION4_TOP_ADDRESS, 0, DMCUB_REGION4_TOP_ADDRESS, + cw4->region.top - cw4->region.base - 1, DMCUB_REGION4_ENABLE, + 1); + + dmub_dcn21_translate_addr(&cw5->offset, fb_base, fb_offset, &offset); + + REG_WRITE(DMCUB_REGION3_CW5_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW5_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW5_BASE_ADDRESS, cw5->region.base); + REG_SET_2(DMCUB_REGION3_CW5_TOP_ADDRESS, 0, + DMCUB_REGION3_CW5_TOP_ADDRESS, cw5->region.top, + DMCUB_REGION3_CW5_ENABLE, 1); + + dmub_dcn21_translate_addr(&cw6->offset, fb_base, fb_offset, &offset); + + REG_WRITE(DMCUB_REGION3_CW6_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW6_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW6_BASE_ADDRESS, cw6->region.base); + REG_SET_2(DMCUB_REGION3_CW6_TOP_ADDRESS, 0, + DMCUB_REGION3_CW6_TOP_ADDRESS, cw6->region.top, + DMCUB_REGION3_CW6_ENABLE, 1); +} + +bool dmub_dcn21_is_auto_load_done(struct dmub_srv *dmub) +{ + return (REG_READ(DMCUB_SCRATCH0) == 3); +} + +bool dmub_dcn21_is_phy_init(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_SCRATCH10) == 0; +} diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.h new file mode 100644 index 0000000000000000000000000000000000000000..f7a93a5dcfa50d505b3089dd6c4f5119dbeda01d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.h @@ -0,0 +1,48 @@ +/* + * Copyright 2019 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: AMD + * + */ + +#ifndef _DMUB_DCN21_H_ +#define _DMUB_DCN21_H_ + +#include "dmub_dcn20.h" + +/* Hardware functions. */ + +void dmub_dcn21_backdoor_load(struct dmub_srv *dmub, + const struct dmub_window *cw0, + const struct dmub_window *cw1); + +void dmub_dcn21_setup_windows(struct dmub_srv *dmub, + const struct dmub_window *cw2, + const struct dmub_window *cw3, + const struct dmub_window *cw4, + const struct dmub_window *cw5, + const struct dmub_window *cw6); + +bool dmub_dcn21_is_auto_load_done(struct dmub_srv *dmub); + +bool dmub_dcn21_is_phy_init(struct dmub_srv *dmub); + +#endif /* _DMUB_DCN21_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.c new file mode 100644 index 0000000000000000000000000000000000000000..4094eca212f0b11b8aa8e8a5a765c6d4bf6a94c1 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.c @@ -0,0 +1,109 @@ +/* + * Copyright 2019 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: AMD + * + */ + +#include "dmub_reg.h" +#include "../inc/dmub_srv.h" + +struct dmub_reg_value_masks { + uint32_t value; + uint32_t mask; +}; + +static inline void +set_reg_field_value_masks(struct dmub_reg_value_masks *field_value_mask, + uint32_t value, uint32_t mask, uint8_t shift) +{ + field_value_mask->value = + (field_value_mask->value & ~mask) | (mask & (value << shift)); + field_value_mask->mask = field_value_mask->mask | mask; +} + +static void set_reg_field_values(struct dmub_reg_value_masks *field_value_mask, + uint32_t addr, int n, uint8_t shift1, + uint32_t mask1, uint32_t field_value1, + va_list ap) +{ + uint32_t shift, mask, field_value; + int i = 1; + + /* gather all bits value/mask getting updated in this register */ + set_reg_field_value_masks(field_value_mask, field_value1, mask1, + shift1); + + while (i < n) { + shift = va_arg(ap, uint32_t); + mask = va_arg(ap, uint32_t); + field_value = va_arg(ap, uint32_t); + + set_reg_field_value_masks(field_value_mask, field_value, mask, + shift); + i++; + } +} + +static inline uint32_t get_reg_field_value_ex(uint32_t reg_value, uint32_t mask, + uint8_t shift) +{ + return (mask & reg_value) >> shift; +} + +void dmub_reg_update(struct dmub_srv *srv, uint32_t addr, int n, uint8_t shift1, + uint32_t mask1, uint32_t field_value1, ...) +{ + struct dmub_reg_value_masks field_value_mask = { 0 }; + uint32_t reg_val; + va_list ap; + + va_start(ap, field_value1); + set_reg_field_values(&field_value_mask, addr, n, shift1, mask1, + field_value1, ap); + va_end(ap); + + reg_val = srv->funcs.reg_read(srv->user_ctx, addr); + reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value; + srv->funcs.reg_write(srv->user_ctx, addr, reg_val); +} + +void dmub_reg_set(struct dmub_srv *srv, uint32_t addr, uint32_t reg_val, int n, + uint8_t shift1, uint32_t mask1, uint32_t field_value1, ...) +{ + struct dmub_reg_value_masks field_value_mask = { 0 }; + va_list ap; + + va_start(ap, field_value1); + set_reg_field_values(&field_value_mask, addr, n, shift1, mask1, + field_value1, ap); + va_end(ap); + + reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value; + srv->funcs.reg_write(srv->user_ctx, addr, reg_val); +} + +void dmub_reg_get(struct dmub_srv *srv, uint32_t addr, uint8_t shift, + uint32_t mask, uint32_t *field_value) +{ + uint32_t reg_val = srv->funcs.reg_read(srv->user_ctx, addr); + *field_value = get_reg_field_value_ex(reg_val, mask, shift); +} diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..bac4ee8f745f393c43f2b3eddc099a9ab542289e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.h @@ -0,0 +1,120 @@ +/* + * Copyright 2019 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: AMD + * + */ + +#ifndef _DMUB_REG_H_ +#define _DMUB_REG_H_ + +#include "../inc/dmub_types.h" + +struct dmub_srv; + +/* Register offset and field lookup. */ + +#define BASE(seg) BASE_INNER(seg) + +#define REG_OFFSET(base_index, addr) (BASE(base_index) + addr) + +#define REG(reg_name) REG_OFFSET(mm ## reg_name ## _BASE_IDX, mm ## reg_name) + +#define FD(reg_field) reg_field ## __SHIFT, reg_field ## _MASK + +#define FN(reg_name, field) FD(reg_name##__##field) + +/* Register reads and writes. */ + +#define REG_READ(reg) ((CTX)->funcs.reg_read((CTX)->user_ctx, REG(reg))) + +#define REG_WRITE(reg, val) \ + ((CTX)->funcs.reg_write((CTX)->user_ctx, REG(reg), (val))) + +/* Register field setting. */ + +#define REG_SET_N(reg_name, n, initial_val, ...) \ + dmub_reg_set(CTX, REG(reg_name), initial_val, n, __VA_ARGS__) + +#define REG_SET(reg_name, initial_val, field, val) \ + REG_SET_N(reg_name, 1, initial_val, \ + FN(reg_name, field), val) + +#define REG_SET_2(reg, init_value, f1, v1, f2, v2) \ + REG_SET_N(reg, 2, init_value, \ + FN(reg, f1), v1, \ + FN(reg, f2), v2) + +#define REG_SET_3(reg, init_value, f1, v1, f2, v2, f3, v3) \ + REG_SET_N(reg, 3, init_value, \ + FN(reg, f1), v1, \ + FN(reg, f2), v2, \ + FN(reg, f3), v3) + +#define REG_SET_4(reg, init_value, f1, v1, f2, v2, f3, v3, f4, v4) \ + REG_SET_N(reg, 4, init_value, \ + FN(reg, f1), v1, \ + FN(reg, f2), v2, \ + FN(reg, f3), v3, \ + FN(reg, f4), v4) + +/* Register field updating. */ + +#define REG_UPDATE_N(reg_name, n, ...)\ + dmub_reg_update(CTX, REG(reg_name), n, __VA_ARGS__) + +#define REG_UPDATE(reg_name, field, val) \ + REG_UPDATE_N(reg_name, 1, \ + FN(reg_name, field), val) + +#define REG_UPDATE_2(reg, f1, v1, f2, v2) \ + REG_UPDATE_N(reg, 2,\ + FN(reg, f1), v1,\ + FN(reg, f2), v2) + +#define REG_UPDATE_3(reg, f1, v1, f2, v2, f3, v3) \ + REG_UPDATE_N(reg, 3, \ + FN(reg, f1), v1, \ + FN(reg, f2), v2, \ + FN(reg, f3), v3) + +#define REG_UPDATE_4(reg, f1, v1, f2, v2, f3, v3, f4, v4) \ + REG_UPDATE_N(reg, 4, \ + FN(reg, f1), v1, \ + FN(reg, f2), v2, \ + FN(reg, f3), v3, \ + FN(reg, f4), v4) + +/* Register field getting. */ + +#define REG_GET(reg_name, field, val) \ + dmub_reg_get(CTX, REG(reg_name), FN(reg_name, field), val) + +void dmub_reg_set(struct dmub_srv *srv, uint32_t addr, uint32_t reg_val, int n, + uint8_t shift1, uint32_t mask1, uint32_t field_value1, ...); + +void dmub_reg_update(struct dmub_srv *srv, uint32_t addr, int n, uint8_t shift1, + uint32_t mask1, uint32_t field_value1, ...); + +void dmub_reg_get(struct dmub_srv *srv, uint32_t addr, uint8_t shift, + uint32_t mask, uint32_t *field_value); + +#endif /* _DMUB_REG_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c new file mode 100644 index 0000000000000000000000000000000000000000..5f39166d3c08c2e65ae438cd92e4005c5039a834 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -0,0 +1,453 @@ +/* + * Copyright 2019 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: AMD + * + */ + +#include "../inc/dmub_srv.h" +#include "dmub_dcn20.h" +#include "dmub_dcn21.h" +#include "dmub_trace_buffer.h" +#include "os_types.h" +/* + * Note: the DMUB service is standalone. No additional headers should be + * added below or above this line unless they reside within the DMUB + * folder. + */ + +/* Alignment for framebuffer memory. */ +#define DMUB_FB_ALIGNMENT (1024 * 1024) + +/* Stack size. */ +#define DMUB_STACK_SIZE (128 * 1024) + +/* Context size. */ +#define DMUB_CONTEXT_SIZE (512 * 1024) + +/* Mailbox size */ +#define DMUB_MAILBOX_SIZE (DMUB_RB_SIZE) + + +/* Number of windows in use. */ +#define DMUB_NUM_WINDOWS (DMUB_WINDOW_6_FW_STATE + 1) +/* Base addresses. */ + +#define DMUB_CW0_BASE (0x60000000) +#define DMUB_CW1_BASE (0x61000000) +#define DMUB_CW3_BASE (0x63000000) +#define DMUB_CW5_BASE (0x65000000) +#define DMUB_CW6_BASE (0x66000000) + +static inline uint32_t dmub_align(uint32_t val, uint32_t factor) +{ + return (val + factor - 1) / factor * factor; +} + +static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic) +{ + struct dmub_srv_hw_funcs *funcs = &dmub->hw_funcs; + + switch (asic) { + case DMUB_ASIC_DCN20: + case DMUB_ASIC_DCN21: + funcs->reset = dmub_dcn20_reset; + funcs->reset_release = dmub_dcn20_reset_release; + funcs->backdoor_load = dmub_dcn20_backdoor_load; + funcs->setup_windows = dmub_dcn20_setup_windows; + funcs->setup_mailbox = dmub_dcn20_setup_mailbox; + funcs->get_inbox1_rptr = dmub_dcn20_get_inbox1_rptr; + funcs->set_inbox1_wptr = dmub_dcn20_set_inbox1_wptr; + funcs->is_supported = dmub_dcn20_is_supported; + funcs->is_hw_init = dmub_dcn20_is_hw_init; + + if (asic == DMUB_ASIC_DCN21) { + funcs->backdoor_load = dmub_dcn21_backdoor_load; + funcs->setup_windows = dmub_dcn21_setup_windows; + funcs->is_auto_load_done = dmub_dcn21_is_auto_load_done; + funcs->is_phy_init = dmub_dcn21_is_phy_init; + } + break; + + default: + return false; + } + + return true; +} + +enum dmub_status dmub_srv_create(struct dmub_srv *dmub, + const struct dmub_srv_create_params *params) +{ + enum dmub_status status = DMUB_STATUS_OK; + + dmub_memset(dmub, 0, sizeof(*dmub)); + + dmub->funcs = params->funcs; + dmub->user_ctx = params->user_ctx; + dmub->asic = params->asic; + dmub->is_virtual = params->is_virtual; + + /* Setup asic dependent hardware funcs. */ + if (!dmub_srv_hw_setup(dmub, params->asic)) { + status = DMUB_STATUS_INVALID; + goto cleanup; + } + + /* Override (some) hardware funcs based on user params. */ + if (params->hw_funcs) { + if (params->hw_funcs->get_inbox1_rptr) + dmub->hw_funcs.get_inbox1_rptr = + params->hw_funcs->get_inbox1_rptr; + + if (params->hw_funcs->set_inbox1_wptr) + dmub->hw_funcs.set_inbox1_wptr = + params->hw_funcs->set_inbox1_wptr; + + if (params->hw_funcs->is_supported) + dmub->hw_funcs.is_supported = + params->hw_funcs->is_supported; + } + + /* Sanity checks for required hw func pointers. */ + if (!dmub->hw_funcs.get_inbox1_rptr || + !dmub->hw_funcs.set_inbox1_wptr) { + status = DMUB_STATUS_INVALID; + goto cleanup; + } + +cleanup: + if (status == DMUB_STATUS_OK) + dmub->sw_init = true; + else + dmub_srv_destroy(dmub); + + return status; +} + +void dmub_srv_destroy(struct dmub_srv *dmub) +{ + dmub_memset(dmub, 0, sizeof(*dmub)); +} + +enum dmub_status +dmub_srv_calc_region_info(struct dmub_srv *dmub, + const struct dmub_srv_region_params *params, + struct dmub_srv_region_info *out) +{ + struct dmub_region *inst = &out->regions[DMUB_WINDOW_0_INST_CONST]; + struct dmub_region *stack = &out->regions[DMUB_WINDOW_1_STACK]; + struct dmub_region *data = &out->regions[DMUB_WINDOW_2_BSS_DATA]; + struct dmub_region *bios = &out->regions[DMUB_WINDOW_3_VBIOS]; + struct dmub_region *mail = &out->regions[DMUB_WINDOW_4_MAILBOX]; + struct dmub_region *trace_buff = &out->regions[DMUB_WINDOW_5_TRACEBUFF]; + struct dmub_region *fw_state = &out->regions[DMUB_WINDOW_6_FW_STATE]; + + if (!dmub->sw_init) + return DMUB_STATUS_INVALID; + + memset(out, 0, sizeof(*out)); + + out->num_regions = DMUB_NUM_WINDOWS; + + inst->base = 0x0; + inst->top = inst->base + params->inst_const_size; + + data->base = dmub_align(inst->top, 256); + data->top = data->base + params->bss_data_size; + + stack->base = dmub_align(data->top, 256); + stack->top = stack->base + DMUB_STACK_SIZE + DMUB_CONTEXT_SIZE; + + bios->base = dmub_align(stack->top, 256); + bios->top = bios->base + params->vbios_size; + + mail->base = dmub_align(bios->top, 256); + mail->top = mail->base + DMUB_MAILBOX_SIZE; + + trace_buff->base = dmub_align(mail->top, 256); + trace_buff->top = trace_buff->base + TRACE_BUF_SIZE; + + fw_state->base = dmub_align(trace_buff->top, 256); + + /* Align firmware state to size of cache line. */ + fw_state->top = + fw_state->base + dmub_align(sizeof(struct dmub_fw_state), 64); + + out->fb_size = dmub_align(fw_state->top, 4096); + + return DMUB_STATUS_OK; +} + +enum dmub_status dmub_srv_calc_fb_info(struct dmub_srv *dmub, + const struct dmub_srv_fb_params *params, + struct dmub_srv_fb_info *out) +{ + uint8_t *cpu_base; + uint64_t gpu_base; + uint32_t i; + + if (!dmub->sw_init) + return DMUB_STATUS_INVALID; + + memset(out, 0, sizeof(*out)); + + if (params->region_info->num_regions != DMUB_NUM_WINDOWS) + return DMUB_STATUS_INVALID; + + cpu_base = (uint8_t *)params->cpu_addr; + gpu_base = params->gpu_addr; + + for (i = 0; i < DMUB_NUM_WINDOWS; ++i) { + const struct dmub_region *reg = + ¶ms->region_info->regions[i]; + + out->fb[i].cpu_addr = cpu_base + reg->base; + out->fb[i].gpu_addr = gpu_base + reg->base; + out->fb[i].size = reg->top - reg->base; + } + + out->num_fb = DMUB_NUM_WINDOWS; + + return DMUB_STATUS_OK; +} + +enum dmub_status dmub_srv_has_hw_support(struct dmub_srv *dmub, + bool *is_supported) +{ + *is_supported = false; + + if (!dmub->sw_init) + return DMUB_STATUS_INVALID; + + if (dmub->hw_funcs.is_supported) + *is_supported = dmub->hw_funcs.is_supported(dmub); + + return DMUB_STATUS_OK; +} + +enum dmub_status dmub_srv_is_hw_init(struct dmub_srv *dmub, bool *is_hw_init) +{ + *is_hw_init = false; + + if (!dmub->sw_init) + return DMUB_STATUS_INVALID; + + if (dmub->hw_funcs.is_hw_init) + *is_hw_init = dmub->hw_funcs.is_hw_init(dmub); + + return DMUB_STATUS_OK; +} + +enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub, + const struct dmub_srv_hw_params *params) +{ + struct dmub_fb *inst_fb = params->fb[DMUB_WINDOW_0_INST_CONST]; + struct dmub_fb *stack_fb = params->fb[DMUB_WINDOW_1_STACK]; + struct dmub_fb *data_fb = params->fb[DMUB_WINDOW_2_BSS_DATA]; + struct dmub_fb *bios_fb = params->fb[DMUB_WINDOW_3_VBIOS]; + struct dmub_fb *mail_fb = params->fb[DMUB_WINDOW_4_MAILBOX]; + struct dmub_fb *tracebuff_fb = params->fb[DMUB_WINDOW_5_TRACEBUFF]; + struct dmub_fb *fw_state_fb = params->fb[DMUB_WINDOW_6_FW_STATE]; + + struct dmub_rb_init_params rb_params; + struct dmub_window cw0, cw1, cw2, cw3, cw4, cw5, cw6; + struct dmub_region inbox1; + + if (!dmub->sw_init) + return DMUB_STATUS_INVALID; + + dmub->fb_base = params->fb_base; + dmub->fb_offset = params->fb_offset; + dmub->psp_version = params->psp_version; + + if (inst_fb && data_fb) { + cw0.offset.quad_part = inst_fb->gpu_addr; + cw0.region.base = DMUB_CW0_BASE; + cw0.region.top = cw0.region.base + inst_fb->size - 1; + + cw1.offset.quad_part = stack_fb->gpu_addr; + cw1.region.base = DMUB_CW1_BASE; + cw1.region.top = cw1.region.base + stack_fb->size - 1; + + if (params->load_inst_const && dmub->hw_funcs.backdoor_load) + dmub->hw_funcs.backdoor_load(dmub, &cw0, &cw1); + } + + if (dmub->hw_funcs.reset) + dmub->hw_funcs.reset(dmub); + + if (inst_fb && data_fb && bios_fb && mail_fb && tracebuff_fb && + fw_state_fb) { + cw2.offset.quad_part = data_fb->gpu_addr; + cw2.region.base = DMUB_CW0_BASE + inst_fb->size; + cw2.region.top = cw2.region.base + data_fb->size; + + cw3.offset.quad_part = bios_fb->gpu_addr; + cw3.region.base = DMUB_CW3_BASE; + cw3.region.top = cw3.region.base + bios_fb->size; + + cw4.offset.quad_part = mail_fb->gpu_addr; + cw4.region.base = cw3.region.top + 1; + cw4.region.top = cw4.region.base + mail_fb->size; + + inbox1.base = cw4.region.base; + inbox1.top = cw4.region.top; + + cw5.offset.quad_part = tracebuff_fb->gpu_addr; + cw5.region.base = DMUB_CW5_BASE; + cw5.region.top = cw5.region.base + tracebuff_fb->size; + + cw6.offset.quad_part = fw_state_fb->gpu_addr; + cw6.region.base = DMUB_CW6_BASE; + cw6.region.top = cw6.region.base + fw_state_fb->size; + + dmub->fw_state = fw_state_fb->cpu_addr; + + if (dmub->hw_funcs.setup_windows) + dmub->hw_funcs.setup_windows(dmub, &cw2, &cw3, &cw4, + &cw5, &cw6); + + if (dmub->hw_funcs.setup_mailbox) + dmub->hw_funcs.setup_mailbox(dmub, &inbox1); + } + + if (mail_fb) { + dmub_memset(&rb_params, 0, sizeof(rb_params)); + rb_params.ctx = dmub; + rb_params.base_address = mail_fb->cpu_addr; + rb_params.capacity = DMUB_RB_SIZE; + + dmub_rb_init(&dmub->inbox1_rb, &rb_params); + } + + if (dmub->hw_funcs.reset_release) + dmub->hw_funcs.reset_release(dmub); + + dmub->hw_init = true; + + return DMUB_STATUS_OK; +} + +enum dmub_status dmub_srv_cmd_queue(struct dmub_srv *dmub, + const struct dmub_cmd_header *cmd) +{ + if (!dmub->hw_init) + return DMUB_STATUS_INVALID; + + if (dmub_rb_push_front(&dmub->inbox1_rb, cmd)) + return DMUB_STATUS_OK; + + return DMUB_STATUS_QUEUE_FULL; +} + +enum dmub_status dmub_srv_cmd_execute(struct dmub_srv *dmub) +{ + if (!dmub->hw_init) + return DMUB_STATUS_INVALID; + + dmub->hw_funcs.set_inbox1_wptr(dmub, dmub->inbox1_rb.wrpt); + return DMUB_STATUS_OK; +} + +enum dmub_status dmub_srv_cmd_submit(struct dmub_srv *dmub, + const struct dmub_cmd_header *cmd, + uint32_t timeout_us) +{ + uint32_t i = 0; + + if (!dmub->hw_init) + return DMUB_STATUS_INVALID; + + for (i = 0; i <= timeout_us; ++i) { + dmub->inbox1_rb.rptr = dmub->hw_funcs.get_inbox1_rptr(dmub); + if (dmub_rb_push_front(&dmub->inbox1_rb, cmd)) { + dmub->hw_funcs.set_inbox1_wptr(dmub, + dmub->inbox1_rb.wrpt); + return DMUB_STATUS_OK; + } + + udelay(1); + } + + return DMUB_STATUS_TIMEOUT; +} + +enum dmub_status dmub_srv_wait_for_auto_load(struct dmub_srv *dmub, + uint32_t timeout_us) +{ + uint32_t i; + + if (!dmub->hw_init) + return DMUB_STATUS_INVALID; + + if (!dmub->hw_funcs.is_auto_load_done) + return DMUB_STATUS_OK; + + for (i = 0; i <= timeout_us; i += 100) { + if (dmub->hw_funcs.is_auto_load_done(dmub)) + return DMUB_STATUS_OK; + + udelay(100); + } + + return DMUB_STATUS_TIMEOUT; +} + +enum dmub_status dmub_srv_wait_for_phy_init(struct dmub_srv *dmub, + uint32_t timeout_us) +{ + uint32_t i = 0; + + if (!dmub->hw_init) + return DMUB_STATUS_INVALID; + + if (!dmub->hw_funcs.is_phy_init) + return DMUB_STATUS_OK; + + for (i = 0; i <= timeout_us; i += 10) { + if (dmub->hw_funcs.is_phy_init(dmub)) + return DMUB_STATUS_OK; + + udelay(10); + } + + return DMUB_STATUS_TIMEOUT; +} + +enum dmub_status dmub_srv_wait_for_idle(struct dmub_srv *dmub, + uint32_t timeout_us) +{ + uint32_t i; + + if (!dmub->hw_init) + return DMUB_STATUS_INVALID; + + for (i = 0; i <= timeout_us; ++i) { + dmub->inbox1_rb.rptr = dmub->hw_funcs.get_inbox1_rptr(dmub); + if (dmub_rb_empty(&dmub->inbox1_rb)) + return DMUB_STATUS_OK; + + udelay(1); + } + + return DMUB_STATUS_TIMEOUT; +} 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 1be6c44fd32f032efbf40cd8994de893f1040219..72b659c63aeae4eab4ba2c2db0380504fd6796b4 100644 --- a/drivers/gpu/drm/amd/display/include/dal_asic_id.h +++ b/drivers/gpu/drm/amd/display/include/dal_asic_id.h @@ -134,23 +134,20 @@ #define PICASSO_A0 0x41 /* DCN1_01 */ #define RAVEN2_A0 0x81 +#define RAVEN2_15D8_REV_E3 0xE3 +#define RAVEN2_15D8_REV_E4 0xE4 #define RAVEN1_F0 0xF0 #define RAVEN_UNKNOWN 0xFF -#define PICASSO_15D8_REV_E3 0xE3 -#define PICASSO_15D8_REV_E4 0xE4 - #define ASICREV_IS_RAVEN(eChipRev) ((eChipRev >= RAVEN_A0) && eChipRev < RAVEN_UNKNOWN) #define ASICREV_IS_PICASSO(eChipRev) ((eChipRev >= PICASSO_A0) && (eChipRev < RAVEN2_A0)) -#define ASICREV_IS_RAVEN2(eChipRev) ((eChipRev >= RAVEN2_A0) && (eChipRev < PICASSO_15D8_REV_E3)) -#define ASICREV_IS_DALI(eChipRev) ((eChipRev >= PICASSO_15D8_REV_E3) && (eChipRev < RAVEN1_F0)) - +#define ASICREV_IS_RAVEN2(eChipRev) ((eChipRev >= RAVEN2_A0) && (eChipRev < RAVEN1_F0)) #define ASICREV_IS_RV1_F0(eChipRev) ((eChipRev >= RAVEN1_F0) && (eChipRev < RAVEN_UNKNOWN)) - +#define ASICREV_IS_DALI(eChipRev) ((eChipRev == RAVEN2_15D8_REV_E3) \ + || (eChipRev == RAVEN2_15D8_REV_E4)) #define FAMILY_RV 142 /* DCN 1*/ -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define FAMILY_NV 143 /* DCN 2*/ @@ -164,12 +161,9 @@ enum { #define ASICREV_IS_NAVI10_P(eChipRev) (eChipRev < NV_NAVI12_P_A0) #define ASICREV_IS_NAVI12_P(eChipRev) ((eChipRev >= NV_NAVI12_P_A0) && (eChipRev < NV_NAVI14_M_A0)) #define ASICREV_IS_NAVI14_M(eChipRev) ((eChipRev >= NV_NAVI14_M_A0) && (eChipRev < NV_UNKNOWN)) -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) #define RENOIR_A0 0x91 #define DEVICE_ID_RENOIR_1636 0x1636 // Renoir #define ASICREV_IS_RENOIR(eChipRev) ((eChipRev >= RENOIR_A0) && (eChipRev < 0xFF)) -#endif /* * ASIC chip ID diff --git a/drivers/gpu/drm/amd/display/include/dal_types.h b/drivers/gpu/drm/amd/display/include/dal_types.h index fcc42372b6cfb9ee3f42b2177d3d790a2d5cdf30..0b6859189ca74b4a6fdbee34007d51cbf7c0bd91 100644 --- a/drivers/gpu/drm/amd/display/include/dal_types.h +++ b/drivers/gpu/drm/amd/display/include/dal_types.h @@ -46,12 +46,8 @@ enum dce_version { DCE_VERSION_MAX, DCN_VERSION_1_0, DCN_VERSION_1_01, -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) DCN_VERSION_2_0, -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN2_1) DCN_VERSION_2_1, -#endif DCN_VERSION_MAX }; diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h index f312834fef505b6f0081e5b011a06f942a9b3b76..d51de94e4bc38873aa4565702d726202f962ec80 100644 --- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h @@ -178,7 +178,8 @@ struct dc_firmware_info { uint32_t default_engine_clk; /* in KHz */ uint32_t dp_phy_ref_clk; /* in KHz - DCE12 only */ uint32_t i2c_engine_ref_clk; /* in KHz - DCE12 only */ - + bool oem_i2c_present; + uint8_t oem_i2c_obj_id; }; diff --git a/drivers/gpu/drm/amd/display/include/i2caux_interface.h b/drivers/gpu/drm/amd/display/include/i2caux_interface.h index bb012cb1a9f58bb515db94502a461a181c49d89f..c7fbb9c3ad6b3fe59814f2f3589dbde139296f59 100644 --- a/drivers/gpu/drm/amd/display/include/i2caux_interface.h +++ b/drivers/gpu/drm/amd/display/include/i2caux_interface.h @@ -42,7 +42,7 @@ struct aux_payload { bool write; bool mot; uint32_t address; - uint8_t length; + uint32_t length; uint8_t *data; /* * used to return the reply type of the transaction diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h index 876b0b3e1a9c9193bd93736138ae333365ba0552..4869d4562e4d8852075e406404963208135b81f1 100644 --- a/drivers/gpu/drm/amd/display/include/link_service_types.h +++ b/drivers/gpu/drm/amd/display/include/link_service_types.h @@ -123,6 +123,13 @@ enum dp_test_pattern { DP_TEST_PATTERN_UNSUPPORTED }; +enum dp_test_pattern_color_space { + DP_TEST_PATTERN_COLOR_SPACE_RGB, + DP_TEST_PATTERN_COLOR_SPACE_YCBCR601, + DP_TEST_PATTERN_COLOR_SPACE_YCBCR709, + DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED +}; + enum dp_panel_mode { /* not required */ DP_PANEL_MODE_DEFAULT, diff --git a/drivers/gpu/drm/amd/display/include/logger_types.h b/drivers/gpu/drm/amd/display/include/logger_types.h index 2b219cdb13ad4b45c91b05ec4f5417684959e709..89a7092670193ac3b68b1cad97e5c55250f77c88 100644 --- a/drivers/gpu/drm/amd/display/include/logger_types.h +++ b/drivers/gpu/drm/amd/display/include/logger_types.h @@ -66,12 +66,8 @@ #define DC_LOG_GAMMA(...) pr_debug("[GAMMA]:"__VA_ARGS__) #define DC_LOG_ALL_GAMMA(...) pr_debug("[GAMMA]:"__VA_ARGS__) #define DC_LOG_ALL_TF_CHANNELS(...) pr_debug("[GAMMA]:"__VA_ARGS__) -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #define DC_LOG_DSC(...) DRM_DEBUG_KMS(__VA_ARGS__) -#endif -#if defined(CONFIG_DRM_AMD_DC_DCN3_0) || defined(CONFIG_DRM_AMD_DC_DCN2_0) #define DC_LOG_DWB(...) DRM_DEBUG_KMS(__VA_ARGS__) -#endif struct dal_logger; @@ -116,9 +112,7 @@ enum dc_log_type { LOG_PERF_TRACE, LOG_DISPLAYSTATS, LOG_HDMI_RETIMER_REDRIVER, -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT LOG_DSC, -#endif LOG_DWB, LOG_GAMMA_DEBUG, LOG_MAX_HW_POINTS, diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index 1de4805cb8c7fc23dc949263b54d3cdac662995a..b52c4d3796511c3365e26e72da78540cb309097b 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -154,6 +154,7 @@ static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) struct fixed31_32 l_pow_m1; struct fixed31_32 base, div; + struct fixed31_32 base2; if (dc_fixpt_lt(in_x, dc_fixpt_zero)) @@ -163,13 +164,15 @@ static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) dc_fixpt_div(dc_fixpt_one, m2)); base = dc_fixpt_sub(l_pow_m1, c1); - if (dc_fixpt_lt(base, dc_fixpt_zero)) - base = dc_fixpt_zero; - div = dc_fixpt_sub(c2, dc_fixpt_mul(c3, l_pow_m1)); - *out_y = dc_fixpt_pow(dc_fixpt_div(base, div), - dc_fixpt_div(dc_fixpt_one, m1)); + base2 = dc_fixpt_div(base, div); + //avoid complex numbers + if (dc_fixpt_lt(base2, dc_fixpt_zero)) + base2 = dc_fixpt_sub(dc_fixpt_zero, base2); + + + *out_y = dc_fixpt_pow(base2, dc_fixpt_div(dc_fixpt_one, m1)); } @@ -937,7 +940,6 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, struct fixed31_32 max_display; struct fixed31_32 min_display; struct fixed31_32 max_content; - struct fixed31_32 min_content; struct fixed31_32 clip = dc_fixpt_one; struct fixed31_32 output; bool use_eetf = false; @@ -951,7 +953,6 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, max_display = dc_fixpt_from_int(fs_params->max_display); min_display = dc_fixpt_from_fraction(fs_params->min_display, 10000); max_content = dc_fixpt_from_int(fs_params->max_content); - min_content = dc_fixpt_from_fraction(fs_params->min_content, 10000); sdr_white_level = dc_fixpt_from_int(fs_params->sdr_white_level); if (fs_params->min_display > 1000) // cap at 0.1 at the bottom @@ -2000,10 +2001,28 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, tf_pts->x_point_at_y1_green = 1; tf_pts->x_point_at_y1_blue = 1; - map_regamma_hw_to_x_user(ramp, coeff, rgb_user, - coordinates_x, axis_x, curve, - MAX_HW_POINTS, tf_pts, - mapUserRamp && ramp && ramp->type == GAMMA_RGB_256); + if (input_tf->tf == TRANSFER_FUNCTION_PQ) { + /* just copy current rgb_regamma into tf_pts */ + struct pwl_float_data_ex *curvePt = curve; + int i = 0; + + while (i <= MAX_HW_POINTS) { + tf_pts->red[i] = curvePt->r; + tf_pts->green[i] = curvePt->g; + tf_pts->blue[i] = curvePt->b; + ++curvePt; + ++i; + } + } else { + //clamps to 0-1 + map_regamma_hw_to_x_user(ramp, coeff, rgb_user, + coordinates_x, axis_x, curve, + MAX_HW_POINTS, tf_pts, + mapUserRamp && ramp && ramp->type == GAMMA_RGB_256); + } + + + if (ramp->type == GAMMA_CUSTOM) apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts); diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index 16e69bbc69aaa7b04a458880199962199abdf824..a94700940fd66e8ebc981b674fa8b53c38a03e95 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -37,8 +37,8 @@ #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65) /* Number of elements in the render times cache array */ #define RENDER_TIMES_MAX_COUNT 10 -/* Threshold to exit/exit BTR (to avoid frequent enter-exits at the lower limit) */ -#define BTR_MAX_MARGIN 2500 +/* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */ +#define BTR_EXIT_MARGIN 2000 /* Threshold to change BTR multiplier (to avoid frequent changes) */ #define BTR_DRIFT_MARGIN 2000 /*Threshold to exit fixed refresh rate*/ @@ -122,7 +122,7 @@ static unsigned int calc_v_total_from_refresh( const struct dc_stream_state *stream, unsigned int refresh_in_uhz) { - unsigned int v_total = stream->timing.v_total; + unsigned int v_total; unsigned int frame_duration_in_ns; frame_duration_in_ns = @@ -254,22 +254,24 @@ static void apply_below_the_range(struct core_freesync *core_freesync, unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF; unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF; unsigned int frames_to_insert = 0; + unsigned int min_frame_duration_in_ns = 0; + unsigned int max_render_time_in_us = in_out_vrr->max_duration_in_us; unsigned int delta_from_mid_point_delta_in_us; - unsigned int max_render_time_in_us = - in_out_vrr->max_duration_in_us - in_out_vrr->btr.margin_in_us; + + min_frame_duration_in_ns = ((unsigned int) (div64_u64( + (1000000000ULL * 1000000), + in_out_vrr->max_refresh_in_uhz))); /* Program BTR */ - if ((last_render_time_in_us + in_out_vrr->btr.margin_in_us / 2) < max_render_time_in_us) { + if (last_render_time_in_us + BTR_EXIT_MARGIN < max_render_time_in_us) { /* Exit Below the Range */ if (in_out_vrr->btr.btr_active) { in_out_vrr->btr.frame_counter = 0; in_out_vrr->btr.btr_active = false; } - } else if (last_render_time_in_us > (max_render_time_in_us + in_out_vrr->btr.margin_in_us / 2)) { + } else if (last_render_time_in_us > max_render_time_in_us) { /* Enter Below the Range */ - if (!in_out_vrr->btr.btr_active) { - in_out_vrr->btr.btr_active = true; - } + in_out_vrr->btr.btr_active = true; } /* BTR set to "not active" so disengage */ @@ -325,9 +327,7 @@ static void apply_below_the_range(struct core_freesync *core_freesync, /* Choose number of frames to insert based on how close it * can get to the mid point of the variable range. */ - if ((frame_time_in_us / mid_point_frames_ceil) > in_out_vrr->min_duration_in_us && - (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2 || - mid_point_frames_floor < 2)) { + if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) { frames_to_insert = mid_point_frames_ceil; delta_from_mid_point_delta_in_us = delta_from_mid_point_in_us_2 - delta_from_mid_point_in_us_1; @@ -343,7 +343,7 @@ static void apply_below_the_range(struct core_freesync *core_freesync, if (in_out_vrr->btr.frames_to_insert != 0 && delta_from_mid_point_delta_in_us < BTR_DRIFT_MARGIN) { if (((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) < - max_render_time_in_us) && + in_out_vrr->max_duration_in_us) && ((last_render_time_in_us / in_out_vrr->btr.frames_to_insert) > in_out_vrr->min_duration_in_us)) frames_to_insert = in_out_vrr->btr.frames_to_insert; @@ -796,11 +796,6 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, refresh_range = in_out_vrr->max_refresh_in_uhz - in_out_vrr->min_refresh_in_uhz; - in_out_vrr->btr.margin_in_us = in_out_vrr->max_duration_in_us - - 2 * in_out_vrr->min_duration_in_us; - if (in_out_vrr->btr.margin_in_us > BTR_MAX_MARGIN) - in_out_vrr->btr.margin_in_us = BTR_MAX_MARGIN; - in_out_vrr->supported = true; } @@ -816,7 +811,6 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, in_out_vrr->btr.inserted_duration_in_us = 0; in_out_vrr->btr.frames_to_insert = 0; in_out_vrr->btr.frame_counter = 0; - in_out_vrr->btr.mid_point_in_us = (in_out_vrr->min_duration_in_us + in_out_vrr->max_duration_in_us) / 2; diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/Makefile b/drivers/gpu/drm/amd/display/modules/hdcp/Makefile index 1c3c6d47973a303c703e41aafb896500b39158e7..904424da01b560b004436c91cf4b3430314141de 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/Makefile +++ b/drivers/gpu/drm/amd/display/modules/hdcp/Makefile @@ -24,7 +24,8 @@ # HDCP = hdcp_ddc.o hdcp_log.o hdcp_psp.o hdcp.o \ - hdcp1_execution.o hdcp1_transition.o + hdcp1_execution.o hdcp1_transition.o \ + hdcp2_execution.o hdcp2_transition.o AMD_DAL_HDCP = $(addprefix $(AMDDALPATH)/modules/hdcp/,$(HDCP)) #$(info ************ DAL-HDCP_MAKEFILE ************) diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.c index d7ac445dec6f239f1d45565bc49e6550ba85425f..8aa528e874c491f1268259079c8804b622ad4687 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.c @@ -37,24 +37,52 @@ static void push_error_status(struct mod_hdcp *hdcp, HDCP_ERROR_TRACE(hdcp, status); } - hdcp->connection.hdcp1_retry_count++; + if (is_hdcp1(hdcp)) { + hdcp->connection.hdcp1_retry_count++; + } else if (is_hdcp2(hdcp)) { + hdcp->connection.hdcp2_retry_count++; + } } static uint8_t is_cp_desired_hdcp1(struct mod_hdcp *hdcp) { - int i, display_enabled = 0; + int i, is_auth_needed = 0; - /* if all displays on the link are disabled, hdcp is not desired */ + /* if all displays on the link don't need authentication, + * hdcp is not desired + */ for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) { if (hdcp->connection.displays[i].state != MOD_HDCP_DISPLAY_INACTIVE && !hdcp->connection.displays[i].adjust.disable) { - display_enabled = 1; + is_auth_needed = 1; break; } } return (hdcp->connection.hdcp1_retry_count < MAX_NUM_OF_ATTEMPTS) && - display_enabled && !hdcp->connection.link.adjust.hdcp1.disable; + is_auth_needed && + !hdcp->connection.link.adjust.hdcp1.disable; +} + +static uint8_t is_cp_desired_hdcp2(struct mod_hdcp *hdcp) +{ + int i, is_auth_needed = 0; + + /* if all displays on the link don't need authentication, + * hdcp is not desired + */ + for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) { + if (hdcp->connection.displays[i].state != MOD_HDCP_DISPLAY_INACTIVE && + !hdcp->connection.displays[i].adjust.disable) { + is_auth_needed = 1; + break; + } + } + + return (hdcp->connection.hdcp2_retry_count < MAX_NUM_OF_ATTEMPTS) && + is_auth_needed && + !hdcp->connection.link.adjust.hdcp2.disable && + !hdcp->connection.is_hdcp2_revoked; } static enum mod_hdcp_status execution(struct mod_hdcp *hdcp, @@ -82,6 +110,11 @@ static enum mod_hdcp_status execution(struct mod_hdcp *hdcp, } else if (is_in_hdcp1_dp_states(hdcp)) { status = mod_hdcp_hdcp1_dp_execution(hdcp, event_ctx, &input->hdcp1); + } else if (is_in_hdcp2_states(hdcp)) { + status = mod_hdcp_hdcp2_execution(hdcp, event_ctx, &input->hdcp2); + } else if (is_in_hdcp2_dp_states(hdcp)) { + status = mod_hdcp_hdcp2_dp_execution(hdcp, + event_ctx, &input->hdcp2); } out: return status; @@ -99,7 +132,10 @@ static enum mod_hdcp_status transition(struct mod_hdcp *hdcp, if (is_in_initialized_state(hdcp)) { if (is_dp_hdcp(hdcp)) - if (is_cp_desired_hdcp1(hdcp)) { + if (is_cp_desired_hdcp2(hdcp)) { + callback_in_ms(0, output); + set_state_id(hdcp, output, D2_A0_DETERMINE_RX_HDCP_CAPABLE); + } else if (is_cp_desired_hdcp1(hdcp)) { callback_in_ms(0, output); set_state_id(hdcp, output, D1_A0_DETERMINE_RX_HDCP_CAPABLE); } else { @@ -107,7 +143,10 @@ static enum mod_hdcp_status transition(struct mod_hdcp *hdcp, set_state_id(hdcp, output, HDCP_CP_NOT_DESIRED); } else if (is_hdmi_dvi_sl_hdcp(hdcp)) - if (is_cp_desired_hdcp1(hdcp)) { + if (is_cp_desired_hdcp2(hdcp)) { + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A0_KNOWN_HDCP2_CAPABLE_RX); + } else if (is_cp_desired_hdcp1(hdcp)) { callback_in_ms(0, output); set_state_id(hdcp, output, H1_A0_WAIT_FOR_ACTIVE_RX); } else { @@ -126,6 +165,12 @@ static enum mod_hdcp_status transition(struct mod_hdcp *hdcp, } else if (is_in_hdcp1_dp_states(hdcp)) { status = mod_hdcp_hdcp1_dp_transition(hdcp, event_ctx, &input->hdcp1, output); + } else if (is_in_hdcp2_states(hdcp)) { + status = mod_hdcp_hdcp2_transition(hdcp, + event_ctx, &input->hdcp2, output); + } else if (is_in_hdcp2_dp_states(hdcp)) { + status = mod_hdcp_hdcp2_dp_transition(hdcp, + event_ctx, &input->hdcp2, output); } else { status = MOD_HDCP_STATUS_INVALID_STATE; } @@ -139,9 +184,13 @@ static enum mod_hdcp_status reset_authentication(struct mod_hdcp *hdcp, enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; if (is_hdcp1(hdcp)) { - if (hdcp->auth.trans_input.hdcp1.create_session != UNKNOWN) + if (hdcp->auth.trans_input.hdcp1.create_session != UNKNOWN) { + /* TODO - update psp to unify create session failure + * recovery between hdcp1 and 2. + */ mod_hdcp_hdcp1_destroy_session(hdcp); + } if (hdcp->auth.trans_input.hdcp1.add_topology == PASS) { status = mod_hdcp_remove_display_topology(hdcp); if (status != MOD_HDCP_STATUS_SUCCESS) { @@ -154,6 +203,27 @@ static enum mod_hdcp_status reset_authentication(struct mod_hdcp *hdcp, memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication)); memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state)); set_state_id(hdcp, output, HDCP_INITIALIZED); + } else if (is_hdcp2(hdcp)) { + if (hdcp->auth.trans_input.hdcp2.create_session == PASS) { + status = mod_hdcp_hdcp2_destroy_session(hdcp); + if (status != MOD_HDCP_STATUS_SUCCESS) { + output->callback_needed = 0; + output->watchdog_timer_needed = 0; + goto out; + } + } + if (hdcp->auth.trans_input.hdcp2.add_topology == PASS) { + status = mod_hdcp_remove_display_topology(hdcp); + if (status != MOD_HDCP_STATUS_SUCCESS) { + output->callback_needed = 0; + output->watchdog_timer_needed = 0; + goto out; + } + } + HDCP_TOP_RESET_AUTH_TRACE(hdcp); + memset(&hdcp->auth, 0, sizeof(struct mod_hdcp_authentication)); + memset(&hdcp->state, 0, sizeof(struct mod_hdcp_state)); + set_state_id(hdcp, output, HDCP_INITIALIZED); } else if (is_in_cp_not_desired_state(hdcp)) { status = mod_hdcp_remove_display_topology(hdcp); if (status != MOD_HDCP_STATUS_SUCCESS) { @@ -347,7 +417,20 @@ enum mod_hdcp_status mod_hdcp_query_display(struct mod_hdcp *hdcp, query->trace = &hdcp->connection.trace; query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; - mod_hdcp_hdcp1_get_link_encryption_status(hdcp, &query->encryption_status); + if (is_display_encryption_enabled(display)) { + if (is_hdcp1(hdcp)) { + query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP1_ON; + } else if (is_hdcp2(hdcp)) { + if (query->link->adjust.hdcp2.force_type == MOD_HDCP_FORCE_TYPE_0) + query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON; + else if (query->link->adjust.hdcp2.force_type == MOD_HDCP_FORCE_TYPE_1) + query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON; + else + query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_ON; + } + } else { + query->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; + } out: return status; @@ -420,7 +503,7 @@ enum mod_hdcp_operation_mode mod_hdcp_signal_type_to_operation_mode( break; default: break; - }; + } return mode; } diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h index 5664bc0b5bd0f75f05d14e18f86e95cd9265a158..f98d3d9ecb6dfa912f028675d9601b7d438eff60 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h @@ -29,32 +29,8 @@ #include "mod_hdcp.h" #include "hdcp_log.h" -#define BCAPS_READY_MASK 0x20 -#define BCAPS_REPEATER_MASK 0x40 -#define BSTATUS_DEVICE_COUNT_MASK 0X007F -#define BSTATUS_MAX_DEVS_EXCEEDED_MASK 0x0080 -#define BSTATUS_MAX_CASCADE_EXCEEDED_MASK 0x0800 -#define BCAPS_HDCP_CAPABLE_MASK_DP 0x01 -#define BCAPS_REPEATER_MASK_DP 0x02 -#define BSTATUS_READY_MASK_DP 0x01 -#define BSTATUS_R0_P_AVAILABLE_MASK_DP 0x02 -#define BSTATUS_LINK_INTEGRITY_FAILURE_MASK_DP 0x04 -#define BSTATUS_REAUTH_REQUEST_MASK_DP 0x08 -#define BINFO_DEVICE_COUNT_MASK_DP 0X007F -#define BINFO_MAX_DEVS_EXCEEDED_MASK_DP 0x0080 -#define BINFO_MAX_CASCADE_EXCEEDED_MASK_DP 0x0800 - -#define RXSTATUS_MSG_SIZE_MASK 0x03FF -#define RXSTATUS_READY_MASK 0x0400 -#define RXSTATUS_REAUTH_REQUEST_MASK 0x0800 -#define RXIDLIST_DEVICE_COUNT_LOWER_MASK 0xf0 -#define RXIDLIST_DEVICE_COUNT_UPPER_MASK 0x01 -#define RXCAPS_BYTE0_HDCP_CAPABLE_MASK_DP 0x02 -#define RXSTATUS_READY_MASK_DP 0x0001 -#define RXSTATUS_H_P_AVAILABLE_MASK_DP 0x0002 -#define RXSTATUS_PAIRING_AVAILABLE_MASK_DP 0x0004 -#define RXSTATUS_REAUTH_REQUEST_MASK_DP 0x0008 -#define RXSTATUS_LINK_INTEGRITY_FAILURE_MASK_DP 0x0010 +#include +#include enum mod_hdcp_trans_input_result { UNKNOWN = 0, @@ -92,8 +68,52 @@ struct mod_hdcp_transition_input_hdcp1 { uint8_t stream_encryption_dp; }; +struct mod_hdcp_transition_input_hdcp2 { + uint8_t hdcp2version_read; + uint8_t hdcp2_capable_check; + uint8_t add_topology; + uint8_t create_session; + uint8_t ake_init_prepare; + uint8_t ake_init_write; + uint8_t rxstatus_read; + uint8_t ake_cert_available; + uint8_t ake_cert_read; + uint8_t ake_cert_validation; + uint8_t stored_km_write; + uint8_t no_stored_km_write; + uint8_t h_prime_available; + uint8_t h_prime_read; + uint8_t pairing_available; + uint8_t pairing_info_read; + uint8_t h_prime_validation; + uint8_t lc_init_prepare; + uint8_t lc_init_write; + uint8_t l_prime_available_poll; + uint8_t l_prime_read; + uint8_t l_prime_validation; + uint8_t eks_prepare; + uint8_t eks_write; + uint8_t enable_encryption; + uint8_t reauth_request_check; + uint8_t rx_id_list_read; + uint8_t device_count_check; + uint8_t rx_id_list_validation; + uint8_t repeater_auth_ack_write; + uint8_t prepare_stream_manage; + uint8_t stream_manage_write; + uint8_t stream_ready_available; + uint8_t stream_ready_read; + uint8_t stream_ready_validation; + + uint8_t rx_caps_read_dp; + uint8_t content_stream_type_write; + uint8_t link_integrity_check_dp; + uint8_t stream_encryption_dp; +}; + union mod_hdcp_transition_input { struct mod_hdcp_transition_input_hdcp1 hdcp1; + struct mod_hdcp_transition_input_hdcp2 hdcp2; }; struct mod_hdcp_message_hdcp1 { @@ -111,8 +131,33 @@ struct mod_hdcp_message_hdcp1 { uint16_t binfo_dp; }; +struct mod_hdcp_message_hdcp2 { + uint8_t hdcp2version_hdmi; + uint8_t rxcaps_dp[3]; + uint8_t rxstatus[2]; + + uint8_t ake_init[12]; + uint8_t ake_cert[534]; + uint8_t ake_no_stored_km[129]; + uint8_t ake_stored_km[33]; + uint8_t ake_h_prime[33]; + uint8_t ake_pairing_info[17]; + uint8_t lc_init[9]; + uint8_t lc_l_prime[33]; + uint8_t ske_eks[25]; + uint8_t rx_id_list[177]; // 22 + 5 * 31 + uint16_t rx_id_list_size; + uint8_t repeater_auth_ack[17]; + uint8_t repeater_auth_stream_manage[68]; // 6 + 2 * 31 + uint16_t stream_manage_size; + uint8_t repeater_auth_stream_ready[33]; + uint8_t rxstatus_dp; + uint8_t content_stream_type_dp[2]; +}; + union mod_hdcp_message { struct mod_hdcp_message_hdcp1 hdcp1; + struct mod_hdcp_message_hdcp2 hdcp2; }; struct mod_hdcp_auth_counters { @@ -125,8 +170,10 @@ struct mod_hdcp_connection { struct mod_hdcp_display displays[MAX_NUM_OF_DISPLAYS]; uint8_t is_repeater; uint8_t is_km_stored; + uint8_t is_hdcp2_revoked; struct mod_hdcp_trace trace; uint8_t hdcp1_retry_count; + uint8_t hdcp2_retry_count; }; /* contains values per authentication cycle */ @@ -194,6 +241,50 @@ enum mod_hdcp_hdcp1_dp_state_id { HDCP1_DP_STATE_END = D1_A7_READ_KSV_LIST, }; +enum mod_hdcp_hdcp2_state_id { + HDCP2_STATE_START = HDCP1_DP_STATE_END, + H2_A0_KNOWN_HDCP2_CAPABLE_RX, + H2_A1_SEND_AKE_INIT, + H2_A1_VALIDATE_AKE_CERT, + H2_A1_SEND_NO_STORED_KM, + H2_A1_READ_H_PRIME, + H2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME, + H2_A1_SEND_STORED_KM, + H2_A1_VALIDATE_H_PRIME, + H2_A2_LOCALITY_CHECK, + H2_A3_EXCHANGE_KS_AND_TEST_FOR_REPEATER, + H2_ENABLE_ENCRYPTION, + H2_A5_AUTHENTICATED, + H2_A6_WAIT_FOR_RX_ID_LIST, + H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK, + H2_A9_SEND_STREAM_MANAGEMENT, + H2_A9_VALIDATE_STREAM_READY, + HDCP2_STATE_END = H2_A9_VALIDATE_STREAM_READY, +}; + +enum mod_hdcp_hdcp2_dp_state_id { + HDCP2_DP_STATE_START = HDCP2_STATE_END, + D2_A0_DETERMINE_RX_HDCP_CAPABLE, + D2_A1_SEND_AKE_INIT, + D2_A1_VALIDATE_AKE_CERT, + D2_A1_SEND_NO_STORED_KM, + D2_A1_READ_H_PRIME, + D2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME, + D2_A1_SEND_STORED_KM, + D2_A1_VALIDATE_H_PRIME, + D2_A2_LOCALITY_CHECK, + D2_A34_EXCHANGE_KS_AND_TEST_FOR_REPEATER, + D2_SEND_CONTENT_STREAM_TYPE, + D2_ENABLE_ENCRYPTION, + D2_A5_AUTHENTICATED, + D2_A6_WAIT_FOR_RX_ID_LIST, + D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK, + D2_A9_SEND_STREAM_MANAGEMENT, + D2_A9_VALIDATE_STREAM_READY, + HDCP2_DP_STATE_END = D2_A9_VALIDATE_STREAM_READY, + HDCP_STATE_END = HDCP2_DP_STATE_END, +}; + /* hdcp1 executions and transitions */ typedef enum mod_hdcp_status (*mod_hdcp_action)(struct mod_hdcp *hdcp); uint8_t mod_hdcp_execute_and_set( @@ -214,6 +305,22 @@ enum mod_hdcp_status mod_hdcp_hdcp1_dp_transition(struct mod_hdcp *hdcp, struct mod_hdcp_transition_input_hdcp1 *input, struct mod_hdcp_output *output); +/* hdcp2 executions and transitions */ +enum mod_hdcp_status mod_hdcp_hdcp2_execution(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input); +enum mod_hdcp_status mod_hdcp_hdcp2_dp_execution(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input); +enum mod_hdcp_status mod_hdcp_hdcp2_transition(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input, + struct mod_hdcp_output *output); +enum mod_hdcp_status mod_hdcp_hdcp2_dp_transition(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input, + struct mod_hdcp_output *output); + /* log functions */ void mod_hdcp_dump_binary_message(uint8_t *msg, uint32_t msg_size, uint8_t *buf, uint32_t buf_size); @@ -234,6 +341,25 @@ enum mod_hdcp_status mod_hdcp_hdcp1_enable_dp_stream_encryption( enum mod_hdcp_status mod_hdcp_hdcp1_link_maintenance(struct mod_hdcp *hdcp); enum mod_hdcp_status mod_hdcp_hdcp1_get_link_encryption_status(struct mod_hdcp *hdcp, enum mod_hdcp_encryption_status *encryption_status); +enum mod_hdcp_status mod_hdcp_hdcp2_create_session(struct mod_hdcp *hdcp); +enum mod_hdcp_status mod_hdcp_hdcp2_destroy_session(struct mod_hdcp *hdcp); +enum mod_hdcp_status mod_hdcp_hdcp2_prepare_ake_init(struct mod_hdcp *hdcp); +enum mod_hdcp_status mod_hdcp_hdcp2_validate_ake_cert(struct mod_hdcp *hdcp); +enum mod_hdcp_status mod_hdcp_hdcp2_validate_h_prime(struct mod_hdcp *hdcp); +enum mod_hdcp_status mod_hdcp_hdcp2_prepare_lc_init(struct mod_hdcp *hdcp); +enum mod_hdcp_status mod_hdcp_hdcp2_validate_l_prime(struct mod_hdcp *hdcp); +enum mod_hdcp_status mod_hdcp_hdcp2_prepare_eks(struct mod_hdcp *hdcp); +enum mod_hdcp_status mod_hdcp_hdcp2_enable_encryption(struct mod_hdcp *hdcp); +enum mod_hdcp_status mod_hdcp_hdcp2_validate_rx_id_list(struct mod_hdcp *hdcp); +enum mod_hdcp_status mod_hdcp_hdcp2_enable_dp_stream_encryption( + struct mod_hdcp *hdcp); +enum mod_hdcp_status mod_hdcp_hdcp2_prepare_stream_management( + struct mod_hdcp *hdcp); +enum mod_hdcp_status mod_hdcp_hdcp2_validate_stream_ready( + struct mod_hdcp *hdcp); +enum mod_hdcp_status mod_hdcp_hdcp2_get_link_encryption_status(struct mod_hdcp *hdcp, + enum mod_hdcp_encryption_status *encryption_status); + /* ddc functions */ enum mod_hdcp_status mod_hdcp_read_bksv(struct mod_hdcp *hdcp); enum mod_hdcp_status mod_hdcp_read_bcaps(struct mod_hdcp *hdcp); @@ -245,6 +371,7 @@ enum mod_hdcp_status mod_hdcp_read_binfo(struct mod_hdcp *hdcp); enum mod_hdcp_status mod_hdcp_write_aksv(struct mod_hdcp *hdcp); enum mod_hdcp_status mod_hdcp_write_ainfo(struct mod_hdcp *hdcp); enum mod_hdcp_status mod_hdcp_write_an(struct mod_hdcp *hdcp); +enum mod_hdcp_status mod_hdcp_read_hdcp2version(struct mod_hdcp *hdcp); enum mod_hdcp_status mod_hdcp_read_rxcaps(struct mod_hdcp *hdcp); enum mod_hdcp_status mod_hdcp_read_rxstatus(struct mod_hdcp *hdcp); enum mod_hdcp_status mod_hdcp_read_ake_cert(struct mod_hdcp *hdcp); @@ -308,11 +435,28 @@ static inline uint8_t is_in_hdcp1_dp_states(struct mod_hdcp *hdcp) current_state(hdcp) <= HDCP1_DP_STATE_END); } +static inline uint8_t is_in_hdcp2_states(struct mod_hdcp *hdcp) +{ + return (current_state(hdcp) > HDCP2_STATE_START && + current_state(hdcp) <= HDCP2_STATE_END); +} + +static inline uint8_t is_in_hdcp2_dp_states(struct mod_hdcp *hdcp) +{ + return (current_state(hdcp) > HDCP2_DP_STATE_START && + current_state(hdcp) <= HDCP2_DP_STATE_END); +} + static inline uint8_t is_hdcp1(struct mod_hdcp *hdcp) { return (is_in_hdcp1_states(hdcp) || is_in_hdcp1_dp_states(hdcp)); } +static inline uint8_t is_hdcp2(struct mod_hdcp *hdcp) +{ + return (is_in_hdcp2_states(hdcp) || is_in_hdcp2_dp_states(hdcp)); +} + static inline uint8_t is_in_cp_not_desired_state(struct mod_hdcp *hdcp) { return current_state(hdcp) == HDCP_CP_NOT_DESIRED; @@ -437,6 +581,7 @@ static inline struct mod_hdcp_display *get_empty_display_container( static inline void reset_retry_counts(struct mod_hdcp *hdcp) { hdcp->connection.hdcp1_retry_count = 0; + hdcp->connection.hdcp2_retry_count = 0; } #endif /* HDCP_H_ */ diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c index 3db4a7da414fc32c99199a8da9bc9056e9fe0f46..04845e43df15c8896439a5e6819a21cd3d6cf7fa 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c @@ -27,9 +27,11 @@ static inline enum mod_hdcp_status validate_bksv(struct mod_hdcp *hdcp) { - uint64_t n = *(uint64_t *)hdcp->auth.msg.hdcp1.bksv; + uint64_t n = 0; uint8_t count = 0; + memcpy(&n, hdcp->auth.msg.hdcp1.bksv, sizeof(uint64_t)); + while (n) { count++; n &= (n - 1); @@ -41,17 +43,17 @@ static inline enum mod_hdcp_status validate_bksv(struct mod_hdcp *hdcp) static inline enum mod_hdcp_status check_ksv_ready(struct mod_hdcp *hdcp) { if (is_dp_hdcp(hdcp)) - return (hdcp->auth.msg.hdcp1.bstatus & BSTATUS_READY_MASK_DP) ? + return (hdcp->auth.msg.hdcp1.bstatus & DP_BSTATUS_READY) ? MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_HDCP1_KSV_LIST_NOT_READY; - return (hdcp->auth.msg.hdcp1.bcaps & BCAPS_READY_MASK) ? + return (hdcp->auth.msg.hdcp1.bcaps & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY) ? MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_HDCP1_KSV_LIST_NOT_READY; } static inline enum mod_hdcp_status check_hdcp_capable_dp(struct mod_hdcp *hdcp) { - return (hdcp->auth.msg.hdcp1.bcaps & BCAPS_HDCP_CAPABLE_MASK_DP) ? + return (hdcp->auth.msg.hdcp1.bcaps & DP_BCAPS_HDCP_CAPABLE) ? MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_HDCP1_NOT_CAPABLE; } @@ -61,7 +63,7 @@ static inline enum mod_hdcp_status check_r0p_available_dp(struct mod_hdcp *hdcp) enum mod_hdcp_status status; if (is_dp_hdcp(hdcp)) { status = (hdcp->auth.msg.hdcp1.bstatus & - BSTATUS_R0_P_AVAILABLE_MASK_DP) ? + DP_BSTATUS_R0_PRIME_READY) ? MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_HDCP1_R0_PRIME_PENDING; } else { @@ -74,7 +76,7 @@ static inline enum mod_hdcp_status check_link_integrity_dp( struct mod_hdcp *hdcp) { return (hdcp->auth.msg.hdcp1.bstatus & - BSTATUS_LINK_INTEGRITY_FAILURE_MASK_DP) ? + DP_BSTATUS_LINK_FAILURE) ? MOD_HDCP_STATUS_HDCP1_LINK_INTEGRITY_FAILURE : MOD_HDCP_STATUS_SUCCESS; } @@ -82,7 +84,7 @@ static inline enum mod_hdcp_status check_link_integrity_dp( static inline enum mod_hdcp_status check_no_reauthentication_request_dp( struct mod_hdcp *hdcp) { - return (hdcp->auth.msg.hdcp1.bstatus & BSTATUS_REAUTH_REQUEST_MASK_DP) ? + return (hdcp->auth.msg.hdcp1.bstatus & DP_BSTATUS_REAUTH_REQ) ? MOD_HDCP_STATUS_HDCP1_REAUTH_REQUEST_ISSUED : MOD_HDCP_STATUS_SUCCESS; } @@ -92,15 +94,13 @@ static inline enum mod_hdcp_status check_no_max_cascade(struct mod_hdcp *hdcp) enum mod_hdcp_status status; if (is_dp_hdcp(hdcp)) - status = (hdcp->auth.msg.hdcp1.binfo_dp & - BINFO_MAX_CASCADE_EXCEEDED_MASK_DP) ? - MOD_HDCP_STATUS_HDCP1_MAX_CASCADE_EXCEEDED_FAILURE : - MOD_HDCP_STATUS_SUCCESS; + status = DRM_HDCP_MAX_CASCADE_EXCEEDED(hdcp->auth.msg.hdcp1.binfo_dp >> 8) + ? MOD_HDCP_STATUS_HDCP1_MAX_CASCADE_EXCEEDED_FAILURE + : MOD_HDCP_STATUS_SUCCESS; else - status = (hdcp->auth.msg.hdcp1.bstatus & - BSTATUS_MAX_CASCADE_EXCEEDED_MASK) ? - MOD_HDCP_STATUS_HDCP1_MAX_CASCADE_EXCEEDED_FAILURE : - MOD_HDCP_STATUS_SUCCESS; + status = DRM_HDCP_MAX_CASCADE_EXCEEDED(hdcp->auth.msg.hdcp1.bstatus >> 8) + ? MOD_HDCP_STATUS_HDCP1_MAX_CASCADE_EXCEEDED_FAILURE + : MOD_HDCP_STATUS_SUCCESS; return status; } @@ -109,13 +109,11 @@ static inline enum mod_hdcp_status check_no_max_devs(struct mod_hdcp *hdcp) enum mod_hdcp_status status; if (is_dp_hdcp(hdcp)) - status = (hdcp->auth.msg.hdcp1.binfo_dp & - BINFO_MAX_DEVS_EXCEEDED_MASK_DP) ? + status = DRM_HDCP_MAX_DEVICE_EXCEEDED(hdcp->auth.msg.hdcp1.binfo_dp) ? MOD_HDCP_STATUS_HDCP1_MAX_DEVS_EXCEEDED_FAILURE : MOD_HDCP_STATUS_SUCCESS; else - status = (hdcp->auth.msg.hdcp1.bstatus & - BSTATUS_MAX_DEVS_EXCEEDED_MASK) ? + status = DRM_HDCP_MAX_DEVICE_EXCEEDED(hdcp->auth.msg.hdcp1.bstatus) ? MOD_HDCP_STATUS_HDCP1_MAX_DEVS_EXCEEDED_FAILURE : MOD_HDCP_STATUS_SUCCESS; return status; @@ -124,8 +122,8 @@ static inline enum mod_hdcp_status check_no_max_devs(struct mod_hdcp *hdcp) static inline uint8_t get_device_count(struct mod_hdcp *hdcp) { return is_dp_hdcp(hdcp) ? - (hdcp->auth.msg.hdcp1.binfo_dp & BINFO_DEVICE_COUNT_MASK_DP) : - (hdcp->auth.msg.hdcp1.bstatus & BSTATUS_DEVICE_COUNT_MASK); + DRM_HDCP_NUM_DOWNSTREAM(hdcp->auth.msg.hdcp1.binfo_dp) : + DRM_HDCP_NUM_DOWNSTREAM(hdcp->auth.msg.hdcp1.bstatus); } static inline enum mod_hdcp_status check_device_count(struct mod_hdcp *hdcp) diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c new file mode 100644 index 0000000000000000000000000000000000000000..f730b94ac3c0633d584524296a1ca403028990b8 --- /dev/null +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c @@ -0,0 +1,886 @@ +/* + * Copyright 2018 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: AMD + * + */ + +#include + +#include "hdcp.h" + +static inline enum mod_hdcp_status check_receiver_id_list_ready(struct mod_hdcp *hdcp) +{ + uint8_t is_ready = 0; + + if (is_dp_hdcp(hdcp)) + is_ready = HDCP_2_2_DP_RXSTATUS_READY(hdcp->auth.msg.hdcp2.rxstatus_dp) ? 1 : 0; + else + is_ready = (HDCP_2_2_HDMI_RXSTATUS_READY(hdcp->auth.msg.hdcp2.rxstatus[0]) && + (HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | + hdcp->auth.msg.hdcp2.rxstatus[0])) ? 1 : 0; + return is_ready ? MOD_HDCP_STATUS_SUCCESS : + MOD_HDCP_STATUS_HDCP2_RX_ID_LIST_NOT_READY; +} + +static inline enum mod_hdcp_status check_hdcp2_capable(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) + status = (hdcp->auth.msg.hdcp2.rxcaps_dp[2] & HDCP_2_2_RX_CAPS_VERSION_VAL) && + HDCP_2_2_DP_HDCP_CAPABLE(hdcp->auth.msg.hdcp2.rxcaps_dp[0]) ? + MOD_HDCP_STATUS_SUCCESS : + MOD_HDCP_STATUS_HDCP2_NOT_CAPABLE; + else + status = (hdcp->auth.msg.hdcp2.hdcp2version_hdmi & HDCP_2_2_HDMI_SUPPORT_MASK) ? + MOD_HDCP_STATUS_SUCCESS : + MOD_HDCP_STATUS_HDCP2_NOT_CAPABLE; + return status; +} + +static inline enum mod_hdcp_status check_reauthentication_request( + struct mod_hdcp *hdcp) +{ + uint8_t ret = 0; + + if (is_dp_hdcp(hdcp)) + ret = HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(hdcp->auth.msg.hdcp2.rxstatus_dp) ? + MOD_HDCP_STATUS_HDCP2_REAUTH_REQUEST : + MOD_HDCP_STATUS_SUCCESS; + else + ret = HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(hdcp->auth.msg.hdcp2.rxstatus[0]) ? + MOD_HDCP_STATUS_HDCP2_REAUTH_REQUEST : + MOD_HDCP_STATUS_SUCCESS; + return ret; +} + +static inline enum mod_hdcp_status check_link_integrity_failure_dp( + struct mod_hdcp *hdcp) +{ + return HDCP_2_2_DP_RXSTATUS_LINK_FAILED(hdcp->auth.msg.hdcp2.rxstatus_dp) ? + MOD_HDCP_STATUS_HDCP2_REAUTH_LINK_INTEGRITY_FAILURE : + MOD_HDCP_STATUS_SUCCESS; +} + +static enum mod_hdcp_status check_ake_cert_available(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + uint16_t size; + + if (is_dp_hdcp(hdcp)) { + status = MOD_HDCP_STATUS_SUCCESS; + } else { + status = mod_hdcp_read_rxstatus(hdcp); + if (status == MOD_HDCP_STATUS_SUCCESS) { + size = HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | + hdcp->auth.msg.hdcp2.rxstatus[0]; + status = (size == sizeof(hdcp->auth.msg.hdcp2.ake_cert)) ? + MOD_HDCP_STATUS_SUCCESS : + MOD_HDCP_STATUS_HDCP2_AKE_CERT_PENDING; + } + } + return status; +} + +static enum mod_hdcp_status check_h_prime_available(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + uint8_t size; + + status = mod_hdcp_read_rxstatus(hdcp); + if (status != MOD_HDCP_STATUS_SUCCESS) + goto out; + + if (is_dp_hdcp(hdcp)) { + status = HDCP_2_2_DP_RXSTATUS_H_PRIME(hdcp->auth.msg.hdcp2.rxstatus_dp) ? + MOD_HDCP_STATUS_SUCCESS : + MOD_HDCP_STATUS_HDCP2_H_PRIME_PENDING; + } else { + size = HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | + hdcp->auth.msg.hdcp2.rxstatus[0]; + status = (size == sizeof(hdcp->auth.msg.hdcp2.ake_h_prime)) ? + MOD_HDCP_STATUS_SUCCESS : + MOD_HDCP_STATUS_HDCP2_H_PRIME_PENDING; + } +out: + return status; +} + +static enum mod_hdcp_status check_pairing_info_available(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + uint8_t size; + + status = mod_hdcp_read_rxstatus(hdcp); + if (status != MOD_HDCP_STATUS_SUCCESS) + goto out; + + if (is_dp_hdcp(hdcp)) { + status = HDCP_2_2_DP_RXSTATUS_PAIRING(hdcp->auth.msg.hdcp2.rxstatus_dp) ? + MOD_HDCP_STATUS_SUCCESS : + MOD_HDCP_STATUS_HDCP2_PAIRING_INFO_PENDING; + } else { + size = HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | + hdcp->auth.msg.hdcp2.rxstatus[0]; + status = (size == sizeof(hdcp->auth.msg.hdcp2.ake_pairing_info)) ? + MOD_HDCP_STATUS_SUCCESS : + MOD_HDCP_STATUS_HDCP2_PAIRING_INFO_PENDING; + } +out: + return status; +} + +static enum mod_hdcp_status poll_l_prime_available(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + uint8_t size; + uint16_t max_wait = 20; // units of ms + uint16_t num_polls = 5; + uint16_t wait_time = max_wait / num_polls; + + if (is_dp_hdcp(hdcp)) + status = MOD_HDCP_STATUS_INVALID_OPERATION; + else + for (; num_polls; num_polls--) { + msleep(wait_time); + + status = mod_hdcp_read_rxstatus(hdcp); + if (status != MOD_HDCP_STATUS_SUCCESS) + break; + + size = HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | + hdcp->auth.msg.hdcp2.rxstatus[0]; + status = (size == sizeof(hdcp->auth.msg.hdcp2.lc_l_prime)) ? + MOD_HDCP_STATUS_SUCCESS : + MOD_HDCP_STATUS_HDCP2_L_PRIME_PENDING; + if (status == MOD_HDCP_STATUS_SUCCESS) + break; + } + return status; +} + +static enum mod_hdcp_status check_stream_ready_available(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + uint8_t size; + + if (is_dp_hdcp(hdcp)) { + status = MOD_HDCP_STATUS_INVALID_OPERATION; + } else { + status = mod_hdcp_read_rxstatus(hdcp); + if (status != MOD_HDCP_STATUS_SUCCESS) + goto out; + size = HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | + hdcp->auth.msg.hdcp2.rxstatus[0]; + status = (size == sizeof(hdcp->auth.msg.hdcp2.repeater_auth_stream_ready)) ? + MOD_HDCP_STATUS_SUCCESS : + MOD_HDCP_STATUS_HDCP2_STREAM_READY_PENDING; + } +out: + return status; +} + +static inline uint8_t get_device_count(struct mod_hdcp *hdcp) +{ + return HDCP_2_2_DEV_COUNT_LO(hdcp->auth.msg.hdcp2.rx_id_list[2]) + + (HDCP_2_2_DEV_COUNT_HI(hdcp->auth.msg.hdcp2.rx_id_list[1]) << 4); +} + +static enum mod_hdcp_status check_device_count(struct mod_hdcp *hdcp) +{ + /* device count must be greater than or equal to tracked hdcp displays */ + return (get_device_count(hdcp) < get_added_display_count(hdcp)) ? + MOD_HDCP_STATUS_HDCP2_DEVICE_COUNT_MISMATCH_FAILURE : + MOD_HDCP_STATUS_SUCCESS; +} + +static uint8_t process_rxstatus(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input, + enum mod_hdcp_status *status) +{ + if (!mod_hdcp_execute_and_set(mod_hdcp_read_rxstatus, + &input->rxstatus_read, status, + hdcp, "rxstatus_read")) + goto out; + if (!mod_hdcp_execute_and_set(check_reauthentication_request, + &input->reauth_request_check, status, + hdcp, "reauth_request_check")) + goto out; + if (is_dp_hdcp(hdcp)) { + if (!mod_hdcp_execute_and_set(check_link_integrity_failure_dp, + &input->link_integrity_check_dp, status, + hdcp, "link_integrity_check_dp")) + goto out; + } + if (hdcp->connection.is_repeater) + if (check_receiver_id_list_ready(hdcp) == + MOD_HDCP_STATUS_SUCCESS) { + HDCP_INPUT_PASS_TRACE(hdcp, "rx_id_list_ready"); + event_ctx->rx_id_list_ready = 1; + if (is_dp_hdcp(hdcp)) + hdcp->auth.msg.hdcp2.rx_id_list_size = + sizeof(hdcp->auth.msg.hdcp2.rx_id_list); + else + hdcp->auth.msg.hdcp2.rx_id_list_size = + HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | + hdcp->auth.msg.hdcp2.rxstatus[0]; + } +out: + return (*status == MOD_HDCP_STATUS_SUCCESS); +} + +static enum mod_hdcp_status known_hdcp2_capable_rx(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { + event_ctx->unexpected_event = 1; + goto out; + } + if (!mod_hdcp_execute_and_set(mod_hdcp_read_hdcp2version, + &input->hdcp2version_read, &status, + hdcp, "hdcp2version_read")) + goto out; + if (!mod_hdcp_execute_and_set(check_hdcp2_capable, + &input->hdcp2_capable_check, &status, + hdcp, "hdcp2_capable")) + goto out; +out: + return status; +} + +static enum mod_hdcp_status send_ake_init(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { + event_ctx->unexpected_event = 1; + goto out; + } + if (!mod_hdcp_execute_and_set(mod_hdcp_add_display_topology, + &input->add_topology, &status, + hdcp, "add_topology")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp2_create_session, + &input->create_session, &status, + hdcp, "create_session")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp2_prepare_ake_init, + &input->ake_init_prepare, &status, + hdcp, "ake_init_prepare")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_write_ake_init, + &input->ake_init_write, &status, + hdcp, "ake_init_write")) + goto out; +out: + return status; +} + +static enum mod_hdcp_status validate_ake_cert(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && + event_ctx->event != MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { + event_ctx->unexpected_event = 1; + goto out; + } + + if (is_hdmi_dvi_sl_hdcp(hdcp)) + if (!mod_hdcp_execute_and_set(check_ake_cert_available, + &input->ake_cert_available, &status, + hdcp, "ake_cert_available")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_read_ake_cert, + &input->ake_cert_read, &status, + hdcp, "ake_cert_read")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp2_validate_ake_cert, + &input->ake_cert_validation, &status, + hdcp, "ake_cert_validation")) + goto out; +out: + return status; +} + +static enum mod_hdcp_status send_no_stored_km(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { + event_ctx->unexpected_event = 1; + goto out; + } + + if (!mod_hdcp_execute_and_set(mod_hdcp_write_no_stored_km, + &input->no_stored_km_write, &status, + hdcp, "no_stored_km_write")) + goto out; +out: + return status; +} + +static enum mod_hdcp_status read_h_prime(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && + event_ctx->event != MOD_HDCP_EVENT_CPIRQ && + event_ctx->event != MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { + event_ctx->unexpected_event = 1; + goto out; + } + + if (!mod_hdcp_execute_and_set(check_h_prime_available, + &input->h_prime_available, &status, + hdcp, "h_prime_available")) + goto out; + + if (!mod_hdcp_execute_and_set(mod_hdcp_read_h_prime, + &input->h_prime_read, &status, + hdcp, "h_prime_read")) + goto out; +out: + return status; +} + +static enum mod_hdcp_status read_pairing_info_and_validate_h_prime( + struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && + event_ctx->event != MOD_HDCP_EVENT_CPIRQ && + event_ctx->event != MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { + event_ctx->unexpected_event = 1; + goto out; + } + + if (!mod_hdcp_execute_and_set(check_pairing_info_available, + &input->pairing_available, &status, + hdcp, "pairing_available")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_read_pairing_info, + &input->pairing_info_read, &status, + hdcp, "pairing_info_read")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp2_validate_h_prime, + &input->h_prime_validation, &status, + hdcp, "h_prime_validation")) + goto out; +out: + return status; +} + +static enum mod_hdcp_status send_stored_km(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { + event_ctx->unexpected_event = 1; + goto out; + } + + if (!mod_hdcp_execute_and_set(mod_hdcp_write_stored_km, + &input->stored_km_write, &status, + hdcp, "stored_km_write")) + goto out; +out: + return status; +} + +static enum mod_hdcp_status validate_h_prime(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && + event_ctx->event != MOD_HDCP_EVENT_CPIRQ && + event_ctx->event != MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { + event_ctx->unexpected_event = 1; + goto out; + } + + if (!mod_hdcp_execute_and_set(check_h_prime_available, + &input->h_prime_available, &status, + hdcp, "h_prime_available")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_read_h_prime, + &input->h_prime_read, &status, + hdcp, "h_prime_read")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp2_validate_h_prime, + &input->h_prime_validation, &status, + hdcp, "h_prime_validation")) + goto out; +out: + return status; +} + +static enum mod_hdcp_status locality_check(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { + event_ctx->unexpected_event = 1; + goto out; + } + + if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp2_prepare_lc_init, + &input->lc_init_prepare, &status, + hdcp, "lc_init_prepare")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_write_lc_init, + &input->lc_init_write, &status, + hdcp, "lc_init_write")) + goto out; + if (is_dp_hdcp(hdcp)) + msleep(16); + else + if (!mod_hdcp_execute_and_set(poll_l_prime_available, + &input->l_prime_available_poll, &status, + hdcp, "l_prime_available_poll")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_read_l_prime, + &input->l_prime_read, &status, + hdcp, "l_prime_read")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp2_validate_l_prime, + &input->l_prime_validation, &status, + hdcp, "l_prime_validation")) + goto out; +out: + return status; +} + +static enum mod_hdcp_status exchange_ks_and_test_for_repeater(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { + event_ctx->unexpected_event = 1; + goto out; + } + + if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp2_prepare_eks, + &input->eks_prepare, &status, + hdcp, "eks_prepare")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_write_eks, + &input->eks_write, &status, + hdcp, "eks_write")) + goto out; +out: + return status; +} + +static enum mod_hdcp_status enable_encryption(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && + event_ctx->event != MOD_HDCP_EVENT_CPIRQ) { + event_ctx->unexpected_event = 1; + goto out; + } + if (event_ctx->event == MOD_HDCP_EVENT_CPIRQ) { + process_rxstatus(hdcp, event_ctx, input, &status); + goto out; + } + + if (is_hdmi_dvi_sl_hdcp(hdcp)) { + if (!process_rxstatus(hdcp, event_ctx, input, &status)) + goto out; + if (event_ctx->rx_id_list_ready) + goto out; + } + if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp2_enable_encryption, + &input->enable_encryption, &status, + hdcp, "enable_encryption")) + goto out; + if (is_dp_mst_hdcp(hdcp)) { + if (!mod_hdcp_execute_and_set( + mod_hdcp_hdcp2_enable_dp_stream_encryption, + &input->stream_encryption_dp, &status, + hdcp, "stream_encryption_dp")) + goto out; + } +out: + return status; +} + +static enum mod_hdcp_status authenticated(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && + event_ctx->event != MOD_HDCP_EVENT_CPIRQ) { + event_ctx->unexpected_event = 1; + goto out; + } + + if (!process_rxstatus(hdcp, event_ctx, input, &status)) + goto out; + if (event_ctx->rx_id_list_ready) + goto out; +out: + return status; +} + +static enum mod_hdcp_status wait_for_rx_id_list(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && + event_ctx->event != MOD_HDCP_EVENT_CPIRQ && + event_ctx->event != MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { + event_ctx->unexpected_event = 1; + goto out; + } + + if (!process_rxstatus(hdcp, event_ctx, input, &status)) + goto out; + if (!event_ctx->rx_id_list_ready) { + status = MOD_HDCP_STATUS_HDCP2_RX_ID_LIST_NOT_READY; + goto out; + } +out: + return status; +} + +static enum mod_hdcp_status verify_rx_id_list_and_send_ack(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && + event_ctx->event != MOD_HDCP_EVENT_CPIRQ) { + event_ctx->unexpected_event = 1; + goto out; + } + if (event_ctx->event == MOD_HDCP_EVENT_CPIRQ) { + process_rxstatus(hdcp, event_ctx, input, &status); + goto out; + } + + if (!mod_hdcp_execute_and_set(mod_hdcp_read_rx_id_list, + &input->rx_id_list_read, + &status, hdcp, "receiver_id_list_read")) + goto out; + if (!mod_hdcp_execute_and_set(check_device_count, + &input->device_count_check, + &status, hdcp, "device_count_check")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp2_validate_rx_id_list, + &input->rx_id_list_validation, + &status, hdcp, "rx_id_list_validation")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_write_repeater_auth_ack, + &input->repeater_auth_ack_write, + &status, hdcp, "repeater_auth_ack_write")) + goto out; +out: + return status; +} + +static enum mod_hdcp_status send_stream_management(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && + event_ctx->event != MOD_HDCP_EVENT_CPIRQ) { + event_ctx->unexpected_event = 1; + goto out; + } + if (event_ctx->event == MOD_HDCP_EVENT_CPIRQ) { + process_rxstatus(hdcp, event_ctx, input, &status); + goto out; + } + + if (is_hdmi_dvi_sl_hdcp(hdcp)) { + if (!process_rxstatus(hdcp, event_ctx, input, &status)) + goto out; + if (event_ctx->rx_id_list_ready) + goto out; + } + if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp2_prepare_stream_management, + &input->prepare_stream_manage, + &status, hdcp, "prepare_stream_manage")) + goto out; + + if (!mod_hdcp_execute_and_set(mod_hdcp_write_stream_manage, + &input->stream_manage_write, + &status, hdcp, "stream_manage_write")) + goto out; +out: + return status; +} + +static enum mod_hdcp_status validate_stream_ready(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && + event_ctx->event != MOD_HDCP_EVENT_CPIRQ && + event_ctx->event != MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { + event_ctx->unexpected_event = 1; + goto out; + } + if (event_ctx->event == MOD_HDCP_EVENT_CPIRQ) { + process_rxstatus(hdcp, event_ctx, input, &status); + goto out; + } + + if (is_hdmi_dvi_sl_hdcp(hdcp)) { + if (!process_rxstatus(hdcp, event_ctx, input, &status)) + goto out; + if (event_ctx->rx_id_list_ready) { + goto out; + } + } + if (is_hdmi_dvi_sl_hdcp(hdcp)) + if (!mod_hdcp_execute_and_set(check_stream_ready_available, + &input->stream_ready_available, + &status, hdcp, "stream_ready_available")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_read_stream_ready, + &input->stream_ready_read, + &status, hdcp, "stream_ready_read")) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_hdcp2_validate_stream_ready, + &input->stream_ready_validation, + &status, hdcp, "stream_ready_validation")) + goto out; + +out: + return status; +} + +static enum mod_hdcp_status determine_rx_hdcp_capable_dp(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK) { + event_ctx->unexpected_event = 1; + goto out; + } + + if (!mod_hdcp_execute_and_set(mod_hdcp_read_rxcaps, + &input->rx_caps_read_dp, + &status, hdcp, "rx_caps_read_dp")) + goto out; + if (!mod_hdcp_execute_and_set(check_hdcp2_capable, + &input->hdcp2_capable_check, &status, + hdcp, "hdcp2_capable_check")) + goto out; +out: + return status; +} + +static enum mod_hdcp_status send_content_stream_type_dp(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + if (event_ctx->event != MOD_HDCP_EVENT_CALLBACK && + event_ctx->event != MOD_HDCP_EVENT_CPIRQ) { + event_ctx->unexpected_event = 1; + goto out; + } + + if (!process_rxstatus(hdcp, event_ctx, input, &status)) + goto out; + if (!mod_hdcp_execute_and_set(mod_hdcp_write_content_type, + &input->content_stream_type_write, &status, + hdcp, "content_stream_type_write")) + goto out; +out: + return status; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_execution(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + switch (current_state(hdcp)) { + case H2_A0_KNOWN_HDCP2_CAPABLE_RX: + status = known_hdcp2_capable_rx(hdcp, event_ctx, input); + break; + case H2_A1_SEND_AKE_INIT: + status = send_ake_init(hdcp, event_ctx, input); + break; + case H2_A1_VALIDATE_AKE_CERT: + status = validate_ake_cert(hdcp, event_ctx, input); + break; + case H2_A1_SEND_NO_STORED_KM: + status = send_no_stored_km(hdcp, event_ctx, input); + break; + case H2_A1_READ_H_PRIME: + status = read_h_prime(hdcp, event_ctx, input); + break; + case H2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME: + status = read_pairing_info_and_validate_h_prime(hdcp, + event_ctx, input); + break; + case H2_A1_SEND_STORED_KM: + status = send_stored_km(hdcp, event_ctx, input); + break; + case H2_A1_VALIDATE_H_PRIME: + status = validate_h_prime(hdcp, event_ctx, input); + break; + case H2_A2_LOCALITY_CHECK: + status = locality_check(hdcp, event_ctx, input); + break; + case H2_A3_EXCHANGE_KS_AND_TEST_FOR_REPEATER: + status = exchange_ks_and_test_for_repeater(hdcp, event_ctx, input); + break; + case H2_ENABLE_ENCRYPTION: + status = enable_encryption(hdcp, event_ctx, input); + break; + case H2_A5_AUTHENTICATED: + status = authenticated(hdcp, event_ctx, input); + break; + case H2_A6_WAIT_FOR_RX_ID_LIST: + status = wait_for_rx_id_list(hdcp, event_ctx, input); + break; + case H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK: + status = verify_rx_id_list_and_send_ack(hdcp, event_ctx, input); + break; + case H2_A9_SEND_STREAM_MANAGEMENT: + status = send_stream_management(hdcp, event_ctx, input); + break; + case H2_A9_VALIDATE_STREAM_READY: + status = validate_stream_ready(hdcp, event_ctx, input); + break; + default: + status = MOD_HDCP_STATUS_INVALID_STATE; + break; + } + + return status; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_dp_execution(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + + switch (current_state(hdcp)) { + case D2_A0_DETERMINE_RX_HDCP_CAPABLE: + status = determine_rx_hdcp_capable_dp(hdcp, event_ctx, input); + break; + case D2_A1_SEND_AKE_INIT: + status = send_ake_init(hdcp, event_ctx, input); + break; + case D2_A1_VALIDATE_AKE_CERT: + status = validate_ake_cert(hdcp, event_ctx, input); + break; + case D2_A1_SEND_NO_STORED_KM: + status = send_no_stored_km(hdcp, event_ctx, input); + break; + case D2_A1_READ_H_PRIME: + status = read_h_prime(hdcp, event_ctx, input); + break; + case D2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME: + status = read_pairing_info_and_validate_h_prime(hdcp, + event_ctx, input); + break; + case D2_A1_SEND_STORED_KM: + status = send_stored_km(hdcp, event_ctx, input); + break; + case D2_A1_VALIDATE_H_PRIME: + status = validate_h_prime(hdcp, event_ctx, input); + break; + case D2_A2_LOCALITY_CHECK: + status = locality_check(hdcp, event_ctx, input); + break; + case D2_A34_EXCHANGE_KS_AND_TEST_FOR_REPEATER: + status = exchange_ks_and_test_for_repeater(hdcp, + event_ctx, input); + break; + case D2_SEND_CONTENT_STREAM_TYPE: + status = send_content_stream_type_dp(hdcp, event_ctx, input); + break; + case D2_ENABLE_ENCRYPTION: + status = enable_encryption(hdcp, event_ctx, input); + break; + case D2_A5_AUTHENTICATED: + status = authenticated(hdcp, event_ctx, input); + break; + case D2_A6_WAIT_FOR_RX_ID_LIST: + status = wait_for_rx_id_list(hdcp, event_ctx, input); + break; + case D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK: + status = verify_rx_id_list_and_send_ack(hdcp, event_ctx, input); + break; + case D2_A9_SEND_STREAM_MANAGEMENT: + status = send_stream_management(hdcp, event_ctx, input); + break; + case D2_A9_VALIDATE_STREAM_READY: + status = validate_stream_ready(hdcp, event_ctx, input); + break; + default: + status = MOD_HDCP_STATUS_INVALID_STATE; + break; + } + + return status; +} diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_transition.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_transition.c new file mode 100644 index 0000000000000000000000000000000000000000..e8043c903a84f67202d4c69bc7d88b146d7c5b75 --- /dev/null +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_transition.c @@ -0,0 +1,674 @@ +/* + * Copyright 2018 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: AMD + * + */ + +#include "hdcp.h" + +enum mod_hdcp_status mod_hdcp_hdcp2_transition(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input, + struct mod_hdcp_output *output) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + struct mod_hdcp_connection *conn = &hdcp->connection; + struct mod_hdcp_link_adjustment *adjust = &hdcp->connection.link.adjust; + + switch (current_state(hdcp)) { + case H2_A0_KNOWN_HDCP2_CAPABLE_RX: + if (input->hdcp2version_read != PASS || + input->hdcp2_capable_check != PASS) { + adjust->hdcp2.disable = 1; + callback_in_ms(0, output); + set_state_id(hdcp, output, HDCP_INITIALIZED); + } else { + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A1_SEND_AKE_INIT); + } + break; + case H2_A1_SEND_AKE_INIT: + if (input->add_topology != PASS || + input->create_session != PASS || + input->ake_init_prepare != PASS) { + /* out of sync with psp state */ + adjust->hdcp2.disable = 1; + fail_and_restart_in_ms(0, &status, output); + break; + } else if (input->ake_init_write != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } + set_watchdog_in_ms(hdcp, 100, output); + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A1_VALIDATE_AKE_CERT); + break; + case H2_A1_VALIDATE_AKE_CERT: + if (input->ake_cert_available != PASS) { + if (event_ctx->event == + MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { + /* 1A-08: consider ake timeout a failure */ + /* some hdmi receivers are not ready for HDCP + * immediately after video becomes active, + * delay 1s before retry on first HDCP message + * timeout. + */ + fail_and_restart_in_ms(1000, &status, output); + } else { + /* continue ake cert polling*/ + callback_in_ms(10, output); + increment_stay_counter(hdcp); + } + break; + } else if (input->ake_cert_read != PASS || + input->ake_cert_validation != PASS) { + /* + * 1A-09: consider invalid ake cert a failure + * 1A-10: consider receiver id listed in SRM a failure + */ + fail_and_restart_in_ms(0, &status, output); + break; + } + if (conn->is_km_stored && + !adjust->hdcp2.force_no_stored_km) { + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A1_SEND_STORED_KM); + } else { + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A1_SEND_NO_STORED_KM); + } + break; + case H2_A1_SEND_NO_STORED_KM: + if (input->no_stored_km_write != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } + if (adjust->hdcp2.increase_h_prime_timeout) + set_watchdog_in_ms(hdcp, 2000, output); + else + set_watchdog_in_ms(hdcp, 1000, output); + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A1_READ_H_PRIME); + break; + case H2_A1_READ_H_PRIME: + if (input->h_prime_available != PASS) { + if (event_ctx->event == + MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { + /* 1A-11-3: consider h' timeout a failure */ + fail_and_restart_in_ms(0, &status, output); + } else { + /* continue h' polling */ + callback_in_ms(100, output); + increment_stay_counter(hdcp); + } + break; + } else if (input->h_prime_read != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } + set_watchdog_in_ms(hdcp, 200, output); + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME); + break; + case H2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME: + if (input->pairing_available != PASS) { + if (event_ctx->event == + MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { + /* 1A-12: consider pairing info timeout + * a failure + */ + fail_and_restart_in_ms(0, &status, output); + } else { + /* continue pairing info polling */ + callback_in_ms(20, output); + increment_stay_counter(hdcp); + } + break; + } else if (input->pairing_info_read != PASS || + input->h_prime_validation != PASS) { + /* 1A-11-1: consider invalid h' a failure */ + fail_and_restart_in_ms(0, &status, output); + break; + } + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A2_LOCALITY_CHECK); + break; + case H2_A1_SEND_STORED_KM: + if (input->stored_km_write != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } + set_watchdog_in_ms(hdcp, 200, output); + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A1_VALIDATE_H_PRIME); + break; + case H2_A1_VALIDATE_H_PRIME: + if (input->h_prime_available != PASS) { + if (event_ctx->event == + MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { + /* 1A-11-2: consider h' timeout a failure */ + fail_and_restart_in_ms(0, &status, output); + } else { + /* continue h' polling */ + callback_in_ms(20, output); + increment_stay_counter(hdcp); + } + break; + } else if (input->h_prime_read != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } else if (input->h_prime_validation != PASS) { + /* 1A-11-1: consider invalid h' a failure */ + adjust->hdcp2.force_no_stored_km = 1; + fail_and_restart_in_ms(0, &status, output); + break; + } + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A2_LOCALITY_CHECK); + break; + case H2_A2_LOCALITY_CHECK: + if (hdcp->state.stay_count > 10 || + input->lc_init_prepare != PASS || + input->lc_init_write != PASS || + input->l_prime_available_poll != PASS || + input->l_prime_read != PASS) { + /* + * 1A-05: consider disconnection after LC init a failure + * 1A-13-1: consider invalid l' a failure + * 1A-13-2: consider l' timeout a failure + */ + fail_and_restart_in_ms(0, &status, output); + break; + } else if (input->l_prime_validation != PASS) { + callback_in_ms(0, output); + increment_stay_counter(hdcp); + break; + } + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A3_EXCHANGE_KS_AND_TEST_FOR_REPEATER); + break; + case H2_A3_EXCHANGE_KS_AND_TEST_FOR_REPEATER: + if (input->eks_prepare != PASS || + input->eks_write != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } + if (conn->is_repeater) { + set_watchdog_in_ms(hdcp, 3000, output); + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A6_WAIT_FOR_RX_ID_LIST); + } else { + /* some CTS equipment requires a delay GREATER than + * 200 ms, so delay 210 ms instead of 200 ms + */ + callback_in_ms(210, output); + set_state_id(hdcp, output, H2_ENABLE_ENCRYPTION); + } + break; + case H2_ENABLE_ENCRYPTION: + if (input->rxstatus_read != PASS || + input->reauth_request_check != PASS) { + /* + * 1A-07: restart hdcp on REAUTH_REQ + * 1B-08: restart hdcp on REAUTH_REQ + */ + fail_and_restart_in_ms(0, &status, output); + break; + } else if (event_ctx->rx_id_list_ready && conn->is_repeater) { + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); + break; + } else if (input->enable_encryption != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A5_AUTHENTICATED); + HDCP_FULL_DDC_TRACE(hdcp); + break; + case H2_A5_AUTHENTICATED: + if (input->rxstatus_read != PASS || + input->reauth_request_check != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } else if (event_ctx->rx_id_list_ready && conn->is_repeater) { + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); + break; + } + callback_in_ms(500, output); + increment_stay_counter(hdcp); + break; + case H2_A6_WAIT_FOR_RX_ID_LIST: + if (input->rxstatus_read != PASS || + input->reauth_request_check != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } else if (!event_ctx->rx_id_list_ready) { + if (event_ctx->event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { + /* 1B-02: consider rx id list timeout a failure */ + /* some CTS equipment's actual timeout + * measurement is slightly greater than 3000 ms. + * Delay 100 ms to ensure it is fully timeout + * before re-authentication. + */ + fail_and_restart_in_ms(100, &status, output); + } else { + callback_in_ms(300, output); + increment_stay_counter(hdcp); + } + break; + } + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); + break; + case H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK: + if (input->rxstatus_read != PASS || + input->reauth_request_check != PASS || + input->rx_id_list_read != PASS || + input->device_count_check != PASS || + input->rx_id_list_validation != PASS || + input->repeater_auth_ack_write != PASS) { + /* 1B-03: consider invalid v' a failure + * 1B-04: consider MAX_DEVS_EXCEEDED a failure + * 1B-05: consider MAX_CASCADE_EXCEEDED a failure + * 1B-06: consider invalid seq_num_V a failure + * 1B-09: consider seq_num_V rollover a failure + */ + fail_and_restart_in_ms(0, &status, output); + break; + } + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A9_SEND_STREAM_MANAGEMENT); + break; + case H2_A9_SEND_STREAM_MANAGEMENT: + if (input->rxstatus_read != PASS || + input->reauth_request_check != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } else if (event_ctx->rx_id_list_ready && conn->is_repeater) { + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); + break; + } else if (input->prepare_stream_manage != PASS || + input->stream_manage_write != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } + set_watchdog_in_ms(hdcp, 100, output); + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A9_VALIDATE_STREAM_READY); + break; + case H2_A9_VALIDATE_STREAM_READY: + if (input->rxstatus_read != PASS || + input->reauth_request_check != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } else if (event_ctx->rx_id_list_ready && conn->is_repeater) { + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); + break; + } else if (input->stream_ready_available != PASS) { + if (event_ctx->event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) { + /* 1B-10-2: restart content stream management on + * stream ready timeout + */ + hdcp->auth.count.stream_management_retry_count++; + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A9_SEND_STREAM_MANAGEMENT); + } else { + callback_in_ms(10, output); + increment_stay_counter(hdcp); + } + break; + } else if (input->stream_ready_read != PASS || + input->stream_ready_validation != PASS) { + /* + * 1B-10-1: restart content stream management + * on invalid M' + */ + if (hdcp->auth.count.stream_management_retry_count > 10) { + fail_and_restart_in_ms(0, &status, output); + } else { + hdcp->auth.count.stream_management_retry_count++; + callback_in_ms(0, output); + set_state_id(hdcp, output, H2_A9_SEND_STREAM_MANAGEMENT); + } + break; + } + callback_in_ms(200, output); + set_state_id(hdcp, output, H2_ENABLE_ENCRYPTION); + break; + default: + status = MOD_HDCP_STATUS_INVALID_STATE; + fail_and_restart_in_ms(0, &status, output); + break; + } + + return status; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_dp_transition(struct mod_hdcp *hdcp, + struct mod_hdcp_event_context *event_ctx, + struct mod_hdcp_transition_input_hdcp2 *input, + struct mod_hdcp_output *output) +{ + enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS; + struct mod_hdcp_connection *conn = &hdcp->connection; + struct mod_hdcp_link_adjustment *adjust = &hdcp->connection.link.adjust; + + switch (current_state(hdcp)) { + case D2_A0_DETERMINE_RX_HDCP_CAPABLE: + if (input->rx_caps_read_dp != PASS || + input->hdcp2_capable_check != PASS) { + adjust->hdcp2.disable = 1; + callback_in_ms(0, output); + set_state_id(hdcp, output, HDCP_INITIALIZED); + } else { + callback_in_ms(0, output); + set_state_id(hdcp, output, D2_A1_SEND_AKE_INIT); + } + break; + case D2_A1_SEND_AKE_INIT: + if (input->add_topology != PASS || + input->create_session != PASS || + input->ake_init_prepare != PASS) { + /* out of sync with psp state */ + adjust->hdcp2.disable = 1; + fail_and_restart_in_ms(0, &status, output); + break; + } else if (input->ake_init_write != PASS) { + /* possibly display not ready */ + fail_and_restart_in_ms(0, &status, output); + break; + } + callback_in_ms(100, output); + set_state_id(hdcp, output, D2_A1_VALIDATE_AKE_CERT); + break; + case D2_A1_VALIDATE_AKE_CERT: + if (input->ake_cert_read != PASS || + input->ake_cert_validation != PASS) { + /* + * 1A-08: consider invalid ake cert a failure + * 1A-09: consider receiver id listed in SRM a failure + */ + fail_and_restart_in_ms(0, &status, output); + break; + } + if (conn->is_km_stored && + !adjust->hdcp2.force_no_stored_km) { + callback_in_ms(0, output); + set_state_id(hdcp, output, D2_A1_SEND_STORED_KM); + } else { + callback_in_ms(0, output); + set_state_id(hdcp, output, D2_A1_SEND_NO_STORED_KM); + } + break; + case D2_A1_SEND_NO_STORED_KM: + if (input->no_stored_km_write != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } + if (adjust->hdcp2.increase_h_prime_timeout) + set_watchdog_in_ms(hdcp, 2000, output); + else + set_watchdog_in_ms(hdcp, 1000, output); + set_state_id(hdcp, output, D2_A1_READ_H_PRIME); + break; + case D2_A1_READ_H_PRIME: + if (input->h_prime_available != PASS) { + if (event_ctx->event == + MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) + /* 1A-10-3: consider h' timeout a failure */ + fail_and_restart_in_ms(0, &status, output); + else + increment_stay_counter(hdcp); + break; + } else if (input->h_prime_read != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } + set_watchdog_in_ms(hdcp, 200, output); + set_state_id(hdcp, output, D2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME); + break; + case D2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME: + if (input->pairing_available != PASS) { + if (event_ctx->event == + MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) + /* + * 1A-11: consider pairing info timeout + * a failure + */ + fail_and_restart_in_ms(0, &status, output); + else + increment_stay_counter(hdcp); + break; + } else if (input->pairing_info_read != PASS || + input->h_prime_validation != PASS) { + /* 1A-10-1: consider invalid h' a failure */ + fail_and_restart_in_ms(0, &status, output); + break; + } + callback_in_ms(0, output); + set_state_id(hdcp, output, D2_A2_LOCALITY_CHECK); + break; + case D2_A1_SEND_STORED_KM: + if (input->stored_km_write != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } + set_watchdog_in_ms(hdcp, 200, output); + set_state_id(hdcp, output, D2_A1_VALIDATE_H_PRIME); + break; + case D2_A1_VALIDATE_H_PRIME: + if (input->h_prime_available != PASS) { + if (event_ctx->event == + MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) + /* 1A-10-2: consider h' timeout a failure */ + fail_and_restart_in_ms(0, &status, output); + else + increment_stay_counter(hdcp); + break; + } else if (input->h_prime_read != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } else if (input->h_prime_validation != PASS) { + /* 1A-10-1: consider invalid h' a failure */ + adjust->hdcp2.force_no_stored_km = 1; + fail_and_restart_in_ms(0, &status, output); + break; + } + callback_in_ms(0, output); + set_state_id(hdcp, output, D2_A2_LOCALITY_CHECK); + break; + case D2_A2_LOCALITY_CHECK: + if (hdcp->state.stay_count > 10 || + input->lc_init_prepare != PASS || + input->lc_init_write != PASS || + input->l_prime_read != PASS) { + /* 1A-12: consider invalid l' a failure */ + fail_and_restart_in_ms(0, &status, output); + break; + } else if (input->l_prime_validation != PASS) { + callback_in_ms(0, output); + increment_stay_counter(hdcp); + break; + } + callback_in_ms(0, output); + set_state_id(hdcp, output, D2_A34_EXCHANGE_KS_AND_TEST_FOR_REPEATER); + break; + case D2_A34_EXCHANGE_KS_AND_TEST_FOR_REPEATER: + if (input->eks_prepare != PASS || + input->eks_write != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } + if (conn->is_repeater) { + set_watchdog_in_ms(hdcp, 3000, output); + set_state_id(hdcp, output, D2_A6_WAIT_FOR_RX_ID_LIST); + } else { + callback_in_ms(0, output); + set_state_id(hdcp, output, D2_SEND_CONTENT_STREAM_TYPE); + } + break; + case D2_SEND_CONTENT_STREAM_TYPE: + if (input->rxstatus_read != PASS || + input->reauth_request_check != PASS || + input->link_integrity_check_dp != PASS || + input->content_stream_type_write != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } + callback_in_ms(210, output); + set_state_id(hdcp, output, D2_ENABLE_ENCRYPTION); + break; + case D2_ENABLE_ENCRYPTION: + if (input->rxstatus_read != PASS || + input->reauth_request_check != PASS || + input->link_integrity_check_dp != PASS) { + /* + * 1A-07: restart hdcp on REAUTH_REQ + * 1B-08: restart hdcp on REAUTH_REQ + */ + fail_and_restart_in_ms(0, &status, output); + break; + } else if (event_ctx->rx_id_list_ready && conn->is_repeater) { + callback_in_ms(0, output); + set_state_id(hdcp, output, D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); + break; + } else if (input->enable_encryption != PASS || + (is_dp_mst_hdcp(hdcp) && input->stream_encryption_dp != PASS)) { + fail_and_restart_in_ms(0, &status, output); + break; + } + set_state_id(hdcp, output, D2_A5_AUTHENTICATED); + HDCP_FULL_DDC_TRACE(hdcp); + break; + case D2_A5_AUTHENTICATED: + if (input->rxstatus_read != PASS || + input->reauth_request_check != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } else if (input->link_integrity_check_dp != PASS) { + if (hdcp->connection.hdcp2_retry_count >= 1) + adjust->hdcp2.force_type = MOD_HDCP_FORCE_TYPE_0; + fail_and_restart_in_ms(0, &status, output); + break; + } else if (event_ctx->rx_id_list_ready && conn->is_repeater) { + callback_in_ms(0, output); + set_state_id(hdcp, output, D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); + break; + } + increment_stay_counter(hdcp); + break; + case D2_A6_WAIT_FOR_RX_ID_LIST: + if (input->rxstatus_read != PASS || + input->reauth_request_check != PASS || + input->link_integrity_check_dp != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } else if (!event_ctx->rx_id_list_ready) { + if (event_ctx->event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) + /* 1B-02: consider rx id list timeout a failure */ + fail_and_restart_in_ms(0, &status, output); + else + increment_stay_counter(hdcp); + break; + } + callback_in_ms(0, output); + set_state_id(hdcp, output, D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); + break; + case D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK: + if (input->rxstatus_read != PASS || + input->reauth_request_check != PASS || + input->link_integrity_check_dp != PASS || + input->rx_id_list_read != PASS || + input->device_count_check != PASS || + input->rx_id_list_validation != PASS || + input->repeater_auth_ack_write != PASS) { + /* + * 1B-03: consider invalid v' a failure + * 1B-04: consider MAX_DEVS_EXCEEDED a failure + * 1B-05: consider MAX_CASCADE_EXCEEDED a failure + * 1B-06: consider invalid seq_num_V a failure + * 1B-09: consider seq_num_V rollover a failure + */ + fail_and_restart_in_ms(0, &status, output); + break; + } + callback_in_ms(0, output); + set_state_id(hdcp, output, D2_A9_SEND_STREAM_MANAGEMENT); + break; + case D2_A9_SEND_STREAM_MANAGEMENT: + if (input->rxstatus_read != PASS || + input->reauth_request_check != PASS || + input->link_integrity_check_dp != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } else if (event_ctx->rx_id_list_ready) { + callback_in_ms(0, output); + set_state_id(hdcp, output, D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); + break; + } else if (input->prepare_stream_manage != PASS || + input->stream_manage_write != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } + callback_in_ms(100, output); + set_state_id(hdcp, output, D2_A9_VALIDATE_STREAM_READY); + break; + case D2_A9_VALIDATE_STREAM_READY: + if (input->rxstatus_read != PASS || + input->reauth_request_check != PASS || + input->link_integrity_check_dp != PASS) { + fail_and_restart_in_ms(0, &status, output); + break; + } else if (event_ctx->rx_id_list_ready) { + callback_in_ms(0, output); + set_state_id(hdcp, output, D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK); + break; + } else if (input->stream_ready_read != PASS || + input->stream_ready_validation != PASS) { + /* + * 1B-10-1: restart content stream management + * on invalid M' + * 1B-10-2: consider stream ready timeout a failure + */ + if (hdcp->auth.count.stream_management_retry_count > 10) { + fail_and_restart_in_ms(0, &status, output); + } else { + hdcp->auth.count.stream_management_retry_count++; + callback_in_ms(0, output); + set_state_id(hdcp, output, D2_A9_SEND_STREAM_MANAGEMENT); + } + break; + } + callback_in_ms(200, output); + set_state_id(hdcp, output, D2_ENABLE_ENCRYPTION); + break; + default: + status = MOD_HDCP_STATUS_INVALID_STATE; + fail_and_restart_in_ms(0, &status, output); + break; + } + return status; +} diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c index e7baae059b857258a8fa97a723dcf9063d296838..ff9d54812e62934053a4d0738e00948b5bdfa19e 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_ddc.c @@ -51,6 +51,26 @@ enum mod_hdcp_ddc_message_id { MOD_HDCP_MESSAGE_ID_READ_KSV_FIFO, MOD_HDCP_MESSAGE_ID_READ_BINFO, + /* HDCP 2.2 */ + + MOD_HDCP_MESSAGE_ID_HDCP2VERSION, + MOD_HDCP_MESSAGE_ID_RX_CAPS, + MOD_HDCP_MESSAGE_ID_WRITE_AKE_INIT, + MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_CERT, + MOD_HDCP_MESSAGE_ID_WRITE_AKE_NO_STORED_KM, + MOD_HDCP_MESSAGE_ID_WRITE_AKE_STORED_KM, + MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_H_PRIME, + MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_PAIRING_INFO, + MOD_HDCP_MESSAGE_ID_WRITE_LC_INIT, + MOD_HDCP_MESSAGE_ID_READ_LC_SEND_L_PRIME, + MOD_HDCP_MESSAGE_ID_WRITE_SKE_SEND_EKS, + MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST, + MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_SEND_ACK, + MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_STREAM_MANAGE, + MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_STREAM_READY, + MOD_HDCP_MESSAGE_ID_READ_RXSTATUS, + MOD_HDCP_MESSAGE_ID_WRITE_CONTENT_STREAM_TYPE, + MOD_HDCP_MESSAGE_ID_MAX }; @@ -70,6 +90,22 @@ static const uint8_t hdcp_i2c_offsets[] = { [MOD_HDCP_MESSAGE_ID_READ_BSTATUS] = 0x41, [MOD_HDCP_MESSAGE_ID_READ_KSV_FIFO] = 0x43, [MOD_HDCP_MESSAGE_ID_READ_BINFO] = 0xFF, + [MOD_HDCP_MESSAGE_ID_HDCP2VERSION] = 0x50, + [MOD_HDCP_MESSAGE_ID_WRITE_AKE_INIT] = 0x60, + [MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_CERT] = 0x80, + [MOD_HDCP_MESSAGE_ID_WRITE_AKE_NO_STORED_KM] = 0x60, + [MOD_HDCP_MESSAGE_ID_WRITE_AKE_STORED_KM] = 0x60, + [MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_H_PRIME] = 0x80, + [MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_PAIRING_INFO] = 0x80, + [MOD_HDCP_MESSAGE_ID_WRITE_LC_INIT] = 0x60, + [MOD_HDCP_MESSAGE_ID_READ_LC_SEND_L_PRIME] = 0x80, + [MOD_HDCP_MESSAGE_ID_WRITE_SKE_SEND_EKS] = 0x60, + [MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST] = 0x80, + [MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_SEND_ACK] = 0x60, + [MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_STREAM_MANAGE] = 0x60, + [MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_STREAM_READY] = 0x80, + [MOD_HDCP_MESSAGE_ID_READ_RXSTATUS] = 0x70, + [MOD_HDCP_MESSAGE_ID_WRITE_CONTENT_STREAM_TYPE] = 0x0 }; static const uint32_t hdcp_dpcd_addrs[] = { @@ -88,6 +124,22 @@ static const uint32_t hdcp_dpcd_addrs[] = { [MOD_HDCP_MESSAGE_ID_READ_BSTATUS] = 0x68029, [MOD_HDCP_MESSAGE_ID_READ_KSV_FIFO] = 0x6802c, [MOD_HDCP_MESSAGE_ID_READ_BINFO] = 0x6802a, + [MOD_HDCP_MESSAGE_ID_RX_CAPS] = 0x6921d, + [MOD_HDCP_MESSAGE_ID_WRITE_AKE_INIT] = 0x69000, + [MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_CERT] = 0x6900b, + [MOD_HDCP_MESSAGE_ID_WRITE_AKE_NO_STORED_KM] = 0x69220, + [MOD_HDCP_MESSAGE_ID_WRITE_AKE_STORED_KM] = 0x692a0, + [MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_H_PRIME] = 0x692c0, + [MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_PAIRING_INFO] = 0x692e0, + [MOD_HDCP_MESSAGE_ID_WRITE_LC_INIT] = 0x692f0, + [MOD_HDCP_MESSAGE_ID_READ_LC_SEND_L_PRIME] = 0x692f8, + [MOD_HDCP_MESSAGE_ID_WRITE_SKE_SEND_EKS] = 0x69318, + [MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST] = 0x69330, + [MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_SEND_ACK] = 0x693e0, + [MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_STREAM_MANAGE] = 0x693f0, + [MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_STREAM_READY] = 0x69473, + [MOD_HDCP_MESSAGE_ID_READ_RXSTATUS] = 0x69493, + [MOD_HDCP_MESSAGE_ID_WRITE_CONTENT_STREAM_TYPE] = 0x69494 }; static enum mod_hdcp_status read(struct mod_hdcp *hdcp, @@ -303,3 +355,277 @@ enum mod_hdcp_status mod_hdcp_write_an(struct mod_hdcp *hdcp) hdcp->auth.msg.hdcp1.an, sizeof(hdcp->auth.msg.hdcp1.an)); } + +enum mod_hdcp_status mod_hdcp_read_hdcp2version(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) + status = MOD_HDCP_STATUS_INVALID_OPERATION; + else + status = read(hdcp, MOD_HDCP_MESSAGE_ID_HDCP2VERSION, + &hdcp->auth.msg.hdcp2.hdcp2version_hdmi, + sizeof(hdcp->auth.msg.hdcp2.hdcp2version_hdmi)); + + return status; +} + +enum mod_hdcp_status mod_hdcp_read_rxcaps(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (!is_dp_hdcp(hdcp)) + status = MOD_HDCP_STATUS_INVALID_OPERATION; + else + status = read(hdcp, MOD_HDCP_MESSAGE_ID_RX_CAPS, + hdcp->auth.msg.hdcp2.rxcaps_dp, + sizeof(hdcp->auth.msg.hdcp2.rxcaps_dp)); + + return status; +} + +enum mod_hdcp_status mod_hdcp_read_rxstatus(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) { + status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_RXSTATUS, + &hdcp->auth.msg.hdcp2.rxstatus_dp, + 1); + } else { + status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_RXSTATUS, + (uint8_t *)&hdcp->auth.msg.hdcp2.rxstatus, + sizeof(hdcp->auth.msg.hdcp2.rxstatus)); + } + return status; +} + +enum mod_hdcp_status mod_hdcp_read_ake_cert(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) { + hdcp->auth.msg.hdcp2.ake_cert[0] = 3; + status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_CERT, + hdcp->auth.msg.hdcp2.ake_cert+1, + sizeof(hdcp->auth.msg.hdcp2.ake_cert)-1); + + } else { + status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_CERT, + hdcp->auth.msg.hdcp2.ake_cert, + sizeof(hdcp->auth.msg.hdcp2.ake_cert)); + } + return status; +} + +enum mod_hdcp_status mod_hdcp_read_h_prime(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) { + hdcp->auth.msg.hdcp2.ake_h_prime[0] = 7; + status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_H_PRIME, + hdcp->auth.msg.hdcp2.ake_h_prime+1, + sizeof(hdcp->auth.msg.hdcp2.ake_h_prime)-1); + + } else { + status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_H_PRIME, + hdcp->auth.msg.hdcp2.ake_h_prime, + sizeof(hdcp->auth.msg.hdcp2.ake_h_prime)); + } + return status; +} + +enum mod_hdcp_status mod_hdcp_read_pairing_info(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) { + hdcp->auth.msg.hdcp2.ake_pairing_info[0] = 8; + status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_PAIRING_INFO, + hdcp->auth.msg.hdcp2.ake_pairing_info+1, + sizeof(hdcp->auth.msg.hdcp2.ake_pairing_info)-1); + + } else { + status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_AKE_SEND_PAIRING_INFO, + hdcp->auth.msg.hdcp2.ake_pairing_info, + sizeof(hdcp->auth.msg.hdcp2.ake_pairing_info)); + } + return status; +} + +enum mod_hdcp_status mod_hdcp_read_l_prime(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) { + hdcp->auth.msg.hdcp2.lc_l_prime[0] = 10; + status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_LC_SEND_L_PRIME, + hdcp->auth.msg.hdcp2.lc_l_prime+1, + sizeof(hdcp->auth.msg.hdcp2.lc_l_prime)-1); + + } else { + status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_LC_SEND_L_PRIME, + hdcp->auth.msg.hdcp2.lc_l_prime, + sizeof(hdcp->auth.msg.hdcp2.lc_l_prime)); + } + return status; +} + +enum mod_hdcp_status mod_hdcp_read_rx_id_list(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) { + hdcp->auth.msg.hdcp2.rx_id_list[0] = 12; + status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST, + hdcp->auth.msg.hdcp2.rx_id_list+1, + sizeof(hdcp->auth.msg.hdcp2.rx_id_list)-1); + + } else { + status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_SEND_RECEIVERID_LIST, + hdcp->auth.msg.hdcp2.rx_id_list, + hdcp->auth.msg.hdcp2.rx_id_list_size); + } + return status; +} + +enum mod_hdcp_status mod_hdcp_read_stream_ready(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) { + hdcp->auth.msg.hdcp2.repeater_auth_stream_ready[0] = 17; + status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_STREAM_READY, + hdcp->auth.msg.hdcp2.repeater_auth_stream_ready+1, + sizeof(hdcp->auth.msg.hdcp2.repeater_auth_stream_ready)-1); + + } else { + status = read(hdcp, MOD_HDCP_MESSAGE_ID_READ_REPEATER_AUTH_STREAM_READY, + hdcp->auth.msg.hdcp2.repeater_auth_stream_ready, + sizeof(hdcp->auth.msg.hdcp2.repeater_auth_stream_ready)); + } + return status; +} + +enum mod_hdcp_status mod_hdcp_write_ake_init(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) + status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_AKE_INIT, + hdcp->auth.msg.hdcp2.ake_init+1, + sizeof(hdcp->auth.msg.hdcp2.ake_init)-1); + else + status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_AKE_INIT, + hdcp->auth.msg.hdcp2.ake_init, + sizeof(hdcp->auth.msg.hdcp2.ake_init)); + return status; +} + +enum mod_hdcp_status mod_hdcp_write_no_stored_km(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) + status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_AKE_NO_STORED_KM, + hdcp->auth.msg.hdcp2.ake_no_stored_km+1, + sizeof(hdcp->auth.msg.hdcp2.ake_no_stored_km)-1); + else + status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_AKE_NO_STORED_KM, + hdcp->auth.msg.hdcp2.ake_no_stored_km, + sizeof(hdcp->auth.msg.hdcp2.ake_no_stored_km)); + return status; +} + +enum mod_hdcp_status mod_hdcp_write_stored_km(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) + status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_AKE_STORED_KM, + hdcp->auth.msg.hdcp2.ake_stored_km+1, + sizeof(hdcp->auth.msg.hdcp2.ake_stored_km)-1); + else + status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_AKE_STORED_KM, + hdcp->auth.msg.hdcp2.ake_stored_km, + sizeof(hdcp->auth.msg.hdcp2.ake_stored_km)); + return status; +} + +enum mod_hdcp_status mod_hdcp_write_lc_init(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) + status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_LC_INIT, + hdcp->auth.msg.hdcp2.lc_init+1, + sizeof(hdcp->auth.msg.hdcp2.lc_init)-1); + else + status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_LC_INIT, + hdcp->auth.msg.hdcp2.lc_init, + sizeof(hdcp->auth.msg.hdcp2.lc_init)); + return status; +} + +enum mod_hdcp_status mod_hdcp_write_eks(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) + status = write(hdcp, + MOD_HDCP_MESSAGE_ID_WRITE_SKE_SEND_EKS, + hdcp->auth.msg.hdcp2.ske_eks+1, + sizeof(hdcp->auth.msg.hdcp2.ske_eks)-1); + else + status = write(hdcp, + MOD_HDCP_MESSAGE_ID_WRITE_SKE_SEND_EKS, + hdcp->auth.msg.hdcp2.ske_eks, + sizeof(hdcp->auth.msg.hdcp2.ske_eks)); + return status; +} + +enum mod_hdcp_status mod_hdcp_write_repeater_auth_ack(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) + status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_SEND_ACK, + hdcp->auth.msg.hdcp2.repeater_auth_ack+1, + sizeof(hdcp->auth.msg.hdcp2.repeater_auth_ack)-1); + else + status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_SEND_ACK, + hdcp->auth.msg.hdcp2.repeater_auth_ack, + sizeof(hdcp->auth.msg.hdcp2.repeater_auth_ack)); + return status; +} + +enum mod_hdcp_status mod_hdcp_write_stream_manage(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) + status = write(hdcp, + MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_STREAM_MANAGE, + hdcp->auth.msg.hdcp2.repeater_auth_stream_manage+1, + hdcp->auth.msg.hdcp2.stream_manage_size-1); + else + status = write(hdcp, + MOD_HDCP_MESSAGE_ID_WRITE_REPEATER_AUTH_STREAM_MANAGE, + hdcp->auth.msg.hdcp2.repeater_auth_stream_manage, + hdcp->auth.msg.hdcp2.stream_manage_size); + return status; +} + +enum mod_hdcp_status mod_hdcp_write_content_type(struct mod_hdcp *hdcp) +{ + enum mod_hdcp_status status; + + if (is_dp_hdcp(hdcp)) + status = write(hdcp, MOD_HDCP_MESSAGE_ID_WRITE_CONTENT_STREAM_TYPE, + hdcp->auth.msg.hdcp2.content_stream_type_dp+1, + sizeof(hdcp->auth.msg.hdcp2.content_stream_type_dp)-1); + else + status = MOD_HDCP_STATUS_INVALID_OPERATION; + return status; +} diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c index 3982ced5f9695c121523385534b088f4d305dd66..724ebcee9a19214e4edb79a64dd2c22231851cb2 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c @@ -116,6 +116,58 @@ char *mod_hdcp_status_to_str(int32_t status) return "MOD_HDCP_STATUS_DDC_FAILURE"; case MOD_HDCP_STATUS_INVALID_OPERATION: return "MOD_HDCP_STATUS_INVALID_OPERATION"; + case MOD_HDCP_STATUS_HDCP2_NOT_CAPABLE: + return "MOD_HDCP_STATUS_HDCP2_NOT_CAPABLE"; + case MOD_HDCP_STATUS_HDCP2_CREATE_SESSION_FAILURE: + return "MOD_HDCP_STATUS_HDCP2_CREATE_SESSION_FAILURE"; + case MOD_HDCP_STATUS_HDCP2_DESTROY_SESSION_FAILURE: + return "MOD_HDCP_STATUS_HDCP2_DESTROY_SESSION_FAILURE"; + case MOD_HDCP_STATUS_HDCP2_PREP_AKE_INIT_FAILURE: + return "MOD_HDCP_STATUS_HDCP2_PREP_AKE_INIT_FAILURE"; + case MOD_HDCP_STATUS_HDCP2_AKE_CERT_PENDING: + return "MOD_HDCP_STATUS_HDCP2_AKE_CERT_PENDING"; + case MOD_HDCP_STATUS_HDCP2_H_PRIME_PENDING: + return "MOD_HDCP_STATUS_HDCP2_H_PRIME_PENDING"; + case MOD_HDCP_STATUS_HDCP2_PAIRING_INFO_PENDING: + return "MOD_HDCP_STATUS_HDCP2_PAIRING_INFO_PENDING"; + case MOD_HDCP_STATUS_HDCP2_VALIDATE_AKE_CERT_FAILURE: + return "MOD_HDCP_STATUS_HDCP2_VALIDATE_AKE_CERT_FAILURE"; + case MOD_HDCP_STATUS_HDCP2_AKE_CERT_REVOKED: + return "MOD_HDCP_STATUS_HDCP2_AKE_CERT_REVOKED"; + case MOD_HDCP_STATUS_HDCP2_VALIDATE_H_PRIME_FAILURE: + return "MOD_HDCP_STATUS_HDCP2_VALIDATE_H_PRIME_FAILURE"; + case MOD_HDCP_STATUS_HDCP2_VALIDATE_PAIRING_INFO_FAILURE: + return "MOD_HDCP_STATUS_HDCP2_VALIDATE_PAIRING_INFO_FAILURE"; + case MOD_HDCP_STATUS_HDCP2_PREP_LC_INIT_FAILURE: + return "MOD_HDCP_STATUS_HDCP2_PREP_LC_INIT_FAILURE"; + case MOD_HDCP_STATUS_HDCP2_L_PRIME_PENDING: + return "MOD_HDCP_STATUS_HDCP2_L_PRIME_PENDING"; + case MOD_HDCP_STATUS_HDCP2_VALIDATE_L_PRIME_FAILURE: + return "MOD_HDCP_STATUS_HDCP2_VALIDATE_L_PRIME_FAILURE"; + case MOD_HDCP_STATUS_HDCP2_PREP_EKS_FAILURE: + return "MOD_HDCP_STATUS_HDCP2_PREP_EKS_FAILURE"; + case MOD_HDCP_STATUS_HDCP2_ENABLE_ENCRYPTION_FAILURE: + return "MOD_HDCP_STATUS_HDCP2_ENABLE_ENCRYPTION_FAILURE"; + case MOD_HDCP_STATUS_HDCP2_VALIDATE_RX_ID_LIST_FAILURE: + return "MOD_HDCP_STATUS_HDCP2_VALIDATE_RX_ID_LIST_FAILURE"; + case MOD_HDCP_STATUS_HDCP2_RX_ID_LIST_REVOKED: + return "MOD_HDCP_STATUS_HDCP2_RX_ID_LIST_REVOKED"; + case MOD_HDCP_STATUS_HDCP2_RX_ID_LIST_NOT_READY: + return "MOD_HDCP_STATUS_HDCP2_RX_ID_LIST_NOT_READY"; + case MOD_HDCP_STATUS_HDCP2_ENABLE_STREAM_ENCRYPTION: + return "MOD_HDCP_STATUS_HDCP2_ENABLE_STREAM_ENCRYPTION"; + case MOD_HDCP_STATUS_HDCP2_STREAM_READY_PENDING: + return "MOD_HDCP_STATUS_HDCP2_STREAM_READY_PENDING"; + case MOD_HDCP_STATUS_HDCP2_VALIDATE_STREAM_READY_FAILURE: + return "MOD_HDCP_STATUS_HDCP2_VALIDATE_STREAM_READY_FAILURE"; + case MOD_HDCP_STATUS_HDCP2_PREPARE_STREAM_MANAGEMENT_FAILURE: + return "MOD_HDCP_STATUS_HDCP2_PREPARE_STREAM_MANAGEMENT_FAILURE"; + case MOD_HDCP_STATUS_HDCP2_REAUTH_REQUEST: + return "MOD_HDCP_STATUS_HDCP2_REAUTH_REQUEST"; + case MOD_HDCP_STATUS_HDCP2_REAUTH_LINK_INTEGRITY_FAILURE: + return "MOD_HDCP_STATUS_HDCP2_REAUTH_LINK_INTEGRITY_FAILURE"; + case MOD_HDCP_STATUS_HDCP2_DEVICE_COUNT_MISMATCH_FAILURE: + return "MOD_HDCP_STATUS_HDCP2_DEVICE_COUNT_MISMATCH_FAILURE"; default: return "MOD_HDCP_STATUS_UNKNOWN"; } @@ -156,6 +208,72 @@ char *mod_hdcp_state_id_to_str(int32_t id) return "D1_A6_WAIT_FOR_READY"; case D1_A7_READ_KSV_LIST: return "D1_A7_READ_KSV_LIST"; + case H2_A0_KNOWN_HDCP2_CAPABLE_RX: + return "H2_A0_KNOWN_HDCP2_CAPABLE_RX"; + case H2_A1_SEND_AKE_INIT: + return "H2_A1_SEND_AKE_INIT"; + case H2_A1_VALIDATE_AKE_CERT: + return "H2_A1_VALIDATE_AKE_CERT"; + case H2_A1_SEND_NO_STORED_KM: + return "H2_A1_SEND_NO_STORED_KM"; + case H2_A1_READ_H_PRIME: + return "H2_A1_READ_H_PRIME"; + case H2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME: + return "H2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME"; + case H2_A1_SEND_STORED_KM: + return "H2_A1_SEND_STORED_KM"; + case H2_A1_VALIDATE_H_PRIME: + return "H2_A1_VALIDATE_H_PRIME"; + case H2_A2_LOCALITY_CHECK: + return "H2_A2_LOCALITY_CHECK"; + case H2_A3_EXCHANGE_KS_AND_TEST_FOR_REPEATER: + return "H2_A3_EXCHANGE_KS_AND_TEST_FOR_REPEATER"; + case H2_ENABLE_ENCRYPTION: + return "H2_ENABLE_ENCRYPTION"; + case H2_A5_AUTHENTICATED: + return "H2_A5_AUTHENTICATED"; + case H2_A6_WAIT_FOR_RX_ID_LIST: + return "H2_A6_WAIT_FOR_RX_ID_LIST"; + case H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK: + return "H2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK"; + case H2_A9_SEND_STREAM_MANAGEMENT: + return "H2_A9_SEND_STREAM_MANAGEMENT"; + case H2_A9_VALIDATE_STREAM_READY: + return "H2_A9_VALIDATE_STREAM_READY"; + case D2_A0_DETERMINE_RX_HDCP_CAPABLE: + return "D2_A0_DETERMINE_RX_HDCP_CAPABLE"; + case D2_A1_SEND_AKE_INIT: + return "D2_A1_SEND_AKE_INIT"; + case D2_A1_VALIDATE_AKE_CERT: + return "D2_A1_VALIDATE_AKE_CERT"; + case D2_A1_SEND_NO_STORED_KM: + return "D2_A1_SEND_NO_STORED_KM"; + case D2_A1_READ_H_PRIME: + return "D2_A1_READ_H_PRIME"; + case D2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME: + return "D2_A1_READ_PAIRING_INFO_AND_VALIDATE_H_PRIME"; + case D2_A1_SEND_STORED_KM: + return "D2_A1_SEND_STORED_KM"; + case D2_A1_VALIDATE_H_PRIME: + return "D2_A1_VALIDATE_H_PRIME"; + case D2_A2_LOCALITY_CHECK: + return "D2_A2_LOCALITY_CHECK"; + case D2_A34_EXCHANGE_KS_AND_TEST_FOR_REPEATER: + return "D2_A34_EXCHANGE_KS_AND_TEST_FOR_REPEATER"; + case D2_SEND_CONTENT_STREAM_TYPE: + return "D2_SEND_CONTENT_STREAM_TYPE"; + case D2_ENABLE_ENCRYPTION: + return "D2_ENABLE_ENCRYPTION"; + case D2_A5_AUTHENTICATED: + return "D2_A5_AUTHENTICATED"; + case D2_A6_WAIT_FOR_RX_ID_LIST: + return "D2_A6_WAIT_FOR_RX_ID_LIST"; + case D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK: + return "D2_A78_VERIFY_RX_ID_LIST_AND_SEND_ACK"; + case D2_A9_SEND_STREAM_MANAGEMENT: + return "D2_A9_SEND_STREAM_MANAGEMENT"; + case D2_A9_VALIDATE_STREAM_READY: + return "D2_A9_VALIDATE_STREAM_READY"; default: return "UNKNOWN_STATE_ID"; }; diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.h b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.h index 2fd0e0a893ef2c5449e10abbca34f70e997085d0..ff91373ebada938618c96db304f8e32a1e512b9d 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.h +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.h @@ -27,7 +27,7 @@ #define MOD_HDCP_LOG_H_ #ifdef CONFIG_DRM_AMD_DC_HDCP -#define HDCP_LOG_ERR(hdcp, ...) DRM_ERROR(__VA_ARGS__) +#define HDCP_LOG_ERR(hdcp, ...) DRM_WARN(__VA_ARGS__) #define HDCP_LOG_VER(hdcp, ...) DRM_DEBUG_KMS(__VA_ARGS__) #define HDCP_LOG_FSM(hdcp, ...) DRM_DEBUG_KMS(__VA_ARGS__) #define HDCP_LOG_TOP(hdcp, ...) pr_debug("[HDCP_TOP]:"__VA_ARGS__) @@ -37,7 +37,7 @@ /* default logs */ #define HDCP_ERROR_TRACE(hdcp, status) \ HDCP_LOG_ERR(hdcp, \ - "[Link %d] ERROR %s IN STATE %s", \ + "[Link %d] WARNING %s IN STATE %s", \ hdcp->config.index, \ mod_hdcp_status_to_str(status), \ mod_hdcp_state_id_to_str(hdcp->state.id)) @@ -45,6 +45,10 @@ HDCP_LOG_VER(hdcp, \ "[Link %d] HDCP 1.4 enabled on display %d", \ hdcp->config.index, displayIndex) +#define HDCP_HDCP2_ENABLED_TRACE(hdcp, displayIndex) \ + HDCP_LOG_VER(hdcp, \ + "[Link %d] HDCP 2.2 enabled on display %d", \ + hdcp->config.index, displayIndex) /* state machine logs */ #define HDCP_REMOVE_DISPLAY_TRACE(hdcp, displayIndex) \ HDCP_LOG_FSM(hdcp, \ @@ -93,26 +97,73 @@ hdcp->buf); \ } while (0) #define HDCP_FULL_DDC_TRACE(hdcp) do { \ - HDCP_DDC_READ_TRACE(hdcp, "BKSV", hdcp->auth.msg.hdcp1.bksv, \ - sizeof(hdcp->auth.msg.hdcp1.bksv)); \ - HDCP_DDC_READ_TRACE(hdcp, "BCAPS", &hdcp->auth.msg.hdcp1.bcaps, \ - sizeof(hdcp->auth.msg.hdcp1.bcaps)); \ - HDCP_DDC_WRITE_TRACE(hdcp, "AN", hdcp->auth.msg.hdcp1.an, \ - sizeof(hdcp->auth.msg.hdcp1.an)); \ - HDCP_DDC_WRITE_TRACE(hdcp, "AKSV", hdcp->auth.msg.hdcp1.aksv, \ - sizeof(hdcp->auth.msg.hdcp1.aksv)); \ - HDCP_DDC_WRITE_TRACE(hdcp, "AINFO", &hdcp->auth.msg.hdcp1.ainfo, \ - sizeof(hdcp->auth.msg.hdcp1.ainfo)); \ - HDCP_DDC_READ_TRACE(hdcp, "RI' / R0'", \ - (uint8_t *)&hdcp->auth.msg.hdcp1.r0p, \ - sizeof(hdcp->auth.msg.hdcp1.r0p)); \ - HDCP_DDC_READ_TRACE(hdcp, "BINFO", \ - (uint8_t *)&hdcp->auth.msg.hdcp1.binfo_dp, \ - sizeof(hdcp->auth.msg.hdcp1.binfo_dp)); \ - HDCP_DDC_READ_TRACE(hdcp, "KSVLIST", hdcp->auth.msg.hdcp1.ksvlist, \ - hdcp->auth.msg.hdcp1.ksvlist_size); \ - HDCP_DDC_READ_TRACE(hdcp, "V'", hdcp->auth.msg.hdcp1.vp, \ - sizeof(hdcp->auth.msg.hdcp1.vp)); \ + if (is_hdcp1(hdcp)) { \ + HDCP_DDC_READ_TRACE(hdcp, "BKSV", hdcp->auth.msg.hdcp1.bksv, \ + sizeof(hdcp->auth.msg.hdcp1.bksv)); \ + HDCP_DDC_READ_TRACE(hdcp, "BCAPS", &hdcp->auth.msg.hdcp1.bcaps, \ + sizeof(hdcp->auth.msg.hdcp1.bcaps)); \ + HDCP_DDC_WRITE_TRACE(hdcp, "AN", hdcp->auth.msg.hdcp1.an, \ + sizeof(hdcp->auth.msg.hdcp1.an)); \ + HDCP_DDC_WRITE_TRACE(hdcp, "AKSV", hdcp->auth.msg.hdcp1.aksv, \ + sizeof(hdcp->auth.msg.hdcp1.aksv)); \ + HDCP_DDC_WRITE_TRACE(hdcp, "AINFO", &hdcp->auth.msg.hdcp1.ainfo, \ + sizeof(hdcp->auth.msg.hdcp1.ainfo)); \ + HDCP_DDC_READ_TRACE(hdcp, "RI' / R0'", \ + (uint8_t *)&hdcp->auth.msg.hdcp1.r0p, \ + sizeof(hdcp->auth.msg.hdcp1.r0p)); \ + HDCP_DDC_READ_TRACE(hdcp, "BINFO", \ + (uint8_t *)&hdcp->auth.msg.hdcp1.binfo_dp, \ + sizeof(hdcp->auth.msg.hdcp1.binfo_dp)); \ + HDCP_DDC_READ_TRACE(hdcp, "KSVLIST", hdcp->auth.msg.hdcp1.ksvlist, \ + hdcp->auth.msg.hdcp1.ksvlist_size); \ + HDCP_DDC_READ_TRACE(hdcp, "V'", hdcp->auth.msg.hdcp1.vp, \ + sizeof(hdcp->auth.msg.hdcp1.vp)); \ + } else { \ + HDCP_DDC_READ_TRACE(hdcp, "HDCP2Version", \ + &hdcp->auth.msg.hdcp2.hdcp2version_hdmi, \ + sizeof(hdcp->auth.msg.hdcp2.hdcp2version_hdmi)); \ + HDCP_DDC_READ_TRACE(hdcp, "Rx Caps", hdcp->auth.msg.hdcp2.rxcaps_dp, \ + sizeof(hdcp->auth.msg.hdcp2.rxcaps_dp)); \ + HDCP_DDC_WRITE_TRACE(hdcp, "AKE Init", hdcp->auth.msg.hdcp2.ake_init, \ + sizeof(hdcp->auth.msg.hdcp2.ake_init)); \ + HDCP_DDC_READ_TRACE(hdcp, "AKE Cert", hdcp->auth.msg.hdcp2.ake_cert, \ + sizeof(hdcp->auth.msg.hdcp2.ake_cert)); \ + HDCP_DDC_WRITE_TRACE(hdcp, "Stored KM", \ + hdcp->auth.msg.hdcp2.ake_stored_km, \ + sizeof(hdcp->auth.msg.hdcp2.ake_stored_km)); \ + HDCP_DDC_WRITE_TRACE(hdcp, "No Stored KM", \ + hdcp->auth.msg.hdcp2.ake_no_stored_km, \ + sizeof(hdcp->auth.msg.hdcp2.ake_no_stored_km)); \ + HDCP_DDC_READ_TRACE(hdcp, "H'", hdcp->auth.msg.hdcp2.ake_h_prime, \ + sizeof(hdcp->auth.msg.hdcp2.ake_h_prime)); \ + HDCP_DDC_READ_TRACE(hdcp, "Pairing Info", \ + hdcp->auth.msg.hdcp2.ake_pairing_info, \ + sizeof(hdcp->auth.msg.hdcp2.ake_pairing_info)); \ + HDCP_DDC_WRITE_TRACE(hdcp, "LC Init", hdcp->auth.msg.hdcp2.lc_init, \ + sizeof(hdcp->auth.msg.hdcp2.lc_init)); \ + HDCP_DDC_READ_TRACE(hdcp, "L'", hdcp->auth.msg.hdcp2.lc_l_prime, \ + sizeof(hdcp->auth.msg.hdcp2.lc_l_prime)); \ + HDCP_DDC_WRITE_TRACE(hdcp, "Exchange KS", hdcp->auth.msg.hdcp2.ske_eks, \ + sizeof(hdcp->auth.msg.hdcp2.ske_eks)); \ + HDCP_DDC_READ_TRACE(hdcp, "Rx Status", \ + (uint8_t *)&hdcp->auth.msg.hdcp2.rxstatus, \ + sizeof(hdcp->auth.msg.hdcp2.rxstatus)); \ + HDCP_DDC_READ_TRACE(hdcp, "Rx Id List", \ + hdcp->auth.msg.hdcp2.rx_id_list, \ + hdcp->auth.msg.hdcp2.rx_id_list_size); \ + HDCP_DDC_WRITE_TRACE(hdcp, "Rx Id List Ack", \ + hdcp->auth.msg.hdcp2.repeater_auth_ack, \ + sizeof(hdcp->auth.msg.hdcp2.repeater_auth_ack)); \ + HDCP_DDC_WRITE_TRACE(hdcp, "Content Stream Management", \ + hdcp->auth.msg.hdcp2.repeater_auth_stream_manage, \ + hdcp->auth.msg.hdcp2.stream_manage_size); \ + HDCP_DDC_READ_TRACE(hdcp, "Stream Ready", \ + hdcp->auth.msg.hdcp2.repeater_auth_stream_ready, \ + sizeof(hdcp->auth.msg.hdcp2.repeater_auth_stream_ready)); \ + HDCP_DDC_WRITE_TRACE(hdcp, "Content Stream Type", \ + hdcp->auth.msg.hdcp2.content_stream_type_dp, \ + sizeof(hdcp->auth.msg.hdcp2.content_stream_type_dp)); \ + } \ } while (0) #define HDCP_TOP_ADD_DISPLAY_TRACE(hdcp, i) \ HDCP_LOG_TOP(hdcp, "[Link %d]\tadd display %d", \ @@ -123,6 +174,9 @@ #define HDCP_TOP_HDCP1_DESTROY_SESSION_TRACE(hdcp) \ HDCP_LOG_TOP(hdcp, "[Link %d]\tdestroy hdcp1 session", \ hdcp->config.index) +#define HDCP_TOP_HDCP2_DESTROY_SESSION_TRACE(hdcp) \ + HDCP_LOG_TOP(hdcp, "[Link %d]\tdestroy hdcp2 session", \ + hdcp->config.index) #define HDCP_TOP_RESET_AUTH_TRACE(hdcp) \ HDCP_LOG_TOP(hdcp, "[Link %d]\treset authentication", hdcp->config.index) #define HDCP_TOP_RESET_CONN_TRACE(hdcp) \ diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c index 646d909bbc37bf1626f9499d9ae6d0e3d3f1305e..ef4eb55f44743e6e95d3a06ee0b8dbb43c4c06e6 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c @@ -31,6 +31,19 @@ #include "amdgpu.h" #include "hdcp_psp.h" +static void hdcp2_message_init(struct mod_hdcp *hdcp, + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_input_v2 *in) +{ + in->session_handle = hdcp->auth.id; + in->prepare.msg1_id = TA_HDCP_HDCP2_MSG_ID__NULL_MESSAGE; + in->prepare.msg2_id = TA_HDCP_HDCP2_MSG_ID__NULL_MESSAGE; + in->process.msg1_desc.msg_id = TA_HDCP_HDCP2_MSG_ID__NULL_MESSAGE; + in->process.msg1_desc.msg_size = 0; + in->process.msg2_desc.msg_id = TA_HDCP_HDCP2_MSG_ID__NULL_MESSAGE; + in->process.msg2_desc.msg_size = 0; + in->process.msg3_desc.msg_id = TA_HDCP_HDCP2_MSG_ID__NULL_MESSAGE; + in->process.msg3_desc.msg_size = 0; +} enum mod_hdcp_status mod_hdcp_remove_display_topology(struct mod_hdcp *hdcp) { @@ -42,7 +55,7 @@ enum mod_hdcp_status mod_hdcp_remove_display_topology(struct mod_hdcp *hdcp) dtm_cmd = (struct ta_dtm_shared_memory *)psp->dtm_context.dtm_shared_buf; for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) { - if (hdcp->connection.displays[i].state == MOD_HDCP_DISPLAY_ACTIVE_AND_ADDED) { + if (is_display_added(&(hdcp->connection.displays[i]))) { memset(dtm_cmd, 0, sizeof(struct ta_dtm_shared_memory)); @@ -96,7 +109,7 @@ enum mod_hdcp_status mod_hdcp_add_display_topology(struct mod_hdcp *hdcp) dtm_cmd->dtm_in_message.topology_update_v2.dig_fe = display->dig_fe; dtm_cmd->dtm_in_message.topology_update_v2.dp_mst_vcid = display->vc_id; dtm_cmd->dtm_in_message.topology_update_v2.max_hdcp_supported_version = - TA_DTM_HDCP_VERSION_MAX_SUPPORTED__1_x; + TA_DTM_HDCP_VERSION_MAX_SUPPORTED__2_2; dtm_cmd->dtm_status = TA_DTM_STATUS__GENERIC_FAILURE; psp_dtm_invoke(psp, dtm_cmd->cmd_id); @@ -326,3 +339,493 @@ enum mod_hdcp_status mod_hdcp_hdcp1_get_link_encryption_status(struct mod_hdcp * return MOD_HDCP_STATUS_SUCCESS; } +enum mod_hdcp_status mod_hdcp_hdcp2_create_session(struct mod_hdcp *hdcp) +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_hdcp_shared_memory *hdcp_cmd; + struct mod_hdcp_display *display = get_first_added_display(hdcp); + + if (!psp->hdcp_context.hdcp_initialized) { + DRM_ERROR("Failed to create hdcp session, HDCP TA is not initialized"); + return MOD_HDCP_STATUS_FAILURE; + } + + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf; + memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); + + if (!display) + return MOD_HDCP_STATUS_DISPLAY_NOT_FOUND; + + hdcp_cmd->in_msg.hdcp2_create_session_v2.display_handle = display->index; + + if (hdcp->connection.link.adjust.hdcp2.force_type == MOD_HDCP_FORCE_TYPE_0) + hdcp_cmd->in_msg.hdcp2_create_session_v2.negotiate_content_type = + TA_HDCP2_CONTENT_TYPE_NEGOTIATION_TYPE__FORCE_TYPE0; + else if (hdcp->connection.link.adjust.hdcp2.force_type == MOD_HDCP_FORCE_TYPE_1) + hdcp_cmd->in_msg.hdcp2_create_session_v2.negotiate_content_type = + TA_HDCP2_CONTENT_TYPE_NEGOTIATION_TYPE__FORCE_TYPE1; + else if (hdcp->connection.link.adjust.hdcp2.force_type == MOD_HDCP_FORCE_TYPE_MAX) + hdcp_cmd->in_msg.hdcp2_create_session_v2.negotiate_content_type = + TA_HDCP2_CONTENT_TYPE_NEGOTIATION_TYPE__MAX_SUPPORTED; + + hdcp_cmd->cmd_id = TA_HDCP_COMMAND__HDCP2_CREATE_SESSION_V2; + + psp_hdcp_invoke(psp, hdcp_cmd->cmd_id); + + if (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS) + return MOD_HDCP_STATUS_HDCP2_CREATE_SESSION_FAILURE; + + hdcp->auth.id = hdcp_cmd->out_msg.hdcp2_create_session_v2.session_handle; + + return MOD_HDCP_STATUS_SUCCESS; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_destroy_session(struct mod_hdcp *hdcp) +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_hdcp_shared_memory *hdcp_cmd; + + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf; + memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); + + hdcp_cmd->in_msg.hdcp2_destroy_session.session_handle = hdcp->auth.id; + hdcp_cmd->cmd_id = TA_HDCP_COMMAND__HDCP2_DESTROY_SESSION; + + psp_hdcp_invoke(psp, hdcp_cmd->cmd_id); + + if (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS) + return MOD_HDCP_STATUS_HDCP2_DESTROY_SESSION_FAILURE; + + HDCP_TOP_HDCP2_DESTROY_SESSION_TRACE(hdcp); + + return MOD_HDCP_STATUS_SUCCESS; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_prepare_ake_init(struct mod_hdcp *hdcp) +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_hdcp_shared_memory *hdcp_cmd; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_input_v2 *msg_in; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_output_v2 *msg_out; + + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf; + memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); + + msg_in = &hdcp_cmd->in_msg.hdcp2_prepare_process_authentication_message_v2; + msg_out = &hdcp_cmd->out_msg.hdcp2_prepare_process_authentication_message_v2; + + hdcp2_message_init(hdcp, msg_in); + + hdcp_cmd->cmd_id = TA_HDCP_COMMAND__HDCP2_PREPARE_PROCESS_AUTHENTICATION_MSG_V2; + msg_in->prepare.msg1_id = TA_HDCP_HDCP2_MSG_ID__AKE_INIT; + + psp_hdcp_invoke(psp, hdcp_cmd->cmd_id); + + if (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS) + return MOD_HDCP_STATUS_HDCP2_PREP_AKE_INIT_FAILURE; + + memcpy(&hdcp->auth.msg.hdcp2.ake_init[0], &msg_out->prepare.transmitter_message[0], + sizeof(hdcp->auth.msg.hdcp2.ake_init)); + + return MOD_HDCP_STATUS_SUCCESS; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_validate_ake_cert(struct mod_hdcp *hdcp) +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_hdcp_shared_memory *hdcp_cmd; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_input_v2 *msg_in; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_output_v2 *msg_out; + + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf; + memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); + + msg_in = &hdcp_cmd->in_msg.hdcp2_prepare_process_authentication_message_v2; + msg_out = &hdcp_cmd->out_msg.hdcp2_prepare_process_authentication_message_v2; + + hdcp2_message_init(hdcp, msg_in); + + msg_in->process.msg1_desc.msg_id = TA_HDCP_HDCP2_MSG_ID__AKE_SEND_CERT; + msg_in->process.msg1_desc.msg_size = TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_SEND_CERT; + + memcpy(&msg_in->process.receiver_message[0], hdcp->auth.msg.hdcp2.ake_cert, + sizeof(hdcp->auth.msg.hdcp2.ake_cert)); + + msg_in->prepare.msg1_id = TA_HDCP_HDCP2_MSG_ID__AKE_NO_STORED_KM; + msg_in->prepare.msg2_id = TA_HDCP_HDCP2_MSG_ID__AKE_STORED_KM; + + hdcp_cmd->cmd_id = TA_HDCP_COMMAND__HDCP2_PREPARE_PROCESS_AUTHENTICATION_MSG_V2; + + psp_hdcp_invoke(psp, hdcp_cmd->cmd_id); + + if (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS) + return MOD_HDCP_STATUS_HDCP2_VALIDATE_AKE_CERT_FAILURE; + + memcpy(hdcp->auth.msg.hdcp2.ake_no_stored_km, &msg_out->prepare.transmitter_message[0], + sizeof(hdcp->auth.msg.hdcp2.ake_no_stored_km)); + + memcpy(hdcp->auth.msg.hdcp2.ake_stored_km, + &msg_out->prepare.transmitter_message[sizeof(hdcp->auth.msg.hdcp2.ake_no_stored_km)], + sizeof(hdcp->auth.msg.hdcp2.ake_stored_km)); + + if (msg_out->process.msg1_status == TA_HDCP2_MSG_AUTHENTICATION_STATUS__SUCCESS) { + hdcp->connection.is_km_stored = msg_out->process.is_km_stored ? 1 : 0; + hdcp->connection.is_repeater = msg_out->process.is_repeater ? 1 : 0; + return MOD_HDCP_STATUS_SUCCESS; + } + + return MOD_HDCP_STATUS_FAILURE; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_validate_h_prime(struct mod_hdcp *hdcp) +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_hdcp_shared_memory *hdcp_cmd; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_input_v2 *msg_in; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_output_v2 *msg_out; + + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf; + memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); + + msg_in = &hdcp_cmd->in_msg.hdcp2_prepare_process_authentication_message_v2; + msg_out = &hdcp_cmd->out_msg.hdcp2_prepare_process_authentication_message_v2; + + hdcp2_message_init(hdcp, msg_in); + + msg_in->process.msg1_desc.msg_id = TA_HDCP_HDCP2_MSG_ID__AKE_SEND_H_PRIME; + msg_in->process.msg1_desc.msg_size = TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_SEND_H_PRIME; + + memcpy(&msg_in->process.receiver_message[0], hdcp->auth.msg.hdcp2.ake_h_prime, + sizeof(hdcp->auth.msg.hdcp2.ake_h_prime)); + + if (!hdcp->connection.is_km_stored) { + msg_in->process.msg2_desc.msg_id = TA_HDCP_HDCP2_MSG_ID__AKE_SEND_PAIRING_INFO; + msg_in->process.msg2_desc.msg_size = TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_SEND_PAIRING_INFO; + memcpy(&msg_in->process.receiver_message[sizeof(hdcp->auth.msg.hdcp2.ake_h_prime)], + hdcp->auth.msg.hdcp2.ake_pairing_info, sizeof(hdcp->auth.msg.hdcp2.ake_pairing_info)); + } + + hdcp_cmd->cmd_id = TA_HDCP_COMMAND__HDCP2_PREPARE_PROCESS_AUTHENTICATION_MSG_V2; + + psp_hdcp_invoke(psp, hdcp_cmd->cmd_id); + + if (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS) + return MOD_HDCP_STATUS_HDCP2_VALIDATE_AKE_CERT_FAILURE; + + if (msg_out->process.msg1_status != TA_HDCP2_MSG_AUTHENTICATION_STATUS__SUCCESS) + return MOD_HDCP_STATUS_HDCP2_VALIDATE_H_PRIME_FAILURE; + else if (!hdcp->connection.is_km_stored && + msg_out->process.msg2_status != TA_HDCP2_MSG_AUTHENTICATION_STATUS__SUCCESS) + return MOD_HDCP_STATUS_HDCP2_VALIDATE_PAIRING_INFO_FAILURE; + + + return MOD_HDCP_STATUS_SUCCESS; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_prepare_lc_init(struct mod_hdcp *hdcp) +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_hdcp_shared_memory *hdcp_cmd; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_input_v2 *msg_in; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_output_v2 *msg_out; + + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf; + memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); + + msg_in = &hdcp_cmd->in_msg.hdcp2_prepare_process_authentication_message_v2; + msg_out = &hdcp_cmd->out_msg.hdcp2_prepare_process_authentication_message_v2; + + hdcp2_message_init(hdcp, msg_in); + + msg_in->prepare.msg1_id = TA_HDCP_HDCP2_MSG_ID__LC_INIT; + + hdcp_cmd->cmd_id = TA_HDCP_COMMAND__HDCP2_PREPARE_PROCESS_AUTHENTICATION_MSG_V2; + + psp_hdcp_invoke(psp, hdcp_cmd->cmd_id); + + if (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS) + return MOD_HDCP_STATUS_HDCP2_PREP_LC_INIT_FAILURE; + + memcpy(hdcp->auth.msg.hdcp2.lc_init, &msg_out->prepare.transmitter_message[0], + sizeof(hdcp->auth.msg.hdcp2.lc_init)); + + return MOD_HDCP_STATUS_SUCCESS; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_validate_l_prime(struct mod_hdcp *hdcp) +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_hdcp_shared_memory *hdcp_cmd; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_input_v2 *msg_in; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_output_v2 *msg_out; + + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf; + memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); + + msg_in = &hdcp_cmd->in_msg.hdcp2_prepare_process_authentication_message_v2; + msg_out = &hdcp_cmd->out_msg.hdcp2_prepare_process_authentication_message_v2; + + hdcp2_message_init(hdcp, msg_in); + + msg_in->process.msg1_desc.msg_id = TA_HDCP_HDCP2_MSG_ID__LC_SEND_L_PRIME; + msg_in->process.msg1_desc.msg_size = TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__LC_SEND_L_PRIME; + + memcpy(&msg_in->process.receiver_message[0], hdcp->auth.msg.hdcp2.lc_l_prime, + sizeof(hdcp->auth.msg.hdcp2.lc_l_prime)); + + hdcp_cmd->cmd_id = TA_HDCP_COMMAND__HDCP2_PREPARE_PROCESS_AUTHENTICATION_MSG_V2; + + psp_hdcp_invoke(psp, hdcp_cmd->cmd_id); + + if (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS) + return MOD_HDCP_STATUS_HDCP2_VALIDATE_L_PRIME_FAILURE; + + if (msg_out->process.msg1_status != TA_HDCP2_MSG_AUTHENTICATION_STATUS__SUCCESS) + return MOD_HDCP_STATUS_HDCP2_VALIDATE_L_PRIME_FAILURE; + + return MOD_HDCP_STATUS_SUCCESS; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_prepare_eks(struct mod_hdcp *hdcp) +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_hdcp_shared_memory *hdcp_cmd; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_input_v2 *msg_in; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_output_v2 *msg_out; + + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf; + memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); + + msg_in = &hdcp_cmd->in_msg.hdcp2_prepare_process_authentication_message_v2; + msg_out = &hdcp_cmd->out_msg.hdcp2_prepare_process_authentication_message_v2; + + hdcp2_message_init(hdcp, msg_in); + + msg_in->prepare.msg1_id = TA_HDCP_HDCP2_MSG_ID__SKE_SEND_EKS; + + if (is_dp_hdcp(hdcp)) + msg_in->prepare.msg2_id = TA_HDCP_HDCP2_MSG_ID__SIGNAL_CONTENT_STREAM_TYPE_DP; + + hdcp_cmd->cmd_id = TA_HDCP_COMMAND__HDCP2_PREPARE_PROCESS_AUTHENTICATION_MSG_V2; + psp_hdcp_invoke(psp, hdcp_cmd->cmd_id); + + if (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS) + return MOD_HDCP_STATUS_HDCP2_PREP_EKS_FAILURE; + + memcpy(hdcp->auth.msg.hdcp2.ske_eks, &msg_out->prepare.transmitter_message[0], + sizeof(hdcp->auth.msg.hdcp2.ske_eks)); + msg_out->prepare.msg1_desc.msg_size = sizeof(hdcp->auth.msg.hdcp2.ske_eks); + + if (is_dp_hdcp(hdcp)) { + memcpy(hdcp->auth.msg.hdcp2.content_stream_type_dp, + &msg_out->prepare.transmitter_message[sizeof(hdcp->auth.msg.hdcp2.ske_eks)], + sizeof(hdcp->auth.msg.hdcp2.content_stream_type_dp)); + } + + return MOD_HDCP_STATUS_SUCCESS; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_enable_encryption(struct mod_hdcp *hdcp) +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_hdcp_shared_memory *hdcp_cmd; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_input_v2 *msg_in; + struct mod_hdcp_display *display = get_first_added_display(hdcp); + + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf; + memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); + + msg_in = &hdcp_cmd->in_msg.hdcp2_prepare_process_authentication_message_v2; + + hdcp2_message_init(hdcp, msg_in); + + if (!display) + return MOD_HDCP_STATUS_DISPLAY_NOT_FOUND; + + hdcp_cmd->in_msg.hdcp1_enable_encryption.session_handle = hdcp->auth.id; + + hdcp_cmd->cmd_id = TA_HDCP_COMMAND__HDCP2_SET_ENCRYPTION; + psp_hdcp_invoke(psp, hdcp_cmd->cmd_id); + + if (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS) + return MOD_HDCP_STATUS_HDCP2_ENABLE_ENCRYPTION_FAILURE; + + if (!is_dp_mst_hdcp(hdcp)) { + display->state = MOD_HDCP_DISPLAY_ENCRYPTION_ENABLED; + HDCP_HDCP2_ENABLED_TRACE(hdcp, display->index); + } + + return MOD_HDCP_STATUS_SUCCESS; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_validate_rx_id_list(struct mod_hdcp *hdcp) +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_hdcp_shared_memory *hdcp_cmd; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_input_v2 *msg_in; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_output_v2 *msg_out; + + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf; + memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); + + msg_in = &hdcp_cmd->in_msg.hdcp2_prepare_process_authentication_message_v2; + msg_out = &hdcp_cmd->out_msg.hdcp2_prepare_process_authentication_message_v2; + + hdcp2_message_init(hdcp, msg_in); + + msg_in->process.msg1_desc.msg_id = TA_HDCP_HDCP2_MSG_ID__REPEATERAUTH_SEND_RECEIVERID_LIST; + msg_in->process.msg1_desc.msg_size = sizeof(hdcp->auth.msg.hdcp2.rx_id_list); + memcpy(&msg_in->process.receiver_message[0], hdcp->auth.msg.hdcp2.rx_id_list, + sizeof(hdcp->auth.msg.hdcp2.rx_id_list)); + + msg_in->prepare.msg1_id = TA_HDCP_HDCP2_MSG_ID__REPEATERAUTH_SEND_ACK; + + hdcp_cmd->cmd_id = TA_HDCP_COMMAND__HDCP2_PREPARE_PROCESS_AUTHENTICATION_MSG_V2; + + psp_hdcp_invoke(psp, hdcp_cmd->cmd_id); + + if (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS) + return MOD_HDCP_STATUS_HDCP2_VALIDATE_RX_ID_LIST_FAILURE; + + memcpy(hdcp->auth.msg.hdcp2.repeater_auth_ack, &msg_out->prepare.transmitter_message[0], + sizeof(hdcp->auth.msg.hdcp2.repeater_auth_ack)); + + if (msg_out->process.msg1_status == TA_HDCP2_MSG_AUTHENTICATION_STATUS__SUCCESS) { + hdcp->connection.is_km_stored = msg_out->process.is_km_stored ? 1 : 0; + hdcp->connection.is_repeater = msg_out->process.is_repeater ? 1 : 0; + return MOD_HDCP_STATUS_SUCCESS; + } + + + return MOD_HDCP_STATUS_HDCP2_VALIDATE_RX_ID_LIST_FAILURE; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_enable_dp_stream_encryption(struct mod_hdcp *hdcp) +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_hdcp_shared_memory *hdcp_cmd; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_input_v2 *msg_in; + uint8_t i; + + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf; + memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); + + msg_in = &hdcp_cmd->in_msg.hdcp2_prepare_process_authentication_message_v2; + + hdcp2_message_init(hdcp, msg_in); + + + for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) { + if (hdcp->connection.displays[i].state != MOD_HDCP_DISPLAY_ACTIVE_AND_ADDED || + hdcp->connection.displays[i].adjust.disable) + continue; + hdcp_cmd->in_msg.hdcp2_enable_dp_stream_encryption.display_handle = hdcp->connection.displays[i].index; + hdcp_cmd->in_msg.hdcp2_enable_dp_stream_encryption.session_handle = hdcp->auth.id; + + hdcp_cmd->cmd_id = TA_HDCP_COMMAND__HDCP2_ENABLE_DP_STREAM_ENCRYPTION; + psp_hdcp_invoke(psp, hdcp_cmd->cmd_id); + + if (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS) + break; + + hdcp->connection.displays[i].state = MOD_HDCP_DISPLAY_ENCRYPTION_ENABLED; + HDCP_HDCP2_ENABLED_TRACE(hdcp, hdcp->connection.displays[i].index); + } + + return (hdcp_cmd->hdcp_status == TA_HDCP_STATUS__SUCCESS) ? MOD_HDCP_STATUS_SUCCESS + : MOD_HDCP_STATUS_HDCP2_ENABLE_STREAM_ENCRYPTION; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_prepare_stream_management(struct mod_hdcp *hdcp) +{ + + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_hdcp_shared_memory *hdcp_cmd; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_input_v2 *msg_in; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_output_v2 *msg_out; + + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf; + memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); + + msg_in = &hdcp_cmd->in_msg.hdcp2_prepare_process_authentication_message_v2; + msg_out = &hdcp_cmd->out_msg.hdcp2_prepare_process_authentication_message_v2; + + hdcp2_message_init(hdcp, msg_in); + + msg_in->prepare.msg1_id = TA_HDCP_HDCP2_MSG_ID__REPEATERAUTH_STREAM_MANAGE; + + + hdcp_cmd->cmd_id = TA_HDCP_COMMAND__HDCP2_PREPARE_PROCESS_AUTHENTICATION_MSG_V2; + psp_hdcp_invoke(psp, hdcp_cmd->cmd_id); + + if (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS) + return MOD_HDCP_STATUS_HDCP2_PREPARE_STREAM_MANAGEMENT_FAILURE; + + hdcp->auth.msg.hdcp2.stream_manage_size = msg_out->prepare.msg1_desc.msg_size; + + memcpy(hdcp->auth.msg.hdcp2.repeater_auth_stream_manage, &msg_out->prepare.transmitter_message[0], + sizeof(hdcp->auth.msg.hdcp2.repeater_auth_stream_manage)); + + return MOD_HDCP_STATUS_SUCCESS; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_validate_stream_ready(struct mod_hdcp *hdcp) +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_hdcp_shared_memory *hdcp_cmd; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_input_v2 *msg_in; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_output_v2 *msg_out; + + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf; + memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); + + msg_in = &hdcp_cmd->in_msg.hdcp2_prepare_process_authentication_message_v2; + msg_out = &hdcp_cmd->out_msg.hdcp2_prepare_process_authentication_message_v2; + + hdcp2_message_init(hdcp, msg_in); + + msg_in->process.msg1_desc.msg_id = TA_HDCP_HDCP2_MSG_ID__REPEATERAUTH_STREAM_READY; + + msg_in->process.msg1_desc.msg_size = sizeof(hdcp->auth.msg.hdcp2.repeater_auth_stream_ready); + + memcpy(&msg_in->process.receiver_message[0], hdcp->auth.msg.hdcp2.repeater_auth_stream_ready, + sizeof(hdcp->auth.msg.hdcp2.repeater_auth_stream_ready)); + + hdcp_cmd->cmd_id = TA_HDCP_COMMAND__HDCP2_PREPARE_PROCESS_AUTHENTICATION_MSG_V2; + psp_hdcp_invoke(psp, hdcp_cmd->cmd_id); + + return (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS) && + (msg_out->process.msg1_status == TA_HDCP2_MSG_AUTHENTICATION_STATUS__SUCCESS) + ? MOD_HDCP_STATUS_SUCCESS + : MOD_HDCP_STATUS_HDCP2_VALIDATE_STREAM_READY_FAILURE; +} + +enum mod_hdcp_status mod_hdcp_hdcp2_get_link_encryption_status(struct mod_hdcp *hdcp, + enum mod_hdcp_encryption_status *encryption_status) +{ + struct psp_context *psp = hdcp->config.psp.handle; + struct ta_hdcp_shared_memory *hdcp_cmd; + + hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.hdcp_shared_buf; + + memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); + + hdcp_cmd->in_msg.hdcp2_get_encryption_status.session_handle = hdcp->auth.id; + hdcp_cmd->out_msg.hdcp2_get_encryption_status.protection_level = 0; + hdcp_cmd->cmd_id = TA_HDCP_COMMAND__HDCP2_GET_ENCRYPTION_STATUS; + *encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; + + psp_hdcp_invoke(psp, hdcp_cmd->cmd_id); + + if (hdcp_cmd->hdcp_status != TA_HDCP_STATUS__SUCCESS) + return MOD_HDCP_STATUS_FAILURE; + + if (hdcp_cmd->out_msg.hdcp2_get_encryption_status.protection_level == 1) { + if (hdcp_cmd->out_msg.hdcp2_get_encryption_status.hdcp2_type == TA_HDCP2_CONTENT_TYPE__TYPE1) + *encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON; + else + *encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON; + } + + return MOD_HDCP_STATUS_SUCCESS; +} diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.h b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.h index 986fc07ea9ea619d66d2e8a26b37c0e451e14f0c..82a5e997d573fddf1c16273a22f0545a88e40ee6 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.h +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.h @@ -36,6 +36,11 @@ enum bgd_security_hdcp_encryption_level { HDCP_ENCRYPTION_LEVEL__ON }; +enum bgd_security_hdcp2_content_type { + HDCP2_CONTENT_TYPE__INVALID = 0, + HDCP2_CONTENT_TYPE__TYPE0, + HDCP2_CONTENT_TYPE__TYPE1 +}; enum ta_dtm_command { TA_DTM_COMMAND__UNUSED_1 = 1, TA_DTM_COMMAND__TOPOLOGY_UPDATE_V2, @@ -121,8 +126,64 @@ enum ta_hdcp_command { TA_HDCP_COMMAND__HDCP1_ENABLE_ENCRYPTION, TA_HDCP_COMMAND__HDCP1_ENABLE_DP_STREAM_ENCRYPTION, TA_HDCP_COMMAND__HDCP1_GET_ENCRYPTION_STATUS, + TA_HDCP_COMMAND__UNUSED_1, + TA_HDCP_COMMAND__HDCP2_DESTROY_SESSION, + TA_HDCP_COMMAND__UNUSED_2, + TA_HDCP_COMMAND__HDCP2_SET_ENCRYPTION, + TA_HDCP_COMMAND__HDCP2_GET_ENCRYPTION_STATUS, + TA_HDCP_COMMAND__UNUSED_3, + TA_HDCP_COMMAND__HDCP2_CREATE_SESSION_V2, + TA_HDCP_COMMAND__HDCP2_PREPARE_PROCESS_AUTHENTICATION_MSG_V2, + TA_HDCP_COMMAND__HDCP2_ENABLE_DP_STREAM_ENCRYPTION +}; + +enum ta_hdcp2_msg_id { + TA_HDCP_HDCP2_MSG_ID__NULL_MESSAGE = 1, + TA_HDCP_HDCP2_MSG_ID__AKE_INIT = 2, + TA_HDCP_HDCP2_MSG_ID__AKE_SEND_CERT = 3, + TA_HDCP_HDCP2_MSG_ID__AKE_NO_STORED_KM = 4, + TA_HDCP_HDCP2_MSG_ID__AKE_STORED_KM = 5, + TA_HDCP_HDCP2_MSG_ID__AKE_SEND_RRX = 6, + TA_HDCP_HDCP2_MSG_ID__AKE_SEND_H_PRIME = 7, + TA_HDCP_HDCP2_MSG_ID__AKE_SEND_PAIRING_INFO = 8, + TA_HDCP_HDCP2_MSG_ID__LC_INIT = 9, + TA_HDCP_HDCP2_MSG_ID__LC_SEND_L_PRIME = 10, + TA_HDCP_HDCP2_MSG_ID__SKE_SEND_EKS = 11, + TA_HDCP_HDCP2_MSG_ID__REPEATERAUTH_SEND_RECEIVERID_LIST = 12, + TA_HDCP_HDCP2_MSG_ID__RTT_READY = 13, + TA_HDCP_HDCP2_MSG_ID__RTT_CHALLENGE = 14, + TA_HDCP_HDCP2_MSG_ID__REPEATERAUTH_SEND_ACK = 15, + TA_HDCP_HDCP2_MSG_ID__REPEATERAUTH_STREAM_MANAGE = 16, + TA_HDCP_HDCP2_MSG_ID__REPEATERAUTH_STREAM_READY = 17, + TA_HDCP_HDCP2_MSG_ID__RECEIVER_AUTH_STATUS = 18, + TA_HDCP_HDCP2_MSG_ID__AKE_TRANSMITTER_INFO = 19, + TA_HDCP_HDCP2_MSG_ID__AKE_RECEIVER_INFO = 20, + TA_HDCP_HDCP2_MSG_ID__SIGNAL_CONTENT_STREAM_TYPE_DP = 129 }; +enum ta_hdcp2_hdcp2_msg_id_max_size { + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__NULL_MESSAGE = 0, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_INIT = 12, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_SEND_CERT = 534, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_NO_STORED_KM = 129, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_STORED_KM = 33, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_SEND_RRX = 9, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_SEND_H_PRIME = 33, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_SEND_PAIRING_INFO = 17, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__LC_INIT = 9, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__LC_SEND_L_PRIME = 33, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__SKE_SEND_EKS = 25, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__REPEATERAUTH_SEND_RECEIVERID_LIST = 181, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__RTT_READY = 1, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__RTT_CHALLENGE = 17, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__REPEATERAUTH_SEND_RACK = 17, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__REPEATERAUTH_STREAM_MANAGE = 13, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__REPEATERAUTH_STREAM_READY = 33, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__RECEIVER_AUTH_STATUS = 4, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_TRANSMITTER_INFO = 6, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_RECEIVER_INFO = 6, + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__SIGNAL_CONTENT_STREAM_TYPE_DP = 1 +}; /* HDCP related enumerations */ /**********************************************************/ @@ -131,6 +192,12 @@ enum ta_hdcp_command { #define TA_HDCP__HDCP1_KSV_SIZE 5 #define TA_HDCP__HDCP1_KSV_LIST_MAX_ENTRIES 127 #define TA_HDCP__HDCP1_V_PRIME_SIZE 20 +#define TA_HDCP__HDCP2_TX_BUF_MAX_SIZE \ + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_NO_STORED_KM + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_STORED_KM + 6 + +// 64 bits boundaries +#define TA_HDCP__HDCP2_RX_BUF_MAX_SIZE \ + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_SEND_CERT + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_RECEIVER_INFO + 4 enum ta_hdcp_status { TA_HDCP_STATUS__SUCCESS = 0x00, @@ -165,9 +232,47 @@ enum ta_hdcp_authentication_status { TA_HDCP_AUTHENTICATION_STATUS__HDCP1_FIRST_PART_COMPLETE = 0x02, TA_HDCP_AUTHENTICATION_STATUS__HDCP1_SECOND_PART_FAILED = 0x03, TA_HDCP_AUTHENTICATION_STATUS__HDCP1_AUTHENTICATED = 0x04, + TA_HDCP_AUTHENTICATION_STATUS__HDCP22_AUTHENTICATION_PENDING = 0x06, + TA_HDCP_AUTHENTICATION_STATUS__HDCP22_AUTHENTICATION_FAILED = 0x07, + TA_HDCP_AUTHENTICATION_STATUS__HDCP22_AUTHENTICATED = 0x08, TA_HDCP_AUTHENTICATION_STATUS__HDCP1_KSV_VALIDATION_FAILED = 0x09 }; +enum ta_hdcp2_msg_authentication_status { + TA_HDCP2_MSG_AUTHENTICATION_STATUS__SUCCESS = 0, + TA_HDCP2_MSG_AUTHENTICATION_STATUS__KM_NOT_AVAILABLE, + TA_HDCP2_MSG_AUTHENTICATION_STATUS__UNUSED, + TA_HDCP2_MSG_AUTHENTICATION_STATUS__INVALID = 100, // everything above does not fail the request + TA_HDCP2_MSG_AUTHENTICATION_STATUS__NOT_ENOUGH_MEMORY, + TA_HDCP2_MSG_AUTHENTICATION_STATUS__NOT_EXPECTED_MSG, + TA_HDCP2_MSG_AUTHENTICATION_STATUS__SIGNATURE_CERTIFICAT_ERROR, + TA_HDCP2_MSG_AUTHENTICATION_STATUS__INCORRECT_HDCP_VERSION, + TA_HDCP2_MSG_AUTHENTICATION_STATUS__UNKNOWN_MESSAGE, + TA_HDCP2_MSG_AUTHENTICATION_STATUS__INVALID_HMAC, + TA_HDCP2_MSG_AUTHENTICATION_STATUS__INVALID_TOPOLOGY, + TA_HDCP2_MSG_AUTHENTICATION_STATUS__INVALID_SEQ_NUM, + TA_HDCP2_MSG_AUTHENTICATION_STATUS__INVALID_SIZE, + TA_HDCP2_MSG_AUTHENTICATION_STATUS__INVALID_LENGTH, + TA_HDCP2_MSG_AUTHENTICATION_STATUS__REAUTH_REQUEST +}; + +enum ta_hdcp_content_type { + TA_HDCP2_CONTENT_TYPE__TYPE0 = 1, + TA_HDCP2_CONTENT_TYPE__TYPE1, +}; + +enum ta_hdcp_content_type_negotiation_type { + TA_HDCP2_CONTENT_TYPE_NEGOTIATION_TYPE__FORCE_TYPE0 = 1, + TA_HDCP2_CONTENT_TYPE_NEGOTIATION_TYPE__FORCE_TYPE1, + TA_HDCP2_CONTENT_TYPE_NEGOTIATION_TYPE__MAX_SUPPORTED +}; + +enum ta_hdcp2_version { + TA_HDCP2_VERSION_UNKNOWN = 0, + TA_HDCP2_VERSION_2_0 = 20, + TA_HDCP2_VERSION_2_1 = 21, + TA_HDCP2_VERSION_2_2 = 22 +}; /* input/output structures for HDCP commands */ /**********************************************************/ @@ -232,6 +337,84 @@ struct ta_hdcp_cmd_hdcp1_get_encryption_status_output { uint32_t protection_level; }; +struct ta_hdcp_cmd_hdcp2_create_session_input_v2 { + uint32_t display_handle; + enum ta_hdcp_content_type_negotiation_type negotiate_content_type; +}; + +struct ta_hdcp_cmd_hdcp2_create_session_output_v2 { + uint32_t session_handle; +}; + +struct ta_hdcp_cmd_hdcp2_destroy_session_input { + uint32_t session_handle; +}; + +struct ta_hdcp_cmd_hdcp2_authentication_message_v2 { + enum ta_hdcp2_msg_id msg_id; + uint32_t msg_size; +}; + +struct ta_hdcp_cmd_hdcp2_process_authentication_message_input_v2 { + struct ta_hdcp_cmd_hdcp2_authentication_message_v2 msg1_desc; + struct ta_hdcp_cmd_hdcp2_authentication_message_v2 msg2_desc; + struct ta_hdcp_cmd_hdcp2_authentication_message_v2 msg3_desc; + uint8_t receiver_message[TA_HDCP__HDCP2_RX_BUF_MAX_SIZE]; +}; + +struct ta_hdcp_cmd_hdcp2_process_authentication_message_output_v2 { + uint32_t hdcp_version; + uint32_t is_km_stored; + uint32_t is_locality_precompute_support; + uint32_t is_repeater; + enum ta_hdcp2_msg_authentication_status msg1_status; + enum ta_hdcp2_msg_authentication_status msg2_status; + enum ta_hdcp2_msg_authentication_status msg3_status; +}; + +struct ta_hdcp_cmd_hdcp2_prepare_authentication_message_input_v2 { + enum ta_hdcp2_msg_id msg1_id; + enum ta_hdcp2_msg_id msg2_id; +}; + +struct ta_hdcp_cmd_hdcp2_prepare_authentication_message_output_v2 { + enum ta_hdcp2_msg_authentication_status msg1_status; + enum ta_hdcp2_msg_authentication_status msg2_status; + struct ta_hdcp_cmd_hdcp2_authentication_message_v2 msg1_desc; + struct ta_hdcp_cmd_hdcp2_authentication_message_v2 msg2_desc; + uint8_t transmitter_message[TA_HDCP__HDCP2_TX_BUF_MAX_SIZE]; +}; + +struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_input_v2 { + uint32_t session_handle; + struct ta_hdcp_cmd_hdcp2_process_authentication_message_input_v2 process; + struct ta_hdcp_cmd_hdcp2_prepare_authentication_message_input_v2 prepare; +}; + +struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_output_v2 { + uint32_t authentication_status; + struct ta_hdcp_cmd_hdcp2_process_authentication_message_output_v2 process; + struct ta_hdcp_cmd_hdcp2_prepare_authentication_message_output_v2 prepare; +}; + +struct ta_hdcp_cmd_hdcp2_set_encryption_input { + uint32_t session_handle; +}; + +struct ta_hdcp_cmd_hdcp2_get_encryption_status_input { + uint32_t session_handle; +}; + +struct ta_hdcp_cmd_hdcp2_get_encryption_status_output { + enum ta_hdcp_content_type hdcp2_type; + uint32_t protection_level; +}; + +struct ta_hdcp_cmd_hdcp2_enable_dp_stream_encryption_input { + uint32_t session_handle; + uint32_t display_handle; +}; + /**********************************************************/ /* Common input structure for HDCP callbacks */ union ta_hdcp_cmd_input { @@ -242,6 +425,13 @@ union ta_hdcp_cmd_input { struct ta_hdcp_cmd_hdcp1_enable_encryption_input hdcp1_enable_encryption; struct ta_hdcp_cmd_hdcp1_enable_dp_stream_encryption_input hdcp1_enable_dp_stream_encryption; struct ta_hdcp_cmd_hdcp1_get_encryption_status_input hdcp1_get_encryption_status; + struct ta_hdcp_cmd_hdcp2_destroy_session_input hdcp2_destroy_session; + struct ta_hdcp_cmd_hdcp2_set_encryption_input hdcp2_set_encryption; + struct ta_hdcp_cmd_hdcp2_get_encryption_status_input hdcp2_get_encryption_status; + struct ta_hdcp_cmd_hdcp2_create_session_input_v2 hdcp2_create_session_v2; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_input_v2 + hdcp2_prepare_process_authentication_message_v2; + struct ta_hdcp_cmd_hdcp2_enable_dp_stream_encryption_input hdcp2_enable_dp_stream_encryption; }; /* Common output structure for HDCP callbacks */ @@ -250,6 +440,10 @@ union ta_hdcp_cmd_output { struct ta_hdcp_cmd_hdcp1_first_part_authentication_output hdcp1_first_part_authentication; struct ta_hdcp_cmd_hdcp1_second_part_authentication_output hdcp1_second_part_authentication; struct ta_hdcp_cmd_hdcp1_get_encryption_status_output hdcp1_get_encryption_status; + struct ta_hdcp_cmd_hdcp2_get_encryption_status_output hdcp2_get_encryption_status; + struct ta_hdcp_cmd_hdcp2_create_session_output_v2 hdcp2_create_session_v2; + struct ta_hdcp_cmd_hdcp2_process_prepare_authentication_message_output_v2 + hdcp2_prepare_process_authentication_message_v2; }; /**********************************************************/ diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h index dbe7835aabcf747c25825e76dac9d2e047bb9025..dc187844d10b1f5e99e4423f15cadb6b422643d5 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h @@ -92,7 +92,6 @@ struct mod_vrr_params_btr { uint32_t inserted_duration_in_us; uint32_t frames_to_insert; uint32_t frame_counter; - uint32_t margin_in_us; }; struct mod_vrr_params_fixed_refresh { diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h b/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h index dea21702edffbb334f73862949aa03a8a4c0d9db..f2a0e1a064da8f755db5d2cfb144ca8b5bb0038e 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h @@ -77,6 +77,7 @@ enum mod_hdcp_status { MOD_HDCP_STATUS_HDCP2_H_PRIME_PENDING, MOD_HDCP_STATUS_HDCP2_PAIRING_INFO_PENDING, MOD_HDCP_STATUS_HDCP2_VALIDATE_AKE_CERT_FAILURE, + MOD_HDCP_STATUS_HDCP2_AKE_CERT_REVOKED, MOD_HDCP_STATUS_HDCP2_VALIDATE_H_PRIME_FAILURE, MOD_HDCP_STATUS_HDCP2_VALIDATE_PAIRING_INFO_FAILURE, MOD_HDCP_STATUS_HDCP2_PREP_LC_INIT_FAILURE, @@ -86,6 +87,7 @@ enum mod_hdcp_status { MOD_HDCP_STATUS_HDCP2_ENABLE_ENCRYPTION_FAILURE, MOD_HDCP_STATUS_HDCP2_RX_ID_LIST_NOT_READY, MOD_HDCP_STATUS_HDCP2_VALIDATE_RX_ID_LIST_FAILURE, + MOD_HDCP_STATUS_HDCP2_RX_ID_LIST_REVOKED, MOD_HDCP_STATUS_HDCP2_ENABLE_STREAM_ENCRYPTION, MOD_HDCP_STATUS_HDCP2_STREAM_READY_PENDING, MOD_HDCP_STATUS_HDCP2_VALIDATE_STREAM_READY_FAILURE, @@ -156,12 +158,18 @@ struct mod_hdcp_link_adjustment_hdcp1 { uint8_t reserved : 6; }; +enum mod_hdcp_force_hdcp_type { + MOD_HDCP_FORCE_TYPE_MAX = 0, + MOD_HDCP_FORCE_TYPE_0, + MOD_HDCP_FORCE_TYPE_1 +}; + struct mod_hdcp_link_adjustment_hdcp2 { uint8_t disable : 1; - uint8_t disable_type1 : 1; + uint8_t force_type : 2; uint8_t force_no_stored_km : 1; uint8_t increase_h_prime_timeout: 1; - uint8_t reserved : 4; + uint8_t reserved : 3; }; struct mod_hdcp_link_adjustment { @@ -184,7 +192,8 @@ enum mod_hdcp_encryption_status { MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF = 0, MOD_HDCP_ENCRYPTION_STATUS_HDCP1_ON, MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON, - MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON + MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON, + MOD_HDCP_ENCRYPTION_STATUS_HDCP2_ON }; /* per link events dm has to notify to hdcp module */ 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 ca8ce3c55337bf968c0d4d76c58ea51f04e76ad5..42cbeffac6402bd099c5ee7f08bb7f1930320be4 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 @@ -26,6 +26,7 @@ #ifndef MOD_INFO_PACKET_H_ #define MOD_INFO_PACKET_H_ +#include "dm_services.h" #include "mod_shared.h" //Forward Declarations struct dc_stream_state; @@ -33,7 +34,8 @@ struct dc_info_packet; struct mod_vrr_params; void mod_build_vsc_infopacket(const struct dc_stream_state *stream, - struct dc_info_packet *info_packet); + struct dc_info_packet *info_packet, + bool *use_vsc_sdp_for_colorimetry); void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream, struct dc_info_packet *info_packet, int ALLMEnabled, int ALLMValue); diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_shared.h b/drivers/gpu/drm/amd/display/modules/inc/mod_shared.h index b45f7d65e76a8a197f2d3dadfc126e91993c6e0f..fe21179043298c206ac43d85bd5c7c79f039aac8 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_shared.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_shared.h @@ -45,7 +45,6 @@ enum vrr_packet_type { PACKET_TYPE_VTEM }; -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) union lut3d_control_flags { unsigned int raw; struct { @@ -104,6 +103,5 @@ struct lut3d_settings { enum lut3d_control_gamut_map map2; enum lut3d_control_rotation_mode rotation2; }; -#endif #endif /* MOD_SHARED_H_ */ 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 db6b08f6d0931876ea504bb2d96af3b90367889b..6a8a056424b85c83dfffcc18d1396bc412fb2c5f 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 @@ -30,6 +30,20 @@ #include "mod_freesync.h" #include "dc.h" +enum vsc_packet_revision { + vsc_packet_undefined = 0, + //01h = VSC SDP supports only 3D stereo. + vsc_packet_rev1 = 1, + //02h = 3D stereo + PSR. + vsc_packet_rev2 = 2, + //03h = 3D stereo + PSR2. + vsc_packet_rev3 = 3, + //04h = 3D stereo + PSR/PSR2 + Y-coordinate. + vsc_packet_rev4 = 4, + //05h = 3D stereo + PSR/PSR2 + Y-coordinate + Pixel Encoding/Colorimetry Format + vsc_packet_rev5 = 5, +}; + #define HDMI_INFOFRAME_TYPE_VENDOR 0x81 #define HF_VSIF_VERSION 1 @@ -116,35 +130,41 @@ enum ColorimetryYCCDP { }; void mod_build_vsc_infopacket(const struct dc_stream_state *stream, - struct dc_info_packet *info_packet) + struct dc_info_packet *info_packet, + bool *use_vsc_sdp_for_colorimetry) { - unsigned int vscPacketRevision = 0; + unsigned int vsc_packet_revision = vsc_packet_undefined; unsigned int i; unsigned int pixelEncoding = 0; unsigned int colorimetryFormat = 0; bool stereo3dSupport = false; + /* Initialize first, later if infopacket is valid determine if VSC SDP + * should be used to signal colorimetry format and pixel encoding. + */ + *use_vsc_sdp_for_colorimetry = false; + if (stream->timing.timing_3d_format != TIMING_3D_FORMAT_NONE && stream->view_format != VIEW_3D_FORMAT_NONE) { - vscPacketRevision = 1; + vsc_packet_revision = vsc_packet_rev1; stereo3dSupport = true; } /*VSC packet set to 2 when DP revision >= 1.2*/ if (stream->psr_version != 0) - vscPacketRevision = 2; + vsc_packet_revision = vsc_packet_rev2; /* Update to revision 5 for extended colorimetry support for DPCD 1.4+ */ if (stream->link->dpcd_caps.dpcd_rev.raw >= 0x14 && stream->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED) - vscPacketRevision = 5; + vsc_packet_revision = vsc_packet_rev5; /* VSC packet not needed based on the features * supported by this DP display */ - if (vscPacketRevision == 0) + if (vsc_packet_revision == vsc_packet_undefined) return; - if (vscPacketRevision == 0x2) { + if (vsc_packet_revision == vsc_packet_rev2) { /* Secondary-data Packet ID = 0*/ info_packet->hb0 = 0x00; /* 07h - Packet Type Value indicating Video @@ -166,7 +186,7 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream, info_packet->valid = true; } - if (vscPacketRevision == 0x1) { + if (vsc_packet_revision == vsc_packet_rev1) { info_packet->hb0 = 0x00; // Secondary-data Packet ID = 0 info_packet->hb1 = 0x07; // 07h = Packet Type Value indicating Video Stream Configuration packet @@ -237,7 +257,7 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream, * the Pixel Encoding/Colorimetry Format and that a Sink device must ignore MISC1, bit 7, and * MISC0, bits 7:1 (MISC1, bit 7. and MISC0, bits 7:1 become "don't care").) */ - if (vscPacketRevision == 0x5) { + if (vsc_packet_revision == vsc_packet_rev5) { /* Secondary-data Packet ID = 0 */ info_packet->hb0 = 0x00; /* 07h - Packet Type Value indicating Video Stream Configuration packet */ @@ -249,6 +269,13 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream, info_packet->valid = true; + /* If we are using VSC SDP revision 05h, use this to signal for + * colorimetry format and pixel encoding. HW should later be + * programmed to set MSA MISC1 bit 6 to indicate ignore + * colorimetry format and pixel encoding in the MSA. + */ + *use_vsc_sdp_for_colorimetry = true; + /* Set VSC SDP fields for pixel encoding and colorimetry format from DP 1.3 specs * Data Bytes DB 18~16 * Bits 3:0 (Colorimetry Format) | Bits 7:4 (Pixel Encoding) @@ -393,7 +420,6 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream, */ info_packet->sb[18] = 0; } - } /** diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index dc7eb28f029672c2de42ffdca58645da575b378e..d655a76bedc6c3da640fce66d6a8b45876e846b4 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -53,7 +53,8 @@ enum amd_ip_block_type { AMD_IP_BLOCK_TYPE_VCE, AMD_IP_BLOCK_TYPE_ACP, AMD_IP_BLOCK_TYPE_VCN, - AMD_IP_BLOCK_TYPE_MES + AMD_IP_BLOCK_TYPE_MES, + AMD_IP_BLOCK_TYPE_JPEG }; enum amd_clockgating_state { @@ -99,6 +100,7 @@ enum amd_powergating_state { #define AMD_CG_SUPPORT_IH_CG (1 << 27) #define AMD_CG_SUPPORT_ATHUB_LS (1 << 28) #define AMD_CG_SUPPORT_ATHUB_MGCG (1 << 29) +#define AMD_CG_SUPPORT_JPEG_MGCG (1 << 30) /* PG flags */ #define AMD_PG_SUPPORT_GFX_PG (1 << 0) #define AMD_PG_SUPPORT_GFX_SMG (1 << 1) @@ -117,6 +119,7 @@ enum amd_powergating_state { #define AMD_PG_SUPPORT_VCN (1 << 14) #define AMD_PG_SUPPORT_VCN_DPG (1 << 15) #define AMD_PG_SUPPORT_ATHUB (1 << 16) +#define AMD_PG_SUPPORT_JPEG (1 << 17) enum PP_FEATURE_MASK { PP_SCLK_DPM_MASK = 0x1, diff --git a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_1_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_1_0_offset.h index 352ffae7a7cac019d6b42794f762a4aef213ee20..2c3ce243861a7e491c7360ccab23561df7b0e894 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_1_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_1_0_offset.h @@ -1964,4 +1964,20 @@ #define mmATC_L2_PERFCOUNTER_RSLT_CNTL 0x084a #define mmATC_L2_PERFCOUNTER_RSLT_CNTL_BASE_IDX 0 +/* MMEA */ +#define mmMMEA0_EDC_CNT_VG20 0x0206 +#define mmMMEA0_EDC_CNT_VG20_BASE_IDX 0 +#define mmMMEA0_EDC_CNT2_VG20 0x0207 +#define mmMMEA0_EDC_CNT2_VG20_BASE_IDX 0 +#define mmMMEA1_EDC_CNT_VG20 0x0346 +#define mmMMEA1_EDC_CNT_VG20_BASE_IDX 0 +#define mmMMEA1_EDC_CNT2_VG20 0x0347 +#define mmMMEA1_EDC_CNT2_VG20_BASE_IDX 0 + +// addressBlock: mmhub_utcl2_vmsharedpfdec +// base address: 0x6a040 +#define mmMC_VM_XGMI_LFB_CNTL 0x0823 +#define mmMC_VM_XGMI_LFB_CNTL_BASE_IDX 0 +#define mmMC_VM_XGMI_LFB_SIZE 0x0824 +#define mmMC_VM_XGMI_LFB_SIZE_BASE_IDX 0 #endif diff --git a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_1_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_1_0_sh_mask.h index 34278ef2aa1b8645b3a6d2b016ab18023df11865..198f5f93ed1ad65a09112c28e495ef0bd3548a92 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_1_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_1_0_sh_mask.h @@ -10124,4 +10124,126 @@ #define ATC_L2_PERFCOUNTER_RSLT_CNTL__CLEAR_ALL_MASK 0x02000000L #define ATC_L2_PERFCOUNTER_RSLT_CNTL__STOP_ALL_ON_SATURATE_MASK 0x04000000L +//MMEA0_EDC_CNT +#define MMEA0_EDC_CNT_VG20__DRAMRD_CMDMEM_SEC_COUNT__SHIFT 0x0 +#define MMEA0_EDC_CNT_VG20__DRAMRD_CMDMEM_DED_COUNT__SHIFT 0x2 +#define MMEA0_EDC_CNT_VG20__DRAMWR_CMDMEM_SEC_COUNT__SHIFT 0x4 +#define MMEA0_EDC_CNT_VG20__DRAMWR_CMDMEM_DED_COUNT__SHIFT 0x6 +#define MMEA0_EDC_CNT_VG20__DRAMWR_DATAMEM_SEC_COUNT__SHIFT 0x8 +#define MMEA0_EDC_CNT_VG20__DRAMWR_DATAMEM_DED_COUNT__SHIFT 0xa +#define MMEA0_EDC_CNT_VG20__RRET_TAGMEM_SEC_COUNT__SHIFT 0xc +#define MMEA0_EDC_CNT_VG20__RRET_TAGMEM_DED_COUNT__SHIFT 0xe +#define MMEA0_EDC_CNT_VG20__WRET_TAGMEM_SEC_COUNT__SHIFT 0x10 +#define MMEA0_EDC_CNT_VG20__WRET_TAGMEM_DED_COUNT__SHIFT 0x12 +#define MMEA0_EDC_CNT_VG20__DRAMRD_PAGEMEM_SED_COUNT__SHIFT 0x14 +#define MMEA0_EDC_CNT_VG20__DRAMWR_PAGEMEM_SED_COUNT__SHIFT 0x16 +#define MMEA0_EDC_CNT_VG20__IORD_CMDMEM_SED_COUNT__SHIFT 0x18 +#define MMEA0_EDC_CNT_VG20__IOWR_CMDMEM_SED_COUNT__SHIFT 0x1a +#define MMEA0_EDC_CNT_VG20__IOWR_DATAMEM_SED_COUNT__SHIFT 0x1c +#define MMEA0_EDC_CNT_VG20__DRAMRD_CMDMEM_SEC_COUNT_MASK 0x00000003L +#define MMEA0_EDC_CNT_VG20__DRAMRD_CMDMEM_DED_COUNT_MASK 0x0000000CL +#define MMEA0_EDC_CNT_VG20__DRAMWR_CMDMEM_SEC_COUNT_MASK 0x00000030L +#define MMEA0_EDC_CNT_VG20__DRAMWR_CMDMEM_DED_COUNT_MASK 0x000000C0L +#define MMEA0_EDC_CNT_VG20__DRAMWR_DATAMEM_SEC_COUNT_MASK 0x00000300L +#define MMEA0_EDC_CNT_VG20__DRAMWR_DATAMEM_DED_COUNT_MASK 0x00000C00L +#define MMEA0_EDC_CNT_VG20__RRET_TAGMEM_SEC_COUNT_MASK 0x00003000L +#define MMEA0_EDC_CNT_VG20__RRET_TAGMEM_DED_COUNT_MASK 0x0000C000L +#define MMEA0_EDC_CNT_VG20__WRET_TAGMEM_SEC_COUNT_MASK 0x00030000L +#define MMEA0_EDC_CNT_VG20__WRET_TAGMEM_DED_COUNT_MASK 0x000C0000L +#define MMEA0_EDC_CNT_VG20__DRAMRD_PAGEMEM_SED_COUNT_MASK 0x00300000L +#define MMEA0_EDC_CNT_VG20__DRAMWR_PAGEMEM_SED_COUNT_MASK 0x00C00000L +#define MMEA0_EDC_CNT_VG20__IORD_CMDMEM_SED_COUNT_MASK 0x03000000L +#define MMEA0_EDC_CNT_VG20__IOWR_CMDMEM_SED_COUNT_MASK 0x0C000000L +#define MMEA0_EDC_CNT_VG20__IOWR_DATAMEM_SED_COUNT_MASK 0x30000000L +//MMEA0_EDC_CNT2 +#define MMEA0_EDC_CNT2_VG20__GMIRD_CMDMEM_SEC_COUNT__SHIFT 0x0 +#define MMEA0_EDC_CNT2_VG20__GMIRD_CMDMEM_DED_COUNT__SHIFT 0x2 +#define MMEA0_EDC_CNT2_VG20__GMIWR_CMDMEM_SEC_COUNT__SHIFT 0x4 +#define MMEA0_EDC_CNT2_VG20__GMIWR_CMDMEM_DED_COUNT__SHIFT 0x6 +#define MMEA0_EDC_CNT2_VG20__GMIWR_DATAMEM_SEC_COUNT__SHIFT 0x8 +#define MMEA0_EDC_CNT2_VG20__GMIWR_DATAMEM_DED_COUNT__SHIFT 0xa +#define MMEA0_EDC_CNT2_VG20__GMIRD_PAGEMEM_SED_COUNT__SHIFT 0xc +#define MMEA0_EDC_CNT2_VG20__GMIWR_PAGEMEM_SED_COUNT__SHIFT 0xe +#define MMEA0_EDC_CNT2_VG20__MAM_D0MEM_SED_COUNT__SHIFT 0x10 +#define MMEA0_EDC_CNT2_VG20__MAM_D1MEM_SED_COUNT__SHIFT 0x12 +#define MMEA0_EDC_CNT2_VG20__MAM_D2MEM_SED_COUNT__SHIFT 0x14 +#define MMEA0_EDC_CNT2_VG20__MAM_D3MEM_SED_COUNT__SHIFT 0x16 +#define MMEA0_EDC_CNT2_VG20__GMIRD_CMDMEM_SEC_COUNT_MASK 0x00000003L +#define MMEA0_EDC_CNT2_VG20__GMIRD_CMDMEM_DED_COUNT_MASK 0x0000000CL +#define MMEA0_EDC_CNT2_VG20__GMIWR_CMDMEM_SEC_COUNT_MASK 0x00000030L +#define MMEA0_EDC_CNT2_VG20__GMIWR_CMDMEM_DED_COUNT_MASK 0x000000C0L +#define MMEA0_EDC_CNT2_VG20__GMIWR_DATAMEM_SEC_COUNT_MASK 0x00000300L +#define MMEA0_EDC_CNT2_VG20__GMIWR_DATAMEM_DED_COUNT_MASK 0x00000C00L +#define MMEA0_EDC_CNT2_VG20__GMIRD_PAGEMEM_SED_COUNT_MASK 0x00003000L +#define MMEA0_EDC_CNT2_VG20__GMIWR_PAGEMEM_SED_COUNT_MASK 0x0000C000L +#define MMEA0_EDC_CNT2_VG20__MAM_D0MEM_SED_COUNT_MASK 0x00030000L +#define MMEA0_EDC_CNT2_VG20__MAM_D1MEM_SED_COUNT_MASK 0x000C0000L +#define MMEA0_EDC_CNT2_VG20__MAM_D2MEM_SED_COUNT_MASK 0x00300000L +#define MMEA0_EDC_CNT2_VG20__MAM_D3MEM_SED_COUNT_MASK 0x00C00000L +//MMEA1_EDC_CNT +#define MMEA1_EDC_CNT_VG20__DRAMRD_CMDMEM_SEC_COUNT__SHIFT 0x0 +#define MMEA1_EDC_CNT_VG20__DRAMRD_CMDMEM_DED_COUNT__SHIFT 0x2 +#define MMEA1_EDC_CNT_VG20__DRAMWR_CMDMEM_SEC_COUNT__SHIFT 0x4 +#define MMEA1_EDC_CNT_VG20__DRAMWR_CMDMEM_DED_COUNT__SHIFT 0x6 +#define MMEA1_EDC_CNT_VG20__DRAMWR_DATAMEM_SEC_COUNT__SHIFT 0x8 +#define MMEA1_EDC_CNT_VG20__DRAMWR_DATAMEM_DED_COUNT__SHIFT 0xa +#define MMEA1_EDC_CNT_VG20__RRET_TAGMEM_SEC_COUNT__SHIFT 0xc +#define MMEA1_EDC_CNT_VG20__RRET_TAGMEM_DED_COUNT__SHIFT 0xe +#define MMEA1_EDC_CNT_VG20__WRET_TAGMEM_SEC_COUNT__SHIFT 0x10 +#define MMEA1_EDC_CNT_VG20__WRET_TAGMEM_DED_COUNT__SHIFT 0x12 +#define MMEA1_EDC_CNT_VG20__DRAMRD_PAGEMEM_SED_COUNT__SHIFT 0x14 +#define MMEA1_EDC_CNT_VG20__DRAMWR_PAGEMEM_SED_COUNT__SHIFT 0x16 +#define MMEA1_EDC_CNT_VG20__IORD_CMDMEM_SED_COUNT__SHIFT 0x18 +#define MMEA1_EDC_CNT_VG20__IOWR_CMDMEM_SED_COUNT__SHIFT 0x1a +#define MMEA1_EDC_CNT_VG20__IOWR_DATAMEM_SED_COUNT__SHIFT 0x1c +#define MMEA1_EDC_CNT_VG20__DRAMRD_CMDMEM_SEC_COUNT_MASK 0x00000003L +#define MMEA1_EDC_CNT_VG20__DRAMRD_CMDMEM_DED_COUNT_MASK 0x0000000CL +#define MMEA1_EDC_CNT_VG20__DRAMWR_CMDMEM_SEC_COUNT_MASK 0x00000030L +#define MMEA1_EDC_CNT_VG20__DRAMWR_CMDMEM_DED_COUNT_MASK 0x000000C0L +#define MMEA1_EDC_CNT_VG20__DRAMWR_DATAMEM_SEC_COUNT_MASK 0x00000300L +#define MMEA1_EDC_CNT_VG20__DRAMWR_DATAMEM_DED_COUNT_MASK 0x00000C00L +#define MMEA1_EDC_CNT_VG20__RRET_TAGMEM_SEC_COUNT_MASK 0x00003000L +#define MMEA1_EDC_CNT_VG20__RRET_TAGMEM_DED_COUNT_MASK 0x0000C000L +#define MMEA1_EDC_CNT_VG20__WRET_TAGMEM_SEC_COUNT_MASK 0x00030000L +#define MMEA1_EDC_CNT_VG20__WRET_TAGMEM_DED_COUNT_MASK 0x000C0000L +#define MMEA1_EDC_CNT_VG20__DRAMRD_PAGEMEM_SED_COUNT_MASK 0x00300000L +#define MMEA1_EDC_CNT_VG20__DRAMWR_PAGEMEM_SED_COUNT_MASK 0x00C00000L +#define MMEA1_EDC_CNT_VG20__IORD_CMDMEM_SED_COUNT_MASK 0x03000000L +#define MMEA1_EDC_CNT_VG20__IOWR_CMDMEM_SED_COUNT_MASK 0x0C000000L +#define MMEA1_EDC_CNT_VG20__IOWR_DATAMEM_SED_COUNT_MASK 0x30000000L +//MMEA1_EDC_CNT2 +#define MMEA1_EDC_CNT2_VG20__GMIRD_CMDMEM_SEC_COUNT__SHIFT 0x0 +#define MMEA1_EDC_CNT2_VG20__GMIRD_CMDMEM_DED_COUNT__SHIFT 0x2 +#define MMEA1_EDC_CNT2_VG20__GMIWR_CMDMEM_SEC_COUNT__SHIFT 0x4 +#define MMEA1_EDC_CNT2_VG20__GMIWR_CMDMEM_DED_COUNT__SHIFT 0x6 +#define MMEA1_EDC_CNT2_VG20__GMIWR_DATAMEM_SEC_COUNT__SHIFT 0x8 +#define MMEA1_EDC_CNT2_VG20__GMIWR_DATAMEM_DED_COUNT__SHIFT 0xa +#define MMEA1_EDC_CNT2_VG20__GMIRD_PAGEMEM_SED_COUNT__SHIFT 0xc +#define MMEA1_EDC_CNT2_VG20__GMIWR_PAGEMEM_SED_COUNT__SHIFT 0xe +#define MMEA1_EDC_CNT2_VG20__MAM_D0MEM_SED_COUNT__SHIFT 0x10 +#define MMEA1_EDC_CNT2_VG20__MAM_D1MEM_SED_COUNT__SHIFT 0x12 +#define MMEA1_EDC_CNT2_VG20__MAM_D2MEM_SED_COUNT__SHIFT 0x14 +#define MMEA1_EDC_CNT2_VG20__MAM_D3MEM_SED_COUNT__SHIFT 0x16 +#define MMEA1_EDC_CNT2_VG20__GMIRD_CMDMEM_SEC_COUNT_MASK 0x00000003L +#define MMEA1_EDC_CNT2_VG20__GMIRD_CMDMEM_DED_COUNT_MASK 0x0000000CL +#define MMEA1_EDC_CNT2_VG20__GMIWR_CMDMEM_SEC_COUNT_MASK 0x00000030L +#define MMEA1_EDC_CNT2_VG20__GMIWR_CMDMEM_DED_COUNT_MASK 0x000000C0L +#define MMEA1_EDC_CNT2_VG20__GMIWR_DATAMEM_SEC_COUNT_MASK 0x00000300L +#define MMEA1_EDC_CNT2_VG20__GMIWR_DATAMEM_DED_COUNT_MASK 0x00000C00L +#define MMEA1_EDC_CNT2_VG20__GMIRD_PAGEMEM_SED_COUNT_MASK 0x00003000L +#define MMEA1_EDC_CNT2_VG20__GMIWR_PAGEMEM_SED_COUNT_MASK 0x0000C000L +#define MMEA1_EDC_CNT2_VG20__MAM_D0MEM_SED_COUNT_MASK 0x00030000L +#define MMEA1_EDC_CNT2_VG20__MAM_D1MEM_SED_COUNT_MASK 0x000C0000L +#define MMEA1_EDC_CNT2_VG20__MAM_D2MEM_SED_COUNT_MASK 0x00300000L +#define MMEA1_EDC_CNT2_VG20__MAM_D3MEM_SED_COUNT_MASK 0x00C00000L + +// addressBlock: mmhub_utcl2_vmsharedpfdec +//MC_VM_XGMI_LFB_CNTL +#define MC_VM_XGMI_LFB_CNTL__PF_LFB_REGION__SHIFT 0x0 +#define MC_VM_XGMI_LFB_CNTL__PF_MAX_REGION__SHIFT 0x4 +#define MC_VM_XGMI_LFB_CNTL__PF_LFB_REGION_MASK 0x00000007L +#define MC_VM_XGMI_LFB_CNTL__PF_MAX_REGION_MASK 0x00000070L +//MC_VM_XGMI_LFB_SIZE +#define MC_VM_XGMI_LFB_SIZE__PF_LFB_SIZE__SHIFT 0x0 +#define MC_VM_XGMI_LFB_SIZE__PF_LFB_SIZE_MASK 0x0000FFFFL #endif diff --git a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_0_offset.h deleted file mode 100644 index f2ae3a58949ed2690010c96dec0d680a3ebed850..0000000000000000000000000000000000000000 --- a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_0_offset.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2018 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 _mmhub_9_4_0_OFFSET_HEADER -#define _mmhub_9_4_0_OFFSET_HEADER - -/* MMEA */ -#define mmMMEA0_SDP_ARB_FINAL_VG20 0x01ee -#define mmMMEA0_SDP_ARB_FINAL_VG20_BASE_IDX 0 -#define mmMMEA0_EDC_CNT_VG20 0x0206 -#define mmMMEA0_EDC_CNT_VG20_BASE_IDX 0 -#define mmMMEA0_EDC_CNT2_VG20 0x0207 -#define mmMMEA0_EDC_CNT2_VG20_BASE_IDX 0 -#define mmMMEA0_EDC_MODE_VG20 0x0210 -#define mmMMEA0_EDC_MODE_VG20_BASE_IDX 0 -#define mmMMEA0_ERR_STATUS_VG20 0x0211 -#define mmMMEA0_ERR_STATUS_VG20_BASE_IDX 0 -#define mmMMEA1_SDP_ARB_FINAL_VG20 0x032e -#define mmMMEA1_SDP_ARB_FINAL_VG20_BASE_IDX 0 -#define mmMMEA1_EDC_CNT_VG20 0x0346 -#define mmMMEA1_EDC_CNT_VG20_BASE_IDX 0 -#define mmMMEA1_EDC_CNT2_VG20 0x0347 -#define mmMMEA1_EDC_CNT2_VG20_BASE_IDX 0 -#define mmMMEA1_EDC_MODE_VG20 0x0350 -#define mmMMEA1_EDC_MODE_VG20_BASE_IDX 0 -#define mmMMEA1_ERR_STATUS_VG20 0x0351 -#define mmMMEA1_ERR_STATUS_VG20_BASE_IDX 0 - -// addressBlock: mmhub_utcl2_vmsharedpfdec -// base address: 0x6a040 -#define mmMC_VM_XGMI_LFB_CNTL 0x0823 -#define mmMC_VM_XGMI_LFB_CNTL_BASE_IDX 0 -#define mmMC_VM_XGMI_LFB_SIZE 0x0824 -#define mmMC_VM_XGMI_LFB_SIZE_BASE_IDX 0 - -#endif diff --git a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_0_sh_mask.h deleted file mode 100644 index c24259ed12a1520e889342778c5aab7dd357d23c..0000000000000000000000000000000000000000 --- a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_9_4_0_sh_mask.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2018 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 _mmhub_9_4_0_SH_MASK_HEADER -#define _mmhub_9_4_0_SH_MASK_HEADER - -//MMEA0_SDP_ARB_FINAL -#define MMEA0_SDP_ARB_FINAL__DRAM_BURST_LIMIT__SHIFT 0x0 -#define MMEA0_SDP_ARB_FINAL__GMI_BURST_LIMIT__SHIFT 0x5 -#define MMEA0_SDP_ARB_FINAL__IO_BURST_LIMIT__SHIFT 0xa -#define MMEA0_SDP_ARB_FINAL__BURST_LIMIT_MULTIPLIER__SHIFT 0xf -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC0__SHIFT 0x11 -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC1__SHIFT 0x12 -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC2__SHIFT 0x13 -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC3__SHIFT 0x14 -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC4__SHIFT 0x15 -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC5__SHIFT 0x16 -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC6__SHIFT 0x17 -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC7__SHIFT 0x18 -#define MMEA0_SDP_ARB_FINAL__ERREVENT_ON_ERROR__SHIFT 0x19 -#define MMEA0_SDP_ARB_FINAL__HALTREQ_ON_ERROR__SHIFT 0x1a -#define MMEA0_SDP_ARB_FINAL__DRAM_BURST_LIMIT_MASK 0x0000001FL -#define MMEA0_SDP_ARB_FINAL__GMI_BURST_LIMIT_MASK 0x000003E0L -#define MMEA0_SDP_ARB_FINAL__IO_BURST_LIMIT_MASK 0x00007C00L -#define MMEA0_SDP_ARB_FINAL__BURST_LIMIT_MULTIPLIER_MASK 0x00018000L -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC0_MASK 0x00020000L -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC1_MASK 0x00040000L -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC2_MASK 0x00080000L -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC3_MASK 0x00100000L -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC4_MASK 0x00200000L -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC5_MASK 0x00400000L -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC6_MASK 0x00800000L -#define MMEA0_SDP_ARB_FINAL__RDONLY_VC7_MASK 0x01000000L -#define MMEA0_SDP_ARB_FINAL__ERREVENT_ON_ERROR_MASK 0x02000000L -#define MMEA0_SDP_ARB_FINAL__HALTREQ_ON_ERROR_MASK 0x04000000L -//MMEA0_EDC_CNT -#define MMEA0_EDC_CNT__DRAMRD_CMDMEM_SEC_COUNT__SHIFT 0x0 -#define MMEA0_EDC_CNT__DRAMRD_CMDMEM_DED_COUNT__SHIFT 0x2 -#define MMEA0_EDC_CNT__DRAMWR_CMDMEM_SEC_COUNT__SHIFT 0x4 -#define MMEA0_EDC_CNT__DRAMWR_CMDMEM_DED_COUNT__SHIFT 0x6 -#define MMEA0_EDC_CNT__DRAMWR_DATAMEM_SEC_COUNT__SHIFT 0x8 -#define MMEA0_EDC_CNT__DRAMWR_DATAMEM_DED_COUNT__SHIFT 0xa -#define MMEA0_EDC_CNT__RRET_TAGMEM_SEC_COUNT__SHIFT 0xc -#define MMEA0_EDC_CNT__RRET_TAGMEM_DED_COUNT__SHIFT 0xe -#define MMEA0_EDC_CNT__WRET_TAGMEM_SEC_COUNT__SHIFT 0x10 -#define MMEA0_EDC_CNT__WRET_TAGMEM_DED_COUNT__SHIFT 0x12 -#define MMEA0_EDC_CNT__DRAMRD_PAGEMEM_SED_COUNT__SHIFT 0x14 -#define MMEA0_EDC_CNT__DRAMWR_PAGEMEM_SED_COUNT__SHIFT 0x16 -#define MMEA0_EDC_CNT__IORD_CMDMEM_SED_COUNT__SHIFT 0x18 -#define MMEA0_EDC_CNT__IOWR_CMDMEM_SED_COUNT__SHIFT 0x1a -#define MMEA0_EDC_CNT__IOWR_DATAMEM_SED_COUNT__SHIFT 0x1c -#define MMEA0_EDC_CNT__DRAMRD_CMDMEM_SEC_COUNT_MASK 0x00000003L -#define MMEA0_EDC_CNT__DRAMRD_CMDMEM_DED_COUNT_MASK 0x0000000CL -#define MMEA0_EDC_CNT__DRAMWR_CMDMEM_SEC_COUNT_MASK 0x00000030L -#define MMEA0_EDC_CNT__DRAMWR_CMDMEM_DED_COUNT_MASK 0x000000C0L -#define MMEA0_EDC_CNT__DRAMWR_DATAMEM_SEC_COUNT_MASK 0x00000300L -#define MMEA0_EDC_CNT__DRAMWR_DATAMEM_DED_COUNT_MASK 0x00000C00L -#define MMEA0_EDC_CNT__RRET_TAGMEM_SEC_COUNT_MASK 0x00003000L -#define MMEA0_EDC_CNT__RRET_TAGMEM_DED_COUNT_MASK 0x0000C000L -#define MMEA0_EDC_CNT__WRET_TAGMEM_SEC_COUNT_MASK 0x00030000L -#define MMEA0_EDC_CNT__WRET_TAGMEM_DED_COUNT_MASK 0x000C0000L -#define MMEA0_EDC_CNT__DRAMRD_PAGEMEM_SED_COUNT_MASK 0x00300000L -#define MMEA0_EDC_CNT__DRAMWR_PAGEMEM_SED_COUNT_MASK 0x00C00000L -#define MMEA0_EDC_CNT__IORD_CMDMEM_SED_COUNT_MASK 0x03000000L -#define MMEA0_EDC_CNT__IOWR_CMDMEM_SED_COUNT_MASK 0x0C000000L -#define MMEA0_EDC_CNT__IOWR_DATAMEM_SED_COUNT_MASK 0x30000000L -//MMEA0_EDC_CNT2 -#define MMEA0_EDC_CNT2__GMIRD_CMDMEM_SEC_COUNT__SHIFT 0x0 -#define MMEA0_EDC_CNT2__GMIRD_CMDMEM_DED_COUNT__SHIFT 0x2 -#define MMEA0_EDC_CNT2__GMIWR_CMDMEM_SEC_COUNT__SHIFT 0x4 -#define MMEA0_EDC_CNT2__GMIWR_CMDMEM_DED_COUNT__SHIFT 0x6 -#define MMEA0_EDC_CNT2__GMIWR_DATAMEM_SEC_COUNT__SHIFT 0x8 -#define MMEA0_EDC_CNT2__GMIWR_DATAMEM_DED_COUNT__SHIFT 0xa -#define MMEA0_EDC_CNT2__GMIRD_PAGEMEM_SED_COUNT__SHIFT 0xc -#define MMEA0_EDC_CNT2__GMIWR_PAGEMEM_SED_COUNT__SHIFT 0xe -#define MMEA0_EDC_CNT2__MAM_D0MEM_SED_COUNT__SHIFT 0x10 -#define MMEA0_EDC_CNT2__MAM_D1MEM_SED_COUNT__SHIFT 0x12 -#define MMEA0_EDC_CNT2__MAM_D2MEM_SED_COUNT__SHIFT 0x14 -#define MMEA0_EDC_CNT2__MAM_D3MEM_SED_COUNT__SHIFT 0x16 -#define MMEA0_EDC_CNT2__GMIRD_CMDMEM_SEC_COUNT_MASK 0x00000003L -#define MMEA0_EDC_CNT2__GMIRD_CMDMEM_DED_COUNT_MASK 0x0000000CL -#define MMEA0_EDC_CNT2__GMIWR_CMDMEM_SEC_COUNT_MASK 0x00000030L -#define MMEA0_EDC_CNT2__GMIWR_CMDMEM_DED_COUNT_MASK 0x000000C0L -#define MMEA0_EDC_CNT2__GMIWR_DATAMEM_SEC_COUNT_MASK 0x00000300L -#define MMEA0_EDC_CNT2__GMIWR_DATAMEM_DED_COUNT_MASK 0x00000C00L -#define MMEA0_EDC_CNT2__GMIRD_PAGEMEM_SED_COUNT_MASK 0x00003000L -#define MMEA0_EDC_CNT2__GMIWR_PAGEMEM_SED_COUNT_MASK 0x0000C000L -#define MMEA0_EDC_CNT2__MAM_D0MEM_SED_COUNT_MASK 0x00030000L -#define MMEA0_EDC_CNT2__MAM_D1MEM_SED_COUNT_MASK 0x000C0000L -#define MMEA0_EDC_CNT2__MAM_D2MEM_SED_COUNT_MASK 0x00300000L -#define MMEA0_EDC_CNT2__MAM_D3MEM_SED_COUNT_MASK 0x00C00000L -//MMEA0_EDC_MODE -#define MMEA0_EDC_MODE__COUNT_FED_OUT__SHIFT 0x10 -#define MMEA0_EDC_MODE__GATE_FUE__SHIFT 0x11 -#define MMEA0_EDC_MODE__DED_MODE__SHIFT 0x14 -#define MMEA0_EDC_MODE__PROP_FED__SHIFT 0x1d -#define MMEA0_EDC_MODE__BYPASS__SHIFT 0x1f -#define MMEA0_EDC_MODE__COUNT_FED_OUT_MASK 0x00010000L -#define MMEA0_EDC_MODE__GATE_FUE_MASK 0x00020000L -#define MMEA0_EDC_MODE__DED_MODE_MASK 0x00300000L -#define MMEA0_EDC_MODE__PROP_FED_MASK 0x20000000L -#define MMEA0_EDC_MODE__BYPASS_MASK 0x80000000L -//MMEA0_ERR_STATUS -#define MMEA0_ERR_STATUS__SDP_RDRSP_STATUS__SHIFT 0x0 -#define MMEA0_ERR_STATUS__SDP_WRRSP_STATUS__SHIFT 0x4 -#define MMEA0_ERR_STATUS__SDP_RDRSP_DATASTATUS__SHIFT 0x8 -#define MMEA0_ERR_STATUS__SDP_RDRSP_DATAPARITY_ERROR__SHIFT 0xa -#define MMEA0_ERR_STATUS__CLEAR_ERROR_STATUS__SHIFT 0xb -#define MMEA0_ERR_STATUS__BUSY_ON_ERROR__SHIFT 0xc -#define MMEA0_ERR_STATUS__FUE_FLAG__SHIFT 0xd -#define MMEA0_ERR_STATUS__SDP_RDRSP_STATUS_MASK 0x0000000FL -#define MMEA0_ERR_STATUS__SDP_WRRSP_STATUS_MASK 0x000000F0L -#define MMEA0_ERR_STATUS__SDP_RDRSP_DATASTATUS_MASK 0x00000300L -#define MMEA0_ERR_STATUS__SDP_RDRSP_DATAPARITY_ERROR_MASK 0x00000400L -#define MMEA0_ERR_STATUS__CLEAR_ERROR_STATUS_MASK 0x00000800L -#define MMEA0_ERR_STATUS__BUSY_ON_ERROR_MASK 0x00001000L -#define MMEA0_ERR_STATUS__FUE_FLAG_MASK 0x00002000L -//MMEA1_SDP_ARB_FINAL -#define MMEA1_SDP_ARB_FINAL__DRAM_BURST_LIMIT__SHIFT 0x0 -#define MMEA1_SDP_ARB_FINAL__GMI_BURST_LIMIT__SHIFT 0x5 -#define MMEA1_SDP_ARB_FINAL__IO_BURST_LIMIT__SHIFT 0xa -#define MMEA1_SDP_ARB_FINAL__BURST_LIMIT_MULTIPLIER__SHIFT 0xf -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC0__SHIFT 0x11 -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC1__SHIFT 0x12 -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC2__SHIFT 0x13 -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC3__SHIFT 0x14 -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC4__SHIFT 0x15 -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC5__SHIFT 0x16 -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC6__SHIFT 0x17 -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC7__SHIFT 0x18 -#define MMEA1_SDP_ARB_FINAL__ERREVENT_ON_ERROR__SHIFT 0x19 -#define MMEA1_SDP_ARB_FINAL__HALTREQ_ON_ERROR__SHIFT 0x1a -#define MMEA1_SDP_ARB_FINAL__DRAM_BURST_LIMIT_MASK 0x0000001FL -#define MMEA1_SDP_ARB_FINAL__GMI_BURST_LIMIT_MASK 0x000003E0L -#define MMEA1_SDP_ARB_FINAL__IO_BURST_LIMIT_MASK 0x00007C00L -#define MMEA1_SDP_ARB_FINAL__BURST_LIMIT_MULTIPLIER_MASK 0x00018000L -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC0_MASK 0x00020000L -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC1_MASK 0x00040000L -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC2_MASK 0x00080000L -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC3_MASK 0x00100000L -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC4_MASK 0x00200000L -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC5_MASK 0x00400000L -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC6_MASK 0x00800000L -#define MMEA1_SDP_ARB_FINAL__RDONLY_VC7_MASK 0x01000000L -#define MMEA1_SDP_ARB_FINAL__ERREVENT_ON_ERROR_MASK 0x02000000L -#define MMEA1_SDP_ARB_FINAL__HALTREQ_ON_ERROR_MASK 0x04000000L -//MMEA1_EDC_CNT -#define MMEA1_EDC_CNT__DRAMRD_CMDMEM_SEC_COUNT__SHIFT 0x0 -#define MMEA1_EDC_CNT__DRAMRD_CMDMEM_DED_COUNT__SHIFT 0x2 -#define MMEA1_EDC_CNT__DRAMWR_CMDMEM_SEC_COUNT__SHIFT 0x4 -#define MMEA1_EDC_CNT__DRAMWR_CMDMEM_DED_COUNT__SHIFT 0x6 -#define MMEA1_EDC_CNT__DRAMWR_DATAMEM_SEC_COUNT__SHIFT 0x8 -#define MMEA1_EDC_CNT__DRAMWR_DATAMEM_DED_COUNT__SHIFT 0xa -#define MMEA1_EDC_CNT__RRET_TAGMEM_SEC_COUNT__SHIFT 0xc -#define MMEA1_EDC_CNT__RRET_TAGMEM_DED_COUNT__SHIFT 0xe -#define MMEA1_EDC_CNT__WRET_TAGMEM_SEC_COUNT__SHIFT 0x10 -#define MMEA1_EDC_CNT__WRET_TAGMEM_DED_COUNT__SHIFT 0x12 -#define MMEA1_EDC_CNT__DRAMRD_PAGEMEM_SED_COUNT__SHIFT 0x14 -#define MMEA1_EDC_CNT__DRAMWR_PAGEMEM_SED_COUNT__SHIFT 0x16 -#define MMEA1_EDC_CNT__IORD_CMDMEM_SED_COUNT__SHIFT 0x18 -#define MMEA1_EDC_CNT__IOWR_CMDMEM_SED_COUNT__SHIFT 0x1a -#define MMEA1_EDC_CNT__IOWR_DATAMEM_SED_COUNT__SHIFT 0x1c -#define MMEA1_EDC_CNT__DRAMRD_CMDMEM_SEC_COUNT_MASK 0x00000003L -#define MMEA1_EDC_CNT__DRAMRD_CMDMEM_DED_COUNT_MASK 0x0000000CL -#define MMEA1_EDC_CNT__DRAMWR_CMDMEM_SEC_COUNT_MASK 0x00000030L -#define MMEA1_EDC_CNT__DRAMWR_CMDMEM_DED_COUNT_MASK 0x000000C0L -#define MMEA1_EDC_CNT__DRAMWR_DATAMEM_SEC_COUNT_MASK 0x00000300L -#define MMEA1_EDC_CNT__DRAMWR_DATAMEM_DED_COUNT_MASK 0x00000C00L -#define MMEA1_EDC_CNT__RRET_TAGMEM_SEC_COUNT_MASK 0x00003000L -#define MMEA1_EDC_CNT__RRET_TAGMEM_DED_COUNT_MASK 0x0000C000L -#define MMEA1_EDC_CNT__WRET_TAGMEM_SEC_COUNT_MASK 0x00030000L -#define MMEA1_EDC_CNT__WRET_TAGMEM_DED_COUNT_MASK 0x000C0000L -#define MMEA1_EDC_CNT__DRAMRD_PAGEMEM_SED_COUNT_MASK 0x00300000L -#define MMEA1_EDC_CNT__DRAMWR_PAGEMEM_SED_COUNT_MASK 0x00C00000L -#define MMEA1_EDC_CNT__IORD_CMDMEM_SED_COUNT_MASK 0x03000000L -#define MMEA1_EDC_CNT__IOWR_CMDMEM_SED_COUNT_MASK 0x0C000000L -#define MMEA1_EDC_CNT__IOWR_DATAMEM_SED_COUNT_MASK 0x30000000L -//MMEA1_EDC_CNT2 -#define MMEA1_EDC_CNT2__GMIRD_CMDMEM_SEC_COUNT__SHIFT 0x0 -#define MMEA1_EDC_CNT2__GMIRD_CMDMEM_DED_COUNT__SHIFT 0x2 -#define MMEA1_EDC_CNT2__GMIWR_CMDMEM_SEC_COUNT__SHIFT 0x4 -#define MMEA1_EDC_CNT2__GMIWR_CMDMEM_DED_COUNT__SHIFT 0x6 -#define MMEA1_EDC_CNT2__GMIWR_DATAMEM_SEC_COUNT__SHIFT 0x8 -#define MMEA1_EDC_CNT2__GMIWR_DATAMEM_DED_COUNT__SHIFT 0xa -#define MMEA1_EDC_CNT2__GMIRD_PAGEMEM_SED_COUNT__SHIFT 0xc -#define MMEA1_EDC_CNT2__GMIWR_PAGEMEM_SED_COUNT__SHIFT 0xe -#define MMEA1_EDC_CNT2__MAM_D0MEM_SED_COUNT__SHIFT 0x10 -#define MMEA1_EDC_CNT2__MAM_D1MEM_SED_COUNT__SHIFT 0x12 -#define MMEA1_EDC_CNT2__MAM_D2MEM_SED_COUNT__SHIFT 0x14 -#define MMEA1_EDC_CNT2__MAM_D3MEM_SED_COUNT__SHIFT 0x16 -#define MMEA1_EDC_CNT2__GMIRD_CMDMEM_SEC_COUNT_MASK 0x00000003L -#define MMEA1_EDC_CNT2__GMIRD_CMDMEM_DED_COUNT_MASK 0x0000000CL -#define MMEA1_EDC_CNT2__GMIWR_CMDMEM_SEC_COUNT_MASK 0x00000030L -#define MMEA1_EDC_CNT2__GMIWR_CMDMEM_DED_COUNT_MASK 0x000000C0L -#define MMEA1_EDC_CNT2__GMIWR_DATAMEM_SEC_COUNT_MASK 0x00000300L -#define MMEA1_EDC_CNT2__GMIWR_DATAMEM_DED_COUNT_MASK 0x00000C00L -#define MMEA1_EDC_CNT2__GMIRD_PAGEMEM_SED_COUNT_MASK 0x00003000L -#define MMEA1_EDC_CNT2__GMIWR_PAGEMEM_SED_COUNT_MASK 0x0000C000L -#define MMEA1_EDC_CNT2__MAM_D0MEM_SED_COUNT_MASK 0x00030000L -#define MMEA1_EDC_CNT2__MAM_D1MEM_SED_COUNT_MASK 0x000C0000L -#define MMEA1_EDC_CNT2__MAM_D2MEM_SED_COUNT_MASK 0x00300000L -#define MMEA1_EDC_CNT2__MAM_D3MEM_SED_COUNT_MASK 0x00C00000L -//MMEA1_EDC_MODE -#define MMEA1_EDC_MODE__COUNT_FED_OUT__SHIFT 0x10 -#define MMEA1_EDC_MODE__GATE_FUE__SHIFT 0x11 -#define MMEA1_EDC_MODE__DED_MODE__SHIFT 0x14 -#define MMEA1_EDC_MODE__PROP_FED__SHIFT 0x1d -#define MMEA1_EDC_MODE__BYPASS__SHIFT 0x1f -#define MMEA1_EDC_MODE__COUNT_FED_OUT_MASK 0x00010000L -#define MMEA1_EDC_MODE__GATE_FUE_MASK 0x00020000L -#define MMEA1_EDC_MODE__DED_MODE_MASK 0x00300000L -#define MMEA1_EDC_MODE__PROP_FED_MASK 0x20000000L -#define MMEA1_EDC_MODE__BYPASS_MASK 0x80000000L -//MMEA1_ERR_STATUS -#define MMEA1_ERR_STATUS__SDP_RDRSP_STATUS__SHIFT 0x0 -#define MMEA1_ERR_STATUS__SDP_WRRSP_STATUS__SHIFT 0x4 -#define MMEA1_ERR_STATUS__SDP_RDRSP_DATASTATUS__SHIFT 0x8 -#define MMEA1_ERR_STATUS__SDP_RDRSP_DATAPARITY_ERROR__SHIFT 0xa -#define MMEA1_ERR_STATUS__CLEAR_ERROR_STATUS__SHIFT 0xb -#define MMEA1_ERR_STATUS__BUSY_ON_ERROR__SHIFT 0xc -#define MMEA1_ERR_STATUS__FUE_FLAG__SHIFT 0xd -#define MMEA1_ERR_STATUS__SDP_RDRSP_STATUS_MASK 0x0000000FL -#define MMEA1_ERR_STATUS__SDP_WRRSP_STATUS_MASK 0x000000F0L -#define MMEA1_ERR_STATUS__SDP_RDRSP_DATASTATUS_MASK 0x00000300L -#define MMEA1_ERR_STATUS__SDP_RDRSP_DATAPARITY_ERROR_MASK 0x00000400L -#define MMEA1_ERR_STATUS__CLEAR_ERROR_STATUS_MASK 0x00000800L -#define MMEA1_ERR_STATUS__BUSY_ON_ERROR_MASK 0x00001000L -#define MMEA1_ERR_STATUS__FUE_FLAG_MASK 0x00002000L - -// addressBlock: mmhub_utcl2_vmsharedpfdec -//MC_VM_XGMI_LFB_CNTL -#define MC_VM_XGMI_LFB_CNTL__PF_LFB_REGION__SHIFT 0x0 -#define MC_VM_XGMI_LFB_CNTL__PF_MAX_REGION__SHIFT 0x4 -#define MC_VM_XGMI_LFB_CNTL__PF_LFB_REGION_MASK 0x00000007L -#define MC_VM_XGMI_LFB_CNTL__PF_MAX_REGION_MASK 0x00000070L -//MC_VM_XGMI_LFB_SIZE -#define MC_VM_XGMI_LFB_SIZE__PF_LFB_SIZE__SHIFT 0x0 -#define MC_VM_XGMI_LFB_SIZE__PF_LFB_SIZE_MASK 0x0000FFFFL - -#endif diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index 7932eb163a00c88450532e93b288a1d05120e801..5087d6bdba6095b0bbb7e23d7c979eabb9d9167b 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -48,7 +48,6 @@ static int amd_powerplay_create(struct amdgpu_device *adev) hwmgr->adev = adev; hwmgr->not_vf = !amdgpu_sriov_vf(adev); - hwmgr->pm_en = (amdgpu_dpm && hwmgr->not_vf) ? true : false; hwmgr->device = amdgpu_cgs_create_device(adev); mutex_init(&hwmgr->smu_lock); hwmgr->chip_family = adev->family; @@ -276,6 +275,9 @@ static int pp_dpm_load_fw(void *handle) { struct pp_hwmgr *hwmgr = handle; + if (!hwmgr->not_vf) + return 0; + if (!hwmgr || !hwmgr->smumgr_funcs || !hwmgr->smumgr_funcs->start_smu) return -EINVAL; diff --git a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c index 5ff7ccedfbed45212865c75bad0289f42688d8e9..6dddd7818558282796f7489d15cac0c3cd8ae93a 100644 --- a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c @@ -415,6 +415,9 @@ int smu_dpm_set_power_gate(struct smu_context *smu, uint32_t block_type, case AMD_IP_BLOCK_TYPE_SDMA: ret = smu_powergate_sdma(smu, gate); break; + case AMD_IP_BLOCK_TYPE_JPEG: + ret = smu_dpm_set_jpeg_enable(smu, gate); + break; default: break; } @@ -527,9 +530,12 @@ bool is_support_sw_smu(struct amdgpu_device *adev) { if (adev->asic_type == CHIP_VEGA20) return (amdgpu_dpm == 2) ? true : false; - else if (adev->asic_type >= CHIP_ARCTURUS) - return true; - else + else if (adev->asic_type >= CHIP_ARCTURUS) { + if (amdgpu_sriov_vf(adev)) + return false; + else + return true; + } else return false; } @@ -1186,10 +1192,9 @@ static int smu_free_memory_pool(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *memory_pool = &smu_table->memory_pool; - int ret = 0; if (memory_pool->size == SMU_MEMORY_POOL_SIZE_ZERO) - return ret; + return 0; amdgpu_bo_free_kernel(&memory_pool->bo, &memory_pool->mc_address, @@ -1197,7 +1202,7 @@ static int smu_free_memory_pool(struct smu_context *smu) memset(memory_pool, 0, sizeof(struct smu_table)); - return ret; + return 0; } static int smu_start_smc_engine(struct smu_context *smu) @@ -1239,6 +1244,7 @@ static int smu_hw_init(void *handle) if (adev->flags & AMD_IS_APU) { smu_powergate_sdma(&adev->smu, false); smu_powergate_vcn(&adev->smu, false); + smu_powergate_jpeg(&adev->smu, false); smu_set_gfx_cgpg(&adev->smu, true); } @@ -1297,6 +1303,7 @@ static int smu_hw_fini(void *handle) if (adev->flags & AMD_IS_APU) { smu_powergate_sdma(&adev->smu, true); smu_powergate_vcn(&adev->smu, true); + smu_powergate_jpeg(&adev->smu, true); } ret = smu_stop_thermal_control(smu); @@ -1376,7 +1383,7 @@ static int smu_suspend(void *handle) if (ret) return ret; - if (adev->in_gpu_reset && baco_feature_is_enabled) { + if (baco_feature_is_enabled) { ret = smu_feature_set_enabled(smu, SMU_FEATURE_BACO_BIT, true); if (ret) { pr_warn("set BACO feature enabled failed, return %d\n", ret); @@ -1937,7 +1944,6 @@ int smu_write_watermarks_table(struct smu_context *smu) int smu_set_watermarks_for_clock_ranges(struct smu_context *smu, struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges) { - int ret = 0; struct smu_table *watermarks = &smu->smu_table.tables[SMU_TABLE_WATERMARKS]; void *table = watermarks->cpu_addr; @@ -1953,7 +1959,7 @@ int smu_set_watermarks_for_clock_ranges(struct smu_context *smu, mutex_unlock(&smu->mutex); - return ret; + return 0; } const struct amd_ip_funcs smu_ip_funcs = { @@ -2451,14 +2457,28 @@ int smu_baco_get_state(struct smu_context *smu, enum smu_baco_state *state) return 0; } -int smu_baco_reset(struct smu_context *smu) +int smu_baco_enter(struct smu_context *smu) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->baco_enter) + ret = smu->ppt_funcs->baco_enter(smu); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_baco_exit(struct smu_context *smu) { int ret = 0; mutex_lock(&smu->mutex); - if (smu->ppt_funcs->baco_reset) - ret = smu->ppt_funcs->baco_reset(smu); + if (smu->ppt_funcs->baco_exit) + ret = smu->ppt_funcs->baco_exit(smu); mutex_unlock(&smu->mutex); diff --git a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c b/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c index ce3566ca3e24bc9c01ea1f382fa7b80b7692d974..17eeb546c550bd38a94999dc78661232792d2499 100644 --- a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c @@ -280,10 +280,8 @@ static int arcturus_get_workload_type(struct smu_context *smu, enum PP_SMC_POWER return -EINVAL; mapping = arcturus_workload_map[profile]; - if (!(mapping.valid_mapping)) { - pr_warn("Unsupported SMU power source: %d\n", profile); + if (!(mapping.valid_mapping)) return -EINVAL; - } return mapping.map_to; } @@ -495,6 +493,7 @@ static int arcturus_store_powerplay_table(struct smu_context *smu) { struct smu_11_0_powerplay_table *powerplay_table = NULL; struct smu_table_context *table_context = &smu->smu_table; + struct smu_baco_context *smu_baco = &smu->smu_baco; int ret = 0; if (!table_context->power_play_table) @@ -507,6 +506,12 @@ static int arcturus_store_powerplay_table(struct smu_context *smu) table_context->thermal_controller_type = powerplay_table->thermal_controller_type; + mutex_lock(&smu_baco->mutex); + if (powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_BACO || + powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_MACO) + smu_baco->platform_support = true; + mutex_unlock(&smu_baco->mutex); + return ret; } @@ -1313,12 +1318,17 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu, "VR", "COMPUTE", "CUSTOM"}; + static const char *title[] = { + "PROFILE_INDEX(NAME)"}; uint32_t i, size = 0; int16_t workload_type = 0; if (!smu->pm_enabled || !buf) return -EINVAL; + size += sprintf(buf + size, "%16s\n", + title[0]); + for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) { /* * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT @@ -2155,7 +2165,8 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .baco_is_support= smu_v11_0_baco_is_support, .baco_get_state = smu_v11_0_baco_get_state, .baco_set_state = smu_v11_0_baco_set_state, - .baco_reset = smu_v11_0_baco_reset, + .baco_enter = smu_v11_0_baco_enter, + .baco_exit = smu_v11_0_baco_exit, .get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq, .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range, .override_pcie_parameters = smu_v11_0_override_pcie_parameters, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c index cc57fb953e627afb2c5827b95508865e4eecafa1..253860d30b20bd9a1973aa1a8f8628adc4edeceb 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c @@ -81,8 +81,8 @@ int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr) adev = hwmgr->adev; /* Skip for suspend/resume case */ - if (smum_is_dpm_running(hwmgr) && !amdgpu_passthrough(adev) - && adev->in_suspend) { + if (!hwmgr->pp_one_vf && smum_is_dpm_running(hwmgr) + && !amdgpu_passthrough(adev) && adev->in_suspend) { pr_info("dpm has been enabled\n"); return 0; } @@ -200,6 +200,9 @@ int phm_stop_thermal_controller(struct pp_hwmgr *hwmgr) { PHM_FUNC_CHECK(hwmgr); + if (!hwmgr->not_vf) + return 0; + if (hwmgr->hwmgr_func->stop_thermal_controller == NULL) return -EINVAL; @@ -237,6 +240,9 @@ int phm_start_thermal_controller(struct pp_hwmgr *hwmgr) TEMP_RANGE_MAX}; struct amdgpu_device *adev = hwmgr->adev; + if (!hwmgr->not_vf) + return 0; + if (hwmgr->hwmgr_func->get_thermal_temperature_range) hwmgr->hwmgr_func->get_thermal_temperature_range( hwmgr, &range); @@ -263,6 +269,8 @@ 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->pp_one_vf) + return false; if (hwmgr->hwmgr_func->check_smc_update_required_for_display_configuration == NULL) return false; @@ -482,6 +490,9 @@ int phm_disable_smc_firmware_ctf(struct pp_hwmgr *hwmgr) { PHM_FUNC_CHECK(hwmgr); + if (!hwmgr->not_vf) + return 0; + if (hwmgr->hwmgr_func->disable_smc_firmware_ctf == NULL) return -EINVAL; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index d2909c91d65bf018766f774da2aaa793488da233..e2b82c9029489af5f9950258c182965d30422e72 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c @@ -221,6 +221,9 @@ int hwmgr_hw_init(struct pp_hwmgr *hwmgr) { int ret = 0; + hwmgr->pp_one_vf = amdgpu_sriov_is_pp_one_vf((struct amdgpu_device *)hwmgr->adev); + hwmgr->pm_en = (amdgpu_dpm && (hwmgr->not_vf || hwmgr->pp_one_vf)) + ? true : false; if (!hwmgr->pm_en) return 0; @@ -279,6 +282,9 @@ err: int hwmgr_hw_fini(struct pp_hwmgr *hwmgr) { + if (!hwmgr->not_vf) + return 0; + if (!hwmgr || !hwmgr->pm_en) return 0; @@ -299,6 +305,9 @@ int hwmgr_suspend(struct pp_hwmgr *hwmgr) { int ret = 0; + if (!hwmgr->not_vf) + return 0; + if (!hwmgr || !hwmgr->pm_en) return 0; @@ -318,6 +327,9 @@ int hwmgr_resume(struct pp_hwmgr *hwmgr) { int ret = 0; + if (!hwmgr->not_vf) + return 0; + if (!hwmgr) return -EINVAL; @@ -365,6 +377,8 @@ int hwmgr_handle_task(struct pp_hwmgr *hwmgr, enum amd_pp_task task_id, switch (task_id) { case AMD_PP_TASK_DISPLAY_CONFIG_CHANGE: + if (!hwmgr->not_vf) + return ret; ret = phm_pre_display_configuration_changed(hwmgr); if (ret) return ret; @@ -381,6 +395,8 @@ int hwmgr_handle_task(struct pp_hwmgr *hwmgr, enum amd_pp_task task_id, enum PP_StateUILabel requested_ui_label; struct pp_power_state *requested_ps = NULL; + if (!hwmgr->not_vf) + return ret; if (user_state == NULL) { ret = -EINVAL; break; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c index 6bf48934fdc4d465b9c28cb99a39c0111d025ea7..31a32a79cfc20f7dfd8d1fb1ead3f7e626007d83 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c @@ -262,20 +262,22 @@ int psm_adjust_power_state_dynamic(struct pp_hwmgr *hwmgr, bool skip_display_set uint32_t index; long workload; - if (!skip_display_settings) - phm_display_configuration_changed(hwmgr); - - if (hwmgr->ps) - power_state_management(hwmgr, new_ps); - else - /* - * for vega12/vega20 which does not support power state manager - * DAL clock limits should also be honoured - */ - phm_apply_clock_adjust_rules(hwmgr); - - if (!skip_display_settings) - phm_notify_smc_display_config_after_ps_adjustment(hwmgr); + if (hwmgr->not_vf) { + if (!skip_display_settings) + phm_display_configuration_changed(hwmgr); + + if (hwmgr->ps) + power_state_management(hwmgr, new_ps); + else + /* + * for vega12/vega20 which does not support power state manager + * DAL clock limits should also be honoured + */ + phm_apply_clock_adjust_rules(hwmgr); + + if (!skip_display_settings) + phm_notify_smc_display_config_after_ps_adjustment(hwmgr); + } if (!phm_force_dpm_levels(hwmgr, hwmgr->request_dpm_level)) hwmgr->dpm_level = hwmgr->request_dpm_level; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c index 1115761982a78fe2f60efee236fa047d1a10811a..4e8ab139bb3bd2cdcc234c10214d74ffaeba1914 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c @@ -1151,12 +1151,11 @@ static int smu10_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, struct smu10_hwmgr *data = hwmgr->backend; struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges; Watermarks_t *table = &(data->water_marks_table); - int result = 0; smu_set_watermarks_for_clocks_ranges(table,wm_with_clock_ranges); smum_smc_table_manager(hwmgr, (uint8_t *)table, (uint16_t)SMU10_WMTABLE, false); data->water_marks_exist = true; - return result; + return 0; } static int smu10_smus_notify_pwe(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index f73dff68e7999b26871acd8b4fbc3ac77a579cd3..d70abada66bf0fadacd0e2d46b85742ffa750896 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -4238,7 +4238,6 @@ static int smu7_check_mc_firmware(struct pp_hwmgr *hwmgr) { struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - uint32_t vbios_version; uint32_t tmp; /* Read MC indirect register offset 0x9F bits [3:0] to see @@ -4247,7 +4246,6 @@ static int smu7_check_mc_firmware(struct pp_hwmgr *hwmgr) */ smu7_get_mc_microcode_version(hwmgr); - vbios_version = hwmgr->microcode_version_info.MC & 0xf; data->need_long_memory_training = false; @@ -4945,7 +4943,7 @@ static int smu7_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf) title[0], title[1], title[2], title[3], title[4], title[5], title[6], title[7]); - len = sizeof(smu7_profiling) / sizeof(struct profile_mode_setting); + len = ARRAY_SIZE(smu7_profiling); for (i = 0; i < len; i++) { if (i == hwmgr->power_profile_mode) { @@ -5077,13 +5075,11 @@ static int smu7_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw PHM_PerformanceLevel *level) { const struct smu7_power_state *ps; - struct smu7_hwmgr *data; uint32_t i; if (level == NULL || hwmgr == NULL || state == NULL) return -EINVAL; - data = hwmgr->backend; ps = cast_const_phw_smu7_power_state(state); i = index > ps->performance_level_count - 1 ? @@ -5189,13 +5185,11 @@ uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock, int smu7_init_function_pointers(struct pp_hwmgr *hwmgr) { - int ret = 0; - hwmgr->hwmgr_func = &smu7_hwmgr_funcs; if (hwmgr->pp_table_version == PP_TABLE_V0) hwmgr->pptable_func = &pptable_funcs; else if (hwmgr->pp_table_version == PP_TABLE_V1) hwmgr->pptable_func = &pptable_v1_0_funcs; - return ret; + return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index d71a492c87a325f975121fc656c05d3598c7f42e..148446570e21362d5f666551f582618e922f54b7 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -912,6 +912,9 @@ static int vega10_hwmgr_backend_init(struct pp_hwmgr *hwmgr) hwmgr->platform_descriptor.clockStep.memoryClock = 500; data->total_active_cus = adev->gfx.cu_info.number; + if (!hwmgr->not_vf) + return result; + /* Setup default Overdrive Fan control settings */ data->odn_fan_table.target_fan_speed = hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM; @@ -979,6 +982,9 @@ static int vega10_setup_dpm_led_config(struct pp_hwmgr *hwmgr) static int vega10_setup_asic_task(struct pp_hwmgr *hwmgr) { + if (!hwmgr->not_vf) + return 0; + PP_ASSERT_WITH_CODE(!vega10_init_sclk_threshold(hwmgr), "Failed to init sclk threshold!", return -EINVAL); @@ -2503,6 +2509,9 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr) "Failed to setup default DPM tables!", return result); + if (!hwmgr->not_vf) + return 0; + /* initialize ODN table */ if (hwmgr->od_enabled) { if (odn_table->max_vddc) { @@ -2826,6 +2835,8 @@ static int vega10_stop_dpm(struct pp_hwmgr *hwmgr, uint32_t bitmap) struct vega10_hwmgr *data = hwmgr->backend; uint32_t i, feature_mask = 0; + if (!hwmgr->not_vf) + return 0; if(data->smu_features[GNLD_LED_DISPLAY].supported == true){ PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr, @@ -2932,61 +2943,73 @@ static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) struct vega10_hwmgr *data = hwmgr->backend; int tmp_result, result = 0; - vega10_enable_disable_PCC_limit_feature(hwmgr, true); - - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_ConfigureTelemetry, data->config_telemetry); + if (hwmgr->not_vf) { + vega10_enable_disable_PCC_limit_feature(hwmgr, true); - tmp_result = vega10_construct_voltage_tables(hwmgr); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to construct voltage tables!", - result = tmp_result); + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_ConfigureTelemetry, data->config_telemetry); - tmp_result = vega10_init_smc_table(hwmgr); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to initialize SMC table!", - result = tmp_result); + tmp_result = vega10_construct_voltage_tables(hwmgr); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to construct voltage tables!", + result = tmp_result); + } - if (PP_CAP(PHM_PlatformCaps_ThermalController)) { - tmp_result = vega10_enable_thermal_protection(hwmgr); + if (hwmgr->not_vf || hwmgr->pp_one_vf) { + tmp_result = vega10_init_smc_table(hwmgr); PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to enable thermal protection!", - result = tmp_result); + "Failed to initialize SMC table!", + result = tmp_result); } - tmp_result = vega10_enable_vrhot_feature(hwmgr); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to enable VR hot feature!", - result = tmp_result); + if (hwmgr->not_vf) { + if (PP_CAP(PHM_PlatformCaps_ThermalController)) { + tmp_result = vega10_enable_thermal_protection(hwmgr); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to enable thermal protection!", + result = tmp_result); + } - tmp_result = vega10_enable_deep_sleep_master_switch(hwmgr); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to enable deep sleep master switch!", - result = tmp_result); + tmp_result = vega10_enable_vrhot_feature(hwmgr); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to enable VR hot feature!", + result = tmp_result); - tmp_result = vega10_start_dpm(hwmgr, SMC_DPM_FEATURES); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to start DPM!", result = tmp_result); + tmp_result = vega10_enable_deep_sleep_master_switch(hwmgr); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to enable deep sleep master switch!", + result = tmp_result); + } - /* enable didt, do not abort if failed didt */ - tmp_result = vega10_enable_didt_config(hwmgr); - PP_ASSERT(!tmp_result, - "Failed to enable didt config!"); + if (hwmgr->not_vf) { + tmp_result = vega10_start_dpm(hwmgr, SMC_DPM_FEATURES); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to start DPM!", result = tmp_result); + } + + if (hwmgr->not_vf) { + /* enable didt, do not abort if failed didt */ + tmp_result = vega10_enable_didt_config(hwmgr); + PP_ASSERT(!tmp_result, + "Failed to enable didt config!"); + } tmp_result = vega10_enable_power_containment(hwmgr); PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to enable power containment!", - result = tmp_result); + "Failed to enable power containment!", + result = tmp_result); - tmp_result = vega10_power_control_set_level(hwmgr); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to power control set level!", - result = tmp_result); + if (hwmgr->not_vf) { + tmp_result = vega10_power_control_set_level(hwmgr); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to power control set level!", + result = tmp_result); - tmp_result = vega10_enable_ulv(hwmgr); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to enable ULV!", - result = tmp_result); + tmp_result = vega10_enable_ulv(hwmgr); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to enable ULV!", + result = tmp_result); + } return result; } @@ -3080,11 +3103,22 @@ static int vega10_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr, performance_level->soc_clock = socclk_dep_table->entries [state_entry->ucSocClockIndexHigh].ulClk; if (gfxclk_dep_table->ucRevId == 0) { - performance_level->gfx_clock = gfxclk_dep_table->entries - [state_entry->ucGfxClockIndexHigh].ulClk; + /* under vega10 pp one vf mode, the gfx clk dpm need be lower + * to level-4 due to the limited 110w-power + */ + if (hwmgr->pp_one_vf && (state_entry->ucGfxClockIndexHigh > 0)) + performance_level->gfx_clock = + gfxclk_dep_table->entries[4].ulClk; + else + performance_level->gfx_clock = gfxclk_dep_table->entries + [state_entry->ucGfxClockIndexHigh].ulClk; } else if (gfxclk_dep_table->ucRevId == 1) { patom_record_V2 = (ATOM_Vega10_GFXCLK_Dependency_Record_V2 *)gfxclk_dep_table->entries; - performance_level->gfx_clock = patom_record_V2[state_entry->ucGfxClockIndexHigh].ulClk; + if (hwmgr->pp_one_vf && (state_entry->ucGfxClockIndexHigh > 0)) + performance_level->gfx_clock = patom_record_V2[4].ulClk; + else + performance_level->gfx_clock = + patom_record_V2[state_entry->ucGfxClockIndexHigh].ulClk; } performance_level->mem_clock = mclk_dep_table->entries @@ -3495,6 +3529,7 @@ static int vega10_upload_dpm_bootup_level(struct pp_hwmgr *hwmgr) smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMinGfxclkByIndex, data->smc_state_table.gfx_boot_level); + data->dpm_table.gfx_table.dpm_state.soft_min_level = data->smc_state_table.gfx_boot_level; } @@ -3518,6 +3553,9 @@ static int vega10_upload_dpm_bootup_level(struct pp_hwmgr *hwmgr) } } + if (!hwmgr->not_vf) + return 0; + if (!data->registry_data.socclk_dpm_key_disabled) { if (data->smc_state_table.soc_boot_level != data->dpm_table.soc_table.dpm_state.soft_min_level) { @@ -3560,6 +3598,9 @@ static int vega10_upload_dpm_max_level(struct pp_hwmgr *hwmgr) } } + if (!hwmgr->not_vf) + return 0; + if (!data->registry_data.socclk_dpm_key_disabled) { if (data->smc_state_table.soc_max_level != data->dpm_table.soc_table.dpm_state.soft_max_level) { @@ -4054,15 +4095,25 @@ static int vega10_get_profiling_clk_mask(struct pp_hwmgr *hwmgr, enum amd_dpm_fo } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { *mclk_mask = 0; } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { - *sclk_mask = table_info->vdd_dep_on_sclk->count - 1; + /* under vega10 pp one vf mode, the gfx clk dpm need be lower + * to level-4 due to the limited power + */ + if (hwmgr->pp_one_vf) + *sclk_mask = 4; + else + *sclk_mask = table_info->vdd_dep_on_sclk->count - 1; *soc_mask = table_info->vdd_dep_on_socclk->count - 1; *mclk_mask = table_info->vdd_dep_on_mclk->count - 1; } + return 0; } static void vega10_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode) { + if (!hwmgr->not_vf) + return; + switch (mode) { case AMD_FAN_CTRL_NONE: vega10_fan_ctrl_set_fan_speed_percent(hwmgr, 100); @@ -4176,6 +4227,9 @@ static int vega10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, break; } + if (!hwmgr->not_vf) + return ret; + if (!ret) { if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK && hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) vega10_set_fan_control_mode(hwmgr, AMD_FAN_CTRL_NONE); @@ -4360,14 +4414,13 @@ static int vega10_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, struct vega10_hwmgr *data = hwmgr->backend; struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_range; Watermarks_t *table = &(data->smc_state_table.water_marks_table); - int result = 0; if (!data->registry_data.disable_water_mark) { smu_set_watermarks_for_clocks_ranges(table, wm_with_clock_ranges); data->water_marks_bitmap = WaterMarksExist; } - return result; + return 0; } static int vega10_get_ppfeature_status(struct pp_hwmgr *hwmgr, char *buf) @@ -4480,7 +4533,7 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr, struct vega10_pcie_table *pcie_table = &(data->dpm_table.pcie_table); struct vega10_odn_clock_voltage_dependency_table *podn_vdd_dep = NULL; - int i, now, size = 0; + int i, now, size = 0, count = 0; switch (type) { case PP_SCLK: @@ -4490,7 +4543,12 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr, smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentGfxclkIndex); now = smum_get_argument(hwmgr); - for (i = 0; i < sclk_table->count; i++) + if (hwmgr->pp_one_vf && + (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)) + count = 5; + else + count = sclk_table->count; + for (i = 0; i < count; i++) size += sprintf(buf + size, "%d: %uMhz %s\n", i, sclk_table->dpm_levels[i].value / 100, (i == now) ? "*" : ""); @@ -4701,6 +4759,9 @@ static int vega10_disable_dpm_tasks(struct pp_hwmgr *hwmgr) { int tmp_result, result = 0; + if (!hwmgr->not_vf) + return 0; + if (PP_CAP(PHM_PlatformCaps_ThermalController)) vega10_disable_thermal_protection(hwmgr); @@ -5252,13 +5313,11 @@ static int vega10_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_ PHM_PerformanceLevel *level) { const struct vega10_power_state *ps; - struct vega10_hwmgr *data; uint32_t i; if (level == NULL || hwmgr == NULL || state == NULL) return -EINVAL; - data = hwmgr->backend; ps = cast_const_phw_vega10_power_state(state); i = index > ps->performance_level_count - 1 ? diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c index 6f26cb241ecce5ddbef2c37b248ce3b3b0c59435..0a677d4bc87b9a4621cef0edae6785929e03e63d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c @@ -1343,6 +1343,9 @@ int vega10_enable_power_containment(struct pp_hwmgr *hwmgr) hwmgr->default_power_limit = hwmgr->power_limit = (uint32_t)(tdp_table->usMaximumPowerDeliveryLimit); + if (!hwmgr->not_vf) + return 0; + if (PP_CAP(PHM_PlatformCaps_PowerContainment)) { if (data->smu_features[GNLD_PPT].supported) PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 7af9ad450ac4540d6ec7d4907e1306ebf456fd6b..aca61d1ff3c2a692b8d7bc7bed17b80e35154cf5 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -499,8 +499,6 @@ static int vega12_get_number_of_dpm_level(struct pp_hwmgr *hwmgr, static int vega12_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr, PPCLK_e clkID, uint32_t index, uint32_t *clock) { - int result = 0; - /* *SMU expects the Clock ID to be in the top 16 bits. *Lower 16 bits specify the level @@ -512,7 +510,7 @@ static int vega12_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr, *clock = smum_get_argument(hwmgr); - return result; + return 0; } static int vega12_setup_single_dpm_table(struct pp_hwmgr *hwmgr, diff --git a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h index ac9758305ab3be1063025e67b126e87f81aeab79..ca3fdc6777cf00cbf8e5611b6b44bdbdb923adac 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h @@ -282,6 +282,7 @@ struct smu_power_gate { bool uvd_gated; bool vce_gated; bool vcn_gated; + bool jpeg_gated; }; struct smu_power_context { @@ -436,6 +437,7 @@ struct pptable_funcs { int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size); int (*dpm_set_uvd_enable)(struct smu_context *smu, bool enable); int (*dpm_set_vce_enable)(struct smu_context *smu, bool enable); + int (*dpm_set_jpeg_enable)(struct smu_context *smu, bool enable); int (*read_sensor)(struct smu_context *smu, enum amd_pp_sensors sensor, void *data, uint32_t *size); int (*pre_display_config_changed)(struct smu_context *smu); @@ -490,6 +492,7 @@ struct pptable_funcs { int (*check_fw_version)(struct smu_context *smu); int (*powergate_sdma)(struct smu_context *smu, bool gate); int (*powergate_vcn)(struct smu_context *smu, bool gate); + int (*powergate_jpeg)(struct smu_context *smu, bool gate); int (*set_gfx_cgpg)(struct smu_context *smu, bool enable); int (*write_pptable)(struct smu_context *smu); int (*set_min_dcef_deep_sleep)(struct smu_context *smu); @@ -543,7 +546,8 @@ struct pptable_funcs { bool (*baco_is_support)(struct smu_context *smu); enum smu_baco_state (*baco_get_state)(struct smu_context *smu); int (*baco_set_state)(struct smu_context *smu, enum smu_baco_state state); - int (*baco_reset)(struct smu_context *smu); + int (*baco_enter)(struct smu_context *smu); + int (*baco_exit)(struct smu_context *smu); int (*mode2_reset)(struct smu_context *smu); int (*get_dpm_ultimate_freq)(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *min, uint32_t *max); int (*set_soft_freq_limited_range)(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t min, uint32_t max); @@ -625,7 +629,8 @@ bool smu_baco_is_support(struct smu_context *smu); int smu_baco_get_state(struct smu_context *smu, enum smu_baco_state *state); -int smu_baco_reset(struct smu_context *smu); +int smu_baco_enter(struct smu_context *smu); +int smu_baco_exit(struct smu_context *smu); int smu_mode2_reset(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index af977675fd3356fc1b25039f9f24335a3545abe1..2ffb666b97e6d609f99a0029d23f4dc9c0aa0ff7 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -741,6 +741,7 @@ struct pp_hwmgr { uint32_t smu_version; bool not_vf; bool pm_en; + bool pp_one_vf; struct mutex smu_lock; uint32_t pp_table_version; diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h b/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h index 719844257713e1dacf795ba601330b1b2d8b36f4..786de774199043c0a1f34f003dc72adb5e2f9269 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h @@ -247,7 +247,8 @@ enum smu_baco_state smu_v11_0_baco_get_state(struct smu_context *smu); int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state); -int smu_v11_0_baco_reset(struct smu_context *smu); +int smu_v11_0_baco_enter(struct smu_context *smu); +int smu_v11_0_baco_exit(struct smu_context *smu); int smu_v11_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *min, uint32_t *max); diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0.h b/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0.h index 9d81d789c713c28598aad0f61629f077935087b8..3f1cd06e273c338ad4f501a2368bb12d895a9fd9 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0.h @@ -57,8 +57,14 @@ int smu_v12_0_powergate_sdma(struct smu_context *smu, bool gate); int smu_v12_0_powergate_vcn(struct smu_context *smu, bool gate); +int smu_v12_0_powergate_jpeg(struct smu_context *smu, bool gate); + int smu_v12_0_set_gfx_cgpg(struct smu_context *smu, bool enable); +int smu_v12_0_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, + void *data, uint32_t *size); + uint32_t smu_v12_0_get_gfxoff_status(struct smu_context *smu); int smu_v12_0_gfx_off_control(struct smu_context *smu, bool enable); @@ -69,6 +75,13 @@ int smu_v12_0_fini_smc_tables(struct smu_context *smu); int smu_v12_0_populate_smc_tables(struct smu_context *smu); +int smu_v12_0_get_enabled_mask(struct smu_context *smu, + uint32_t *feature_mask, uint32_t num); + +int smu_v12_0_get_current_clk_freq(struct smu_context *smu, + enum smu_clk_type clk_id, + uint32_t *value); + int smu_v12_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *min, uint32_t *max); diff --git a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c index 4a14fd1f9fd59ad7db9cd4727c91ef44ccffd297..15403b7979d6d4d32d43f94a09e0cb4ae6e8b2b5 100644 --- a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c +++ b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c @@ -384,8 +384,10 @@ navi10_get_allowed_feature_mask(struct smu_context *smu, *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ATHUB_PG_BIT); if (smu->adev->pg_flags & AMD_PG_SUPPORT_VCN) - *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VCN_PG_BIT) - | FEATURE_MASK(FEATURE_JPEG_PG_BIT); + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VCN_PG_BIT); + + if (smu->adev->pg_flags & AMD_PG_SUPPORT_JPEG) + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_JPEG_PG_BIT); /* disable DPM UCLK and DS SOCCLK on navi10 A0 secure board */ if (is_asic_secure(smu)) { @@ -665,6 +667,31 @@ static int navi10_dpm_set_uvd_enable(struct smu_context *smu, bool enable) return ret; } +static int navi10_dpm_set_jpeg_enable(struct smu_context *smu, bool enable) +{ + struct smu_power_context *smu_power = &smu->smu_power; + struct smu_power_gate *power_gate = &smu_power->power_gate; + int ret = 0; + + if (enable) { + if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { + ret = smu_send_smc_msg(smu, SMU_MSG_PowerUpJpeg); + if (ret) + return ret; + } + power_gate->jpeg_gated = false; + } else { + if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { + ret = smu_send_smc_msg(smu, SMU_MSG_PowerDownJpeg); + if (ret) + return ret; + } + power_gate->jpeg_gated = true; + } + + return ret; +} + static int navi10_get_current_clk_freq_by_table(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *value) @@ -2012,6 +2039,7 @@ static const struct pptable_funcs navi10_ppt_funcs = { .get_allowed_feature_mask = navi10_get_allowed_feature_mask, .set_default_dpm_table = navi10_set_default_dpm_table, .dpm_set_uvd_enable = navi10_dpm_set_uvd_enable, + .dpm_set_jpeg_enable = navi10_dpm_set_jpeg_enable, .get_current_clk_freq_by_table = navi10_get_current_clk_freq_by_table, .print_clk_levels = navi10_print_clk_levels, .force_clk_levels = navi10_force_clk_levels, @@ -2080,7 +2108,8 @@ static const struct pptable_funcs navi10_ppt_funcs = { .baco_is_support= smu_v11_0_baco_is_support, .baco_get_state = smu_v11_0_baco_get_state, .baco_set_state = smu_v11_0_baco_set_state, - .baco_reset = smu_v11_0_baco_reset, + .baco_enter = smu_v11_0_baco_enter, + .baco_exit = smu_v11_0_baco_exit, .get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq, .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range, .override_pcie_parameters = smu_v11_0_override_pcie_parameters, diff --git a/drivers/gpu/drm/amd/powerplay/renoir_ppt.c b/drivers/gpu/drm/amd/powerplay/renoir_ppt.c index 977bdd962e9830a580ba4e5f5a12a2e027ff0e4e..89a54f8e08d36e856934910587679754ceeb7c2c 100644 --- a/drivers/gpu/drm/amd/powerplay/renoir_ppt.c +++ b/drivers/gpu/drm/amd/powerplay/renoir_ppt.c @@ -31,6 +31,9 @@ #include "renoir_ppt.h" +#define CLK_MAP(clk, index) \ + [SMU_##clk] = {1, (index)} + #define MSG_MAP(msg, index) \ [SMU_MSG_##msg] = {1, (index)} @@ -104,6 +107,14 @@ static struct smu_12_0_cmn2aisc_mapping renoir_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(SetHardMinFclkByFreq, PPSMC_MSG_SetHardMinFclkByFreq), }; +static struct smu_12_0_cmn2aisc_mapping renoir_clk_map[SMU_CLK_COUNT] = { + CLK_MAP(GFXCLK, CLOCK_GFXCLK), + CLK_MAP(SCLK, CLOCK_GFXCLK), + CLK_MAP(SOCCLK, CLOCK_SOCCLK), + CLK_MAP(UCLK, CLOCK_UMCCLK), + CLK_MAP(MCLK, CLOCK_UMCCLK), +}; + static struct smu_12_0_cmn2aisc_mapping renoir_table_map[SMU_TABLE_COUNT] = { TAB_MAP_VALID(WATERMARKS), TAB_MAP_INVALID(CUSTOM_DPM), @@ -125,6 +136,21 @@ static int renoir_get_smu_msg_index(struct smu_context *smc, uint32_t index) return mapping.map_to; } +static int renoir_get_smu_clk_index(struct smu_context *smc, uint32_t index) +{ + struct smu_12_0_cmn2aisc_mapping mapping; + + if (index >= SMU_CLK_COUNT) + return -EINVAL; + + mapping = renoir_clk_map[index]; + if (!(mapping.valid_mapping)) { + return -EINVAL; + } + + return mapping.map_to; +} + static int renoir_get_smu_table_index(struct smu_context *smc, uint32_t index) { struct smu_12_0_cmn2aisc_mapping mapping; @@ -139,6 +165,27 @@ static int renoir_get_smu_table_index(struct smu_context *smc, uint32_t index) return mapping.map_to; } +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; + + if (!smu_table->metrics_time || time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(100))) { + ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, + (void *)smu_table->metrics_table, false); + if (ret) { + pr_info("Failed to export SMU metrics table!\n"); + return ret; + } + smu_table->metrics_time = jiffies; + } + + memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t)); + + return ret; +} + static int renoir_tables_init(struct smu_context *smu, struct smu_table *tables) { struct smu_table_context *smu_table = &smu->smu_table; @@ -154,6 +201,11 @@ static int renoir_tables_init(struct smu_context *smu, struct smu_table *tables) if (!smu_table->clocks_table) return -ENOMEM; + smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); + if (!smu_table->metrics_table) + return -ENOMEM; + smu_table->metrics_time = 0; + return 0; } @@ -301,6 +353,51 @@ static int renoir_dpm_set_uvd_enable(struct smu_context *smu, bool enable) return ret; } +static int renoir_dpm_set_jpeg_enable(struct smu_context *smu, bool enable) +{ + struct smu_power_context *smu_power = &smu->smu_power; + struct smu_power_gate *power_gate = &smu_power->power_gate; + int ret = 0; + + if (enable) { + if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 0); + if (ret) + return ret; + } + power_gate->jpeg_gated = false; + } else { + if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerDownJpeg, 0); + if (ret) + return ret; + } + power_gate->jpeg_gated = true; + } + + return ret; +} + +static int renoir_get_current_clk_freq_by_table(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *value) +{ + int ret = 0, clk_id = 0; + SmuMetrics_t metrics; + + ret = renoir_get_metrics_table(smu, &metrics); + if (ret) + return ret; + + clk_id = smu_clk_get_index(smu, clk_type); + if (clk_id < 0) + return clk_id; + + *value = metrics.ClockFrequency[clk_id]; + + return ret; +} + static int renoir_force_dpm_limit_value(struct smu_context *smu, bool highest) { int ret = 0, i = 0; @@ -361,6 +458,50 @@ static int renoir_unforce_dpm_levels(struct smu_context *smu) { return ret; } +static int renoir_get_gpu_temperature(struct smu_context *smu, uint32_t *value) +{ + int ret = 0; + SmuMetrics_t metrics; + + if (!value) + return -EINVAL; + + ret = renoir_get_metrics_table(smu, &metrics); + if (ret) + return ret; + + *value = (metrics.GfxTemperature / 100) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + + return 0; +} + +static int renoir_get_current_activity_percent(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value) +{ + int ret = 0; + SmuMetrics_t metrics; + + if (!value) + return -EINVAL; + + ret = renoir_get_metrics_table(smu, &metrics); + if (ret) + return ret; + + switch (sensor) { + case AMDGPU_PP_SENSOR_GPU_LOAD: + *value = metrics.AverageGfxActivity / 100; + break; + default: + pr_err("Invalid sensor for retrieving clock activity\n"); + return -EINVAL; + } + + return 0; +} + static int renoir_get_workload_type(struct smu_context *smu, uint32_t profile) { @@ -674,8 +815,36 @@ static int renoir_get_power_profile_mode(struct smu_context *smu, return size; } +static int renoir_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, + void *data, uint32_t *size) +{ + int ret = 0; + + if (!data || !size) + return -EINVAL; + + mutex_lock(&smu->sensor_lock); + switch (sensor) { + case AMDGPU_PP_SENSOR_GPU_LOAD: + ret = renoir_get_current_activity_percent(smu, sensor, (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GPU_TEMP: + ret = renoir_get_gpu_temperature(smu, (uint32_t *)data); + *size = 4; + break; + default: + ret = smu_v12_0_read_sensor(smu, sensor, data, size); + } + mutex_unlock(&smu->sensor_lock); + + return ret; +} + static const struct pptable_funcs renoir_ppt_funcs = { .get_smu_msg_index = renoir_get_smu_msg_index, + .get_smu_clk_index = renoir_get_smu_clk_index, .get_smu_table_index = renoir_get_smu_table_index, .tables_init = renoir_tables_init, .set_power_state = NULL, @@ -683,6 +852,8 @@ static const struct pptable_funcs renoir_ppt_funcs = { .print_clk_levels = renoir_print_clk_levels, .get_current_power_state = renoir_get_current_power_state, .dpm_set_uvd_enable = renoir_dpm_set_uvd_enable, + .dpm_set_jpeg_enable = renoir_dpm_set_jpeg_enable, + .get_current_clk_freq_by_table = renoir_get_current_clk_freq_by_table, .force_dpm_limit_value = renoir_force_dpm_limit_value, .unforce_dpm_levels = renoir_unforce_dpm_levels, .get_workload_type = renoir_get_workload_type, @@ -693,10 +864,12 @@ static const struct pptable_funcs renoir_ppt_funcs = { .get_dpm_clock_table = renoir_get_dpm_clock_table, .set_watermarks_table = renoir_set_watermarks_table, .get_power_profile_mode = renoir_get_power_profile_mode, + .read_sensor = renoir_read_sensor, .check_fw_status = smu_v12_0_check_fw_status, .check_fw_version = smu_v12_0_check_fw_version, .powergate_sdma = smu_v12_0_powergate_sdma, .powergate_vcn = smu_v12_0_powergate_vcn, + .powergate_jpeg = smu_v12_0_powergate_jpeg, .send_smc_msg_with_param = smu_v12_0_send_msg_with_param, .read_smc_arg = smu_v12_0_read_arg, .set_gfx_cgpg = smu_v12_0_set_gfx_cgpg, @@ -704,6 +877,8 @@ static const struct pptable_funcs renoir_ppt_funcs = { .init_smc_tables = smu_v12_0_init_smc_tables, .fini_smc_tables = smu_v12_0_fini_smc_tables, .populate_smc_tables = smu_v12_0_populate_smc_tables, + .get_enabled_mask = smu_v12_0_get_enabled_mask, + .get_current_clk_freq = smu_v12_0_get_current_clk_freq, .get_dpm_ultimate_freq = smu_v12_0_get_dpm_ultimate_freq, .mode2_reset = smu_v12_0_mode2_reset, .set_soft_freq_limited_range = smu_v12_0_set_soft_freq_limited_range, diff --git a/drivers/gpu/drm/amd/powerplay/smu_internal.h b/drivers/gpu/drm/amd/powerplay/smu_internal.h index 8872f8b2d5029e83d122250ff1594be0dba8070b..60ce1fccaeb51020444ad212c8de734c501ec128 100644 --- a/drivers/gpu/drm/amd/powerplay/smu_internal.h +++ b/drivers/gpu/drm/amd/powerplay/smu_internal.h @@ -42,6 +42,8 @@ ((smu)->ppt_funcs->powergate_sdma ? (smu)->ppt_funcs->powergate_sdma((smu), (gate)) : 0) #define smu_powergate_vcn(smu, gate) \ ((smu)->ppt_funcs->powergate_vcn ? (smu)->ppt_funcs->powergate_vcn((smu), (gate)) : 0) +#define smu_powergate_jpeg(smu, gate) \ + ((smu)->ppt_funcs->powergate_jpeg ? (smu)->ppt_funcs->powergate_jpeg((smu), (gate)) : 0) #define smu_get_vbios_bootup_values(smu) \ ((smu)->ppt_funcs->get_vbios_bootup_values ? (smu)->ppt_funcs->get_vbios_bootup_values((smu)) : 0) @@ -170,6 +172,8 @@ int smu_send_smc_msg(struct smu_context *smu, enum smu_message_type msg); ((smu)->ppt_funcs->dpm_set_uvd_enable ? (smu)->ppt_funcs->dpm_set_uvd_enable((smu), (enable)) : 0) #define smu_dpm_set_vce_enable(smu, enable) \ ((smu)->ppt_funcs->dpm_set_vce_enable ? (smu)->ppt_funcs->dpm_set_vce_enable((smu), (enable)) : 0) +#define smu_dpm_set_jpeg_enable(smu, enable) \ + ((smu)->ppt_funcs->dpm_set_jpeg_enable ? (smu)->ppt_funcs->dpm_set_jpeg_enable((smu), (enable)) : 0) #define smu_set_watermarks_table(smu, tab, clock_ranges) \ ((smu)->ppt_funcs->set_watermarks_table ? (smu)->ppt_funcs->set_watermarks_table((smu), (tab), (clock_ranges)) : 0) diff --git a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c b/drivers/gpu/drm/amd/powerplay/smu_v11_0.c index e4268a627effec922120236d5292803fc0c1a351..7781d245f8ef1d4137ad8811a1e54540f9cafb6e 100644 --- a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c +++ b/drivers/gpu/drm/amd/powerplay/smu_v11_0.c @@ -37,6 +37,7 @@ #include "soc15_common.h" #include "atom.h" #include "amd_pcie.h" +#include "amdgpu_ras.h" #include "asic_reg/thm/thm_11_0_2_offset.h" #include "asic_reg/thm/thm_11_0_2_sh_mask.h" @@ -79,15 +80,13 @@ static int smu_v11_0_wait_for_response(struct smu_context *smu) for (i = 0; i < timeout; i++) { cur_value = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90); if ((cur_value & MP1_C2PMSG_90__CONTENT_MASK) != 0) - break; + return cur_value == 0x1 ? 0 : -EIO; + udelay(1); } /* timeout means wrong logic */ - if (i == timeout) - return -ETIME; - - return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90) == 0x1 ? 0 : -EIO; + return -ETIME; } int @@ -103,9 +102,11 @@ smu_v11_0_send_msg_with_param(struct smu_context *smu, return index; ret = smu_v11_0_wait_for_response(smu); - if (ret) - pr_err("failed send message: %10s (%d) \tparam: 0x%08x response %#x\n", - smu_get_message_name(smu, msg), index, param, ret); + if (ret) { + pr_err("Msg issuing pre-check failed and " + "SMU may be not in the right state!\n"); + return ret; + } WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); @@ -1617,7 +1618,9 @@ bool smu_v11_0_baco_is_support(struct smu_context *smu) if (!baco_support) return false; - if (!smu_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT)) + /* Arcturus does not support this bit mask */ + if (smu_feature_is_supported(smu, SMU_FEATURE_BACO_BIT) && + !smu_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT)) return false; val = RREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP0); @@ -1643,6 +1646,10 @@ int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state) { struct smu_baco_context *smu_baco = &smu->smu_baco; + struct amdgpu_device *adev = smu->adev; + struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); + uint32_t bif_doorbell_intr_cntl; + uint32_t data; int ret = 0; if (smu_v11_0_baco_get_state(smu) == state) @@ -1650,10 +1657,37 @@ int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state) mutex_lock(&smu_baco->mutex); - if (state == SMU_BACO_STATE_ENTER) - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnterBaco, BACO_SEQ_BACO); - else + bif_doorbell_intr_cntl = RREG32_SOC15(NBIO, 0, mmBIF_DOORBELL_INT_CNTL); + + if (state == SMU_BACO_STATE_ENTER) { + bif_doorbell_intr_cntl = REG_SET_FIELD(bif_doorbell_intr_cntl, + BIF_DOORBELL_INT_CNTL, + DOORBELL_INTERRUPT_DISABLE, 1); + WREG32_SOC15(NBIO, 0, mmBIF_DOORBELL_INT_CNTL, bif_doorbell_intr_cntl); + + if (!ras || !ras->supported) { + data = RREG32_SOC15(THM, 0, mmTHM_BACO_CNTL); + data |= 0x80000000; + WREG32_SOC15(THM, 0, mmTHM_BACO_CNTL, data); + + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnterBaco, 0); + } else { + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnterBaco, 1); + } + } else { ret = smu_send_smc_msg(smu, SMU_MSG_ExitBaco); + if (ret) + goto out; + + bif_doorbell_intr_cntl = REG_SET_FIELD(bif_doorbell_intr_cntl, + BIF_DOORBELL_INT_CNTL, + DOORBELL_INTERRUPT_DISABLE, 0); + WREG32_SOC15(NBIO, 0, mmBIF_DOORBELL_INT_CNTL, bif_doorbell_intr_cntl); + + /* clear vbios scratch 6 and 7 for coming asic reinit */ + WREG32(adev->bios_scratch_reg_offset + 6, 0); + WREG32(adev->bios_scratch_reg_offset + 7, 0); + } if (ret) goto out; @@ -1663,13 +1697,17 @@ out: return ret; } -int smu_v11_0_baco_reset(struct smu_context *smu) +int smu_v11_0_baco_enter(struct smu_context *smu) { + struct amdgpu_device *adev = smu->adev; int ret = 0; - ret = smu_v11_0_baco_set_armd3_sequence(smu, BACO_SEQ_BACO); - if (ret) - return ret; + /* Arcturus does not need this audio workaround */ + if (adev->asic_type != CHIP_ARCTURUS) { + ret = smu_v11_0_baco_set_armd3_sequence(smu, BACO_SEQ_BACO); + if (ret) + return ret; + } ret = smu_v11_0_baco_set_state(smu, SMU_BACO_STATE_ENTER); if (ret) @@ -1677,6 +1715,13 @@ int smu_v11_0_baco_reset(struct smu_context *smu) msleep(10); + return ret; +} + +int smu_v11_0_baco_exit(struct smu_context *smu) +{ + int ret = 0; + ret = smu_v11_0_baco_set_state(smu, SMU_BACO_STATE_EXIT); if (ret) return ret; diff --git a/drivers/gpu/drm/amd/powerplay/smu_v12_0.c b/drivers/gpu/drm/amd/powerplay/smu_v12_0.c index 094cfc46adace5c7e8e02f1fc8ac7b453a1bc5a7..2ac7f2f231b6ac1d9dc63e8caf4f4dfb1a8a9397 100644 --- a/drivers/gpu/drm/amd/powerplay/smu_v12_0.c +++ b/drivers/gpu/drm/amd/powerplay/smu_v12_0.c @@ -66,15 +66,13 @@ int smu_v12_0_wait_for_response(struct smu_context *smu) for (i = 0; i < adev->usec_timeout; i++) { cur_value = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90); if ((cur_value & MP1_C2PMSG_90__CONTENT_MASK) != 0) - break; + return cur_value == 0x1 ? 0 : -EIO; + udelay(1); } /* timeout means wrong logic */ - if (i == adev->usec_timeout) - return -ETIME; - - return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90) == 0x1 ? 0 : -EIO; + return -ETIME; } int @@ -90,9 +88,11 @@ smu_v12_0_send_msg_with_param(struct smu_context *smu, return index; ret = smu_v12_0_wait_for_response(smu); - if (ret) - pr_err("Failed to send message 0x%x, response 0x%x, param 0x%x\n", - index, ret, param); + if (ret) { + pr_err("Msg issuing pre-check failed and " + "SMU may be not in the right state!\n"); + return ret; + } WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); @@ -179,6 +179,17 @@ int smu_v12_0_powergate_vcn(struct smu_context *smu, bool gate) return smu_send_smc_msg(smu, SMU_MSG_PowerUpVcn); } +int smu_v12_0_powergate_jpeg(struct smu_context *smu, bool gate) +{ + if (!(smu->adev->flags & AMD_IS_APU)) + return 0; + + if (gate) + return smu_send_smc_msg_with_param(smu, SMU_MSG_PowerDownJpeg, 0); + else + return smu_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 0); +} + int smu_v12_0_set_gfx_cgpg(struct smu_context *smu, bool enable) { if (!(smu->adev->pg_flags & AMD_PG_SUPPORT_GFX_PG)) @@ -188,6 +199,39 @@ int smu_v12_0_set_gfx_cgpg(struct smu_context *smu, bool enable) SMU_MSG_SetGfxCGPG, enable ? 1 : 0); } +int smu_v12_0_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, + void *data, uint32_t *size) +{ + int ret = 0; + + if(!data || !size) + return -EINVAL; + + switch (sensor) { + case AMDGPU_PP_SENSOR_GFX_MCLK: + ret = smu_get_current_clk_freq(smu, SMU_UCLK, (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GFX_SCLK: + ret = smu_get_current_clk_freq(smu, SMU_GFXCLK, (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_MIN_FAN_RPM: + *(uint32_t *)data = 0; + *size = 4; + break; + default: + ret = smu_common_read_sensor(smu, sensor, data, size); + break; + } + + if (ret) + *size = 0; + + return ret; +} + /** * smu_v12_0_get_gfxoff_status - get gfxoff status * @@ -286,6 +330,55 @@ int smu_v12_0_populate_smc_tables(struct smu_context *smu) return smu_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false); } +int smu_v12_0_get_enabled_mask(struct smu_context *smu, + uint32_t *feature_mask, uint32_t num) +{ + uint32_t feature_mask_high = 0, feature_mask_low = 0; + int ret = 0; + + if (!feature_mask || num < 2) + return -EINVAL; + + ret = smu_send_smc_msg(smu, SMU_MSG_GetEnabledSmuFeaturesHigh); + if (ret) + return ret; + ret = smu_read_smc_arg(smu, &feature_mask_high); + if (ret) + return ret; + + ret = smu_send_smc_msg(smu, SMU_MSG_GetEnabledSmuFeaturesLow); + if (ret) + return ret; + ret = smu_read_smc_arg(smu, &feature_mask_low); + if (ret) + return ret; + + feature_mask[0] = feature_mask_low; + feature_mask[1] = feature_mask_high; + + return ret; +} + +int smu_v12_0_get_current_clk_freq(struct smu_context *smu, + enum smu_clk_type clk_id, + uint32_t *value) +{ + int ret = 0; + uint32_t freq = 0; + + if (clk_id >= SMU_CLK_COUNT || !value) + return -EINVAL; + + ret = smu_get_current_clk_freq_by_table(smu, clk_id, &freq); + if (ret) + return ret; + + freq *= 100; + *value = freq; + + return ret; +} + int smu_v12_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *min, uint32_t *max) { diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c index 15590fd86ef4ac5d3fb4a36c8a2467c61ad9390e..868e2d5f6e621e1c04980314de23b6f9180e2353 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c @@ -653,8 +653,8 @@ static int ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(struct pp_hwmgr *hwmgr) static int ci_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr) { struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); - uint16_t HiSidd = smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd; - uint16_t LoSidd = smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd; + uint16_t HiSidd; + uint16_t LoSidd; struct phm_cac_tdp_table *cac_table = hwmgr->dyn_state.cac_dtp_table; HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c index da025b1d302dad7056e4b5398fcddbf21470ebfe..32ebb383c4568f623599154761e7356229d12987 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c @@ -940,7 +940,7 @@ static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr, { int result; /* PP_Clocks minClocks; */ - uint32_t threshold, mvdd; + uint32_t mvdd; struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); struct phm_ppt_v1_information *table_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); @@ -973,8 +973,6 @@ static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr, level->VoltageDownHyst = 0; level->PowerThrottle = 0; - threshold = clock * data->fast_watermark_threshold / 100; - data->display_timing.min_clock_in_sr = hwmgr->display_config->min_core_set_clock_in_sr; if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) @@ -1501,7 +1499,7 @@ static int fiji_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr, uint32_t dram_timing; uint32_t dram_timing2; uint32_t burstTime; - ULONG state, trrds, trrdl; + ULONG trrds, trrdl; int result; result = atomctrl_set_engine_dram_timings_rv770(hwmgr, @@ -1513,7 +1511,6 @@ static int fiji_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr, dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2); burstTime = cgs_read_register(hwmgr->device, mmMC_ARB_BURST_TIME); - state = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, STATE0); trrds = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDS0); trrdl = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDL0); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c index 742b3dc1f6cba748012c054da7cc77849d6d270b..adfbcbe5d113a0238b091753fd69908508400c87 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c @@ -61,15 +61,29 @@ static uint32_t smu9_wait_for_response(struct pp_hwmgr *hwmgr) uint32_t reg; uint32_t ret; - reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + /* Due to the L1 policy problem under SRIOV, we have to use + * mmMP1_SMN_C2PMSG_103 as the driver response register + */ + if (hwmgr->pp_one_vf) { + reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_103); - ret = phm_wait_for_register_unequal(hwmgr, reg, - 0, MP1_C2PMSG_90__CONTENT_MASK); + ret = phm_wait_for_register_unequal(hwmgr, reg, + 0, MP1_C2PMSG_103__CONTENT_MASK); - if (ret) - pr_err("No response from smu\n"); + if (ret) + pr_err("No response from smu\n"); - return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90); + return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_103); + } else { + reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + + ret = phm_wait_for_register_unequal(hwmgr, reg, + 0, MP1_C2PMSG_90__CONTENT_MASK); + + if (ret) + pr_err("No response from smu\n"); + return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90); + } } /* @@ -83,7 +97,11 @@ static int smu9_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, { struct amdgpu_device *adev = hwmgr->adev; - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_66, msg); + if (hwmgr->pp_one_vf) { + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_101, msg); + } else { + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_66, msg); + } return 0; } @@ -101,7 +119,10 @@ int smu9_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) smu9_wait_for_response(hwmgr); - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); + if (hwmgr->pp_one_vf) + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_103, 0); + else + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); smu9_send_msg_to_smc_without_waiting(hwmgr, msg); @@ -127,9 +148,17 @@ int smu9_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, smu9_wait_for_response(hwmgr); - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); - - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82, parameter); + /* Due to the L1 policy problem under SRIOV, we have to use + * mmMP1_SMN_C2PMSG_101 as the driver message register and + * mmMP1_SMN_C2PMSG_102 as the driver parameter register. + */ + if (hwmgr->pp_one_vf) { + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_103, 0); + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_102, parameter); + } else { + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82, parameter); + } smu9_send_msg_to_smc_without_waiting(hwmgr, msg); @@ -144,5 +173,8 @@ uint32_t smu9_get_argument(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = hwmgr->adev; - return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82); + if (hwmgr->pp_one_vf) + return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_102); + else + return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82); } diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c index 0f3836fd9666f4d2745bbf0d29b0cab36a686245..39427ca32a150dc5f9edf17e84177198967bf757 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c @@ -71,6 +71,12 @@ static int vega10_copy_table_to_smc(struct pp_hwmgr *hwmgr, { struct vega10_smumgr *priv = hwmgr->smu_backend; + /* under sriov, vbios or hypervisor driver + * has already copy table to smc so here only skip it + */ + if (!hwmgr->not_vf) + return 0; + PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, "Invalid SMU Table ID!", return -EINVAL); PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, @@ -100,6 +106,14 @@ int vega10_enable_smc_features(struct pp_hwmgr *hwmgr, int msg = enable ? PPSMC_MSG_EnableSmuFeatures : PPSMC_MSG_DisableSmuFeatures; + /* VF has no permission to change smu feature due + * to security concern even under pp one vf mode + * it still can't do it. For vega10, the smu in + * vbios will enable the appropriate features. + * */ + if (!hwmgr->not_vf) + return 0; + return smum_send_msg_to_smc_with_parameter(hwmgr, msg, feature_mask); } diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c index ae18fbcb26fb19ce8ad203c649d22c017717c423..b0e0d67cd54b3e72987f37604326e6f0f48e9085 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c @@ -1114,7 +1114,6 @@ static int vegam_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, (struct phm_ppt_v1_information *)(hwmgr->pptable); SMIO_Pattern vol_level; uint32_t mvdd; - uint16_t us_mvdd; table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC; @@ -1168,17 +1167,6 @@ static int vegam_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, "in Clock Dependency Table", ); - us_mvdd = 0; - if ((SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control) || - (data->mclk_dpm_key_disabled)) - us_mvdd = data->vbios_boot_state.mvdd_bootup_value; - else { - if (!vegam_populate_mvdd_value(hwmgr, - data->dpm_table.mclk_table.dpm_levels[0].value, - &vol_level)) - us_mvdd = vol_level.Voltage; - } - if (!vegam_populate_mvdd_value(hwmgr, 0, &vol_level)) table->MemoryACPILevel.MinMvdd = PP_HOST_TO_SMC_UL(vol_level.Voltage); else @@ -1383,11 +1371,16 @@ static int vegam_populate_smc_boot_level(struct pp_hwmgr *hwmgr, result = phm_find_boot_level(&(data->dpm_table.sclk_table), data->vbios_boot_state.sclk_bootup_value, (uint32_t *)&(table->GraphicsBootLevel)); + if (result) + return result; result = phm_find_boot_level(&(data->dpm_table.mclk_table), data->vbios_boot_state.mclk_bootup_value, (uint32_t *)&(table->MemoryBootLevel)); + if (result) + return result; + table->BootVddc = data->vbios_boot_state.vddc_bootup_value * VOLTAGE_SCALE; table->BootVddci = data->vbios_boot_state.vddci_bootup_value * @@ -1493,7 +1486,7 @@ static int vegam_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) struct vegam_smumgr *smu_data = (struct vegam_smumgr *)(hwmgr->smu_backend); - uint8_t i, stretch_amount, stretch_amount2, volt_offset = 0; + uint8_t i, stretch_amount, volt_offset = 0; struct phm_ppt_v1_information *table_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table = @@ -1532,11 +1525,9 @@ static int vegam_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) (table_info->cac_dtp_table->ucCKS_LDO_REFSEL != 0) ? table_info->cac_dtp_table->ucCKS_LDO_REFSEL : 5; /* Populate CKS Lookup Table */ - if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5) - stretch_amount2 = 0; - else if (stretch_amount == 3 || stretch_amount == 4) - stretch_amount2 = 1; - else { + if (!(stretch_amount == 1 || stretch_amount == 2 || + stretch_amount == 5 || stretch_amount == 3 || + stretch_amount == 4)) { phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ClockStretcher); PP_ASSERT_WITH_CODE(false, diff --git a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c b/drivers/gpu/drm/amd/powerplay/vega20_ppt.c index 60b9ff097142639d18fbc037f6cb2cfcfa2db3d8..12bcc3e3ba99058cd9eb78d5f020b9760d52e45c 100644 --- a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c +++ b/drivers/gpu/drm/amd/powerplay/vega20_ppt.c @@ -3256,7 +3256,8 @@ static const struct pptable_funcs vega20_ppt_funcs = { .baco_is_support= smu_v11_0_baco_is_support, .baco_get_state = smu_v11_0_baco_get_state, .baco_set_state = smu_v11_0_baco_set_state, - .baco_reset = smu_v11_0_baco_reset, + .baco_enter = smu_v11_0_baco_enter, + .baco_exit = smu_v11_0_baco_exit, .get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq, .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range, .override_pcie_parameters = smu_v11_0_override_pcie_parameters, diff --git a/drivers/gpu/drm/arc/arcpgu_crtc.c b/drivers/gpu/drm/arc/arcpgu_crtc.c index dfaddbb7da0dbe8b753f0c2f2e5a7b8af44ff4fa..8ae1e1f97a735a40391adb2e772b0ba19f4dde58 100644 --- a/drivers/gpu/drm/arc/arcpgu_crtc.c +++ b/drivers/gpu/drm/arc/arcpgu_crtc.c @@ -20,9 +20,10 @@ #define ENCODE_PGU_XY(x, y) ((((x) - 1) << 16) | ((y) - 1)) -static struct simplefb_format supported_formats[] = { - { "r5g6b5", 16, {11, 5}, {5, 6}, {0, 5}, {0, 0}, DRM_FORMAT_RGB565 }, - { "r8g8b8", 24, {16, 8}, {8, 8}, {0, 8}, {0, 0}, DRM_FORMAT_RGB888 }, +static const u32 arc_pgu_supported_formats[] = { + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, }; static void arc_pgu_set_pxl_fmt(struct drm_crtc *crtc) @@ -30,22 +31,24 @@ static void arc_pgu_set_pxl_fmt(struct drm_crtc *crtc) struct arcpgu_drm_private *arcpgu = crtc_to_arcpgu_priv(crtc); const struct drm_framebuffer *fb = crtc->primary->state->fb; uint32_t pixel_format = fb->format->format; - struct simplefb_format *format = NULL; + u32 format = DRM_FORMAT_INVALID; int i; + u32 reg_ctrl; - for (i = 0; i < ARRAY_SIZE(supported_formats); i++) { - if (supported_formats[i].fourcc == pixel_format) - format = &supported_formats[i]; + for (i = 0; i < ARRAY_SIZE(arc_pgu_supported_formats); i++) { + if (arc_pgu_supported_formats[i] == pixel_format) + format = arc_pgu_supported_formats[i]; } - if (WARN_ON(!format)) + if (WARN_ON(format == DRM_FORMAT_INVALID)) return; - if (format->fourcc == DRM_FORMAT_RGB888) - arc_pgu_write(arcpgu, ARCPGU_REG_CTRL, - arc_pgu_read(arcpgu, ARCPGU_REG_CTRL) | - ARCPGU_MODE_RGB888_MASK); - + reg_ctrl = arc_pgu_read(arcpgu, ARCPGU_REG_CTRL); + if (format == DRM_FORMAT_RGB565) + reg_ctrl &= ~ARCPGU_MODE_XRGB8888; + else + reg_ctrl |= ARCPGU_MODE_XRGB8888; + arc_pgu_write(arcpgu, ARCPGU_REG_CTRL, reg_ctrl); } static const struct drm_crtc_funcs arc_pgu_crtc_funcs = { @@ -193,18 +196,15 @@ static struct drm_plane *arc_pgu_plane_init(struct drm_device *drm) { struct arcpgu_drm_private *arcpgu = drm->dev_private; struct drm_plane *plane = NULL; - u32 formats[ARRAY_SIZE(supported_formats)], i; int ret; plane = devm_kzalloc(drm->dev, sizeof(*plane), GFP_KERNEL); if (!plane) return ERR_PTR(-ENOMEM); - for (i = 0; i < ARRAY_SIZE(supported_formats); i++) - formats[i] = supported_formats[i].fourcc; - ret = drm_universal_plane_init(drm, plane, 0xff, &arc_pgu_plane_funcs, - formats, ARRAY_SIZE(formats), + arc_pgu_supported_formats, + ARRAY_SIZE(arc_pgu_supported_formats), NULL, DRM_PLANE_TYPE_PRIMARY, NULL); if (ret) diff --git a/drivers/gpu/drm/arc/arcpgu_regs.h b/drivers/gpu/drm/arc/arcpgu_regs.h index dab2c380f7f38e1398085bdbf2f695ee019d6f76..b689a382d556ca42ac313c1c1e463c882b648083 100644 --- a/drivers/gpu/drm/arc/arcpgu_regs.h +++ b/drivers/gpu/drm/arc/arcpgu_regs.h @@ -25,7 +25,7 @@ #define ARCPGU_CTRL_VS_POL_OFST 0x3 #define ARCPGU_CTRL_HS_POL_MASK 0x1 #define ARCPGU_CTRL_HS_POL_OFST 0x4 -#define ARCPGU_MODE_RGB888_MASK 0x04 +#define ARCPGU_MODE_XRGB8888 BIT(2) #define ARCPGU_STAT_BUSY_MASK 0x02 #endif diff --git a/drivers/gpu/drm/arm/display/Kconfig b/drivers/gpu/drm/arm/display/Kconfig index e87ff8623076c8e69b846fb98879ebb7127273ad..cec0639e3aa1fc8cdd6c846759bb9212444133c9 100644 --- a/drivers/gpu/drm/arm/display/Kconfig +++ b/drivers/gpu/drm/arm/display/Kconfig @@ -12,9 +12,3 @@ config DRM_KOMEDA Processor driver. It supports the D71 variants of the hardware. If compiled as a module it will be called komeda. - -config DRM_KOMEDA_ERROR_PRINT - bool "Enable komeda error print" - depends on DRM_KOMEDA - help - Choose this option to enable error printing. diff --git a/drivers/gpu/drm/arm/display/include/malidp_product.h b/drivers/gpu/drm/arm/display/include/malidp_product.h index 1053b11352eb346707dafbb298c84d7781392a7b..16a8a2c22c423e6781b8f185b243b39e6a937f63 100644 --- a/drivers/gpu/drm/arm/display/include/malidp_product.h +++ b/drivers/gpu/drm/arm/display/include/malidp_product.h @@ -18,7 +18,8 @@ #define MALIDP_CORE_ID_STATUS(__core_id) (((__u32)(__core_id)) & 0xFF) /* Mali-display product IDs */ -#define MALIDP_D71_PRODUCT_ID 0x0071 +#define MALIDP_D71_PRODUCT_ID 0x0071 +#define MALIDP_D32_PRODUCT_ID 0x0032 union komeda_config_id { struct { diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile index f095a1c68ac7b1859bcacbd408ba8ef268a38663..1931a7fa1a1448ec49019178b3bedbe26e53128c 100644 --- a/drivers/gpu/drm/arm/display/komeda/Makefile +++ b/drivers/gpu/drm/arm/display/komeda/Makefile @@ -16,12 +16,11 @@ komeda-y := \ komeda_crtc.o \ komeda_plane.o \ komeda_wb_connector.o \ - komeda_private_obj.o + komeda_private_obj.o \ + komeda_event.o komeda-y += \ d71/d71_dev.o \ d71/d71_component.o -komeda-$(CONFIG_DRM_KOMEDA_ERROR_PRINT) += komeda_event.o - obj-$(CONFIG_DRM_KOMEDA) += komeda.o diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c index f0ba26e282c32ae75ee3c66d805ed8ee489c5c42..8a02ade369db47c03bc35f83e702779dc73259f8 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c @@ -1044,7 +1044,9 @@ static int d71_merger_init(struct d71_dev *d71, static void d71_improc_update(struct komeda_component *c, struct komeda_component_state *state) { + struct drm_crtc_state *crtc_st = state->crtc->state; struct komeda_improc_state *st = to_improc_st(state); + struct d71_pipeline *pipe = to_d71_pipeline(c->pipeline); u32 __iomem *reg = c->reg; u32 index, mask = 0, ctrl = 0; @@ -1055,6 +1057,24 @@ static void d71_improc_update(struct komeda_component *c, malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize)); malidp_write32(reg, IPS_DEPTH, st->color_depth); + if (crtc_st->color_mgmt_changed) { + mask |= IPS_CTRL_FT | IPS_CTRL_RGB; + + if (crtc_st->gamma_lut) { + malidp_write_group(pipe->dou_ft_coeff_addr, FT_COEFF0, + KOMEDA_N_GAMMA_COEFFS, + st->fgamma_coeffs); + ctrl |= IPS_CTRL_FT; /* enable gamma */ + } + + if (crtc_st->ctm) { + malidp_write_group(reg, IPS_RGB_RGB_COEFF0, + KOMEDA_N_CTM_COEFFS, + st->ctm_coeffs); + ctrl |= IPS_CTRL_RGB; /* enable gamut */ + } + } + mask |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; /* config color format */ @@ -1250,7 +1270,7 @@ static int d71_timing_ctrlr_init(struct d71_dev *d71, ctrlr = to_ctrlr(c); - ctrlr->supports_dual_link = true; + ctrlr->supports_dual_link = d71->supports_dual_link; return 0; } diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c index 822b23a1ce75a826a4c3d58a69175faea039a922..00fa56c29b3eb3c167e75929318118f225f30cc3 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c @@ -20,8 +20,10 @@ static u64 get_lpu_event(struct d71_pipeline *d71_pipeline) evts |= KOMEDA_EVENT_IBSY; if (raw_status & LPU_IRQ_EOW) evts |= KOMEDA_EVENT_EOW; + if (raw_status & LPU_IRQ_OVR) + evts |= KOMEDA_EVENT_OVR; - if (raw_status & (LPU_IRQ_ERR | LPU_IRQ_IBSY)) { + if (raw_status & (LPU_IRQ_ERR | LPU_IRQ_IBSY | LPU_IRQ_OVR)) { u32 restore = 0, tbu_status; /* Check error of LPU status */ status = malidp_read32(reg, BLK_STATUS); @@ -45,6 +47,15 @@ static u64 get_lpu_event(struct d71_pipeline *d71_pipeline) restore |= LPU_STATUS_ACE3; evts |= KOMEDA_ERR_ACE3; } + if (status & LPU_STATUS_FEMPTY) { + restore |= LPU_STATUS_FEMPTY; + evts |= KOMEDA_EVENT_EMPTY; + } + if (status & LPU_STATUS_FFULL) { + restore |= LPU_STATUS_FFULL; + evts |= KOMEDA_EVENT_FULL; + } + if (restore != 0) malidp_write32_mask(reg, BLK_STATUS, restore, 0); @@ -371,23 +382,33 @@ static int d71_enum_resources(struct komeda_dev *mdev) goto err_cleanup; } - /* probe PERIPH */ + /* Only the legacy HW has the periph block, the newer merges the periph + * into GCU + */ value = malidp_read32(d71->periph_addr, BLK_BLOCK_INFO); - if (BLOCK_INFO_BLK_TYPE(value) != D71_BLK_TYPE_PERIPH) { - DRM_ERROR("access blk periph but got blk: %d.\n", - BLOCK_INFO_BLK_TYPE(value)); - err = -EINVAL; - goto err_cleanup; + if (BLOCK_INFO_BLK_TYPE(value) != D71_BLK_TYPE_PERIPH) + d71->periph_addr = NULL; + + if (d71->periph_addr) { + /* probe PERIPHERAL in legacy HW */ + value = malidp_read32(d71->periph_addr, PERIPH_CONFIGURATION_ID); + + d71->max_line_size = value & PERIPH_MAX_LINE_SIZE ? 4096 : 2048; + d71->max_vsize = 4096; + d71->num_rich_layers = value & PERIPH_NUM_RICH_LAYERS ? 2 : 1; + d71->supports_dual_link = !!(value & PERIPH_SPLIT_EN); + d71->integrates_tbu = !!(value & PERIPH_TBU_EN); + } else { + value = malidp_read32(d71->gcu_addr, GCU_CONFIGURATION_ID0); + d71->max_line_size = GCU_MAX_LINE_SIZE(value); + d71->max_vsize = GCU_MAX_NUM_LINES(value); + + value = malidp_read32(d71->gcu_addr, GCU_CONFIGURATION_ID1); + d71->num_rich_layers = GCU_NUM_RICH_LAYERS(value); + d71->supports_dual_link = GCU_DISPLAY_SPLIT_EN(value); + d71->integrates_tbu = GCU_DISPLAY_TBU_EN(value); } - value = malidp_read32(d71->periph_addr, PERIPH_CONFIGURATION_ID); - - d71->max_line_size = value & PERIPH_MAX_LINE_SIZE ? 4096 : 2048; - d71->max_vsize = 4096; - d71->num_rich_layers = value & PERIPH_NUM_RICH_LAYERS ? 2 : 1; - d71->supports_dual_link = value & PERIPH_SPLIT_EN ? true : false; - d71->integrates_tbu = value & PERIPH_TBU_EN ? true : false; - for (i = 0; i < d71->num_pipelines; i++) { pipe = komeda_pipeline_add(mdev, sizeof(struct d71_pipeline), &d71_pipeline_funcs); @@ -414,8 +435,11 @@ static int d71_enum_resources(struct komeda_dev *mdev) d71->pipes[i] = to_d71_pipeline(pipe); } - /* loop the register blks and probe */ - i = 2; /* exclude GCU and PERIPH */ + /* loop the register blks and probe. + * NOTE: d71->num_blocks includes reserved blocks. + * d71->num_blocks = GCU + valid blocks + reserved blocks + */ + i = 1; /* exclude GCU */ offset = D71_BLOCK_SIZE; /* skip GCU */ while (i < d71->num_blocks) { blk_base = mdev->reg_base + (offset >> 2); @@ -425,9 +449,9 @@ static int d71_enum_resources(struct komeda_dev *mdev) err = d71_probe_block(d71, &blk, blk_base); if (err) goto err_cleanup; - i++; } + i++; offset += D71_BLOCK_SIZE; } @@ -594,10 +618,26 @@ static const struct komeda_dev_funcs d71_chip_funcs = { const struct komeda_dev_funcs * d71_identify(u32 __iomem *reg_base, struct komeda_chip_info *chip) { + const struct komeda_dev_funcs *funcs; + u32 product_id; + + chip->core_id = malidp_read32(reg_base, GLB_CORE_ID); + + product_id = MALIDP_CORE_ID_PRODUCT_ID(chip->core_id); + + switch (product_id) { + case MALIDP_D71_PRODUCT_ID: + case MALIDP_D32_PRODUCT_ID: + funcs = &d71_chip_funcs; + break; + default: + DRM_ERROR("Unsupported product: 0x%x\n", product_id); + return NULL; + } + chip->arch_id = malidp_read32(reg_base, GLB_ARCH_ID); - chip->core_id = malidp_read32(reg_base, GLB_CORE_ID); chip->core_info = malidp_read32(reg_base, GLB_CORE_INFO); chip->bus_width = D71_BUS_WIDTH_16_BYTES; - return &d71_chip_funcs; + return funcs; } diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h b/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h index 1727dc9939090e910f6aa7e6904b0e800c18873c..e80172a0b320c95c14e87c49c19a2f73ccad9429 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h @@ -72,6 +72,19 @@ #define GCU_CONTROL_MODE(x) ((x) & 0x7) #define GCU_CONTROL_SRST BIT(16) +/* GCU_CONFIGURATION registers */ +#define GCU_CONFIGURATION_ID0 0x100 +#define GCU_CONFIGURATION_ID1 0x104 + +/* GCU configuration */ +#define GCU_MAX_LINE_SIZE(x) ((x) & 0xFFFF) +#define GCU_MAX_NUM_LINES(x) ((x) >> 16) +#define GCU_NUM_RICH_LAYERS(x) ((x) & 0x7) +#define GCU_NUM_PIPELINES(x) (((x) >> 3) & 0x7) +#define GCU_NUM_SCALERS(x) (((x) >> 6) & 0x7) +#define GCU_DISPLAY_SPLIT_EN(x) (((x) >> 16) & 0x1) +#define GCU_DISPLAY_TBU_EN(x) (((x) >> 17) & 0x1) + /* GCU opmode */ #define INACTIVE_MODE 0 #define TBU_CONNECT_MODE 1 @@ -162,6 +175,7 @@ #define TBU_DOUTSTDCAPB_MASK 0x3F /* LPU_IRQ_BITS */ +#define LPU_IRQ_OVR BIT(9) #define LPU_IRQ_IBSY BIT(10) #define LPU_IRQ_ERR BIT(11) #define LPU_IRQ_EOW BIT(12) @@ -172,6 +186,8 @@ #define LPU_STATUS_AXIE BIT(4) #define LPU_STATUS_AXIRP BIT(5) #define LPU_STATUS_AXIWP BIT(6) +#define LPU_STATUS_FEMPTY BIT(11) +#define LPU_STATUS_FFULL BIT(14) #define LPU_STATUS_ACE0 BIT(16) #define LPU_STATUS_ACE1 BIT(17) #define LPU_STATUS_ACE2 BIT(18) diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.c b/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.c index 9d14a92dbb17a3a84c9ed8d57b830a8f5a603e77..d8e449e6ebda286382179bce3f66d1a4812750b9 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.c @@ -65,3 +65,69 @@ const s32 *komeda_select_yuv2rgb_coeffs(u32 color_encoding, u32 color_range) return coeffs; } + +struct gamma_curve_sector { + u32 boundary_start; + u32 num_of_segments; + u32 segment_width; +}; + +struct gamma_curve_segment { + u32 start; + u32 end; +}; + +static struct gamma_curve_sector sector_tbl[] = { + { 0, 4, 4 }, + { 16, 4, 4 }, + { 32, 4, 8 }, + { 64, 4, 16 }, + { 128, 4, 32 }, + { 256, 4, 64 }, + { 512, 16, 32 }, + { 1024, 24, 128 }, +}; + +static void +drm_lut_to_coeffs(struct drm_property_blob *lut_blob, u32 *coeffs, + struct gamma_curve_sector *sector_tbl, u32 num_sectors) +{ + struct drm_color_lut *lut; + u32 i, j, in, num = 0; + + if (!lut_blob) + return; + + lut = lut_blob->data; + + for (i = 0; i < num_sectors; i++) { + for (j = 0; j < sector_tbl[i].num_of_segments; j++) { + in = sector_tbl[i].boundary_start + + j * sector_tbl[i].segment_width; + + coeffs[num++] = drm_color_lut_extract(lut[in].red, + KOMEDA_COLOR_PRECISION); + } + } + + coeffs[num] = BIT(KOMEDA_COLOR_PRECISION); +} + +void drm_lut_to_fgamma_coeffs(struct drm_property_blob *lut_blob, u32 *coeffs) +{ + drm_lut_to_coeffs(lut_blob, coeffs, sector_tbl, ARRAY_SIZE(sector_tbl)); +} + +void drm_ctm_to_coeffs(struct drm_property_blob *ctm_blob, u32 *coeffs) +{ + struct drm_color_ctm *ctm; + u32 i; + + if (!ctm_blob) + return; + + ctm = ctm_blob->data; + + for (i = 0; i < KOMEDA_N_CTM_COEFFS; i++) + coeffs[i] = drm_color_ctm_s31_32_to_qm_n(ctm->matrix[i], 3, 12); +} diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.h b/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.h index a2df218f58e79c8b4045e6d8e6f59aa144e12a27..2f46684661126b626ba176dc3dbc8dd017089a8d 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_color_mgmt.h @@ -11,7 +11,15 @@ #include #define KOMEDA_N_YUV2RGB_COEFFS 12 +#define KOMEDA_N_RGB2YUV_COEFFS 12 +#define KOMEDA_COLOR_PRECISION 12 +#define KOMEDA_N_GAMMA_COEFFS 65 +#define KOMEDA_COLOR_LUT_SIZE BIT(KOMEDA_COLOR_PRECISION) +#define KOMEDA_N_CTM_COEFFS 9 + +void drm_lut_to_fgamma_coeffs(struct drm_property_blob *lut_blob, u32 *coeffs); +void drm_ctm_to_coeffs(struct drm_property_blob *ctm_blob, u32 *coeffs); const s32 *komeda_select_yuv2rgb_coeffs(u32 color_encoding, u32 color_range); -#endif +#endif /*_KOMEDA_COLOR_MGMT_H_*/ diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c index 252015210fbc8620f53ebcfee52ee5c89aaac59b..56bd938961eeea29a1895616a4a3f3da716aad5d 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c @@ -5,6 +5,7 @@ * */ #include +#include #include #include @@ -274,6 +275,7 @@ static void komeda_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old) { + pm_runtime_get_sync(crtc->dev->dev); komeda_crtc_prepare(to_kcrtc(crtc)); drm_crtc_vblank_on(crtc); WARN_ON(drm_crtc_vblank_get(crtc)); @@ -372,6 +374,7 @@ komeda_crtc_atomic_disable(struct drm_crtc *crtc, drm_crtc_vblank_put(crtc); drm_crtc_vblank_off(crtc); komeda_crtc_unprepare(kcrtc); + pm_runtime_put(crtc->dev->dev); } static void @@ -617,6 +620,8 @@ static int komeda_crtc_add(struct komeda_kms_dev *kms, crtc->port = kcrtc->master->of_output_port; + drm_crtc_enable_color_mgmt(crtc, 0, true, KOMEDA_COLOR_LUT_SIZE); + return err; } diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c index 937a6d4c486571d06ca61a343d656f857caf5ed6..1d767473ba8a0613fc96d8ae9fae8feedcd0e0c9 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #ifdef CONFIG_DEBUG_FS #include @@ -27,12 +28,16 @@ static int komeda_register_show(struct seq_file *sf, void *x) seq_puts(sf, "\n====== Komeda register dump =========\n"); + pm_runtime_get_sync(mdev->dev); + if (mdev->funcs->dump_register) mdev->funcs->dump_register(mdev, sf); for (i = 0; i < mdev->n_pipelines; i++) komeda_pipeline_dump_register(mdev->pipelines[i], sf); + pm_runtime_put(mdev->dev); + return 0; } @@ -58,6 +63,8 @@ static void komeda_debugfs_init(struct komeda_dev *mdev) mdev->debugfs_root = debugfs_create_dir("komeda", NULL); debugfs_create_file("register", 0444, mdev->debugfs_root, mdev, &komeda_register_fops); + debugfs_create_x16("err_verbosity", 0664, mdev->debugfs_root, + &mdev->err_verbosity); } #endif @@ -113,22 +120,14 @@ static struct attribute_group komeda_sysfs_attr_group = { .attrs = komeda_sysfs_entries, }; -static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np) +static int komeda_parse_pipe_dt(struct komeda_pipeline *pipe) { - struct komeda_pipeline *pipe; + struct device_node *np = pipe->of_node; struct clk *clk; - u32 pipe_id; - int ret = 0; - - ret = of_property_read_u32(np, "reg", &pipe_id); - if (ret != 0 || pipe_id >= mdev->n_pipelines) - return -EINVAL; - - pipe = mdev->pipelines[pipe_id]; clk = of_clk_get_by_name(np, "pxclk"); if (IS_ERR(clk)) { - DRM_ERROR("get pxclk for pipeline %d failed!\n", pipe_id); + DRM_ERROR("get pxclk for pipeline %d failed!\n", pipe->id); return PTR_ERR(clk); } pipe->pxlclk = clk; @@ -142,7 +141,6 @@ static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np) of_graph_get_port_by_id(np, KOMEDA_OF_PORT_OUTPUT); pipe->dual_link = pipe->of_output_links[0] && pipe->of_output_links[1]; - pipe->of_node = of_node_get(np); return 0; } @@ -151,7 +149,9 @@ static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev) { struct platform_device *pdev = to_platform_device(dev); struct device_node *child, *np = dev->of_node; - int ret; + struct komeda_pipeline *pipe; + u32 pipe_id = U32_MAX; + int ret = -1; mdev->irq = platform_get_irq(pdev, 0); if (mdev->irq < 0) { @@ -166,37 +166,44 @@ static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev) ret = 0; for_each_available_child_of_node(np, child) { - if (of_node_cmp(child->name, "pipeline") == 0) { - ret = komeda_parse_pipe_dt(mdev, child); - if (ret) { - DRM_ERROR("parse pipeline dt error!\n"); - of_node_put(child); - break; + if (of_node_name_eq(child, "pipeline")) { + of_property_read_u32(child, "reg", &pipe_id); + if (pipe_id >= mdev->n_pipelines) { + DRM_WARN("Skip the redundant DT node: pipeline-%u.\n", + pipe_id); + continue; } + mdev->pipelines[pipe_id]->of_node = of_node_get(child); } } - return ret; + for (pipe_id = 0; pipe_id < mdev->n_pipelines; pipe_id++) { + pipe = mdev->pipelines[pipe_id]; + + if (!pipe->of_node) { + DRM_ERROR("Pipeline-%d doesn't have a DT node.\n", + pipe->id); + return -EINVAL; + } + ret = komeda_parse_pipe_dt(pipe); + if (ret) + return ret; + } + + return 0; } struct komeda_dev *komeda_dev_create(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); - const struct komeda_product_data *product; + komeda_identify_func komeda_identify; struct komeda_dev *mdev; - struct resource *io_res; int err = 0; - product = of_device_get_match_data(dev); - if (!product) + komeda_identify = of_device_get_match_data(dev); + if (!komeda_identify) return ERR_PTR(-ENODEV); - io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!io_res) { - DRM_ERROR("No registers defined.\n"); - return ERR_PTR(-ENODEV); - } - mdev = devm_kzalloc(dev, sizeof(*mdev), GFP_KERNEL); if (!mdev) return ERR_PTR(-ENOMEM); @@ -204,7 +211,7 @@ struct komeda_dev *komeda_dev_create(struct device *dev) mutex_init(&mdev->lock); mdev->dev = dev; - mdev->reg_base = devm_ioremap_resource(dev, io_res); + mdev->reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mdev->reg_base)) { DRM_ERROR("Map register space failed.\n"); err = PTR_ERR(mdev->reg_base); @@ -222,11 +229,9 @@ struct komeda_dev *komeda_dev_create(struct device *dev) clk_prepare_enable(mdev->aclk); - mdev->funcs = product->identify(mdev->reg_base, &mdev->chip); - if (!komeda_product_match(mdev, product->product_id)) { - DRM_ERROR("DT configured %x mismatch with real HW %x.\n", - product->product_id, - MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id)); + mdev->funcs = komeda_identify(mdev->reg_base, &mdev->chip); + if (!mdev->funcs) { + DRM_ERROR("Failed to identify the HW.\n"); err = -ENODEV; goto disable_clk; } @@ -263,15 +268,6 @@ struct komeda_dev *komeda_dev_create(struct device *dev) if (!mdev->iommu) DRM_INFO("continue without IOMMU support!\n"); - if (mdev->iommu && mdev->funcs->connect_iommu) { - err = mdev->funcs->connect_iommu(mdev); - if (err) { - DRM_ERROR("connect iommu failed.\n"); - mdev->iommu = NULL; - goto disable_clk; - } - } - clk_disable_unprepare(mdev->aclk); err = sysfs_create_group(&dev->kobj, &komeda_sysfs_attr_group); @@ -280,6 +276,8 @@ struct komeda_dev *komeda_dev_create(struct device *dev) goto err_cleanup; } + mdev->err_verbosity = KOMEDA_DEV_PRINT_ERR_EVENTS; + #ifdef CONFIG_DEBUG_FS komeda_debugfs_init(mdev); #endif @@ -308,11 +306,6 @@ void komeda_dev_destroy(struct komeda_dev *mdev) if (mdev->aclk) clk_prepare_enable(mdev->aclk); - if (mdev->iommu && mdev->funcs->disconnect_iommu) - if (mdev->funcs->disconnect_iommu(mdev)) - DRM_ERROR("disconnect iommu failed.\n"); - mdev->iommu = NULL; - for (i = 0; i < mdev->n_pipelines; i++) { komeda_pipeline_destroy(mdev, mdev->pipelines[i]); mdev->pipelines[i] = NULL; @@ -341,44 +334,26 @@ void komeda_dev_destroy(struct komeda_dev *mdev) int komeda_dev_resume(struct komeda_dev *mdev) { - int ret = 0; - clk_prepare_enable(mdev->aclk); - if (mdev->iommu && mdev->funcs->connect_iommu) { - ret = mdev->funcs->connect_iommu(mdev); - if (ret < 0) { - DRM_ERROR("connect iommu failed.\n"); - goto disable_clk; - } - } - - ret = mdev->funcs->enable_irq(mdev); + mdev->funcs->enable_irq(mdev); -disable_clk: - clk_disable_unprepare(mdev->aclk); + if (mdev->iommu && mdev->funcs->connect_iommu) + if (mdev->funcs->connect_iommu(mdev)) + DRM_ERROR("connect iommu failed.\n"); - return ret; + return 0; } int komeda_dev_suspend(struct komeda_dev *mdev) { - int ret = 0; - - clk_prepare_enable(mdev->aclk); - - if (mdev->iommu && mdev->funcs->disconnect_iommu) { - ret = mdev->funcs->disconnect_iommu(mdev); - if (ret < 0) { + if (mdev->iommu && mdev->funcs->disconnect_iommu) + if (mdev->funcs->disconnect_iommu(mdev)) DRM_ERROR("disconnect iommu failed.\n"); - goto disable_clk; - } - } - ret = mdev->funcs->disable_irq(mdev); + mdev->funcs->disable_irq(mdev); -disable_clk: clk_disable_unprepare(mdev->aclk); - return ret; + return 0; } diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h index 414200233b64b4441dfa38d9cf58313ac7a1e374..ce27f2f27c240afcdcf836f43deed58fbffbea9f 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h @@ -20,6 +20,8 @@ #define KOMEDA_EVENT_OVR BIT_ULL(4) #define KOMEDA_EVENT_EOW BIT_ULL(5) #define KOMEDA_EVENT_MODE BIT_ULL(6) +#define KOMEDA_EVENT_FULL BIT_ULL(7) +#define KOMEDA_EVENT_EMPTY BIT_ULL(8) #define KOMEDA_ERR_TETO BIT_ULL(14) #define KOMEDA_ERR_TEMR BIT_ULL(15) @@ -49,12 +51,15 @@ KOMEDA_ERR_ZME | KOMEDA_ERR_MERR | KOMEDA_ERR_TCF |\ KOMEDA_ERR_TTNG | KOMEDA_ERR_TTF) -#define KOMEDA_WARN_EVENTS KOMEDA_ERR_CSCE +#define KOMEDA_WARN_EVENTS \ + (KOMEDA_ERR_CSCE | KOMEDA_EVENT_FULL | KOMEDA_EVENT_EMPTY) -/* malidp device id */ -enum { - MALI_D71 = 0, -}; +#define KOMEDA_INFO_EVENTS (0 \ + | KOMEDA_EVENT_VSYNC \ + | KOMEDA_EVENT_FLIP \ + | KOMEDA_EVENT_EOW \ + | KOMEDA_EVENT_MODE \ + ) /* pipeline DT ports */ enum { @@ -69,12 +74,6 @@ struct komeda_chip_info { u32 bus_width; }; -struct komeda_product_data { - u32 product_id; - const struct komeda_dev_funcs *(*identify)(u32 __iomem *reg, - struct komeda_chip_info *info); -}; - struct komeda_dev; struct komeda_events { @@ -202,6 +201,23 @@ struct komeda_dev { /** @debugfs_root: root directory of komeda debugfs */ struct dentry *debugfs_root; + /** + * @err_verbosity: bitmask for how much extra info to print on error + * + * See KOMEDA_DEV_* macros for details. Low byte contains the debug + * level categories, the high byte contains extra debug options. + */ + u16 err_verbosity; + /* Print a single line per error per frame with error events. */ +#define KOMEDA_DEV_PRINT_ERR_EVENTS BIT(0) + /* Print a single line per warning per frame with error events. */ +#define KOMEDA_DEV_PRINT_WARN_EVENTS BIT(1) + /* Print a single line per info event per frame with error events. */ +#define KOMEDA_DEV_PRINT_INFO_EVENTS BIT(2) + /* Dump DRM state on an error or warning event. */ +#define KOMEDA_DEV_PRINT_DUMP_STATE_ON_EVENT BIT(8) + /* Disable rate limiting of event prints (normally one per commit) */ +#define KOMEDA_DEV_PRINT_DISABLE_RATELIMIT BIT(12) }; static inline bool @@ -210,6 +226,9 @@ komeda_product_match(struct komeda_dev *mdev, u32 target) return MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id) == target; } +typedef const struct komeda_dev_funcs * +(*komeda_identify_func)(u32 __iomem *reg, struct komeda_chip_info *chip); + const struct komeda_dev_funcs * d71_identify(u32 __iomem *reg, struct komeda_chip_info *chip); @@ -218,11 +237,7 @@ void komeda_dev_destroy(struct komeda_dev *mdev); struct komeda_dev *dev_to_mdev(struct device *dev); -#ifdef CONFIG_DRM_KOMEDA_ERROR_PRINT -void komeda_print_events(struct komeda_events *evts); -#else -static inline void komeda_print_events(struct komeda_events *evts) {} -#endif +void komeda_print_events(struct komeda_events *evts, struct drm_device *dev); int komeda_dev_resume(struct komeda_dev *mdev); int komeda_dev_suspend(struct komeda_dev *mdev); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c index d6c2222c5d3305928cd806078bcdbdacccef203c..ea5cd1e1730494e60bca57643f65dc23bcfb7f00 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c @@ -33,6 +33,12 @@ static void komeda_unbind(struct device *dev) return; komeda_kms_detach(mdrv->kms); + + if (pm_runtime_enabled(dev)) + pm_runtime_disable(dev); + else + komeda_dev_suspend(mdrv->mdev); + komeda_dev_destroy(mdrv->mdev); dev_set_drvdata(dev, NULL); @@ -54,6 +60,10 @@ static int komeda_bind(struct device *dev) goto free_mdrv; } + pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) + komeda_dev_resume(mdrv->mdev); + mdrv->kms = komeda_kms_attach(mdrv->mdev); if (IS_ERR(mdrv->kms)) { err = PTR_ERR(mdrv->kms); @@ -65,6 +75,11 @@ static int komeda_bind(struct device *dev) return 0; destroy_mdev: + if (pm_runtime_enabled(dev)) + pm_runtime_disable(dev); + else + komeda_dev_suspend(mdrv->mdev); + komeda_dev_destroy(mdrv->mdev); free_mdrv: @@ -123,29 +138,37 @@ static int komeda_platform_remove(struct platform_device *pdev) return 0; } -static const struct komeda_product_data komeda_products[] = { - [MALI_D71] = { - .product_id = MALIDP_D71_PRODUCT_ID, - .identify = d71_identify, - }, -}; - static const struct of_device_id komeda_of_match[] = { - { .compatible = "arm,mali-d71", .data = &komeda_products[MALI_D71], }, + { .compatible = "arm,mali-d71", .data = d71_identify, }, + { .compatible = "arm,mali-d32", .data = d71_identify, }, {}, }; MODULE_DEVICE_TABLE(of, komeda_of_match); +static int komeda_rt_pm_suspend(struct device *dev) +{ + struct komeda_drv *mdrv = dev_get_drvdata(dev); + + return komeda_dev_suspend(mdrv->mdev); +} + +static int komeda_rt_pm_resume(struct device *dev) +{ + struct komeda_drv *mdrv = dev_get_drvdata(dev); + + return komeda_dev_resume(mdrv->mdev); +} + static int __maybe_unused komeda_pm_suspend(struct device *dev) { struct komeda_drv *mdrv = dev_get_drvdata(dev); - struct drm_device *drm = &mdrv->kms->base; int res; - res = drm_mode_config_helper_suspend(drm); + res = drm_mode_config_helper_suspend(&mdrv->kms->base); - komeda_dev_suspend(mdrv->mdev); + if (!pm_runtime_status_suspended(dev)) + komeda_dev_suspend(mdrv->mdev); return res; } @@ -153,15 +176,16 @@ static int __maybe_unused komeda_pm_suspend(struct device *dev) static int __maybe_unused komeda_pm_resume(struct device *dev) { struct komeda_drv *mdrv = dev_get_drvdata(dev); - struct drm_device *drm = &mdrv->kms->base; - komeda_dev_resume(mdrv->mdev); + if (!pm_runtime_status_suspended(dev)) + komeda_dev_resume(mdrv->mdev); - return drm_mode_config_helper_resume(drm); + return drm_mode_config_helper_resume(&mdrv->kms->base); } static const struct dev_pm_ops komeda_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(komeda_pm_suspend, komeda_pm_resume) + SET_RUNTIME_PM_OPS(komeda_rt_pm_suspend, komeda_rt_pm_resume, NULL) }; static struct platform_driver komeda_platform_driver = { diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_event.c b/drivers/gpu/drm/arm/display/komeda/komeda_event.c index a36fb86cc054455f9d6773390923efc6a01e6148..53f944e66dfc75f5c53456d1629fea8288f35afb 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_event.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_event.c @@ -4,6 +4,7 @@ * Author: James.Qian.Wang * */ +#include #include #include "komeda_dev.h" @@ -16,6 +17,7 @@ struct komeda_str { /* return 0 on success, < 0 on no space. */ +__printf(2, 3) static int komeda_sprintf(struct komeda_str *str, const char *fmt, ...) { va_list args; @@ -76,6 +78,8 @@ static void evt_str(struct komeda_str *str, u64 events) /* LPU errors or events */ evt_sprintf(str, events & KOMEDA_EVENT_IBSY, "IBSY|"); + evt_sprintf(str, events & KOMEDA_EVENT_EMPTY, "EMPTY|"); + evt_sprintf(str, events & KOMEDA_EVENT_FULL, "FULL|"); evt_sprintf(str, events & KOMEDA_ERR_AXIE, "AXIE|"); evt_sprintf(str, events & KOMEDA_ERR_ACE0, "ACE0|"); evt_sprintf(str, events & KOMEDA_ERR_ACE1, "ACE1|"); @@ -107,20 +111,31 @@ static bool is_new_frame(struct komeda_events *a) (KOMEDA_EVENT_FLIP | KOMEDA_EVENT_EOW); } -void komeda_print_events(struct komeda_events *evts) +void komeda_print_events(struct komeda_events *evts, struct drm_device *dev) { - u64 print_evts = KOMEDA_ERR_EVENTS; + u64 print_evts = 0; static bool en_print = true; + struct komeda_dev *mdev = dev->dev_private; + u16 const err_verbosity = mdev->err_verbosity; + u64 evts_mask = evts->global | evts->pipes[0] | evts->pipes[1]; /* reduce the same msg print, only print the first evt for one frame */ if (evts->global || is_new_frame(evts)) en_print = true; - if (!en_print) + if (!(err_verbosity & KOMEDA_DEV_PRINT_DISABLE_RATELIMIT) && !en_print) return; - if ((evts->global | evts->pipes[0] | evts->pipes[1]) & print_evts) { + if (err_verbosity & KOMEDA_DEV_PRINT_ERR_EVENTS) + print_evts |= KOMEDA_ERR_EVENTS; + if (err_verbosity & KOMEDA_DEV_PRINT_WARN_EVENTS) + print_evts |= KOMEDA_WARN_EVENTS; + if (err_verbosity & KOMEDA_DEV_PRINT_INFO_EVENTS) + print_evts |= KOMEDA_INFO_EVENTS; + + if (evts_mask & print_evts) { char msg[256]; struct komeda_str str; + struct drm_printer p = drm_info_printer(dev->dev); str.str = msg; str.sz = sizeof(msg); @@ -134,6 +149,9 @@ void komeda_print_events(struct komeda_events *evts) evt_str(&str, evts->pipes[1]); DRM_ERROR("err detect: %s\n", msg); + if ((err_verbosity & KOMEDA_DEV_PRINT_DUMP_STATE_ON_EVENT) && + (evts_mask & (KOMEDA_ERR_EVENTS | KOMEDA_WARN_EVENTS))) + drm_state_dump(dev, &p); en_print = false; } diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c index 52648b4008bc3fb4ce448a777f6b661fe5156189..442d4656150ae664b8e1ebc3a511beec83505126 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c @@ -48,7 +48,7 @@ static irqreturn_t komeda_kms_irq_handler(int irq, void *data) memset(&evts, 0, sizeof(evts)); status = mdev->funcs->irq_handler(mdev, &evts); - komeda_print_events(&evts); + komeda_print_events(&evts, drm); /* Notify the crtc to handle the events */ for (i = 0; i < kms->n_crtcs; i++) @@ -308,10 +308,6 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev) if (err) goto free_component_binding; - err = mdev->funcs->enable_irq(mdev); - if (err) - goto free_component_binding; - drm->irq_enabled = true; drm_kms_helper_poll_init(drm); @@ -325,7 +321,6 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev) free_interrupts: drm_kms_helper_poll_fini(drm); drm->irq_enabled = false; - mdev->funcs->disable_irq(mdev); free_component_binding: component_unbind_all(mdev->dev, drm); cleanup_mode_config: @@ -347,7 +342,6 @@ void komeda_kms_detach(struct komeda_kms_dev *kms) drm_kms_helper_poll_fini(drm); drm_atomic_helper_shutdown(drm); drm->irq_enabled = false; - mdev->funcs->disable_irq(mdev); component_unbind_all(mdev->dev, drm); drm_mode_config_cleanup(drm); komeda_kms_cleanup_private_objs(kms); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h index bd6ca7c8703734600256dcaea96fe398e3ae96e6..ac8725e248537e5737d16cd36860401c42073500 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h @@ -11,6 +11,7 @@ #include #include #include "malidp_utils.h" +#include "komeda_color_mgmt.h" #define KOMEDA_MAX_PIPELINES 2 #define KOMEDA_PIPELINE_MAX_LAYERS 4 @@ -327,6 +328,8 @@ struct komeda_improc_state { struct komeda_component_state base; u8 color_format, color_depth; u16 hsize, vsize; + u32 fgamma_coeffs[KOMEDA_N_GAMMA_COEFFS]; + u32 ctm_coeffs[KOMEDA_N_CTM_COEFFS]; }; /* display timing controller */ diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c index 52750116aa19b7e640a2ffd7d047d5fe32421b38..8f32ae7c25d069a69a5686d565a97872c4619772 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c @@ -802,6 +802,12 @@ komeda_improc_validate(struct komeda_improc *improc, st->color_format = BIT(__ffs(avail_formats)); } + if (kcrtc_st->base.color_mgmt_changed) { + drm_lut_to_fgamma_coeffs(kcrtc_st->base.gamma_lut, + st->fgamma_coeffs); + drm_ctm_to_coeffs(kcrtc_st->base.ctm, st->ctm_coeffs); + } + komeda_component_add_input(&st->base, &dflow->input, 0); komeda_component_set_output(&dflow->input, &improc->base, 0); diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 3c70a53813bf2e9e2626c9c0e850392ef9e63cbc..37715cc6064e68805617eb6401f704cde7f07eb5 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -512,7 +512,7 @@ static int malidp_de_plane_check(struct drm_plane *plane, int i, ret; unsigned int block_w, block_h; - if (!state->crtc || !state->fb) + if (!state->crtc || WARN_ON(!state->fb)) return 0; fb = state->fb; diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c index 090cc0d699aef06caa9362367555f5720a7be45f..ac8a78bfda032006ba0731bb69b2b8bdb96c5720 100644 --- a/drivers/gpu/drm/armada/armada_fbdev.c +++ b/drivers/gpu/drm/armada/armada_fbdev.c @@ -16,7 +16,7 @@ #include "armada_fb.h" #include "armada_gem.h" -static /*const*/ struct fb_ops armada_fb_ops = { +static const struct fb_ops armada_fb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, .fb_fillrect = drm_fb_helper_cfb_fillrect, diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c index 93cf8b8bfcffa6a41e2b1ad66f21ef2affee8223..976685f2939e8d5a1fc866bc157b03e2997e5e30 100644 --- a/drivers/gpu/drm/armada/armada_gem.c +++ b/drivers/gpu/drm/armada/armada_gem.c @@ -461,16 +461,6 @@ static void armada_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach, kfree(sgt); } -static void *armada_gem_dmabuf_no_kmap(struct dma_buf *buf, unsigned long n) -{ - return NULL; -} - -static void -armada_gem_dmabuf_no_kunmap(struct dma_buf *buf, unsigned long n, void *addr) -{ -} - static int armada_gem_dmabuf_mmap(struct dma_buf *buf, struct vm_area_struct *vma) { @@ -481,8 +471,6 @@ static const struct dma_buf_ops armada_gem_prime_dmabuf_ops = { .map_dma_buf = armada_gem_prime_map_dma_buf, .unmap_dma_buf = armada_gem_prime_unmap_dma_buf, .release = drm_gem_dmabuf_release, - .map = armada_gem_dmabuf_no_kmap, - .unmap = armada_gem_dmabuf_no_kunmap, .mmap = armada_gem_dmabuf_mmap, }; diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 1f17794b0890974727df6731224375aea171e6d8..30aa73a5d9b723f3400e330c7e681487d67bd9aa 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include "ast_drv.h" @@ -86,9 +85,42 @@ 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 drm_device *dev; + int ret; + ast_kick_out_firmware_fb(pdev); - return drm_get_pci_dev(pdev, ent, &driver); + ret = pci_enable_device(pdev); + if (ret) + return ret; + + dev = drm_dev_alloc(&driver, &pdev->dev); + if (IS_ERR(dev)) { + ret = PTR_ERR(dev); + goto err_pci_disable_device; + } + + dev->pdev = pdev; + pci_set_drvdata(pdev, dev); + + ret = ast_driver_load(dev, ent->driver_data); + if (ret) + goto err_drm_dev_put; + + ret = drm_dev_register(dev, ent->driver_data); + if (ret) + goto err_ast_driver_unload; + + return 0; + +err_ast_driver_unload: + ast_driver_unload(dev); +err_drm_dev_put: + drm_dev_put(dev); +err_pci_disable_device: + pci_disable_device(pdev); + return ret; + } static void @@ -96,17 +128,19 @@ ast_pci_remove(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - drm_put_dev(dev); + drm_dev_unregister(dev); + ast_driver_unload(dev); + drm_dev_put(dev); } - - static int ast_drm_freeze(struct drm_device *dev) { - drm_kms_helper_poll_disable(dev); - pci_save_state(dev->pdev); - drm_fb_helper_set_suspend_unlocked(dev->fb_helper, true); + int error; + error = drm_mode_config_helper_suspend(dev); + if (error) + return error; + pci_save_state(dev->pdev); return 0; } @@ -114,11 +148,7 @@ static int ast_drm_thaw(struct drm_device *dev) { ast_post_gpu(dev); - drm_mode_config_reset(dev); - drm_helper_resume_force_mode(dev); - drm_fb_helper_set_suspend_unlocked(dev->fb_helper, false); - - return 0; + return drm_mode_config_helper_resume(dev); } static int ast_drm_resume(struct drm_device *dev) @@ -131,8 +161,6 @@ static int ast_drm_resume(struct drm_device *dev) ret = ast_drm_thaw(dev); if (ret) return ret; - - drm_kms_helper_poll_enable(dev); return 0; } @@ -150,6 +178,7 @@ static int ast_pm_suspend(struct device *dev) pci_set_power_state(pdev, PCI_D3hot); return 0; } + static int ast_pm_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); @@ -165,7 +194,6 @@ static int ast_pm_freeze(struct device *dev) if (!ddev || !ddev->dev_private) return -ENODEV; return ast_drm_freeze(ddev); - } static int ast_pm_thaw(struct device *dev) @@ -203,10 +231,9 @@ static struct pci_driver ast_pci_driver = { DEFINE_DRM_GEM_FOPS(ast_fops); static struct drm_driver driver = { - .driver_features = DRIVER_MODESET | DRIVER_GEM, - - .load = ast_driver_load, - .unload = ast_driver_unload, + .driver_features = DRIVER_ATOMIC | + DRIVER_GEM | + DRIVER_MODESET, .fops = &ast_fops, .name = DRIVER_NAME, diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index ff161bd622f3c696efae487c0e801afabd93e42a..f5d8780776ae9ee3331c07d23755d6df94930fc1 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -121,6 +121,9 @@ struct ast_private { unsigned int next_index; } cursor; + struct drm_plane primary_plane; + struct drm_plane cursor_plane; + bool support_wide_screen; enum { ast_use_p2a, @@ -137,8 +140,6 @@ struct ast_private { int ast_driver_load(struct drm_device *dev, unsigned long flags); void ast_driver_unload(struct drm_device *dev); -struct ast_gem_object; - #define AST_IO_AR_PORT_WRITE (0x40) #define AST_IO_MISC_PORT_WRITE (0x42) #define AST_IO_VGA_ENABLE_PORT (0x43) @@ -280,6 +281,17 @@ struct ast_vbios_mode_info { const struct ast_vbios_enhtable *enh_table; }; +struct ast_crtc_state { + struct drm_crtc_state base; + + /* Last known format of primary plane */ + const struct drm_format_info *format; + + struct ast_vbios_mode_info vbios_mode_info; +}; + +#define to_ast_crtc_state(state) container_of(state, struct ast_crtc_state, base) + extern int ast_mode_init(struct drm_device *dev); extern void ast_mode_fini(struct drm_device *dev); @@ -289,10 +301,6 @@ extern void ast_mode_fini(struct drm_device *dev); int ast_mm_init(struct ast_private *ast); void ast_mm_fini(struct ast_private *ast); -int ast_gem_create(struct drm_device *dev, - u32 size, bool iskernel, - struct drm_gem_object **obj); - /* ast post */ void ast_enable_vga(struct drm_device *dev); void ast_enable_mmio(struct drm_device *dev); diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 21715d6a9b56027e704ec380964fccdbb374816e..b79f484e9bd28dda977955f67c8ee5488a89a385 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -28,6 +28,7 @@ #include +#include #include #include #include @@ -387,8 +388,33 @@ static int ast_get_dram_info(struct drm_device *dev) return 0; } +enum drm_mode_status ast_mode_config_mode_valid(struct drm_device *dev, + const struct drm_display_mode *mode) +{ + static const unsigned long max_bpp = 4; /* DRM_FORMAT_XRGBA8888 */ + + struct ast_private *ast = dev->dev_private; + unsigned long fbsize, fbpages, max_fbpages; + + /* To support double buffering, a framebuffer may not + * consume more than half of the available VRAM. + */ + max_fbpages = (ast->vram_size / 2) >> PAGE_SHIFT; + + fbsize = mode->hdisplay * mode->vdisplay * max_bpp; + fbpages = DIV_ROUND_UP(fbsize, PAGE_SIZE); + + if (fbpages > max_fbpages) + return MODE_MEM; + + return MODE_OK; +} + static const struct drm_mode_config_funcs ast_mode_funcs = { - .fb_create = drm_gem_fb_create + .fb_create = drm_gem_fb_create, + .mode_valid = ast_mode_config_mode_valid, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, }; static u32 ast_get_vram_info(struct drm_device *dev) @@ -506,6 +532,8 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags) if (ret) goto out_free; + drm_mode_config_reset(dev); + ret = drm_fbdev_generic_setup(dev, 32); if (ret) goto out_free; @@ -535,27 +563,3 @@ void ast_driver_unload(struct drm_device *dev) pci_iounmap(dev->pdev, ast->regs); kfree(ast); } - -int ast_gem_create(struct drm_device *dev, - u32 size, bool iskernel, - struct drm_gem_object **obj) -{ - struct drm_gem_vram_object *gbo; - int ret; - - *obj = NULL; - - size = roundup(size, PAGE_SIZE); - if (size == 0) - return -EINVAL; - - gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev, size, 0, false); - if (IS_ERR(gbo)) { - ret = PTR_ERR(gbo); - if (ret != -ERESTARTSYS) - DRM_ERROR("failed to allocate GEM object\n"); - return ret; - } - *obj = &gbo->bo.base; - return 0; -} diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index b13eaa2619abefac656b81c55c212ce8965a5124..34608f0499eb41077d9b60b1d133a89b72fd597c 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -31,6 +31,9 @@ #include #include +#include +#include +#include #include #include #include @@ -43,11 +46,14 @@ static struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev); static void ast_i2c_destroy(struct ast_i2c_chan *i2c); -static int ast_cursor_set(struct drm_crtc *crtc, - struct drm_file *file_priv, - uint32_t handle, - uint32_t width, - uint32_t height); +static int ast_cursor_move(struct drm_crtc *crtc, + int x, int y); + + +static u32 copy_cursor_image(u8 *src, u8 *dst, int width, int height); +static int ast_cursor_update(void *dst, void *src, unsigned int width, + unsigned int height); +static void ast_cursor_set_base(struct ast_private *ast, u64 address); static int ast_cursor_move(struct drm_crtc *crtc, int x, int y); @@ -65,9 +71,8 @@ static inline void ast_load_palette_index(struct ast_private *ast, ast_io_read8(ast, AST_IO_SEQ_PORT); } -static void ast_crtc_load_lut(struct drm_crtc *crtc) +static void ast_crtc_load_lut(struct ast_private *ast, struct drm_crtc *crtc) { - struct ast_private *ast = crtc->dev->dev_private; u16 *r, *g, *b; int i; @@ -82,36 +87,32 @@ static void ast_crtc_load_lut(struct drm_crtc *crtc) ast_load_palette_index(ast, i, *r++ >> 8, *g++ >> 8, *b++ >> 8); } -static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mode *mode, +static bool ast_get_vbios_mode_info(const struct drm_format_info *format, + const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, struct ast_vbios_mode_info *vbios_mode) { - struct ast_private *ast = crtc->dev->dev_private; - const struct drm_framebuffer *fb = crtc->primary->fb; - u32 refresh_rate_index = 0, mode_id, color_index, refresh_rate; + u32 refresh_rate_index = 0, refresh_rate; const struct ast_vbios_enhtable *best = NULL; u32 hborder, vborder; bool check_sync; - switch (fb->format->cpp[0] * 8) { + switch (format->cpp[0] * 8) { case 8: vbios_mode->std_table = &vbios_stdtable[VGAModeIndex]; - color_index = VGAModeIndex - 1; break; case 16: vbios_mode->std_table = &vbios_stdtable[HiCModeIndex]; - color_index = HiCModeIndex; break; case 24: case 32: vbios_mode->std_table = &vbios_stdtable[TrueCModeIndex]; - color_index = TrueCModeIndex; break; default: return false; } - switch (crtc->mode.crtc_hdisplay) { + switch (mode->crtc_hdisplay) { case 640: vbios_mode->enh_table = &res_640x480[refresh_rate_index]; break; @@ -122,7 +123,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo vbios_mode->enh_table = &res_1024x768[refresh_rate_index]; break; case 1280: - if (crtc->mode.crtc_vdisplay == 800) + if (mode->crtc_vdisplay == 800) vbios_mode->enh_table = &res_1280x800[refresh_rate_index]; else vbios_mode->enh_table = &res_1280x1024[refresh_rate_index]; @@ -134,7 +135,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo vbios_mode->enh_table = &res_1440x900[refresh_rate_index]; break; case 1600: - if (crtc->mode.crtc_vdisplay == 900) + if (mode->crtc_vdisplay == 900) vbios_mode->enh_table = &res_1600x900[refresh_rate_index]; else vbios_mode->enh_table = &res_1600x1200[refresh_rate_index]; @@ -143,7 +144,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo vbios_mode->enh_table = &res_1680x1050[refresh_rate_index]; break; case 1920: - if (crtc->mode.crtc_vdisplay == 1080) + if (mode->crtc_vdisplay == 1080) vbios_mode->enh_table = &res_1920x1080[refresh_rate_index]; else vbios_mode->enh_table = &res_1920x1200[refresh_rate_index]; @@ -154,7 +155,8 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo refresh_rate = drm_mode_vrefresh(mode); check_sync = vbios_mode->enh_table->flags & WideScreenMode; - do { + + while (1) { const struct ast_vbios_enhtable *loop = vbios_mode->enh_table; while (loop->refresh_rate != 0xff) { @@ -178,7 +180,8 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo if (best || !check_sync) break; check_sync = 0; - } while (1); + } + if (best) vbios_mode->enh_table = best; @@ -203,38 +206,67 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo vbios_mode->enh_table->vfp + vbios_mode->enh_table->vsync); - refresh_rate_index = vbios_mode->enh_table->refresh_rate_index; - mode_id = vbios_mode->enh_table->mode_id; + return true; +} - if (ast->chip == AST1180) { - /* TODO 1180 */ - } else { - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8c, (u8)((color_index & 0xf) << 4)); - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8d, refresh_rate_index & 0xff); - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff); - - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0x00); - if (vbios_mode->enh_table->flags & NewModeInfo) { - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8); - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, - fb->format->cpp[0] * 8); - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000); - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay); - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8); - - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x96, adjusted_mode->crtc_vdisplay); - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x97, adjusted_mode->crtc_vdisplay >> 8); - } +static void ast_set_vbios_color_reg(struct ast_private *ast, + const struct drm_format_info *format, + const struct ast_vbios_mode_info *vbios_mode) +{ + u32 color_index; + + switch (format->cpp[0]) { + case 1: + color_index = VGAModeIndex - 1; + break; + case 2: + color_index = HiCModeIndex; + break; + case 3: + case 4: + color_index = TrueCModeIndex; + default: + return; } - return true; + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8c, (u8)((color_index & 0x0f) << 4)); + + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0x00); + + if (vbios_mode->enh_table->flags & NewModeInfo) { + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, format->cpp[0] * 8); + } +} + +static void ast_set_vbios_mode_reg(struct ast_private *ast, + const struct drm_display_mode *adjusted_mode, + const struct ast_vbios_mode_info *vbios_mode) +{ + u32 refresh_rate_index, mode_id; + + refresh_rate_index = vbios_mode->enh_table->refresh_rate_index; + mode_id = vbios_mode->enh_table->mode_id; + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8d, refresh_rate_index & 0xff); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0x00); + + if (vbios_mode->enh_table->flags & NewModeInfo) { + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x96, adjusted_mode->crtc_vdisplay); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x97, adjusted_mode->crtc_vdisplay >> 8); + } } -static void ast_set_std_reg(struct drm_crtc *crtc, struct drm_display_mode *mode, + +static void ast_set_std_reg(struct ast_private *ast, + struct drm_display_mode *mode, struct ast_vbios_mode_info *vbios_mode) { - struct ast_private *ast = crtc->dev->dev_private; const struct ast_vbios_stdtable *stdtable; u32 i; u8 jreg; @@ -244,18 +276,21 @@ static void ast_set_std_reg(struct drm_crtc *crtc, struct drm_display_mode *mode jreg = stdtable->misc; ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg); - /* Set SEQ */ + /* Set SEQ; except Screen Disable field */ ast_set_index_reg(ast, AST_IO_SEQ_PORT, 0x00, 0x03); - for (i = 0; i < 4; i++) { + ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x01, 0xdf, stdtable->seq[0]); + for (i = 1; i < 4; i++) { jreg = stdtable->seq[i]; - if (!i) - jreg |= 0x20; ast_set_index_reg(ast, AST_IO_SEQ_PORT, (i + 1) , jreg); } - /* Set CRTC */ + /* Set CRTC; except base address and offset */ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x00); - for (i = 0; i < 25; i++) + for (i = 0; i < 12; i++) + ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, stdtable->crtc[i]); + for (i = 14; i < 19; i++) + ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, stdtable->crtc[i]); + for (i = 20; i < 25; i++) ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, stdtable->crtc[i]); /* set AR */ @@ -276,10 +311,10 @@ static void ast_set_std_reg(struct drm_crtc *crtc, struct drm_display_mode *mode ast_set_index_reg(ast, AST_IO_GR_PORT, i, stdtable->gr[i]); } -static void ast_set_crtc_reg(struct drm_crtc *crtc, struct drm_display_mode *mode, +static void ast_set_crtc_reg(struct ast_private *ast, + struct drm_display_mode *mode, struct ast_vbios_mode_info *vbios_mode) { - struct ast_private *ast = crtc->dev->dev_private; u8 jreg05 = 0, jreg07 = 0, jreg09 = 0, jregAC = 0, jregAD = 0, jregAE = 0; u16 temp, precache = 0; @@ -385,11 +420,9 @@ static void ast_set_crtc_reg(struct drm_crtc *crtc, struct drm_display_mode *mod ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x80); } -static void ast_set_offset_reg(struct drm_crtc *crtc) +static void ast_set_offset_reg(struct ast_private *ast, + struct drm_framebuffer *fb) { - struct ast_private *ast = crtc->dev->dev_private; - const struct drm_framebuffer *fb = crtc->primary->fb; - u16 offset; offset = fb->pitches[0] >> 3; @@ -397,10 +430,10 @@ static void ast_set_offset_reg(struct drm_crtc *crtc) ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xb0, (offset >> 8) & 0x3f); } -static void ast_set_dclk_reg(struct drm_device *dev, struct drm_display_mode *mode, +static void ast_set_dclk_reg(struct ast_private *ast, + struct drm_display_mode *mode, struct ast_vbios_mode_info *vbios_mode) { - struct ast_private *ast = dev->dev_private; const struct ast_vbios_dclk_info *clk_info; if (ast->chip == AST2500) @@ -415,14 +448,12 @@ static void ast_set_dclk_reg(struct drm_device *dev, struct drm_display_mode *mo ((clk_info->param3 & 0x3) << 4)); } -static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode, - struct ast_vbios_mode_info *vbios_mode) +static void ast_set_color_reg(struct ast_private *ast, + const struct drm_format_info *format) { - struct ast_private *ast = crtc->dev->dev_private; - const struct drm_framebuffer *fb = crtc->primary->fb; u8 jregA0 = 0, jregA3 = 0, jregA8 = 0; - switch (fb->format->cpp[0] * 8) { + switch (format->cpp[0] * 8) { case 8: jregA0 = 0x70; jregA3 = 0x01; @@ -444,7 +475,10 @@ static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa0, 0x8f, jregA0); ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xf0, jregA3); ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa8, 0xfd, jregA8); +} +static void ast_set_crtthd_reg(struct ast_private *ast) +{ /* Set Threshold */ if (ast->chip == AST2300 || ast->chip == AST2400 || ast->chip == AST2500) { @@ -462,10 +496,10 @@ static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode } } -static void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mode, - struct ast_vbios_mode_info *vbios_mode) +static void ast_set_sync_reg(struct ast_private *ast, + struct drm_display_mode *mode, + struct ast_vbios_mode_info *vbios_mode) { - struct ast_private *ast = dev->dev_private; u8 jreg; jreg = ast_io_read8(ast, AST_IO_MISC_PORT_READ); @@ -475,23 +509,9 @@ static void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mo ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg); } -static bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode, - struct ast_vbios_mode_info *vbios_mode) -{ - const struct drm_framebuffer *fb = crtc->primary->fb; - - switch (fb->format->cpp[0] * 8) { - case 8: - break; - default: - return false; - } - return true; -} - -static void ast_set_start_address_crt1(struct drm_crtc *crtc, unsigned offset) +static void ast_set_start_address_crt1(struct ast_private *ast, + unsigned offset) { - struct ast_private *ast = crtc->dev->dev_private; u32 addr; addr = offset >> 2; @@ -501,6 +521,247 @@ static void ast_set_start_address_crt1(struct drm_crtc *crtc, unsigned offset) } +/* + * Primary plane + */ + +static const uint32_t ast_primary_plane_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB565, + DRM_FORMAT_C8, +}; + +static int ast_primary_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct drm_crtc_state *crtc_state; + struct ast_crtc_state *ast_crtc_state; + int ret; + + if (!state->crtc) + return 0; + + crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc); + + ret = drm_atomic_helper_check_plane_state(state, crtc_state, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + false, true); + if (ret) + return ret; + + if (!state->visible) + return 0; + + ast_crtc_state = to_ast_crtc_state(crtc_state); + + ast_crtc_state->format = state->fb->format; + + return 0; +} + +void ast_primary_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct ast_private *ast = plane->dev->dev_private; + struct drm_plane_state *state = plane->state; + struct drm_gem_vram_object *gbo; + s64 gpu_addr; + + gbo = drm_gem_vram_of_gem(state->fb->obj[0]); + gpu_addr = drm_gem_vram_offset(gbo); + if (WARN_ON_ONCE(gpu_addr < 0)) + return; /* Bug: we didn't pin the BO to VRAM in prepare_fb. */ + + ast_set_offset_reg(ast, state->fb); + ast_set_start_address_crt1(ast, (u32)gpu_addr); + + ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x00); +} + +static void +ast_primary_plane_helper_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct ast_private *ast = plane->dev->dev_private; + + ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x20); +} + +static const struct drm_plane_helper_funcs ast_primary_plane_helper_funcs = { + .prepare_fb = drm_gem_vram_plane_helper_prepare_fb, + .cleanup_fb = drm_gem_vram_plane_helper_cleanup_fb, + .atomic_check = ast_primary_plane_helper_atomic_check, + .atomic_update = ast_primary_plane_helper_atomic_update, + .atomic_disable = ast_primary_plane_helper_atomic_disable, +}; + +static const struct drm_plane_funcs ast_primary_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, +}; + +/* + * Cursor plane + */ + +static const uint32_t ast_cursor_plane_formats[] = { + DRM_FORMAT_ARGB8888, +}; + +static int +ast_cursor_plane_helper_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *new_state) +{ + struct drm_framebuffer *fb = new_state->fb; + struct drm_crtc *crtc = new_state->crtc; + struct drm_gem_vram_object *gbo; + struct ast_private *ast; + int ret; + void *src, *dst; + + if (!crtc || !fb) + return 0; + + if (WARN_ON_ONCE(fb->width > AST_MAX_HWC_WIDTH) || + WARN_ON_ONCE(fb->height > AST_MAX_HWC_HEIGHT)) + return -EINVAL; /* BUG: didn't test in atomic_check() */ + + ast = crtc->dev->dev_private; + + gbo = drm_gem_vram_of_gem(fb->obj[0]); + src = drm_gem_vram_vmap(gbo); + if (IS_ERR(src)) { + ret = PTR_ERR(src); + goto err_drm_gem_vram_unpin; + } + + dst = drm_gem_vram_vmap(ast->cursor.gbo[ast->cursor.next_index]); + if (IS_ERR(dst)) { + ret = PTR_ERR(dst); + goto err_drm_gem_vram_vunmap_src; + } + + ret = ast_cursor_update(dst, src, fb->width, fb->height); + if (ret) + goto err_drm_gem_vram_vunmap_dst; + + /* Always unmap buffers here. Destination buffers are + * perma-pinned while the driver is active. We're only + * changing ref-counters here. + */ + drm_gem_vram_vunmap(ast->cursor.gbo[ast->cursor.next_index], dst); + drm_gem_vram_vunmap(gbo, src); + + return 0; + +err_drm_gem_vram_vunmap_dst: + drm_gem_vram_vunmap(ast->cursor.gbo[ast->cursor.next_index], dst); +err_drm_gem_vram_vunmap_src: + drm_gem_vram_vunmap(gbo, src); +err_drm_gem_vram_unpin: + drm_gem_vram_unpin(gbo); + return ret; +} + +static int ast_cursor_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct drm_framebuffer *fb = state->fb; + struct drm_crtc_state *crtc_state; + int ret; + + if (!state->crtc) + return 0; + + crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc); + + ret = drm_atomic_helper_check_plane_state(state, crtc_state, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + true, true); + if (ret) + return ret; + + if (!state->visible) + return 0; + + if (fb->width > AST_MAX_HWC_WIDTH || fb->height > AST_MAX_HWC_HEIGHT) + return -EINVAL; + + return 0; +} + +static void +ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct drm_plane_state *state = plane->state; + struct drm_crtc *crtc = state->crtc; + struct drm_framebuffer *fb = state->fb; + struct ast_private *ast = plane->dev->dev_private; + struct ast_crtc *ast_crtc = to_ast_crtc(crtc); + struct drm_gem_vram_object *gbo; + s64 off; + u8 jreg; + + ast_crtc->offset_x = AST_MAX_HWC_WIDTH - fb->width; + ast_crtc->offset_y = AST_MAX_HWC_WIDTH - fb->height; + + if (state->fb != old_state->fb) { + /* A new cursor image was installed. */ + gbo = ast->cursor.gbo[ast->cursor.next_index]; + off = drm_gem_vram_offset(gbo); + if (WARN_ON_ONCE(off < 0)) + return; /* Bug: we didn't pin cursor HW BO to VRAM. */ + ast_cursor_set_base(ast, off); + + ++ast->cursor.next_index; + ast->cursor.next_index %= ARRAY_SIZE(ast->cursor.gbo); + } + + ast_cursor_move(crtc, state->crtc_x, state->crtc_y); + + jreg = 0x2; + /* enable ARGB cursor */ + jreg |= 1; + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, jreg); +} + +static void +ast_cursor_plane_helper_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct ast_private *ast = plane->dev->dev_private; + + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, 0x00); +} + +static const struct drm_plane_helper_funcs ast_cursor_plane_helper_funcs = { + .prepare_fb = ast_cursor_plane_helper_prepare_fb, + .cleanup_fb = NULL, /* not required for cursor plane */ + .atomic_check = ast_cursor_plane_helper_atomic_check, + .atomic_update = ast_cursor_plane_helper_atomic_update, + .atomic_disable = ast_cursor_plane_helper_atomic_disable, +}; + +static const struct drm_plane_funcs ast_cursor_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, +}; + +/* + * CRTC + */ + static void ast_crtc_dpms(struct drm_crtc *crtc, int mode) { struct ast_private *ast = crtc->dev->dev_private; @@ -508,179 +769,196 @@ static void ast_crtc_dpms(struct drm_crtc *crtc, int mode) if (ast->chip == AST1180) return; + /* TODO: Maybe control display signal generation with + * Sync Enable (bit CR17.7). + */ switch (mode) { case DRM_MODE_DPMS_ON: case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: - ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0); if (ast->tx_chip_type == AST_TX_DP501) ast_set_dp501_video_output(crtc->dev, 1); - ast_crtc_load_lut(crtc); + ast_crtc_load_lut(ast, crtc); break; case DRM_MODE_DPMS_OFF: if (ast->tx_chip_type == AST_TX_DP501) ast_set_dp501_video_output(crtc->dev, 0); - ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x20); break; } } -static int ast_crtc_do_set_base(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int x, int y, int atomic) +static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) { - struct drm_gem_vram_object *gbo; - int ret; - s64 gpu_addr; + struct ast_private *ast = crtc->dev->dev_private; + struct ast_crtc_state *ast_state; + const struct drm_format_info *format; + bool succ; - if (!atomic && fb) { - gbo = drm_gem_vram_of_gem(fb->obj[0]); - drm_gem_vram_unpin(gbo); + if (ast->chip == AST1180) { + DRM_ERROR("AST 1180 modesetting not supported\n"); + return -EINVAL; } - gbo = drm_gem_vram_of_gem(crtc->primary->fb->obj[0]); + ast_state = to_ast_crtc_state(state); - ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); - if (ret) - return ret; - gpu_addr = drm_gem_vram_offset(gbo); - if (gpu_addr < 0) { - ret = (int)gpu_addr; - goto err_drm_gem_vram_unpin; - } + format = ast_state->format; + if (!format) + return 0; - ast_set_offset_reg(crtc); - ast_set_start_address_crt1(crtc, (u32)gpu_addr); + succ = ast_get_vbios_mode_info(format, &state->mode, + &state->adjusted_mode, + &ast_state->vbios_mode_info); + if (!succ) + return -EINVAL; return 0; - -err_drm_gem_vram_unpin: - drm_gem_vram_unpin(gbo); - return ret; } -static int ast_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb) +static void ast_crtc_helper_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { - return ast_crtc_do_set_base(crtc, old_fb, x, y, 0); + struct ast_private *ast = crtc->dev->dev_private; + + ast_open_key(ast); } -static int ast_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, - int x, int y, - struct drm_framebuffer *old_fb) +static void ast_crtc_helper_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct drm_device *dev = crtc->dev; - struct ast_private *ast = crtc->dev->dev_private; - struct ast_vbios_mode_info vbios_mode; - bool ret; - if (ast->chip == AST1180) { - DRM_ERROR("AST 1180 modesetting not supported\n"); - return -EINVAL; - } + struct ast_private *ast = dev->dev_private; + struct ast_crtc_state *ast_state; + const struct drm_format_info *format; + struct ast_vbios_mode_info *vbios_mode_info; + struct drm_display_mode *adjusted_mode; - ret = ast_get_vbios_mode_info(crtc, mode, adjusted_mode, &vbios_mode); - if (ret == false) - return -EINVAL; - ast_open_key(ast); + crtc->state->no_vblank = true; - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x06); + ast_state = to_ast_crtc_state(crtc->state); - ast_set_std_reg(crtc, adjusted_mode, &vbios_mode); - ast_set_crtc_reg(crtc, adjusted_mode, &vbios_mode); - ast_set_offset_reg(crtc); - ast_set_dclk_reg(dev, adjusted_mode, &vbios_mode); - ast_set_ext_reg(crtc, adjusted_mode, &vbios_mode); - ast_set_sync_reg(dev, adjusted_mode, &vbios_mode); - ast_set_dac_reg(crtc, adjusted_mode, &vbios_mode); + format = ast_state->format; + if (!format) + return; - ast_crtc_mode_set_base(crtc, x, y, old_fb); + vbios_mode_info = &ast_state->vbios_mode_info; - return 0; -} + ast_set_color_reg(ast, format); + ast_set_vbios_color_reg(ast, format, vbios_mode_info); -static void ast_crtc_disable(struct drm_crtc *crtc) -{ - DRM_DEBUG_KMS("\n"); - ast_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); - if (crtc->primary->fb) { - struct drm_framebuffer *fb = crtc->primary->fb; - struct drm_gem_vram_object *gbo = - drm_gem_vram_of_gem(fb->obj[0]); + if (!crtc->state->mode_changed) + return; - drm_gem_vram_unpin(gbo); - } - crtc->primary->fb = NULL; + adjusted_mode = &crtc->state->adjusted_mode; + + ast_set_vbios_mode_reg(ast, adjusted_mode, vbios_mode_info); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x06); + ast_set_std_reg(ast, adjusted_mode, vbios_mode_info); + ast_set_crtc_reg(ast, adjusted_mode, vbios_mode_info); + ast_set_dclk_reg(ast, adjusted_mode, vbios_mode_info); + ast_set_crtthd_reg(ast); + ast_set_sync_reg(ast, adjusted_mode, vbios_mode_info); } -static void ast_crtc_prepare(struct drm_crtc *crtc) +static void +ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { - + ast_crtc_dpms(crtc, DRM_MODE_DPMS_ON); } -static void ast_crtc_commit(struct drm_crtc *crtc) +static void +ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { - struct ast_private *ast = crtc->dev->dev_private; - ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0); - ast_crtc_load_lut(crtc); + ast_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); } - static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = { - .dpms = ast_crtc_dpms, - .mode_set = ast_crtc_mode_set, - .mode_set_base = ast_crtc_mode_set_base, - .disable = ast_crtc_disable, - .prepare = ast_crtc_prepare, - .commit = ast_crtc_commit, - + .atomic_check = ast_crtc_helper_atomic_check, + .atomic_begin = ast_crtc_helper_atomic_begin, + .atomic_flush = ast_crtc_helper_atomic_flush, + .atomic_enable = ast_crtc_helper_atomic_enable, + .atomic_disable = ast_crtc_helper_atomic_disable, }; -static void ast_crtc_reset(struct drm_crtc *crtc) +static void ast_crtc_destroy(struct drm_crtc *crtc) { - + drm_crtc_cleanup(crtc); + kfree(crtc); } -static int ast_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size, - struct drm_modeset_acquire_ctx *ctx) +static struct drm_crtc_state * +ast_crtc_atomic_duplicate_state(struct drm_crtc *crtc) { - ast_crtc_load_lut(crtc); + struct ast_crtc_state *new_ast_state, *ast_state; - return 0; -} + if (WARN_ON(!crtc->state)) + return NULL; + new_ast_state = kmalloc(sizeof(*new_ast_state), GFP_KERNEL); + if (!new_ast_state) + return NULL; + __drm_atomic_helper_crtc_duplicate_state(crtc, &new_ast_state->base); -static void ast_crtc_destroy(struct drm_crtc *crtc) + ast_state = to_ast_crtc_state(crtc->state); + + new_ast_state->format = ast_state->format; + memcpy(&new_ast_state->vbios_mode_info, &ast_state->vbios_mode_info, + sizeof(new_ast_state->vbios_mode_info)); + + return &new_ast_state->base; +} + +static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) { - drm_crtc_cleanup(crtc); - kfree(crtc); + struct ast_crtc_state *ast_state = to_ast_crtc_state(state); + + __drm_atomic_helper_crtc_destroy_state(&ast_state->base); + kfree(ast_state); } static const struct drm_crtc_funcs ast_crtc_funcs = { - .cursor_set = ast_cursor_set, - .cursor_move = ast_cursor_move, - .reset = ast_crtc_reset, + .reset = drm_atomic_helper_crtc_reset, .set_config = drm_crtc_helper_set_config, - .gamma_set = ast_crtc_gamma_set, + .gamma_set = drm_atomic_helper_legacy_gamma_set, .destroy = ast_crtc_destroy, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = ast_crtc_atomic_duplicate_state, + .atomic_destroy_state = ast_crtc_atomic_destroy_state, }; static int ast_crtc_init(struct drm_device *dev) { + struct ast_private *ast = dev->dev_private; struct ast_crtc *crtc; + int ret; crtc = kzalloc(sizeof(struct ast_crtc), GFP_KERNEL); if (!crtc) return -ENOMEM; - drm_crtc_init(dev, &crtc->base, &ast_crtc_funcs); + ret = drm_crtc_init_with_planes(dev, &crtc->base, &ast->primary_plane, + &ast->cursor_plane, &ast_crtc_funcs, + NULL); + if (ret) + goto err_kfree; + drm_mode_crtc_set_gamma_size(&crtc->base, 256); drm_crtc_helper_add(&crtc->base, &ast_crtc_helper_funcs); return 0; + +err_kfree: + kfree(crtc); + return ret; } +/* + * Encoder + */ + static void ast_encoder_destroy(struct drm_encoder *encoder) { drm_encoder_cleanup(encoder); @@ -691,35 +969,6 @@ static const struct drm_encoder_funcs ast_enc_funcs = { .destroy = ast_encoder_destroy, }; -static void ast_encoder_dpms(struct drm_encoder *encoder, int mode) -{ - -} - -static void ast_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ -} - -static void ast_encoder_prepare(struct drm_encoder *encoder) -{ - -} - -static void ast_encoder_commit(struct drm_encoder *encoder) -{ - -} - - -static const struct drm_encoder_helper_funcs ast_enc_helper_funcs = { - .dpms = ast_encoder_dpms, - .prepare = ast_encoder_prepare, - .commit = ast_encoder_commit, - .mode_set = ast_encoder_mode_set, -}; - static int ast_encoder_init(struct drm_device *dev) { struct ast_encoder *ast_encoder; @@ -730,12 +979,15 @@ static int ast_encoder_init(struct drm_device *dev) drm_encoder_init(dev, &ast_encoder->base, &ast_enc_funcs, DRM_MODE_ENCODER_DAC, NULL); - drm_encoder_helper_add(&ast_encoder->base, &ast_enc_helper_funcs); ast_encoder->base.possible_crtcs = 1; return 0; } +/* + * Connector + */ + static int ast_get_modes(struct drm_connector *connector) { struct ast_connector *ast_connector = to_ast_connector(connector); @@ -834,14 +1086,16 @@ static void ast_connector_destroy(struct drm_connector *connector) } static const struct drm_connector_helper_funcs ast_connector_helper_funcs = { - .mode_valid = ast_mode_valid, .get_modes = ast_get_modes, + .mode_valid = ast_mode_valid, }; static const struct drm_connector_funcs ast_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .reset = drm_atomic_helper_connector_reset, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = ast_connector_destroy, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int ast_connector_init(struct drm_device *dev) @@ -890,8 +1144,7 @@ static int ast_cursor_init(struct drm_device *dev) size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE); for (i = 0; i < ARRAY_SIZE(ast->cursor.gbo); ++i) { - gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev, - size, 0, false); + gbo = drm_gem_vram_create(dev, size, 0); if (IS_ERR(gbo)) { ret = PTR_ERR(gbo); goto err_drm_gem_vram_put; @@ -934,10 +1187,39 @@ static void ast_cursor_fini(struct drm_device *dev) int ast_mode_init(struct drm_device *dev) { + struct ast_private *ast = dev->dev_private; + int ret; + + memset(&ast->primary_plane, 0, sizeof(ast->primary_plane)); + ret = drm_universal_plane_init(dev, &ast->primary_plane, 0x01, + &ast_primary_plane_funcs, + ast_primary_plane_formats, + ARRAY_SIZE(ast_primary_plane_formats), + NULL, DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) { + DRM_ERROR("ast: drm_universal_plane_init() failed: %d\n", ret); + return ret; + } + drm_plane_helper_add(&ast->primary_plane, + &ast_primary_plane_helper_funcs); + + ret = drm_universal_plane_init(dev, &ast->cursor_plane, 0x01, + &ast_cursor_plane_funcs, + ast_cursor_plane_formats, + ARRAY_SIZE(ast_cursor_plane_formats), + NULL, DRM_PLANE_TYPE_CURSOR, NULL); + if (ret) { + DRM_ERROR("drm_universal_plane_failed(): %d\n", ret); + return ret; + } + drm_plane_helper_add(&ast->cursor_plane, + &ast_cursor_plane_helper_funcs); + ast_cursor_init(dev); ast_crtc_init(dev); ast_encoder_init(dev); ast_connector_init(dev); + return 0; } @@ -1153,106 +1435,6 @@ static void ast_cursor_set_base(struct ast_private *ast, u64 address) ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xca, addr2); } -static int ast_show_cursor(struct drm_crtc *crtc, void *src, - unsigned int width, unsigned int height) -{ - struct ast_private *ast = crtc->dev->dev_private; - struct ast_crtc *ast_crtc = to_ast_crtc(crtc); - struct drm_gem_vram_object *gbo; - void *dst; - s64 off; - int ret; - u8 jreg; - - gbo = ast->cursor.gbo[ast->cursor.next_index]; - dst = drm_gem_vram_vmap(gbo); - if (IS_ERR(dst)) - return PTR_ERR(dst); - off = drm_gem_vram_offset(gbo); - if (off < 0) { - ret = (int)off; - goto err_drm_gem_vram_vunmap; - } - - ret = ast_cursor_update(dst, src, width, height); - if (ret) - goto err_drm_gem_vram_vunmap; - ast_cursor_set_base(ast, off); - - ast_crtc->offset_x = AST_MAX_HWC_WIDTH - width; - ast_crtc->offset_y = AST_MAX_HWC_WIDTH - height; - - jreg = 0x2; - /* enable ARGB cursor */ - jreg |= 1; - ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, jreg); - - ++ast->cursor.next_index; - ast->cursor.next_index %= ARRAY_SIZE(ast->cursor.gbo); - - drm_gem_vram_vunmap(gbo, dst); - - return 0; - -err_drm_gem_vram_vunmap: - drm_gem_vram_vunmap(gbo, dst); - return ret; -} - -static void ast_hide_cursor(struct drm_crtc *crtc) -{ - struct ast_private *ast = crtc->dev->dev_private; - - ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, 0x00); -} - -static int ast_cursor_set(struct drm_crtc *crtc, - struct drm_file *file_priv, - uint32_t handle, - uint32_t width, - uint32_t height) -{ - struct drm_gem_object *obj; - struct drm_gem_vram_object *gbo; - u8 *src; - int ret; - - if (!handle) { - ast_hide_cursor(crtc); - return 0; - } - - if (width > AST_MAX_HWC_WIDTH || height > AST_MAX_HWC_HEIGHT) - return -EINVAL; - - obj = drm_gem_object_lookup(file_priv, handle); - if (!obj) { - DRM_ERROR("Cannot find cursor object %x for crtc\n", handle); - return -ENOENT; - } - gbo = drm_gem_vram_of_gem(obj); - src = drm_gem_vram_vmap(gbo); - if (IS_ERR(src)) { - ret = PTR_ERR(src); - goto err_drm_gem_object_put_unlocked; - } - - ret = ast_show_cursor(crtc, src, width, height); - if (ret) - goto err_drm_gem_vram_vunmap; - - drm_gem_vram_vunmap(gbo, src); - drm_gem_object_put_unlocked(obj); - - return 0; - -err_drm_gem_vram_vunmap: - drm_gem_vram_vunmap(gbo, src); -err_drm_gem_object_put_unlocked: - drm_gem_object_put_unlocked(obj); - return ret; -} - static int ast_cursor_move(struct drm_crtc *crtc, int x, int y) { diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c index f2e73e6d46b8515bea140d8a9c74461b51aea2ea..10985134ce0badd32b75ac2f5a6a41b08a3a9406 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c @@ -73,7 +73,11 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c) unsigned long prate; unsigned int mask = ATMEL_HLCDC_CLKDIV_MASK | ATMEL_HLCDC_CLKPOL; unsigned int cfg = 0; - int div; + int div, ret; + + ret = clk_prepare_enable(crtc->dc->hlcdc->sys_clk); + if (ret) + return; vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay; vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end; @@ -95,14 +99,14 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c) (adj->crtc_hdisplay - 1) | ((adj->crtc_vdisplay - 1) << 16)); + prate = clk_get_rate(crtc->dc->hlcdc->sys_clk); + mode_rate = adj->crtc_clock * 1000; if (!crtc->dc->desc->fixed_clksrc) { + prate *= 2; cfg |= ATMEL_HLCDC_CLKSEL; mask |= ATMEL_HLCDC_CLKSEL; } - prate = 2 * clk_get_rate(crtc->dc->hlcdc->sys_clk); - mode_rate = adj->crtc_clock * 1000; - div = DIV_ROUND_UP(prate, mode_rate); if (div < 2) { div = 2; @@ -117,8 +121,8 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c) int div_low = prate / mode_rate; if (div_low >= 2 && - ((prate / div_low - mode_rate) < - 10 * (mode_rate - prate / div))) + (10 * (prate / div_low - mode_rate) < + (mode_rate - prate / div))) /* * At least 10 times better when using a higher * frequency than requested, instead of a lower. @@ -147,6 +151,8 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c) ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO | ATMEL_HLCDC_GUARDTIME_MASK | ATMEL_HLCDC_MODE_MASK, cfg); + + clk_disable_unprepare(crtc->dc->hlcdc->sys_clk); } static enum drm_mode_status diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 92640298ad41e14f912f15774e4ee6737eea6c0c..112aa5066ceedd687cec94d22b8c47712a9444aa 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -557,12 +557,6 @@ static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static struct drm_framebuffer *atmel_hlcdc_fb_create(struct drm_device *dev, - struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) -{ - return drm_gem_fb_create(dev, file_priv, mode_cmd); -} - struct atmel_hlcdc_dc_commit { struct work_struct work; struct drm_device *dev; @@ -657,7 +651,7 @@ error: } static const struct drm_mode_config_funcs mode_config_funcs = { - .fb_create = atmel_hlcdc_fb_create, + .fb_create = drm_gem_fb_create, .atomic_check = drm_atomic_helper_check, .atomic_commit = atmel_hlcdc_dc_atomic_commit, }; @@ -727,18 +721,10 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev) dc->hlcdc = dev_get_drvdata(dev->dev->parent); dev->dev_private = dc; - if (dc->desc->fixed_clksrc) { - ret = clk_prepare_enable(dc->hlcdc->sys_clk); - if (ret) { - dev_err(dev->dev, "failed to enable sys_clk\n"); - goto err_destroy_wq; - } - } - ret = clk_prepare_enable(dc->hlcdc->periph_clk); if (ret) { dev_err(dev->dev, "failed to enable periph_clk\n"); - goto err_sys_clk_disable; + goto err_destroy_wq; } pm_runtime_enable(dev->dev); @@ -774,9 +760,6 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev) err_periph_clk_disable: pm_runtime_disable(dev->dev); clk_disable_unprepare(dc->hlcdc->periph_clk); -err_sys_clk_disable: - if (dc->desc->fixed_clksrc) - clk_disable_unprepare(dc->hlcdc->sys_clk); err_destroy_wq: destroy_workqueue(dc->wq); @@ -801,8 +784,6 @@ static void atmel_hlcdc_dc_unload(struct drm_device *dev) pm_runtime_disable(dev->dev); clk_disable_unprepare(dc->hlcdc->periph_clk); - if (dc->desc->fixed_clksrc) - clk_disable_unprepare(dc->hlcdc->sys_clk); destroy_workqueue(dc->wq); } @@ -916,8 +897,6 @@ static int atmel_hlcdc_dc_drm_suspend(struct device *dev) regmap_read(regmap, ATMEL_HLCDC_IMR, &dc->suspend.imr); regmap_write(regmap, ATMEL_HLCDC_IDR, dc->suspend.imr); clk_disable_unprepare(dc->hlcdc->periph_clk); - if (dc->desc->fixed_clksrc) - clk_disable_unprepare(dc->hlcdc->sys_clk); return 0; } @@ -927,8 +906,6 @@ static int atmel_hlcdc_dc_drm_resume(struct device *dev) struct drm_device *drm_dev = dev_get_drvdata(dev); struct atmel_hlcdc_dc *dc = drm_dev->dev_private; - if (dc->desc->fixed_clksrc) - clk_prepare_enable(dc->hlcdc->sys_clk); clk_prepare_enable(dc->hlcdc->periph_clk); regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, dc->suspend.imr); diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index 034f202dfe8fa7734c4c6e306e18246baff4887b..40800ec5700a8a3ed87745e9f0d3e786d3e19779 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -604,7 +604,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, int ret; int i; - if (!state->base.crtc || !fb) + if (!state->base.crtc || WARN_ON(!fb)) return 0; crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc); diff --git a/drivers/gpu/drm/bochs/bochs_hw.c b/drivers/gpu/drm/bochs/bochs_hw.c index e567bdfa2ab8e52d2daa1881e788efa9b5ad1b37..b615b7dfdd9dab92d7149f5af7b671f774d9277e 100644 --- a/drivers/gpu/drm/bochs/bochs_hw.c +++ b/drivers/gpu/drm/bochs/bochs_hw.c @@ -255,7 +255,7 @@ void bochs_hw_setformat(struct bochs_device *bochs, DRM_ERROR("%s: Huh? Got framebuffer format 0x%x", __func__, format->format); break; - }; + } } void bochs_hw_setbase(struct bochs_device *bochs, diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 34362976cd6fd726e48b46aaf33b698aa8e95fb4..0b9ca58624550f439a2e9f2a677d1e6e98436ad0 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -16,16 +16,6 @@ config DRM_PANEL_BRIDGE menu "Display Interface Bridges" depends on DRM && DRM_BRIDGE -config DRM_ANALOGIX_ANX78XX - tristate "Analogix ANX78XX bridge" - select DRM_KMS_HELPER - select REGMAP_I2C - ---help--- - ANX78XX is an ultra-low power Full-HD SlimPort transmitter - designed for portable devices. The ANX78XX transforms - the HDMI output of an application processor to MyDP - or DisplayPort. - config DRM_CDNS_DSI tristate "Cadence DPI/DSI bridge" select DRM_KMS_HELPER @@ -45,14 +35,14 @@ config DRM_DUMB_VGA_DAC Support for non-programmable RGB to VGA DAC bridges, such as ADI ADV7123, TI THS8134 and THS8135 or passive resistor ladder DACs. -config DRM_LVDS_ENCODER - tristate "Transparent parallel to LVDS encoder support" +config DRM_LVDS_CODEC + tristate "Transparent LVDS encoders and decoders support" depends on OF select DRM_KMS_HELPER select DRM_PANEL_BRIDGE help - Support for transparent parallel to LVDS encoders that don't require - any configuration. + Support for transparent LVDS encoders and decoders that don't + require any configuration. config DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW tristate "MegaChips stdp4028-ge-b850v3-fw and stdp2690-ge-b850v3-fw" @@ -60,10 +50,10 @@ config DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW select DRM_KMS_HELPER select DRM_PANEL ---help--- - This is a driver for the display bridges of - GE B850v3 that convert dual channel LVDS - to DP++. This is used with the i.MX6 imx-ldb - driver. You are likely to say N here. + This is a driver for the display bridges of + GE B850v3 that convert dual channel LVDS + to DP++. This is used with the i.MX6 imx-ldb + driver. You are likely to say N here. config DRM_NXP_PTN3460 tristate "NXP PTN3460 DP/LVDS bridge" diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 4934fcf5a6f82a1cec7a016684c4b6ccefb0751b..cd16ce83027078017ec96f4ad2bf910c26278b39 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -1,8 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o -obj-$(CONFIG_DRM_LVDS_ENCODER) += lvds-encoder.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 obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o @@ -12,8 +11,9 @@ obj-$(CONFIG_DRM_SII9234) += sii9234.o obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o -obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/ obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/ obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o + +obj-y += analogix/ obj-y += synopsys/ diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.h b/drivers/gpu/drm/bridge/analogix-anx78xx.h deleted file mode 100644 index 55d6c21097403198176eb7a8983d863ed85b2d02..0000000000000000000000000000000000000000 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.h +++ /dev/null @@ -1,703 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright(c) 2016, Analogix Semiconductor. All rights reserved. - */ - -#ifndef __ANX78xx_H -#define __ANX78xx_H - -/***************************************************************/ -/* Register definitions for RX_PO */ -/***************************************************************/ - -/* - * System Control and Status - */ - -/* Software Reset Register 1 */ -#define SP_SOFTWARE_RESET1_REG 0x11 -#define SP_VIDEO_RST BIT(4) -#define SP_HDCP_MAN_RST BIT(2) -#define SP_TMDS_RST BIT(1) -#define SP_SW_MAN_RST BIT(0) - -/* System Status Register */ -#define SP_SYSTEM_STATUS_REG 0x14 -#define SP_TMDS_CLOCK_DET BIT(1) -#define SP_TMDS_DE_DET BIT(0) - -/* HDMI Status Register */ -#define SP_HDMI_STATUS_REG 0x15 -#define SP_HDMI_AUD_LAYOUT BIT(3) -#define SP_HDMI_DET BIT(0) -# define SP_DVI_MODE 0 -# define SP_HDMI_MODE 1 - -/* HDMI Mute Control Register */ -#define SP_HDMI_MUTE_CTRL_REG 0x16 -#define SP_AUD_MUTE BIT(1) -#define SP_VID_MUTE BIT(0) - -/* System Power Down Register 1 */ -#define SP_SYSTEM_POWER_DOWN1_REG 0x18 -#define SP_PWDN_CTRL BIT(0) - -/* - * Audio and Video Auto Control - */ - -/* Auto Audio and Video Control register */ -#define SP_AUDVID_CTRL_REG 0x20 -#define SP_AVC_OE BIT(7) -#define SP_AAC_OE BIT(6) -#define SP_AVC_EN BIT(1) -#define SP_AAC_EN BIT(0) - -/* Audio Exception Enable Registers */ -#define SP_AUD_EXCEPTION_ENABLE_BASE (0x24 - 1) -/* Bits for Audio Exception Enable Register 3 */ -#define SP_AEC_EN21 BIT(5) - -/* - * Interrupt - */ - -/* Interrupt Status Register 1 */ -#define SP_INT_STATUS1_REG 0x31 -/* Bits for Interrupt Status Register 1 */ -#define SP_HDMI_DVI BIT(7) -#define SP_CKDT_CHG BIT(6) -#define SP_SCDT_CHG BIT(5) -#define SP_PCLK_CHG BIT(4) -#define SP_PLL_UNLOCK BIT(3) -#define SP_CABLE_PLUG_CHG BIT(2) -#define SP_SET_MUTE BIT(1) -#define SP_SW_INTR BIT(0) -/* Bits for Interrupt Status Register 2 */ -#define SP_HDCP_ERR BIT(5) -#define SP_AUDIO_SAMPLE_CHG BIT(0) /* undocumented */ -/* Bits for Interrupt Status Register 3 */ -#define SP_AUD_MODE_CHG BIT(0) -/* Bits for Interrupt Status Register 5 */ -#define SP_AUDIO_RCV BIT(0) -/* Bits for Interrupt Status Register 6 */ -#define SP_INT_STATUS6_REG 0x36 -#define SP_CTS_RCV BIT(7) -#define SP_NEW_AUD_PKT BIT(4) -#define SP_NEW_AVI_PKT BIT(1) -#define SP_NEW_CP_PKT BIT(0) -/* Bits for Interrupt Status Register 7 */ -#define SP_NO_VSI BIT(7) -#define SP_NEW_VS BIT(4) - -/* Interrupt Mask 1 Status Registers */ -#define SP_INT_MASK1_REG 0x41 - -/* HDMI US TIMER Control Register */ -#define SP_HDMI_US_TIMER_CTRL_REG 0x49 -#define SP_MS_TIMER_MARGIN_10_8_MASK 0x07 - -/* - * TMDS Control - */ - -/* TMDS Control Registers */ -#define SP_TMDS_CTRL_BASE (0x50 - 1) -/* Bits for TMDS Control Register 7 */ -#define SP_PD_RT BIT(0) - -/* - * Video Control - */ - -/* Video Status Register */ -#define SP_VIDEO_STATUS_REG 0x70 -#define SP_COLOR_DEPTH_MASK 0xf0 -#define SP_COLOR_DEPTH_SHIFT 4 -# define SP_COLOR_DEPTH_MODE_LEGACY 0x00 -# define SP_COLOR_DEPTH_MODE_24BIT 0x04 -# define SP_COLOR_DEPTH_MODE_30BIT 0x05 -# define SP_COLOR_DEPTH_MODE_36BIT 0x06 -# define SP_COLOR_DEPTH_MODE_48BIT 0x07 - -/* Video Data Range Control Register */ -#define SP_VID_DATA_RANGE_CTRL_REG 0x83 -#define SP_R2Y_INPUT_LIMIT BIT(1) - -/* Pixel Clock High Resolution Counter Registers */ -#define SP_PCLK_HIGHRES_CNT_BASE (0x8c - 1) - -/* - * Audio Control - */ - -/* Number of Audio Channels Status Registers */ -#define SP_AUD_CH_STATUS_REG_NUM 6 - -/* Audio IN S/PDIF Channel Status Registers */ -#define SP_AUD_SPDIF_CH_STATUS_BASE 0xc7 - -/* Audio IN S/PDIF Channel Status Register 4 */ -#define SP_FS_FREQ_MASK 0x0f -# define SP_FS_FREQ_44100HZ 0x00 -# define SP_FS_FREQ_48000HZ 0x02 -# define SP_FS_FREQ_32000HZ 0x03 -# define SP_FS_FREQ_88200HZ 0x08 -# define SP_FS_FREQ_96000HZ 0x0a -# define SP_FS_FREQ_176400HZ 0x0c -# define SP_FS_FREQ_192000HZ 0x0e - -/* - * Micellaneous Control Block - */ - -/* CHIP Control Register */ -#define SP_CHIP_CTRL_REG 0xe3 -#define SP_MAN_HDMI5V_DET BIT(3) -#define SP_PLLLOCK_CKDT_EN BIT(2) -#define SP_ANALOG_CKDT_EN BIT(1) -#define SP_DIGITAL_CKDT_EN BIT(0) - -/* Packet Receiving Status Register */ -#define SP_PACKET_RECEIVING_STATUS_REG 0xf3 -#define SP_AVI_RCVD BIT(5) -#define SP_VSI_RCVD BIT(1) - -/***************************************************************/ -/* Register definitions for RX_P1 */ -/***************************************************************/ - -/* HDCP BCAPS Shadow Register */ -#define SP_HDCP_BCAPS_SHADOW_REG 0x2a -#define SP_BCAPS_REPEATER BIT(5) - -/* HDCP Status Register */ -#define SP_RX_HDCP_STATUS_REG 0x3f -#define SP_AUTH_EN BIT(4) - -/* - * InfoFrame and Control Packet Registers - */ - -/* AVI InfoFrame packet checksum */ -#define SP_AVI_INFOFRAME_CHECKSUM 0xa3 - -/* AVI InfoFrame Registers */ -#define SP_AVI_INFOFRAME_DATA_BASE 0xa4 - -#define SP_AVI_COLOR_F_MASK 0x60 -#define SP_AVI_COLOR_F_SHIFT 5 - -/* Audio InfoFrame Registers */ -#define SP_AUD_INFOFRAME_DATA_BASE 0xc4 -#define SP_AUD_INFOFRAME_LAYOUT_MASK 0x0f - -/* MPEG/HDMI Vendor Specific InfoFrame Packet type code */ -#define SP_MPEG_VS_INFOFRAME_TYPE_REG 0xe0 - -/* MPEG/HDMI Vendor Specific InfoFrame Packet length */ -#define SP_MPEG_VS_INFOFRAME_LEN_REG 0xe2 - -/* MPEG/HDMI Vendor Specific InfoFrame Packet version number */ -#define SP_MPEG_VS_INFOFRAME_VER_REG 0xe1 - -/* MPEG/HDMI Vendor Specific InfoFrame Packet content */ -#define SP_MPEG_VS_INFOFRAME_DATA_BASE 0xe4 - -/* General Control Packet Register */ -#define SP_GENERAL_CTRL_PACKET_REG 0x9f -#define SP_CLEAR_AVMUTE BIT(4) -#define SP_SET_AVMUTE BIT(0) - -/***************************************************************/ -/* Register definitions for TX_P0 */ -/***************************************************************/ - -/* HDCP Status Register */ -#define SP_TX_HDCP_STATUS_REG 0x00 -#define SP_AUTH_FAIL BIT(5) -#define SP_AUTHEN_PASS BIT(1) - -/* HDCP Control Register 0 */ -#define SP_HDCP_CTRL0_REG 0x01 -#define SP_RX_REPEATER BIT(6) -#define SP_RE_AUTH BIT(5) -#define SP_SW_AUTH_OK BIT(4) -#define SP_HARD_AUTH_EN BIT(3) -#define SP_HDCP_ENC_EN BIT(2) -#define SP_BKSV_SRM_PASS BIT(1) -#define SP_KSVLIST_VLD BIT(0) -/* HDCP Function Enabled */ -#define SP_HDCP_FUNCTION_ENABLED (BIT(0) | BIT(1) | BIT(2) | BIT(3)) - -/* HDCP Receiver BSTATUS Register 0 */ -#define SP_HDCP_RX_BSTATUS0_REG 0x1b -/* HDCP Receiver BSTATUS Register 1 */ -#define SP_HDCP_RX_BSTATUS1_REG 0x1c - -/* HDCP Embedded "Blue Screen" Content Registers */ -#define SP_HDCP_VID0_BLUE_SCREEN_REG 0x2c -#define SP_HDCP_VID1_BLUE_SCREEN_REG 0x2d -#define SP_HDCP_VID2_BLUE_SCREEN_REG 0x2e - -/* HDCP Wait R0 Timing Register */ -#define SP_HDCP_WAIT_R0_TIME_REG 0x40 - -/* HDCP Link Integrity Check Timer Register */ -#define SP_HDCP_LINK_CHECK_TIMER_REG 0x41 - -/* HDCP Repeater Ready Wait Timer Register */ -#define SP_HDCP_RPTR_RDY_WAIT_TIME_REG 0x42 - -/* HDCP Auto Timer Register */ -#define SP_HDCP_AUTO_TIMER_REG 0x51 - -/* HDCP Key Status Register */ -#define SP_HDCP_KEY_STATUS_REG 0x5e - -/* HDCP Key Command Register */ -#define SP_HDCP_KEY_COMMAND_REG 0x5f -#define SP_DISABLE_SYNC_HDCP BIT(2) - -/* OTP Memory Key Protection Registers */ -#define SP_OTP_KEY_PROTECT1_REG 0x60 -#define SP_OTP_KEY_PROTECT2_REG 0x61 -#define SP_OTP_KEY_PROTECT3_REG 0x62 -#define SP_OTP_PSW1 0xa2 -#define SP_OTP_PSW2 0x7e -#define SP_OTP_PSW3 0xc6 - -/* DP System Control Registers */ -#define SP_DP_SYSTEM_CTRL_BASE (0x80 - 1) -/* Bits for DP System Control Register 2 */ -#define SP_CHA_STA BIT(2) -/* Bits for DP System Control Register 3 */ -#define SP_HPD_STATUS BIT(6) -#define SP_STRM_VALID BIT(2) -/* Bits for DP System Control Register 4 */ -#define SP_ENHANCED_MODE BIT(3) - -/* DP Video Control Register */ -#define SP_DP_VIDEO_CTRL_REG 0x84 -#define SP_COLOR_F_MASK 0x06 -#define SP_COLOR_F_SHIFT 1 -#define SP_BPC_MASK 0xe0 -#define SP_BPC_SHIFT 5 -# define SP_BPC_6BITS 0x00 -# define SP_BPC_8BITS 0x01 -# define SP_BPC_10BITS 0x02 -# define SP_BPC_12BITS 0x03 - -/* DP Audio Control Register */ -#define SP_DP_AUDIO_CTRL_REG 0x87 -#define SP_AUD_EN BIT(0) - -/* 10us Pulse Generate Timer Registers */ -#define SP_I2C_GEN_10US_TIMER0_REG 0x88 -#define SP_I2C_GEN_10US_TIMER1_REG 0x89 - -/* Packet Send Control Register */ -#define SP_PACKET_SEND_CTRL_REG 0x90 -#define SP_AUD_IF_UP BIT(7) -#define SP_AVI_IF_UD BIT(6) -#define SP_MPEG_IF_UD BIT(5) -#define SP_SPD_IF_UD BIT(4) -#define SP_AUD_IF_EN BIT(3) -#define SP_AVI_IF_EN BIT(2) -#define SP_MPEG_IF_EN BIT(1) -#define SP_SPD_IF_EN BIT(0) - -/* DP HDCP Control Register */ -#define SP_DP_HDCP_CTRL_REG 0x92 -#define SP_AUTO_EN BIT(7) -#define SP_AUTO_START BIT(5) -#define SP_LINK_POLLING BIT(1) - -/* DP Main Link Bandwidth Setting Register */ -#define SP_DP_MAIN_LINK_BW_SET_REG 0xa0 -#define SP_LINK_BW_SET_MASK 0x1f -#define SP_INITIAL_SLIM_M_AUD_SEL BIT(5) - -/* DP Training Pattern Set Register */ -#define SP_DP_TRAINING_PATTERN_SET_REG 0xa2 - -/* DP Lane 0 Link Training Control Register */ -#define SP_DP_LANE0_LT_CTRL_REG 0xa3 -#define SP_TX_SW_SET_MASK 0x1b -#define SP_MAX_PRE_REACH BIT(5) -#define SP_MAX_DRIVE_REACH BIT(4) -#define SP_PRE_EMP_LEVEL1 BIT(3) -#define SP_DRVIE_CURRENT_LEVEL1 BIT(0) - -/* DP Link Training Control Register */ -#define SP_DP_LT_CTRL_REG 0xa8 -#define SP_LT_ERROR_TYPE_MASK 0x70 -# define SP_LT_NO_ERROR 0x00 -# define SP_LT_AUX_WRITE_ERROR 0x01 -# define SP_LT_MAX_DRIVE_REACHED 0x02 -# define SP_LT_WRONG_LANE_COUNT_SET 0x03 -# define SP_LT_LOOP_SAME_5_TIME 0x04 -# define SP_LT_CR_FAIL_IN_EQ 0x05 -# define SP_LT_EQ_LOOP_5_TIME 0x06 -#define SP_LT_EN BIT(0) - -/* DP CEP Training Control Registers */ -#define SP_DP_CEP_TRAINING_CTRL0_REG 0xa9 -#define SP_DP_CEP_TRAINING_CTRL1_REG 0xaa - -/* DP Debug Register 1 */ -#define SP_DP_DEBUG1_REG 0xb0 -#define SP_DEBUG_PLL_LOCK BIT(4) -#define SP_POLLING_EN BIT(1) - -/* DP Polling Control Register */ -#define SP_DP_POLLING_CTRL_REG 0xb4 -#define SP_AUTO_POLLING_DISABLE BIT(0) - -/* DP Link Debug Control Register */ -#define SP_DP_LINK_DEBUG_CTRL_REG 0xb8 -#define SP_M_VID_DEBUG BIT(5) -#define SP_NEW_PRBS7 BIT(4) -#define SP_INSERT_ER BIT(1) -#define SP_PRBS31_EN BIT(0) - -/* AUX Misc control Register */ -#define SP_AUX_MISC_CTRL_REG 0xbf - -/* DP PLL control Register */ -#define SP_DP_PLL_CTRL_REG 0xc7 -#define SP_PLL_RST BIT(6) - -/* DP Analog Power Down Register */ -#define SP_DP_ANALOG_POWER_DOWN_REG 0xc8 -#define SP_CH0_PD BIT(0) - -/* DP Misc Control Register */ -#define SP_DP_MISC_CTRL_REG 0xcd -#define SP_EQ_TRAINING_LOOP BIT(6) - -/* DP Extra I2C Device Address Register */ -#define SP_DP_EXTRA_I2C_DEV_ADDR_REG 0xce -#define SP_I2C_STRETCH_DISABLE BIT(7) - -#define SP_I2C_EXTRA_ADDR 0x50 - -/* DP Downspread Control Register 1 */ -#define SP_DP_DOWNSPREAD_CTRL1_REG 0xd0 - -/* DP M Value Calculation Control Register */ -#define SP_DP_M_CALCULATION_CTRL_REG 0xd9 -#define SP_M_GEN_CLK_SEL BIT(0) - -/* AUX Channel Access Status Register */ -#define SP_AUX_CH_STATUS_REG 0xe0 -#define SP_AUX_STATUS 0x0f - -/* AUX Channel DEFER Control Register */ -#define SP_AUX_DEFER_CTRL_REG 0xe2 -#define SP_DEFER_CTRL_EN BIT(7) - -/* DP Buffer Data Count Register */ -#define SP_BUF_DATA_COUNT_REG 0xe4 -#define SP_BUF_DATA_COUNT_MASK 0x1f -#define SP_BUF_CLR BIT(7) - -/* DP AUX Channel Control Register 1 */ -#define SP_DP_AUX_CH_CTRL1_REG 0xe5 -#define SP_AUX_TX_COMM_MASK 0x0f -#define SP_AUX_LENGTH_MASK 0xf0 -#define SP_AUX_LENGTH_SHIFT 4 - -/* DP AUX CH Address Register 0 */ -#define SP_AUX_ADDR_7_0_REG 0xe6 - -/* DP AUX CH Address Register 1 */ -#define SP_AUX_ADDR_15_8_REG 0xe7 - -/* DP AUX CH Address Register 2 */ -#define SP_AUX_ADDR_19_16_REG 0xe8 -#define SP_AUX_ADDR_19_16_MASK 0x0f - -/* DP AUX Channel Control Register 2 */ -#define SP_DP_AUX_CH_CTRL2_REG 0xe9 -#define SP_AUX_SEL_RXCM BIT(6) -#define SP_AUX_CHSEL BIT(3) -#define SP_AUX_PN_INV BIT(2) -#define SP_ADDR_ONLY BIT(1) -#define SP_AUX_EN BIT(0) - -/* DP Video Stream Control InfoFrame Register */ -#define SP_DP_3D_VSC_CTRL_REG 0xea -#define SP_INFO_FRAME_VSC_EN BIT(0) - -/* DP Video Stream Data Byte 1 Register */ -#define SP_DP_VSC_DB1_REG 0xeb - -/* DP AUX Channel Control Register 3 */ -#define SP_DP_AUX_CH_CTRL3_REG 0xec -#define SP_WAIT_COUNTER_7_0_MASK 0xff - -/* DP AUX Channel Control Register 4 */ -#define SP_DP_AUX_CH_CTRL4_REG 0xed - -/* DP AUX Buffer Data Registers */ -#define SP_DP_BUF_DATA0_REG 0xf0 - -/***************************************************************/ -/* Register definitions for TX_P2 */ -/***************************************************************/ - -/* - * Core Register Definitions - */ - -/* Device ID Low Byte Register */ -#define SP_DEVICE_IDL_REG 0x02 - -/* Device ID High Byte Register */ -#define SP_DEVICE_IDH_REG 0x03 - -/* Device version register */ -#define SP_DEVICE_VERSION_REG 0x04 - -/* Power Down Control Register */ -#define SP_POWERDOWN_CTRL_REG 0x05 -#define SP_REGISTER_PD BIT(7) -#define SP_HDCP_PD BIT(5) -#define SP_AUDIO_PD BIT(4) -#define SP_VIDEO_PD BIT(3) -#define SP_LINK_PD BIT(2) -#define SP_TOTAL_PD BIT(1) - -/* Reset Control Register 1 */ -#define SP_RESET_CTRL1_REG 0x06 -#define SP_MISC_RST BIT(7) -#define SP_VIDCAP_RST BIT(6) -#define SP_VIDFIF_RST BIT(5) -#define SP_AUDFIF_RST BIT(4) -#define SP_AUDCAP_RST BIT(3) -#define SP_HDCP_RST BIT(2) -#define SP_SW_RST BIT(1) -#define SP_HW_RST BIT(0) - -/* Reset Control Register 2 */ -#define SP_RESET_CTRL2_REG 0x07 -#define SP_AUX_RST BIT(2) -#define SP_SERDES_FIFO_RST BIT(1) -#define SP_I2C_REG_RST BIT(0) - -/* Video Control Register 1 */ -#define SP_VID_CTRL1_REG 0x08 -#define SP_VIDEO_EN BIT(7) -#define SP_VIDEO_MUTE BIT(2) -#define SP_DE_GEN BIT(1) -#define SP_DEMUX BIT(0) - -/* Video Control Register 2 */ -#define SP_VID_CTRL2_REG 0x09 -#define SP_IN_COLOR_F_MASK 0x03 -#define SP_IN_YC_BIT_SEL BIT(2) -#define SP_IN_BPC_MASK 0x70 -#define SP_IN_BPC_SHIFT 4 -# define SP_IN_BPC_12BIT 0x03 -# define SP_IN_BPC_10BIT 0x02 -# define SP_IN_BPC_8BIT 0x01 -# define SP_IN_BPC_6BIT 0x00 -#define SP_IN_D_RANGE BIT(7) - -/* Video Control Register 3 */ -#define SP_VID_CTRL3_REG 0x0a -#define SP_HPD_OUT BIT(6) - -/* Video Control Register 5 */ -#define SP_VID_CTRL5_REG 0x0c -#define SP_CSC_STD_SEL BIT(7) -#define SP_XVYCC_RNG_LMT BIT(6) -#define SP_RANGE_Y2R BIT(5) -#define SP_CSPACE_Y2R BIT(4) -#define SP_RGB_RNG_LMT BIT(3) -#define SP_Y_RNG_LMT BIT(2) -#define SP_RANGE_R2Y BIT(1) -#define SP_CSPACE_R2Y BIT(0) - -/* Video Control Register 6 */ -#define SP_VID_CTRL6_REG 0x0d -#define SP_TEST_PATTERN_EN BIT(7) -#define SP_VIDEO_PROCESS_EN BIT(6) -#define SP_VID_US_MODE BIT(3) -#define SP_VID_DS_MODE BIT(2) -#define SP_UP_SAMPLE BIT(1) -#define SP_DOWN_SAMPLE BIT(0) - -/* Video Control Register 8 */ -#define SP_VID_CTRL8_REG 0x0f -#define SP_VID_VRES_TH BIT(0) - -/* Total Line Status Low Byte Register */ -#define SP_TOTAL_LINE_STAL_REG 0x24 - -/* Total Line Status High Byte Register */ -#define SP_TOTAL_LINE_STAH_REG 0x25 - -/* Active Line Status Low Byte Register */ -#define SP_ACT_LINE_STAL_REG 0x26 - -/* Active Line Status High Byte Register */ -#define SP_ACT_LINE_STAH_REG 0x27 - -/* Vertical Front Porch Status Register */ -#define SP_V_F_PORCH_STA_REG 0x28 - -/* Vertical SYNC Width Status Register */ -#define SP_V_SYNC_STA_REG 0x29 - -/* Vertical Back Porch Status Register */ -#define SP_V_B_PORCH_STA_REG 0x2a - -/* Total Pixel Status Low Byte Register */ -#define SP_TOTAL_PIXEL_STAL_REG 0x2b - -/* Total Pixel Status High Byte Register */ -#define SP_TOTAL_PIXEL_STAH_REG 0x2c - -/* Active Pixel Status Low Byte Register */ -#define SP_ACT_PIXEL_STAL_REG 0x2d - -/* Active Pixel Status High Byte Register */ -#define SP_ACT_PIXEL_STAH_REG 0x2e - -/* Horizontal Front Porch Status Low Byte Register */ -#define SP_H_F_PORCH_STAL_REG 0x2f - -/* Horizontal Front Porch Statys High Byte Register */ -#define SP_H_F_PORCH_STAH_REG 0x30 - -/* Horizontal SYNC Width Status Low Byte Register */ -#define SP_H_SYNC_STAL_REG 0x31 - -/* Horizontal SYNC Width Status High Byte Register */ -#define SP_H_SYNC_STAH_REG 0x32 - -/* Horizontal Back Porch Status Low Byte Register */ -#define SP_H_B_PORCH_STAL_REG 0x33 - -/* Horizontal Back Porch Status High Byte Register */ -#define SP_H_B_PORCH_STAH_REG 0x34 - -/* InfoFrame AVI Packet DB1 Register */ -#define SP_INFOFRAME_AVI_DB1_REG 0x70 - -/* Bit Control Specific Register */ -#define SP_BIT_CTRL_SPECIFIC_REG 0x80 -#define SP_BIT_CTRL_SELECT_SHIFT 1 -#define SP_ENABLE_BIT_CTRL BIT(0) - -/* InfoFrame Audio Packet DB1 Register */ -#define SP_INFOFRAME_AUD_DB1_REG 0x83 - -/* InfoFrame MPEG Packet DB1 Register */ -#define SP_INFOFRAME_MPEG_DB1_REG 0xb0 - -/* Audio Channel Status Registers */ -#define SP_AUD_CH_STATUS_BASE 0xd0 - -/* Audio Channel Num Register 5 */ -#define SP_I2S_CHANNEL_NUM_MASK 0xe0 -# define SP_I2S_CH_NUM_1 (0x00 << 5) -# define SP_I2S_CH_NUM_2 (0x01 << 5) -# define SP_I2S_CH_NUM_3 (0x02 << 5) -# define SP_I2S_CH_NUM_4 (0x03 << 5) -# define SP_I2S_CH_NUM_5 (0x04 << 5) -# define SP_I2S_CH_NUM_6 (0x05 << 5) -# define SP_I2S_CH_NUM_7 (0x06 << 5) -# define SP_I2S_CH_NUM_8 (0x07 << 5) -#define SP_EXT_VUCP BIT(2) -#define SP_VBIT BIT(1) -#define SP_AUDIO_LAYOUT BIT(0) - -/* Analog Debug Register 2 */ -#define SP_ANALOG_DEBUG2_REG 0xdd -#define SP_FORCE_SW_OFF_BYPASS 0x20 -#define SP_XTAL_FRQ 0x1c -# define SP_XTAL_FRQ_19M2 (0x00 << 2) -# define SP_XTAL_FRQ_24M (0x01 << 2) -# define SP_XTAL_FRQ_25M (0x02 << 2) -# define SP_XTAL_FRQ_26M (0x03 << 2) -# define SP_XTAL_FRQ_27M (0x04 << 2) -# define SP_XTAL_FRQ_38M4 (0x05 << 2) -# define SP_XTAL_FRQ_52M (0x06 << 2) -#define SP_POWERON_TIME_1P5MS 0x03 - -/* Analog Control 0 Register */ -#define SP_ANALOG_CTRL0_REG 0xe1 - -/* Common Interrupt Status Register 1 */ -#define SP_COMMON_INT_STATUS_BASE (0xf1 - 1) -#define SP_PLL_LOCK_CHG 0x40 - -/* Common Interrupt Status Register 2 */ -#define SP_COMMON_INT_STATUS2 0xf2 -#define SP_HDCP_AUTH_CHG BIT(1) -#define SP_HDCP_AUTH_DONE BIT(0) - -#define SP_HDCP_LINK_CHECK_FAIL BIT(0) - -/* Common Interrupt Status Register 4 */ -#define SP_COMMON_INT_STATUS4_REG 0xf4 -#define SP_HPD_IRQ BIT(6) -#define SP_HPD_ESYNC_ERR BIT(4) -#define SP_HPD_CHG BIT(2) -#define SP_HPD_LOST BIT(1) -#define SP_HPD_PLUG BIT(0) - -/* DP Interrupt Status Register */ -#define SP_DP_INT_STATUS1_REG 0xf7 -#define SP_TRAINING_FINISH BIT(5) -#define SP_POLLING_ERR BIT(4) - -/* Common Interrupt Mask Register */ -#define SP_COMMON_INT_MASK_BASE (0xf8 - 1) - -#define SP_COMMON_INT_MASK4_REG 0xfb - -/* DP Interrupts Mask Register */ -#define SP_DP_INT_MASK1_REG 0xfe - -/* Interrupt Control Register */ -#define SP_INT_CTRL_REG 0xff - -/***************************************************************/ -/* Register definitions for TX_P1 */ -/***************************************************************/ - -/* DP TX Link Training Control Register */ -#define SP_DP_TX_LT_CTRL0_REG 0x30 - -/* PD 1.2 Lint Training 80bit Pattern Register */ -#define SP_DP_LT_80BIT_PATTERN0_REG 0x80 -#define SP_DP_LT_80BIT_PATTERN_REG_NUM 10 - -/* Audio Interface Control Register 0 */ -#define SP_AUD_INTERFACE_CTRL0_REG 0x5f -#define SP_AUD_INTERFACE_DISABLE 0x80 - -/* Audio Interface Control Register 2 */ -#define SP_AUD_INTERFACE_CTRL2_REG 0x60 -#define SP_M_AUD_ADJUST_ST 0x04 - -/* Audio Interface Control Register 3 */ -#define SP_AUD_INTERFACE_CTRL3_REG 0x62 - -/* Audio Interface Control Register 4 */ -#define SP_AUD_INTERFACE_CTRL4_REG 0x67 - -/* Audio Interface Control Register 5 */ -#define SP_AUD_INTERFACE_CTRL5_REG 0x68 - -/* Audio Interface Control Register 6 */ -#define SP_AUD_INTERFACE_CTRL6_REG 0x69 - -/* Firmware Version Register */ -#define SP_FW_VER_REG 0xb7 - -#endif diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig index e930ff9b5cd48496fada6930ce27cf6837170894..e1fa7d8203739317c42755255516ec1a08b2f9b6 100644 --- a/drivers/gpu/drm/bridge/analogix/Kconfig +++ b/drivers/gpu/drm/bridge/analogix/Kconfig @@ -1,4 +1,27 @@ # SPDX-License-Identifier: GPL-2.0-only +config DRM_ANALOGIX_ANX6345 + tristate "Analogix ANX6345 bridge" + depends on OF + select DRM_ANALOGIX_DP + select DRM_KMS_HELPER + select REGMAP_I2C + help + ANX6345 is an ultra-low Full-HD DisplayPort/eDP + transmitter designed for portable devices. The + ANX6345 transforms the LVTTL RGB output of an + application processor to eDP or DisplayPort. + +config DRM_ANALOGIX_ANX78XX + tristate "Analogix ANX78XX bridge" + select DRM_ANALOGIX_DP + select DRM_KMS_HELPER + select REGMAP_I2C + help + ANX78XX is an ultra-low power Full-HD SlimPort transmitter + designed for portable devices. The ANX78XX transforms + the HDMI output of an application processor to MyDP + or DisplayPort. + config DRM_ANALOGIX_DP tristate depends on DRM diff --git a/drivers/gpu/drm/bridge/analogix/Makefile b/drivers/gpu/drm/bridge/analogix/Makefile index fdbf3fd2f087a93ef7aa2a9abaa1e558087a7b58..97669b374098ceabbda5d22b95962f41bcfc833b 100644 --- a/drivers/gpu/drm/bridge/analogix/Makefile +++ b/drivers/gpu/drm/bridge/analogix/Makefile @@ -1,3 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -analogix_dp-objs := analogix_dp_core.o analogix_dp_reg.o +analogix_dp-objs := analogix_dp_core.o analogix_dp_reg.o analogix-i2c-dptx.o +obj-$(CONFIG_DRM_ANALOGIX_ANX6345) += analogix-anx6345.o +obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix_dp.o diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c new file mode 100644 index 0000000000000000000000000000000000000000..56f55c53abfd8bfccdc6cf88e94ea211cf001f1f --- /dev/null +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c @@ -0,0 +1,817 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2016, Analogix Semiconductor. + * Copyright(c) 2017, Icenowy Zheng + * + * Based on anx7808 driver obtained from chromeos with copyright: + * Copyright(c) 2013, Google Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "analogix-i2c-dptx.h" +#include "analogix-i2c-txcommon.h" + +#define POLL_DELAY 50000 /* us */ +#define POLL_TIMEOUT 5000000 /* us */ + +#define I2C_IDX_DPTX 0 +#define I2C_IDX_TXCOM 1 + +static const u8 anx6345_i2c_addresses[] = { + [I2C_IDX_DPTX] = 0x70, + [I2C_IDX_TXCOM] = 0x72, +}; +#define I2C_NUM_ADDRESSES ARRAY_SIZE(anx6345_i2c_addresses) + +struct anx6345 { + struct drm_dp_aux aux; + struct drm_bridge bridge; + struct i2c_client *client; + struct edid *edid; + struct drm_connector connector; + struct drm_panel *panel; + struct regulator *dvdd12; + struct regulator *dvdd25; + struct gpio_desc *gpiod_reset; + struct mutex lock; /* protect EDID access */ + + /* I2C Slave addresses of ANX6345 are mapped as DPTX and SYS */ + struct i2c_client *i2c_clients[I2C_NUM_ADDRESSES]; + struct regmap *map[I2C_NUM_ADDRESSES]; + + u16 chipid; + u8 dpcd[DP_RECEIVER_CAP_SIZE]; + + bool powered; +}; + +static inline struct anx6345 *connector_to_anx6345(struct drm_connector *c) +{ + return container_of(c, struct anx6345, connector); +} + +static inline struct anx6345 *bridge_to_anx6345(struct drm_bridge *bridge) +{ + return container_of(bridge, struct anx6345, bridge); +} + +static int anx6345_set_bits(struct regmap *map, u8 reg, u8 mask) +{ + return regmap_update_bits(map, reg, mask, mask); +} + +static int anx6345_clear_bits(struct regmap *map, u8 reg, u8 mask) +{ + return regmap_update_bits(map, reg, mask, 0); +} + +static ssize_t anx6345_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct anx6345 *anx6345 = container_of(aux, struct anx6345, aux); + + return anx_dp_aux_transfer(anx6345->map[I2C_IDX_DPTX], msg); +} + +static int anx6345_dp_link_training(struct anx6345 *anx6345) +{ + unsigned int value; + u8 dp_bw, dpcd[2]; + int err; + + err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], + SP_POWERDOWN_CTRL_REG, + SP_TOTAL_PD); + if (err) + return err; + + err = drm_dp_dpcd_readb(&anx6345->aux, DP_MAX_LINK_RATE, &dp_bw); + if (err < 0) + return err; + + switch (dp_bw) { + case DP_LINK_BW_1_62: + case DP_LINK_BW_2_7: + break; + + default: + DRM_DEBUG_KMS("DP bandwidth (%#02x) not supported\n", dp_bw); + return -EINVAL; + } + + err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG, + SP_VIDEO_MUTE); + if (err) + return err; + + err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], + SP_VID_CTRL1_REG, SP_VIDEO_EN); + if (err) + return err; + + /* Get DPCD info */ + err = drm_dp_dpcd_read(&anx6345->aux, DP_DPCD_REV, + &anx6345->dpcd, DP_RECEIVER_CAP_SIZE); + if (err < 0) { + DRM_ERROR("Failed to read DPCD: %d\n", err); + return err; + } + + /* Clear channel x SERDES power down */ + err = anx6345_clear_bits(anx6345->map[I2C_IDX_DPTX], + SP_DP_ANALOG_POWER_DOWN_REG, SP_CH0_PD); + if (err) + return err; + + /* + * Power up the sink (DP_SET_POWER register is only available on DPCD + * v1.1 and later). + */ + if (anx6345->dpcd[DP_DPCD_REV] >= 0x11) { + err = drm_dp_dpcd_readb(&anx6345->aux, DP_SET_POWER, &dpcd[0]); + if (err < 0) { + DRM_ERROR("Failed to read DP_SET_POWER register: %d\n", + err); + return err; + } + + dpcd[0] &= ~DP_SET_POWER_MASK; + dpcd[0] |= DP_SET_POWER_D0; + + err = drm_dp_dpcd_writeb(&anx6345->aux, DP_SET_POWER, dpcd[0]); + if (err < 0) { + DRM_ERROR("Failed to power up DisplayPort link: %d\n", + err); + return err; + } + + /* + * According to the DP 1.1 specification, a "Sink Device must + * exit the power saving state within 1 ms" (Section 2.5.3.1, + * Table 5-52, "Sink Control Field" (register 0x600). + */ + usleep_range(1000, 2000); + } + + /* Possibly enable downspread on the sink */ + err = regmap_write(anx6345->map[I2C_IDX_DPTX], + SP_DP_DOWNSPREAD_CTRL1_REG, 0); + if (err) + return err; + + if (anx6345->dpcd[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0_5) { + DRM_DEBUG("Enable downspread on the sink\n"); + /* 4000PPM */ + err = regmap_write(anx6345->map[I2C_IDX_DPTX], + SP_DP_DOWNSPREAD_CTRL1_REG, 8); + if (err) + return err; + + err = drm_dp_dpcd_writeb(&anx6345->aux, DP_DOWNSPREAD_CTRL, + DP_SPREAD_AMP_0_5); + if (err < 0) + return err; + } else { + err = drm_dp_dpcd_writeb(&anx6345->aux, DP_DOWNSPREAD_CTRL, 0); + if (err < 0) + return err; + } + + /* Set the lane count and the link rate on the sink */ + if (drm_dp_enhanced_frame_cap(anx6345->dpcd)) + err = anx6345_set_bits(anx6345->map[I2C_IDX_DPTX], + SP_DP_SYSTEM_CTRL_BASE + 4, + SP_ENHANCED_MODE); + else + err = anx6345_clear_bits(anx6345->map[I2C_IDX_DPTX], + SP_DP_SYSTEM_CTRL_BASE + 4, + SP_ENHANCED_MODE); + if (err) + return err; + + dpcd[0] = drm_dp_max_link_rate(anx6345->dpcd); + dpcd[0] = drm_dp_link_rate_to_bw_code(dpcd[0]); + err = regmap_write(anx6345->map[I2C_IDX_DPTX], + SP_DP_MAIN_LINK_BW_SET_REG, dpcd[0]); + if (err) + return err; + + dpcd[1] = drm_dp_max_lane_count(anx6345->dpcd); + + err = regmap_write(anx6345->map[I2C_IDX_DPTX], + SP_DP_LANE_COUNT_SET_REG, dpcd[1]); + if (err) + return err; + + if (drm_dp_enhanced_frame_cap(anx6345->dpcd)) + dpcd[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + + err = drm_dp_dpcd_write(&anx6345->aux, DP_LINK_BW_SET, dpcd, + sizeof(dpcd)); + + if (err < 0) { + DRM_ERROR("Failed to configure link: %d\n", err); + return err; + } + + /* Start training on the source */ + err = regmap_write(anx6345->map[I2C_IDX_DPTX], SP_DP_LT_CTRL_REG, + SP_LT_EN); + if (err) + return err; + + return regmap_read_poll_timeout(anx6345->map[I2C_IDX_DPTX], + SP_DP_LT_CTRL_REG, + value, !(value & SP_DP_LT_INPROGRESS), + POLL_DELAY, POLL_TIMEOUT); +} + +static int anx6345_tx_initialization(struct anx6345 *anx6345) +{ + int err, i; + + /* FIXME: colordepth is hardcoded for now */ + err = regmap_write(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL2_REG, + SP_IN_BPC_6BIT << SP_IN_BPC_SHIFT); + if (err) + return err; + + err = regmap_write(anx6345->map[I2C_IDX_DPTX], SP_DP_PLL_CTRL_REG, 0); + if (err) + return err; + + err = regmap_write(anx6345->map[I2C_IDX_TXCOM], + SP_ANALOG_DEBUG1_REG, 0); + if (err) + return err; + + err = regmap_write(anx6345->map[I2C_IDX_DPTX], + SP_DP_LINK_DEBUG_CTRL_REG, + SP_NEW_PRBS7 | SP_M_VID_DEBUG); + if (err) + return err; + + err = regmap_write(anx6345->map[I2C_IDX_DPTX], + SP_DP_ANALOG_POWER_DOWN_REG, 0); + if (err) + return err; + + /* Force HPD */ + err = anx6345_set_bits(anx6345->map[I2C_IDX_DPTX], + SP_DP_SYSTEM_CTRL_BASE + 3, + SP_HPD_FORCE | SP_HPD_CTRL); + if (err) + return err; + + for (i = 0; i < 4; i++) { + /* 4 lanes */ + err = regmap_write(anx6345->map[I2C_IDX_DPTX], + SP_DP_LANE0_LT_CTRL_REG + i, 0); + if (err) + return err; + } + + /* Reset AUX */ + err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], + SP_RESET_CTRL2_REG, SP_AUX_RST); + if (err) + return err; + + return anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], + SP_RESET_CTRL2_REG, SP_AUX_RST); +} + +static void anx6345_poweron(struct anx6345 *anx6345) +{ + int err; + + /* Ensure reset is asserted before starting power on sequence */ + gpiod_set_value_cansleep(anx6345->gpiod_reset, 1); + usleep_range(1000, 2000); + + err = regulator_enable(anx6345->dvdd12); + if (err) { + DRM_ERROR("Failed to enable dvdd12 regulator: %d\n", + err); + return; + } + + /* T1 - delay between VDD12 and VDD25 should be 0-2ms */ + usleep_range(1000, 2000); + + err = regulator_enable(anx6345->dvdd25); + if (err) { + DRM_ERROR("Failed to enable dvdd25 regulator: %d\n", + err); + return; + } + + /* T2 - delay between RESETN and all power rail stable, + * should be 2-5ms + */ + usleep_range(2000, 5000); + + gpiod_set_value_cansleep(anx6345->gpiod_reset, 0); + + /* Power on registers module */ + anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG, + SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD | SP_LINK_PD); + anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG, + SP_REGISTER_PD | SP_TOTAL_PD); + + if (anx6345->panel) + drm_panel_prepare(anx6345->panel); + + anx6345->powered = true; +} + +static void anx6345_poweroff(struct anx6345 *anx6345) +{ + int err; + + gpiod_set_value_cansleep(anx6345->gpiod_reset, 1); + usleep_range(1000, 2000); + + if (anx6345->panel) + drm_panel_unprepare(anx6345->panel); + + err = regulator_disable(anx6345->dvdd25); + if (err) { + DRM_ERROR("Failed to disable dvdd25 regulator: %d\n", + err); + return; + } + + usleep_range(5000, 10000); + + err = regulator_disable(anx6345->dvdd12); + if (err) { + DRM_ERROR("Failed to disable dvdd12 regulator: %d\n", + err); + return; + } + + usleep_range(1000, 2000); + + anx6345->powered = false; +} + +static int anx6345_start(struct anx6345 *anx6345) +{ + int err; + + if (!anx6345->powered) + anx6345_poweron(anx6345); + + /* Power on needed modules */ + err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], + SP_POWERDOWN_CTRL_REG, + SP_VIDEO_PD | SP_LINK_PD); + + err = anx6345_tx_initialization(anx6345); + if (err) { + DRM_ERROR("Failed eDP transmitter initialization: %d\n", err); + anx6345_poweroff(anx6345); + return err; + } + + err = anx6345_dp_link_training(anx6345); + if (err) { + DRM_ERROR("Failed link training: %d\n", err); + anx6345_poweroff(anx6345); + return err; + } + + /* + * This delay seems to help keep the hardware in a good state. Without + * it, there are times where it fails silently. + */ + usleep_range(10000, 15000); + + return 0; +} + +static int anx6345_config_dp_output(struct anx6345 *anx6345) +{ + int err; + + err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG, + SP_VIDEO_MUTE); + if (err) + return err; + + /* Enable DP output */ + err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG, + SP_VIDEO_EN); + if (err) + return err; + + /* Force stream valid */ + return anx6345_set_bits(anx6345->map[I2C_IDX_DPTX], + SP_DP_SYSTEM_CTRL_BASE + 3, + SP_STRM_FORCE | SP_STRM_CTRL); +} + +static int anx6345_get_downstream_info(struct anx6345 *anx6345) +{ + u8 value; + int err; + + err = drm_dp_dpcd_readb(&anx6345->aux, DP_SINK_COUNT, &value); + if (err < 0) { + DRM_ERROR("Get sink count failed %d\n", err); + return err; + } + + if (!DP_GET_SINK_COUNT(value)) { + DRM_ERROR("Downstream disconnected\n"); + return -EIO; + } + + return 0; +} + +static int anx6345_get_modes(struct drm_connector *connector) +{ + struct anx6345 *anx6345 = connector_to_anx6345(connector); + int err, num_modes = 0; + bool power_off = false; + + mutex_lock(&anx6345->lock); + + if (!anx6345->edid) { + if (!anx6345->powered) { + anx6345_poweron(anx6345); + power_off = true; + } + + err = anx6345_get_downstream_info(anx6345); + if (err) { + DRM_ERROR("Failed to get downstream info: %d\n", err); + goto unlock; + } + + anx6345->edid = drm_get_edid(connector, &anx6345->aux.ddc); + if (!anx6345->edid) + DRM_ERROR("Failed to read EDID from panel\n"); + + err = drm_connector_update_edid_property(connector, + anx6345->edid); + if (err) { + DRM_ERROR("Failed to update EDID property: %d\n", err); + goto unlock; + } + } + + num_modes += drm_add_edid_modes(connector, anx6345->edid); + +unlock: + if (power_off) + anx6345_poweroff(anx6345); + + mutex_unlock(&anx6345->lock); + + if (!num_modes && anx6345->panel) + num_modes += drm_panel_get_modes(anx6345->panel, connector); + + return num_modes; +} + +static const struct drm_connector_helper_funcs anx6345_connector_helper_funcs = { + .get_modes = anx6345_get_modes, +}; + +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); +} + +static const struct drm_connector_funcs anx6345_connector_funcs = { + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = anx6345_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, +}; + +static int anx6345_bridge_attach(struct drm_bridge *bridge) +{ + struct anx6345 *anx6345 = bridge_to_anx6345(bridge); + int err; + + if (!bridge->encoder) { + DRM_ERROR("Parent encoder object not found"); + return -ENODEV; + } + + /* Register aux channel */ + anx6345->aux.name = "DP-AUX"; + anx6345->aux.dev = &anx6345->client->dev; + anx6345->aux.transfer = anx6345_aux_transfer; + + err = drm_dp_aux_register(&anx6345->aux); + if (err < 0) { + DRM_ERROR("Failed to register aux channel: %d\n", err); + return err; + } + + err = drm_connector_init(bridge->dev, &anx6345->connector, + &anx6345_connector_funcs, + DRM_MODE_CONNECTOR_eDP); + if (err) { + DRM_ERROR("Failed to initialize connector: %d\n", err); + return err; + } + + drm_connector_helper_add(&anx6345->connector, + &anx6345_connector_helper_funcs); + + err = drm_connector_register(&anx6345->connector); + if (err) { + DRM_ERROR("Failed to register connector: %d\n", err); + return err; + } + + anx6345->connector.polled = DRM_CONNECTOR_POLL_HPD; + + err = drm_connector_attach_encoder(&anx6345->connector, + bridge->encoder); + if (err) { + DRM_ERROR("Failed to link up connector to encoder: %d\n", err); + 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; +} + +static enum drm_mode_status +anx6345_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode) +{ + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + return MODE_NO_INTERLACE; + + /* Max 1200p at 5.4 Ghz, one lane */ + if (mode->clock > 154000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static void anx6345_bridge_disable(struct drm_bridge *bridge) +{ + struct anx6345 *anx6345 = bridge_to_anx6345(bridge); + + /* Power off all modules except configuration registers access */ + anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG, + SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD | SP_LINK_PD); + if (anx6345->panel) + drm_panel_disable(anx6345->panel); + + if (anx6345->powered) + anx6345_poweroff(anx6345); +} + +static void anx6345_bridge_enable(struct drm_bridge *bridge) +{ + struct anx6345 *anx6345 = bridge_to_anx6345(bridge); + int err; + + if (anx6345->panel) + drm_panel_enable(anx6345->panel); + + err = anx6345_start(anx6345); + if (err) { + DRM_ERROR("Failed to initialize: %d\n", err); + return; + } + + err = anx6345_config_dp_output(anx6345); + if (err) + DRM_ERROR("Failed to enable DP output: %d\n", err); +} + +static const struct drm_bridge_funcs anx6345_bridge_funcs = { + .attach = anx6345_bridge_attach, + .mode_valid = anx6345_bridge_mode_valid, + .disable = anx6345_bridge_disable, + .enable = anx6345_bridge_enable, +}; + +static void unregister_i2c_dummy_clients(struct anx6345 *anx6345) +{ + unsigned int i; + + for (i = 1; i < ARRAY_SIZE(anx6345->i2c_clients); i++) + if (anx6345->i2c_clients[i] && + anx6345->i2c_clients[i]->addr != anx6345->client->addr) + i2c_unregister_device(anx6345->i2c_clients[i]); +} + +static const struct regmap_config anx6345_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xff, + .cache_type = REGCACHE_NONE, +}; + +static const u16 anx6345_chipid_list[] = { + 0x6345, +}; + +static bool anx6345_get_chip_id(struct anx6345 *anx6345) +{ + unsigned int i, idl, idh, version; + + if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_IDL_REG, &idl)) + return false; + + if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_IDH_REG, &idh)) + return false; + + anx6345->chipid = (u8)idl | ((u8)idh << 8); + + if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_VERSION_REG, + &version)) + return false; + + for (i = 0; i < ARRAY_SIZE(anx6345_chipid_list); i++) { + if (anx6345->chipid == anx6345_chipid_list[i]) { + DRM_INFO("Found ANX%x (ver. %d) eDP Transmitter\n", + anx6345->chipid, version); + return true; + } + } + + DRM_ERROR("ANX%x (ver. %d) not supported by this driver\n", + anx6345->chipid, version); + + return false; +} + +static int anx6345_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct anx6345 *anx6345; + struct device *dev; + int i, err; + + anx6345 = devm_kzalloc(&client->dev, sizeof(*anx6345), GFP_KERNEL); + if (!anx6345) + return -ENOMEM; + + mutex_init(&anx6345->lock); + + anx6345->bridge.of_node = client->dev.of_node; + + anx6345->client = client; + i2c_set_clientdata(client, anx6345); + + dev = &anx6345->client->dev; + + err = drm_of_find_panel_or_bridge(client->dev.of_node, 1, 0, + &anx6345->panel, NULL); + if (err == -EPROBE_DEFER) + return err; + + if (err) + DRM_DEBUG("No panel found\n"); + + /* 1.2V digital core power regulator */ + anx6345->dvdd12 = devm_regulator_get(dev, "dvdd12-supply"); + if (IS_ERR(anx6345->dvdd12)) { + DRM_ERROR("dvdd12-supply not found\n"); + return PTR_ERR(anx6345->dvdd12); + } + + /* 2.5V digital core power regulator */ + anx6345->dvdd25 = devm_regulator_get(dev, "dvdd25-supply"); + if (IS_ERR(anx6345->dvdd25)) { + DRM_ERROR("dvdd25-supply not found\n"); + return PTR_ERR(anx6345->dvdd25); + } + + /* GPIO for chip reset */ + anx6345->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(anx6345->gpiod_reset)) { + DRM_ERROR("Reset gpio not found\n"); + return PTR_ERR(anx6345->gpiod_reset); + } + + /* Map slave addresses of ANX6345 */ + for (i = 0; i < I2C_NUM_ADDRESSES; i++) { + if (anx6345_i2c_addresses[i] >> 1 != client->addr) + anx6345->i2c_clients[i] = i2c_new_dummy_device(client->adapter, + anx6345_i2c_addresses[i] >> 1); + else + anx6345->i2c_clients[i] = client; + + if (IS_ERR(anx6345->i2c_clients[i])) { + err = PTR_ERR(anx6345->i2c_clients[i]); + DRM_ERROR("Failed to reserve I2C bus %02x\n", + anx6345_i2c_addresses[i]); + goto err_unregister_i2c; + } + + anx6345->map[i] = devm_regmap_init_i2c(anx6345->i2c_clients[i], + &anx6345_regmap_config); + if (IS_ERR(anx6345->map[i])) { + err = PTR_ERR(anx6345->map[i]); + DRM_ERROR("Failed regmap initialization %02x\n", + anx6345_i2c_addresses[i]); + goto err_unregister_i2c; + } + } + + /* Look for supported chip ID */ + anx6345_poweron(anx6345); + if (anx6345_get_chip_id(anx6345)) { + anx6345->bridge.funcs = &anx6345_bridge_funcs; + drm_bridge_add(&anx6345->bridge); + + return 0; + } else { + anx6345_poweroff(anx6345); + err = -ENODEV; + } + +err_unregister_i2c: + unregister_i2c_dummy_clients(anx6345); + return err; +} + +static int anx6345_i2c_remove(struct i2c_client *client) +{ + struct anx6345 *anx6345 = i2c_get_clientdata(client); + + drm_bridge_remove(&anx6345->bridge); + + unregister_i2c_dummy_clients(anx6345); + + kfree(anx6345->edid); + + mutex_destroy(&anx6345->lock); + + return 0; +} + +static const struct i2c_device_id anx6345_id[] = { + { "anx6345", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, anx6345_id); + +static const struct of_device_id anx6345_match_table[] = { + { .compatible = "analogix,anx6345", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, anx6345_match_table); + +static struct i2c_driver anx6345_driver = { + .driver = { + .name = "anx6345", + .of_match_table = of_match_ptr(anx6345_match_table), + }, + .probe = anx6345_i2c_probe, + .remove = anx6345_i2c_remove, + .id_table = anx6345_id, +}; +module_i2c_driver(anx6345_driver); + +MODULE_DESCRIPTION("ANX6345 eDP Transmitter driver"); +MODULE_AUTHOR("Icenowy Zheng "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c similarity index 90% rename from drivers/gpu/drm/bridge/analogix-anx78xx.c rename to drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c index 274989f96a9167643a24532b7d9b777cd4b8c3df..41867be037510150a39cc21ab83f8a150e8463ea 100644 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c @@ -36,8 +36,6 @@ #define I2C_IDX_RX_P1 4 #define XTAL_CLK 270 /* 27M */ -#define AUX_CH_BUFFER_SIZE 16 -#define AUX_WAIT_TIMEOUT_MS 15 static const u8 anx7808_i2c_addresses[] = { [I2C_IDX_TX_P0] = 0x78, @@ -107,153 +105,11 @@ static int anx78xx_clear_bits(struct regmap *map, u8 reg, u8 mask) return regmap_update_bits(map, reg, mask, 0); } -static bool anx78xx_aux_op_finished(struct anx78xx *anx78xx) -{ - unsigned int value; - int err; - - err = regmap_read(anx78xx->map[I2C_IDX_TX_P0], SP_DP_AUX_CH_CTRL2_REG, - &value); - if (err < 0) - return false; - - return (value & SP_AUX_EN) == 0; -} - -static int anx78xx_aux_wait(struct anx78xx *anx78xx) -{ - unsigned long timeout; - unsigned int status; - int err; - - timeout = jiffies + msecs_to_jiffies(AUX_WAIT_TIMEOUT_MS) + 1; - - while (!anx78xx_aux_op_finished(anx78xx)) { - if (time_after(jiffies, timeout)) { - if (!anx78xx_aux_op_finished(anx78xx)) { - DRM_ERROR("Timed out waiting AUX to finish\n"); - return -ETIMEDOUT; - } - - break; - } - - usleep_range(1000, 2000); - } - - /* Read the AUX channel access status */ - err = regmap_read(anx78xx->map[I2C_IDX_TX_P0], SP_AUX_CH_STATUS_REG, - &status); - if (err < 0) { - DRM_ERROR("Failed to read from AUX channel: %d\n", err); - return err; - } - - if (status & SP_AUX_STATUS) { - DRM_ERROR("Failed to wait for AUX channel (status: %02x)\n", - status); - return -ETIMEDOUT; - } - - return 0; -} - -static int anx78xx_aux_address(struct anx78xx *anx78xx, unsigned int addr) -{ - int err; - - err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_AUX_ADDR_7_0_REG, - addr & 0xff); - if (err) - return err; - - err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_AUX_ADDR_15_8_REG, - (addr & 0xff00) >> 8); - if (err) - return err; - - /* - * DP AUX CH Address Register #2, only update bits[3:0] - * [7:4] RESERVED - * [3:0] AUX_ADDR[19:16], Register control AUX CH address. - */ - err = regmap_update_bits(anx78xx->map[I2C_IDX_TX_P0], - SP_AUX_ADDR_19_16_REG, - SP_AUX_ADDR_19_16_MASK, - (addr & 0xf0000) >> 16); - - if (err) - return err; - - return 0; -} - static ssize_t anx78xx_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { struct anx78xx *anx78xx = container_of(aux, struct anx78xx, aux); - u8 ctrl1 = msg->request; - u8 ctrl2 = SP_AUX_EN; - u8 *buffer = msg->buffer; - int err; - - /* The DP AUX transmit and receive buffer has 16 bytes. */ - if (WARN_ON(msg->size > AUX_CH_BUFFER_SIZE)) - return -E2BIG; - - /* Zero-sized messages specify address-only transactions. */ - if (msg->size < 1) - ctrl2 |= SP_ADDR_ONLY; - else /* For non-zero-sized set the length field. */ - ctrl1 |= (msg->size - 1) << SP_AUX_LENGTH_SHIFT; - - if ((msg->request & DP_AUX_I2C_READ) == 0) { - /* When WRITE | MOT write values to data buffer */ - err = regmap_bulk_write(anx78xx->map[I2C_IDX_TX_P0], - SP_DP_BUF_DATA0_REG, buffer, - msg->size); - if (err) - return err; - } - - /* Write address and request */ - err = anx78xx_aux_address(anx78xx, msg->address); - if (err) - return err; - - err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_DP_AUX_CH_CTRL1_REG, - ctrl1); - if (err) - return err; - - /* Start transaction */ - err = regmap_update_bits(anx78xx->map[I2C_IDX_TX_P0], - SP_DP_AUX_CH_CTRL2_REG, SP_ADDR_ONLY | - SP_AUX_EN, ctrl2); - if (err) - return err; - - err = anx78xx_aux_wait(anx78xx); - if (err) - return err; - - msg->reply = DP_AUX_I2C_REPLY_ACK; - - if ((msg->size > 0) && (msg->request & DP_AUX_I2C_READ)) { - /* Read values from data buffer */ - err = regmap_bulk_read(anx78xx->map[I2C_IDX_TX_P0], - SP_DP_BUF_DATA0_REG, buffer, - msg->size); - if (err) - return err; - } - - err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_TX_P0], - SP_DP_AUX_CH_CTRL2_REG, SP_ADDR_ONLY); - if (err) - return err; - - return msg->size; + return anx_dp_aux_transfer(anx78xx->map[I2C_IDX_TX_P0], msg); } static int anx78xx_set_hpd(struct anx78xx *anx78xx) diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.h b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.h new file mode 100644 index 0000000000000000000000000000000000000000..db2a2725acb24ef2002408247fb3d287f9c82c7c --- /dev/null +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.h @@ -0,0 +1,249 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2016, Analogix Semiconductor. All rights reserved. + */ + +#ifndef __ANX78xx_H +#define __ANX78xx_H + +#include "analogix-i2c-dptx.h" +#include "analogix-i2c-txcommon.h" + +/***************************************************************/ +/* Register definitions for RX_PO */ +/***************************************************************/ + +/* + * System Control and Status + */ + +/* Software Reset Register 1 */ +#define SP_SOFTWARE_RESET1_REG 0x11 +#define SP_VIDEO_RST BIT(4) +#define SP_HDCP_MAN_RST BIT(2) +#define SP_TMDS_RST BIT(1) +#define SP_SW_MAN_RST BIT(0) + +/* System Status Register */ +#define SP_SYSTEM_STATUS_REG 0x14 +#define SP_TMDS_CLOCK_DET BIT(1) +#define SP_TMDS_DE_DET BIT(0) + +/* HDMI Status Register */ +#define SP_HDMI_STATUS_REG 0x15 +#define SP_HDMI_AUD_LAYOUT BIT(3) +#define SP_HDMI_DET BIT(0) +# define SP_DVI_MODE 0 +# define SP_HDMI_MODE 1 + +/* HDMI Mute Control Register */ +#define SP_HDMI_MUTE_CTRL_REG 0x16 +#define SP_AUD_MUTE BIT(1) +#define SP_VID_MUTE BIT(0) + +/* System Power Down Register 1 */ +#define SP_SYSTEM_POWER_DOWN1_REG 0x18 +#define SP_PWDN_CTRL BIT(0) + +/* + * Audio and Video Auto Control + */ + +/* Auto Audio and Video Control register */ +#define SP_AUDVID_CTRL_REG 0x20 +#define SP_AVC_OE BIT(7) +#define SP_AAC_OE BIT(6) +#define SP_AVC_EN BIT(1) +#define SP_AAC_EN BIT(0) + +/* Audio Exception Enable Registers */ +#define SP_AUD_EXCEPTION_ENABLE_BASE (0x24 - 1) +/* Bits for Audio Exception Enable Register 3 */ +#define SP_AEC_EN21 BIT(5) + +/* + * Interrupt + */ + +/* Interrupt Status Register 1 */ +#define SP_INT_STATUS1_REG 0x31 +/* Bits for Interrupt Status Register 1 */ +#define SP_HDMI_DVI BIT(7) +#define SP_CKDT_CHG BIT(6) +#define SP_SCDT_CHG BIT(5) +#define SP_PCLK_CHG BIT(4) +#define SP_PLL_UNLOCK BIT(3) +#define SP_CABLE_PLUG_CHG BIT(2) +#define SP_SET_MUTE BIT(1) +#define SP_SW_INTR BIT(0) +/* Bits for Interrupt Status Register 2 */ +#define SP_HDCP_ERR BIT(5) +#define SP_AUDIO_SAMPLE_CHG BIT(0) /* undocumented */ +/* Bits for Interrupt Status Register 3 */ +#define SP_AUD_MODE_CHG BIT(0) +/* Bits for Interrupt Status Register 5 */ +#define SP_AUDIO_RCV BIT(0) +/* Bits for Interrupt Status Register 6 */ +#define SP_INT_STATUS6_REG 0x36 +#define SP_CTS_RCV BIT(7) +#define SP_NEW_AUD_PKT BIT(4) +#define SP_NEW_AVI_PKT BIT(1) +#define SP_NEW_CP_PKT BIT(0) +/* Bits for Interrupt Status Register 7 */ +#define SP_NO_VSI BIT(7) +#define SP_NEW_VS BIT(4) + +/* Interrupt Mask 1 Status Registers */ +#define SP_INT_MASK1_REG 0x41 + +/* HDMI US TIMER Control Register */ +#define SP_HDMI_US_TIMER_CTRL_REG 0x49 +#define SP_MS_TIMER_MARGIN_10_8_MASK 0x07 + +/* + * TMDS Control + */ + +/* TMDS Control Registers */ +#define SP_TMDS_CTRL_BASE (0x50 - 1) +/* Bits for TMDS Control Register 7 */ +#define SP_PD_RT BIT(0) + +/* + * Video Control + */ + +/* Video Status Register */ +#define SP_VIDEO_STATUS_REG 0x70 +#define SP_COLOR_DEPTH_MASK 0xf0 +#define SP_COLOR_DEPTH_SHIFT 4 +# define SP_COLOR_DEPTH_MODE_LEGACY 0x00 +# define SP_COLOR_DEPTH_MODE_24BIT 0x04 +# define SP_COLOR_DEPTH_MODE_30BIT 0x05 +# define SP_COLOR_DEPTH_MODE_36BIT 0x06 +# define SP_COLOR_DEPTH_MODE_48BIT 0x07 + +/* Video Data Range Control Register */ +#define SP_VID_DATA_RANGE_CTRL_REG 0x83 +#define SP_R2Y_INPUT_LIMIT BIT(1) + +/* Pixel Clock High Resolution Counter Registers */ +#define SP_PCLK_HIGHRES_CNT_BASE (0x8c - 1) + +/* + * Audio Control + */ + +/* Number of Audio Channels Status Registers */ +#define SP_AUD_CH_STATUS_REG_NUM 6 + +/* Audio IN S/PDIF Channel Status Registers */ +#define SP_AUD_SPDIF_CH_STATUS_BASE 0xc7 + +/* Audio IN S/PDIF Channel Status Register 4 */ +#define SP_FS_FREQ_MASK 0x0f +# define SP_FS_FREQ_44100HZ 0x00 +# define SP_FS_FREQ_48000HZ 0x02 +# define SP_FS_FREQ_32000HZ 0x03 +# define SP_FS_FREQ_88200HZ 0x08 +# define SP_FS_FREQ_96000HZ 0x0a +# define SP_FS_FREQ_176400HZ 0x0c +# define SP_FS_FREQ_192000HZ 0x0e + +/* + * Micellaneous Control Block + */ + +/* CHIP Control Register */ +#define SP_CHIP_CTRL_REG 0xe3 +#define SP_MAN_HDMI5V_DET BIT(3) +#define SP_PLLLOCK_CKDT_EN BIT(2) +#define SP_ANALOG_CKDT_EN BIT(1) +#define SP_DIGITAL_CKDT_EN BIT(0) + +/* Packet Receiving Status Register */ +#define SP_PACKET_RECEIVING_STATUS_REG 0xf3 +#define SP_AVI_RCVD BIT(5) +#define SP_VSI_RCVD BIT(1) + +/***************************************************************/ +/* Register definitions for RX_P1 */ +/***************************************************************/ + +/* HDCP BCAPS Shadow Register */ +#define SP_HDCP_BCAPS_SHADOW_REG 0x2a +#define SP_BCAPS_REPEATER BIT(5) + +/* HDCP Status Register */ +#define SP_RX_HDCP_STATUS_REG 0x3f +#define SP_AUTH_EN BIT(4) + +/* + * InfoFrame and Control Packet Registers + */ + +/* AVI InfoFrame packet checksum */ +#define SP_AVI_INFOFRAME_CHECKSUM 0xa3 + +/* AVI InfoFrame Registers */ +#define SP_AVI_INFOFRAME_DATA_BASE 0xa4 + +#define SP_AVI_COLOR_F_MASK 0x60 +#define SP_AVI_COLOR_F_SHIFT 5 + +/* Audio InfoFrame Registers */ +#define SP_AUD_INFOFRAME_DATA_BASE 0xc4 +#define SP_AUD_INFOFRAME_LAYOUT_MASK 0x0f + +/* MPEG/HDMI Vendor Specific InfoFrame Packet type code */ +#define SP_MPEG_VS_INFOFRAME_TYPE_REG 0xe0 + +/* MPEG/HDMI Vendor Specific InfoFrame Packet length */ +#define SP_MPEG_VS_INFOFRAME_LEN_REG 0xe2 + +/* MPEG/HDMI Vendor Specific InfoFrame Packet version number */ +#define SP_MPEG_VS_INFOFRAME_VER_REG 0xe1 + +/* MPEG/HDMI Vendor Specific InfoFrame Packet content */ +#define SP_MPEG_VS_INFOFRAME_DATA_BASE 0xe4 + +/* General Control Packet Register */ +#define SP_GENERAL_CTRL_PACKET_REG 0x9f +#define SP_CLEAR_AVMUTE BIT(4) +#define SP_SET_AVMUTE BIT(0) + +/***************************************************************/ +/* Register definitions for TX_P1 */ +/***************************************************************/ + +/* DP TX Link Training Control Register */ +#define SP_DP_TX_LT_CTRL0_REG 0x30 + +/* PD 1.2 Lint Training 80bit Pattern Register */ +#define SP_DP_LT_80BIT_PATTERN0_REG 0x80 +#define SP_DP_LT_80BIT_PATTERN_REG_NUM 10 + +/* Audio Interface Control Register 0 */ +#define SP_AUD_INTERFACE_CTRL0_REG 0x5f +#define SP_AUD_INTERFACE_DISABLE 0x80 + +/* Audio Interface Control Register 2 */ +#define SP_AUD_INTERFACE_CTRL2_REG 0x60 +#define SP_M_AUD_ADJUST_ST 0x04 + +/* Audio Interface Control Register 3 */ +#define SP_AUD_INTERFACE_CTRL3_REG 0x62 + +/* Audio Interface Control Register 4 */ +#define SP_AUD_INTERFACE_CTRL4_REG 0x67 + +/* Audio Interface Control Register 5 */ +#define SP_AUD_INTERFACE_CTRL5_REG 0x68 + +/* Audio Interface Control Register 6 */ +#define SP_AUD_INTERFACE_CTRL6_REG 0x69 + +/* Firmware Version Register */ +#define SP_FW_VER_REG 0xb7 + +#endif diff --git a/drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.c b/drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.c new file mode 100644 index 0000000000000000000000000000000000000000..fe40bab215306f8101209f90feeb49308be416a2 --- /dev/null +++ b/drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.c @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2016, Analogix Semiconductor. + * + * Based on anx7808 driver obtained from chromeos with copyright: + * Copyright(c) 2013, Google Inc. + */ +#include + +#include +#include +#include + +#include "analogix-i2c-dptx.h" + +#define AUX_WAIT_TIMEOUT_MS 15 +#define AUX_CH_BUFFER_SIZE 16 + +static int anx_i2c_dp_clear_bits(struct regmap *map, u8 reg, u8 mask) +{ + return regmap_update_bits(map, reg, mask, 0); +} + +static bool anx_dp_aux_op_finished(struct regmap *map_dptx) +{ + unsigned int value; + int err; + + err = regmap_read(map_dptx, SP_DP_AUX_CH_CTRL2_REG, &value); + if (err < 0) + return false; + + return (value & SP_AUX_EN) == 0; +} + +static int anx_dp_aux_wait(struct regmap *map_dptx) +{ + unsigned long timeout; + unsigned int status; + int err; + + timeout = jiffies + msecs_to_jiffies(AUX_WAIT_TIMEOUT_MS) + 1; + + while (!anx_dp_aux_op_finished(map_dptx)) { + if (time_after(jiffies, timeout)) { + if (!anx_dp_aux_op_finished(map_dptx)) { + DRM_ERROR("Timed out waiting AUX to finish\n"); + return -ETIMEDOUT; + } + + break; + } + + usleep_range(1000, 2000); + } + + /* Read the AUX channel access status */ + err = regmap_read(map_dptx, SP_AUX_CH_STATUS_REG, &status); + if (err < 0) { + DRM_ERROR("Failed to read from AUX channel: %d\n", err); + return err; + } + + if (status & SP_AUX_STATUS) { + DRM_ERROR("Failed to wait for AUX channel (status: %02x)\n", + status); + return -ETIMEDOUT; + } + + return 0; +} + +static int anx_dp_aux_address(struct regmap *map_dptx, unsigned int addr) +{ + int err; + + err = regmap_write(map_dptx, SP_AUX_ADDR_7_0_REG, addr & 0xff); + if (err) + return err; + + err = regmap_write(map_dptx, SP_AUX_ADDR_15_8_REG, + (addr & 0xff00) >> 8); + if (err) + return err; + + /* + * DP AUX CH Address Register #2, only update bits[3:0] + * [7:4] RESERVED + * [3:0] AUX_ADDR[19:16], Register control AUX CH address. + */ + err = regmap_update_bits(map_dptx, SP_AUX_ADDR_19_16_REG, + SP_AUX_ADDR_19_16_MASK, + (addr & 0xf0000) >> 16); + + if (err) + return err; + + return 0; +} + +ssize_t anx_dp_aux_transfer(struct regmap *map_dptx, + struct drm_dp_aux_msg *msg) +{ + u8 ctrl1 = msg->request; + u8 ctrl2 = SP_AUX_EN; + u8 *buffer = msg->buffer; + int err; + + /* The DP AUX transmit and receive buffer has 16 bytes. */ + if (WARN_ON(msg->size > AUX_CH_BUFFER_SIZE)) + return -E2BIG; + + /* Zero-sized messages specify address-only transactions. */ + if (msg->size < 1) + ctrl2 |= SP_ADDR_ONLY; + else /* For non-zero-sized set the length field. */ + ctrl1 |= (msg->size - 1) << SP_AUX_LENGTH_SHIFT; + + if ((msg->size > 0) && ((msg->request & DP_AUX_I2C_READ) == 0)) { + /* When WRITE | MOT write values to data buffer */ + err = regmap_bulk_write(map_dptx, + SP_DP_BUF_DATA0_REG, buffer, + msg->size); + if (err) + return err; + } + + /* Write address and request */ + err = anx_dp_aux_address(map_dptx, msg->address); + if (err) + return err; + + err = regmap_write(map_dptx, SP_DP_AUX_CH_CTRL1_REG, ctrl1); + if (err) + return err; + + /* Start transaction */ + err = regmap_update_bits(map_dptx, SP_DP_AUX_CH_CTRL2_REG, + SP_ADDR_ONLY | SP_AUX_EN, ctrl2); + if (err) + return err; + + err = anx_dp_aux_wait(map_dptx); + if (err) + return err; + + msg->reply = DP_AUX_I2C_REPLY_ACK; + + if ((msg->size > 0) && (msg->request & DP_AUX_I2C_READ)) { + /* Read values from data buffer */ + err = regmap_bulk_read(map_dptx, + SP_DP_BUF_DATA0_REG, buffer, + msg->size); + if (err) + return err; + } + + err = anx_i2c_dp_clear_bits(map_dptx, SP_DP_AUX_CH_CTRL2_REG, + SP_ADDR_ONLY); + if (err) + return err; + + return msg->size; +} +EXPORT_SYMBOL_GPL(anx_dp_aux_transfer); diff --git a/drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.h b/drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.h new file mode 100644 index 0000000000000000000000000000000000000000..663c4bea6e70f0a0ddfb32ccdeacee7f2b46ea77 --- /dev/null +++ b/drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.h @@ -0,0 +1,256 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2016, Analogix Semiconductor. + * + * Based on anx7808 driver obtained from chromeos with copyright: + * Copyright(c) 2013, Google Inc. + */ +#ifndef _ANALOGIX_I2C_DPTX_H_ +#define _ANALOGIX_I2C_DPTX_H_ + +/***************************************************************/ +/* Register definitions for TX_P0 */ +/***************************************************************/ + +/* HDCP Status Register */ +#define SP_TX_HDCP_STATUS_REG 0x00 +#define SP_AUTH_FAIL BIT(5) +#define SP_AUTHEN_PASS BIT(1) + +/* HDCP Control Register 0 */ +#define SP_HDCP_CTRL0_REG 0x01 +#define SP_RX_REPEATER BIT(6) +#define SP_RE_AUTH BIT(5) +#define SP_SW_AUTH_OK BIT(4) +#define SP_HARD_AUTH_EN BIT(3) +#define SP_HDCP_ENC_EN BIT(2) +#define SP_BKSV_SRM_PASS BIT(1) +#define SP_KSVLIST_VLD BIT(0) +/* HDCP Function Enabled */ +#define SP_HDCP_FUNCTION_ENABLED (BIT(0) | BIT(1) | BIT(2) | BIT(3)) + +/* HDCP Receiver BSTATUS Register 0 */ +#define SP_HDCP_RX_BSTATUS0_REG 0x1b +/* HDCP Receiver BSTATUS Register 1 */ +#define SP_HDCP_RX_BSTATUS1_REG 0x1c + +/* HDCP Embedded "Blue Screen" Content Registers */ +#define SP_HDCP_VID0_BLUE_SCREEN_REG 0x2c +#define SP_HDCP_VID1_BLUE_SCREEN_REG 0x2d +#define SP_HDCP_VID2_BLUE_SCREEN_REG 0x2e + +/* HDCP Wait R0 Timing Register */ +#define SP_HDCP_WAIT_R0_TIME_REG 0x40 + +/* HDCP Link Integrity Check Timer Register */ +#define SP_HDCP_LINK_CHECK_TIMER_REG 0x41 + +/* HDCP Repeater Ready Wait Timer Register */ +#define SP_HDCP_RPTR_RDY_WAIT_TIME_REG 0x42 + +/* HDCP Auto Timer Register */ +#define SP_HDCP_AUTO_TIMER_REG 0x51 + +/* HDCP Key Status Register */ +#define SP_HDCP_KEY_STATUS_REG 0x5e + +/* HDCP Key Command Register */ +#define SP_HDCP_KEY_COMMAND_REG 0x5f +#define SP_DISABLE_SYNC_HDCP BIT(2) + +/* OTP Memory Key Protection Registers */ +#define SP_OTP_KEY_PROTECT1_REG 0x60 +#define SP_OTP_KEY_PROTECT2_REG 0x61 +#define SP_OTP_KEY_PROTECT3_REG 0x62 +#define SP_OTP_PSW1 0xa2 +#define SP_OTP_PSW2 0x7e +#define SP_OTP_PSW3 0xc6 + +/* DP System Control Registers */ +#define SP_DP_SYSTEM_CTRL_BASE (0x80 - 1) +/* Bits for DP System Control Register 2 */ +#define SP_CHA_STA BIT(2) +/* Bits for DP System Control Register 3 */ +#define SP_HPD_STATUS BIT(6) +#define SP_HPD_FORCE BIT(5) +#define SP_HPD_CTRL BIT(4) +#define SP_STRM_VALID BIT(2) +#define SP_STRM_FORCE BIT(1) +#define SP_STRM_CTRL BIT(0) +/* Bits for DP System Control Register 4 */ +#define SP_ENHANCED_MODE BIT(3) + +/* DP Video Control Register */ +#define SP_DP_VIDEO_CTRL_REG 0x84 +#define SP_COLOR_F_MASK 0x06 +#define SP_COLOR_F_SHIFT 1 +#define SP_BPC_MASK 0xe0 +#define SP_BPC_SHIFT 5 +# define SP_BPC_6BITS 0x00 +# define SP_BPC_8BITS 0x01 +# define SP_BPC_10BITS 0x02 +# define SP_BPC_12BITS 0x03 + +/* DP Audio Control Register */ +#define SP_DP_AUDIO_CTRL_REG 0x87 +#define SP_AUD_EN BIT(0) + +/* 10us Pulse Generate Timer Registers */ +#define SP_I2C_GEN_10US_TIMER0_REG 0x88 +#define SP_I2C_GEN_10US_TIMER1_REG 0x89 + +/* Packet Send Control Register */ +#define SP_PACKET_SEND_CTRL_REG 0x90 +#define SP_AUD_IF_UP BIT(7) +#define SP_AVI_IF_UD BIT(6) +#define SP_MPEG_IF_UD BIT(5) +#define SP_SPD_IF_UD BIT(4) +#define SP_AUD_IF_EN BIT(3) +#define SP_AVI_IF_EN BIT(2) +#define SP_MPEG_IF_EN BIT(1) +#define SP_SPD_IF_EN BIT(0) + +/* DP HDCP Control Register */ +#define SP_DP_HDCP_CTRL_REG 0x92 +#define SP_AUTO_EN BIT(7) +#define SP_AUTO_START BIT(5) +#define SP_LINK_POLLING BIT(1) + +/* DP Main Link Bandwidth Setting Register */ +#define SP_DP_MAIN_LINK_BW_SET_REG 0xa0 +#define SP_LINK_BW_SET_MASK 0x1f +#define SP_INITIAL_SLIM_M_AUD_SEL BIT(5) + +/* DP Lane Count Setting Register */ +#define SP_DP_LANE_COUNT_SET_REG 0xa1 + +/* DP Training Pattern Set Register */ +#define SP_DP_TRAINING_PATTERN_SET_REG 0xa2 + +/* DP Lane 0 Link Training Control Register */ +#define SP_DP_LANE0_LT_CTRL_REG 0xa3 +#define SP_TX_SW_SET_MASK 0x1b +#define SP_MAX_PRE_REACH BIT(5) +#define SP_MAX_DRIVE_REACH BIT(4) +#define SP_PRE_EMP_LEVEL1 BIT(3) +#define SP_DRVIE_CURRENT_LEVEL1 BIT(0) + +/* DP Link Training Control Register */ +#define SP_DP_LT_CTRL_REG 0xa8 +#define SP_DP_LT_INPROGRESS 0x80 +#define SP_LT_ERROR_TYPE_MASK 0x70 +# define SP_LT_NO_ERROR 0x00 +# define SP_LT_AUX_WRITE_ERROR 0x01 +# define SP_LT_MAX_DRIVE_REACHED 0x02 +# define SP_LT_WRONG_LANE_COUNT_SET 0x03 +# define SP_LT_LOOP_SAME_5_TIME 0x04 +# define SP_LT_CR_FAIL_IN_EQ 0x05 +# define SP_LT_EQ_LOOP_5_TIME 0x06 +#define SP_LT_EN BIT(0) + +/* DP CEP Training Control Registers */ +#define SP_DP_CEP_TRAINING_CTRL0_REG 0xa9 +#define SP_DP_CEP_TRAINING_CTRL1_REG 0xaa + +/* DP Debug Register 1 */ +#define SP_DP_DEBUG1_REG 0xb0 +#define SP_DEBUG_PLL_LOCK BIT(4) +#define SP_POLLING_EN BIT(1) + +/* DP Polling Control Register */ +#define SP_DP_POLLING_CTRL_REG 0xb4 +#define SP_AUTO_POLLING_DISABLE BIT(0) + +/* DP Link Debug Control Register */ +#define SP_DP_LINK_DEBUG_CTRL_REG 0xb8 +#define SP_M_VID_DEBUG BIT(5) +#define SP_NEW_PRBS7 BIT(4) +#define SP_INSERT_ER BIT(1) +#define SP_PRBS31_EN BIT(0) + +/* AUX Misc control Register */ +#define SP_AUX_MISC_CTRL_REG 0xbf + +/* DP PLL control Register */ +#define SP_DP_PLL_CTRL_REG 0xc7 +#define SP_PLL_RST BIT(6) + +/* DP Analog Power Down Register */ +#define SP_DP_ANALOG_POWER_DOWN_REG 0xc8 +#define SP_CH0_PD BIT(0) + +/* DP Misc Control Register */ +#define SP_DP_MISC_CTRL_REG 0xcd +#define SP_EQ_TRAINING_LOOP BIT(6) + +/* DP Extra I2C Device Address Register */ +#define SP_DP_EXTRA_I2C_DEV_ADDR_REG 0xce +#define SP_I2C_STRETCH_DISABLE BIT(7) + +#define SP_I2C_EXTRA_ADDR 0x50 + +/* DP Downspread Control Register 1 */ +#define SP_DP_DOWNSPREAD_CTRL1_REG 0xd0 + +/* DP M Value Calculation Control Register */ +#define SP_DP_M_CALCULATION_CTRL_REG 0xd9 +#define SP_M_GEN_CLK_SEL BIT(0) + +/* AUX Channel Access Status Register */ +#define SP_AUX_CH_STATUS_REG 0xe0 +#define SP_AUX_STATUS 0x0f + +/* AUX Channel DEFER Control Register */ +#define SP_AUX_DEFER_CTRL_REG 0xe2 +#define SP_DEFER_CTRL_EN BIT(7) + +/* DP Buffer Data Count Register */ +#define SP_BUF_DATA_COUNT_REG 0xe4 +#define SP_BUF_DATA_COUNT_MASK 0x1f +#define SP_BUF_CLR BIT(7) + +/* DP AUX Channel Control Register 1 */ +#define SP_DP_AUX_CH_CTRL1_REG 0xe5 +#define SP_AUX_TX_COMM_MASK 0x0f +#define SP_AUX_LENGTH_MASK 0xf0 +#define SP_AUX_LENGTH_SHIFT 4 + +/* DP AUX CH Address Register 0 */ +#define SP_AUX_ADDR_7_0_REG 0xe6 + +/* DP AUX CH Address Register 1 */ +#define SP_AUX_ADDR_15_8_REG 0xe7 + +/* DP AUX CH Address Register 2 */ +#define SP_AUX_ADDR_19_16_REG 0xe8 +#define SP_AUX_ADDR_19_16_MASK 0x0f + +/* DP AUX Channel Control Register 2 */ +#define SP_DP_AUX_CH_CTRL2_REG 0xe9 +#define SP_AUX_SEL_RXCM BIT(6) +#define SP_AUX_CHSEL BIT(3) +#define SP_AUX_PN_INV BIT(2) +#define SP_ADDR_ONLY BIT(1) +#define SP_AUX_EN BIT(0) + +/* DP Video Stream Control InfoFrame Register */ +#define SP_DP_3D_VSC_CTRL_REG 0xea +#define SP_INFO_FRAME_VSC_EN BIT(0) + +/* DP Video Stream Data Byte 1 Register */ +#define SP_DP_VSC_DB1_REG 0xeb + +/* DP AUX Channel Control Register 3 */ +#define SP_DP_AUX_CH_CTRL3_REG 0xec +#define SP_WAIT_COUNTER_7_0_MASK 0xff + +/* DP AUX Channel Control Register 4 */ +#define SP_DP_AUX_CH_CTRL4_REG 0xed + +/* DP AUX Buffer Data Registers */ +#define SP_DP_BUF_DATA0_REG 0xf0 + +ssize_t anx_dp_aux_transfer(struct regmap *map_dptx, + struct drm_dp_aux_msg *msg); + +#endif diff --git a/drivers/gpu/drm/bridge/analogix/analogix-i2c-txcommon.h b/drivers/gpu/drm/bridge/analogix/analogix-i2c-txcommon.h new file mode 100644 index 0000000000000000000000000000000000000000..3c843497d83595fe5a0e84130a7a0aa183384d38 --- /dev/null +++ b/drivers/gpu/drm/bridge/analogix/analogix-i2c-txcommon.h @@ -0,0 +1,234 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2016, Analogix Semiconductor. All rights reserved. + */ +#ifndef _ANALOGIX_I2C_TXCOMMON_H_ +#define _ANALOGIX_I2C_TXCOMMON_H_ + +/***************************************************************/ +/* Register definitions for TX_P2 */ +/***************************************************************/ + +/* + * Core Register Definitions + */ + +/* Device ID Low Byte Register */ +#define SP_DEVICE_IDL_REG 0x02 + +/* Device ID High Byte Register */ +#define SP_DEVICE_IDH_REG 0x03 + +/* Device version register */ +#define SP_DEVICE_VERSION_REG 0x04 + +/* Power Down Control Register */ +#define SP_POWERDOWN_CTRL_REG 0x05 +#define SP_REGISTER_PD BIT(7) +#define SP_HDCP_PD BIT(5) +#define SP_AUDIO_PD BIT(4) +#define SP_VIDEO_PD BIT(3) +#define SP_LINK_PD BIT(2) +#define SP_TOTAL_PD BIT(1) + +/* Reset Control Register 1 */ +#define SP_RESET_CTRL1_REG 0x06 +#define SP_MISC_RST BIT(7) +#define SP_VIDCAP_RST BIT(6) +#define SP_VIDFIF_RST BIT(5) +#define SP_AUDFIF_RST BIT(4) +#define SP_AUDCAP_RST BIT(3) +#define SP_HDCP_RST BIT(2) +#define SP_SW_RST BIT(1) +#define SP_HW_RST BIT(0) + +/* Reset Control Register 2 */ +#define SP_RESET_CTRL2_REG 0x07 +#define SP_AUX_RST BIT(2) +#define SP_SERDES_FIFO_RST BIT(1) +#define SP_I2C_REG_RST BIT(0) + +/* Video Control Register 1 */ +#define SP_VID_CTRL1_REG 0x08 +#define SP_VIDEO_EN BIT(7) +#define SP_VIDEO_MUTE BIT(2) +#define SP_DE_GEN BIT(1) +#define SP_DEMUX BIT(0) + +/* Video Control Register 2 */ +#define SP_VID_CTRL2_REG 0x09 +#define SP_IN_COLOR_F_MASK 0x03 +#define SP_IN_YC_BIT_SEL BIT(2) +#define SP_IN_BPC_MASK 0x70 +#define SP_IN_BPC_SHIFT 4 +# define SP_IN_BPC_12BIT 0x03 +# define SP_IN_BPC_10BIT 0x02 +# define SP_IN_BPC_8BIT 0x01 +# define SP_IN_BPC_6BIT 0x00 +#define SP_IN_D_RANGE BIT(7) + +/* Video Control Register 3 */ +#define SP_VID_CTRL3_REG 0x0a +#define SP_HPD_OUT BIT(6) + +/* Video Control Register 5 */ +#define SP_VID_CTRL5_REG 0x0c +#define SP_CSC_STD_SEL BIT(7) +#define SP_XVYCC_RNG_LMT BIT(6) +#define SP_RANGE_Y2R BIT(5) +#define SP_CSPACE_Y2R BIT(4) +#define SP_RGB_RNG_LMT BIT(3) +#define SP_Y_RNG_LMT BIT(2) +#define SP_RANGE_R2Y BIT(1) +#define SP_CSPACE_R2Y BIT(0) + +/* Video Control Register 6 */ +#define SP_VID_CTRL6_REG 0x0d +#define SP_TEST_PATTERN_EN BIT(7) +#define SP_VIDEO_PROCESS_EN BIT(6) +#define SP_VID_US_MODE BIT(3) +#define SP_VID_DS_MODE BIT(2) +#define SP_UP_SAMPLE BIT(1) +#define SP_DOWN_SAMPLE BIT(0) + +/* Video Control Register 8 */ +#define SP_VID_CTRL8_REG 0x0f +#define SP_VID_VRES_TH BIT(0) + +/* Total Line Status Low Byte Register */ +#define SP_TOTAL_LINE_STAL_REG 0x24 + +/* Total Line Status High Byte Register */ +#define SP_TOTAL_LINE_STAH_REG 0x25 + +/* Active Line Status Low Byte Register */ +#define SP_ACT_LINE_STAL_REG 0x26 + +/* Active Line Status High Byte Register */ +#define SP_ACT_LINE_STAH_REG 0x27 + +/* Vertical Front Porch Status Register */ +#define SP_V_F_PORCH_STA_REG 0x28 + +/* Vertical SYNC Width Status Register */ +#define SP_V_SYNC_STA_REG 0x29 + +/* Vertical Back Porch Status Register */ +#define SP_V_B_PORCH_STA_REG 0x2a + +/* Total Pixel Status Low Byte Register */ +#define SP_TOTAL_PIXEL_STAL_REG 0x2b + +/* Total Pixel Status High Byte Register */ +#define SP_TOTAL_PIXEL_STAH_REG 0x2c + +/* Active Pixel Status Low Byte Register */ +#define SP_ACT_PIXEL_STAL_REG 0x2d + +/* Active Pixel Status High Byte Register */ +#define SP_ACT_PIXEL_STAH_REG 0x2e + +/* Horizontal Front Porch Status Low Byte Register */ +#define SP_H_F_PORCH_STAL_REG 0x2f + +/* Horizontal Front Porch Statys High Byte Register */ +#define SP_H_F_PORCH_STAH_REG 0x30 + +/* Horizontal SYNC Width Status Low Byte Register */ +#define SP_H_SYNC_STAL_REG 0x31 + +/* Horizontal SYNC Width Status High Byte Register */ +#define SP_H_SYNC_STAH_REG 0x32 + +/* Horizontal Back Porch Status Low Byte Register */ +#define SP_H_B_PORCH_STAL_REG 0x33 + +/* Horizontal Back Porch Status High Byte Register */ +#define SP_H_B_PORCH_STAH_REG 0x34 + +/* InfoFrame AVI Packet DB1 Register */ +#define SP_INFOFRAME_AVI_DB1_REG 0x70 + +/* Bit Control Specific Register */ +#define SP_BIT_CTRL_SPECIFIC_REG 0x80 +#define SP_BIT_CTRL_SELECT_SHIFT 1 +#define SP_ENABLE_BIT_CTRL BIT(0) + +/* InfoFrame Audio Packet DB1 Register */ +#define SP_INFOFRAME_AUD_DB1_REG 0x83 + +/* InfoFrame MPEG Packet DB1 Register */ +#define SP_INFOFRAME_MPEG_DB1_REG 0xb0 + +/* Audio Channel Status Registers */ +#define SP_AUD_CH_STATUS_BASE 0xd0 + +/* Audio Channel Num Register 5 */ +#define SP_I2S_CHANNEL_NUM_MASK 0xe0 +# define SP_I2S_CH_NUM_1 (0x00 << 5) +# define SP_I2S_CH_NUM_2 (0x01 << 5) +# define SP_I2S_CH_NUM_3 (0x02 << 5) +# define SP_I2S_CH_NUM_4 (0x03 << 5) +# define SP_I2S_CH_NUM_5 (0x04 << 5) +# define SP_I2S_CH_NUM_6 (0x05 << 5) +# define SP_I2S_CH_NUM_7 (0x06 << 5) +# define SP_I2S_CH_NUM_8 (0x07 << 5) +#define SP_EXT_VUCP BIT(2) +#define SP_VBIT BIT(1) +#define SP_AUDIO_LAYOUT BIT(0) + +/* Analog Debug Register 1 */ +#define SP_ANALOG_DEBUG1_REG 0xdc + +/* Analog Debug Register 2 */ +#define SP_ANALOG_DEBUG2_REG 0xdd +#define SP_FORCE_SW_OFF_BYPASS 0x20 +#define SP_XTAL_FRQ 0x1c +# define SP_XTAL_FRQ_19M2 (0x00 << 2) +# define SP_XTAL_FRQ_24M (0x01 << 2) +# define SP_XTAL_FRQ_25M (0x02 << 2) +# define SP_XTAL_FRQ_26M (0x03 << 2) +# define SP_XTAL_FRQ_27M (0x04 << 2) +# define SP_XTAL_FRQ_38M4 (0x05 << 2) +# define SP_XTAL_FRQ_52M (0x06 << 2) +#define SP_POWERON_TIME_1P5MS 0x03 + +/* Analog Control 0 Register */ +#define SP_ANALOG_CTRL0_REG 0xe1 + +/* Common Interrupt Status Register 1 */ +#define SP_COMMON_INT_STATUS_BASE (0xf1 - 1) +#define SP_PLL_LOCK_CHG 0x40 + +/* Common Interrupt Status Register 2 */ +#define SP_COMMON_INT_STATUS2 0xf2 +#define SP_HDCP_AUTH_CHG BIT(1) +#define SP_HDCP_AUTH_DONE BIT(0) + +#define SP_HDCP_LINK_CHECK_FAIL BIT(0) + +/* Common Interrupt Status Register 4 */ +#define SP_COMMON_INT_STATUS4_REG 0xf4 +#define SP_HPD_IRQ BIT(6) +#define SP_HPD_ESYNC_ERR BIT(4) +#define SP_HPD_CHG BIT(2) +#define SP_HPD_LOST BIT(1) +#define SP_HPD_PLUG BIT(0) + +/* DP Interrupt Status Register */ +#define SP_DP_INT_STATUS1_REG 0xf7 +#define SP_TRAINING_FINISH BIT(5) +#define SP_POLLING_ERR BIT(4) + +/* Common Interrupt Mask Register */ +#define SP_COMMON_INT_MASK_BASE (0xf8 - 1) + +#define SP_COMMON_INT_MASK4_REG 0xfb + +/* DP Interrupts Mask Register */ +#define SP_DP_INT_MASK1_REG 0xfe + +/* Interrupt Control Register */ +#define SP_INT_CTRL_REG 0xff + +#endif /* _ANALOGIX_I2C_TXCOMMON_H_ */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index bb411fe52ae83d673b069b004acd6f1071334acf..6fab71985cd49eeb000431172b315399c26ed504 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1111,7 +1111,7 @@ static int analogix_dp_get_modes(struct drm_connector *connector) int ret, num_modes = 0; if (dp->plat_data->panel) { - num_modes += drm_panel_get_modes(dp->plat_data->panel); + num_modes += drm_panel_get_modes(dp->plat_data->panel, connector); } else { ret = analogix_dp_prepare_panel(dp, true, false); if (ret) { @@ -1289,19 +1289,21 @@ struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp, return conn_state->crtc; } -static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +static void +analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { + struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; int ret; - crtc = analogix_dp_get_new_crtc(dp, state); + crtc = analogix_dp_get_new_crtc(dp, old_state); if (!crtc) return; - old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); + old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc); /* Don't touch the panel if we're coming back from PSR */ if (old_crtc_state && old_crtc_state->self_refresh_active) return; @@ -1366,20 +1368,22 @@ out_dp_clk_pre: return ret; } -static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +static void +analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { + struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; int timeout_loop = 0; int ret; - crtc = analogix_dp_get_new_crtc(dp, state); + crtc = analogix_dp_get_new_crtc(dp, old_state); if (!crtc) return; - old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); + old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc); /* Not a full enable, just disable PSR and continue */ if (old_crtc_state && old_crtc_state->self_refresh_active) { ret = analogix_dp_disable_psr(dp); @@ -1440,18 +1444,20 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) dp->dpms_mode = DRM_MODE_DPMS_OFF; } -static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +static void +analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { + struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state = NULL; - crtc = analogix_dp_get_new_crtc(dp, state); + crtc = analogix_dp_get_new_crtc(dp, old_state); if (!crtc) goto out; - new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); if (!new_crtc_state) goto out; @@ -1463,20 +1469,21 @@ out: analogix_dp_bridge_disable(bridge); } -static -void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +static void +analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { + struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state; int ret; - crtc = analogix_dp_get_new_crtc(dp, state); + crtc = analogix_dp_get_new_crtc(dp, old_state); if (!crtc) return; - new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); if (!new_crtc_state || !new_crtc_state->self_refresh_active) return; diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c index 3a5bd4e7fd1e3b8ce257cb05ca52591f884fdfff..b7c97f0602417bc11c2226893f40b3feab972367 100644 --- a/drivers/gpu/drm/bridge/cdns-dsi.c +++ b/drivers/gpu/drm/bridge/cdns-dsi.c @@ -512,7 +512,7 @@ static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi, struct cdns_dsi_output *output = &dsi->output; unsigned int tmp; bool sync_pulse = false; - int bpp, nlanes; + int bpp; memset(dsi_cfg, 0, sizeof(*dsi_cfg)); @@ -520,7 +520,6 @@ static int cdns_dsi_mode2cfg(struct cdns_dsi *dsi, sync_pulse = true; bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format); - nlanes = output->dev->lanes; if (mode_valid_check) tmp = mode->htotal - @@ -785,13 +784,12 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge) unsigned long tx_byte_period; struct cdns_dsi_cfg dsi_cfg; u32 tmp, reg_wakeup, div; - int bpp, nlanes; + int nlanes; if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0)) return; mode = &bridge->encoder->crtc->state->adjusted_mode; - bpp = mipi_dsi_pixel_format_to_bpp(output->dev->format); nlanes = output->dev->lanes; WARN_ON_ONCE(cdns_dsi_check_conf(dsi, mode, &dsi_cfg, false)); diff --git a/drivers/gpu/drm/bridge/lvds-codec.c b/drivers/gpu/drm/bridge/lvds-codec.c new file mode 100644 index 0000000000000000000000000000000000000000..5f04cc11227eacfec418e5bf353d1773d0886d55 --- /dev/null +++ b/drivers/gpu/drm/bridge/lvds-codec.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2019 Renesas Electronics Corporation + * Copyright (C) 2016 Laurent Pinchart + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +struct lvds_codec { + struct drm_bridge bridge; + struct drm_bridge *panel_bridge; + struct gpio_desc *powerdown_gpio; + u32 connector_type; +}; + +static int lvds_codec_attach(struct drm_bridge *bridge) +{ + struct lvds_codec *lvds_codec = container_of(bridge, + struct lvds_codec, bridge); + + return drm_bridge_attach(bridge->encoder, lvds_codec->panel_bridge, + bridge); +} + +static void lvds_codec_enable(struct drm_bridge *bridge) +{ + struct lvds_codec *lvds_codec = container_of(bridge, + struct lvds_codec, bridge); + + if (lvds_codec->powerdown_gpio) + gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 0); +} + +static void lvds_codec_disable(struct drm_bridge *bridge) +{ + struct lvds_codec *lvds_codec = container_of(bridge, + struct lvds_codec, bridge); + + if (lvds_codec->powerdown_gpio) + gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 1); +} + +static struct drm_bridge_funcs funcs = { + .attach = lvds_codec_attach, + .enable = lvds_codec_enable, + .disable = lvds_codec_disable, +}; + +static int lvds_codec_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *panel_node; + struct drm_panel *panel; + struct lvds_codec *lvds_codec; + + lvds_codec = devm_kzalloc(dev, sizeof(*lvds_codec), GFP_KERNEL); + if (!lvds_codec) + return -ENOMEM; + + lvds_codec->connector_type = (uintptr_t)of_device_get_match_data(dev); + lvds_codec->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown", + GPIOD_OUT_HIGH); + if (IS_ERR(lvds_codec->powerdown_gpio)) { + int err = PTR_ERR(lvds_codec->powerdown_gpio); + + if (err != -EPROBE_DEFER) + dev_err(dev, "powerdown GPIO failure: %d\n", err); + return err; + } + + /* Locate the panel DT node. */ + panel_node = of_graph_get_remote_node(dev->of_node, 1, 0); + if (!panel_node) { + dev_dbg(dev, "panel DT node not found\n"); + return -ENXIO; + } + + panel = of_drm_find_panel(panel_node); + of_node_put(panel_node); + if (IS_ERR(panel)) { + dev_dbg(dev, "panel not found, deferring probe\n"); + return PTR_ERR(panel); + } + + lvds_codec->panel_bridge = + devm_drm_panel_bridge_add_typed(dev, panel, + lvds_codec->connector_type); + if (IS_ERR(lvds_codec->panel_bridge)) + return PTR_ERR(lvds_codec->panel_bridge); + + /* + * The panel_bridge bridge is attached to the panel's of_node, + * but we need a bridge attached to our of_node for our user + * to look up. + */ + lvds_codec->bridge.of_node = dev->of_node; + lvds_codec->bridge.funcs = &funcs; + drm_bridge_add(&lvds_codec->bridge); + + platform_set_drvdata(pdev, lvds_codec); + + return 0; +} + +static int lvds_codec_remove(struct platform_device *pdev) +{ + struct lvds_codec *lvds_codec = platform_get_drvdata(pdev); + + drm_bridge_remove(&lvds_codec->bridge); + + return 0; +} + +static const struct of_device_id lvds_codec_match[] = { + { + .compatible = "lvds-decoder", + .data = (void *)DRM_MODE_CONNECTOR_DPI, + }, + { + .compatible = "lvds-encoder", + .data = (void *)DRM_MODE_CONNECTOR_LVDS, + }, + { + .compatible = "thine,thc63lvdm83d", + .data = (void *)DRM_MODE_CONNECTOR_LVDS, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, lvds_codec_match); + +static struct platform_driver lvds_codec_driver = { + .probe = lvds_codec_probe, + .remove = lvds_codec_remove, + .driver = { + .name = "lvds-codec", + .of_match_table = lvds_codec_match, + }, +}; +module_platform_driver(lvds_codec_driver); + +MODULE_AUTHOR("Laurent Pinchart "); +MODULE_DESCRIPTION("LVDS encoders and decoders"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c deleted file mode 100644 index e2132a8d5106c29a14806b9d504d40271e5b8952..0000000000000000000000000000000000000000 --- a/drivers/gpu/drm/bridge/lvds-encoder.c +++ /dev/null @@ -1,155 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Laurent Pinchart - */ - -#include -#include -#include -#include -#include - -#include -#include - -struct lvds_encoder { - struct drm_bridge bridge; - struct drm_bridge *panel_bridge; - struct gpio_desc *powerdown_gpio; -}; - -static int lvds_encoder_attach(struct drm_bridge *bridge) -{ - struct lvds_encoder *lvds_encoder = container_of(bridge, - struct lvds_encoder, - bridge); - - return drm_bridge_attach(bridge->encoder, lvds_encoder->panel_bridge, - bridge); -} - -static void lvds_encoder_enable(struct drm_bridge *bridge) -{ - struct lvds_encoder *lvds_encoder = container_of(bridge, - struct lvds_encoder, - bridge); - - if (lvds_encoder->powerdown_gpio) - gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 0); -} - -static void lvds_encoder_disable(struct drm_bridge *bridge) -{ - struct lvds_encoder *lvds_encoder = container_of(bridge, - struct lvds_encoder, - bridge); - - if (lvds_encoder->powerdown_gpio) - gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 1); -} - -static struct drm_bridge_funcs funcs = { - .attach = lvds_encoder_attach, - .enable = lvds_encoder_enable, - .disable = lvds_encoder_disable, -}; - -static int lvds_encoder_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *port; - struct device_node *endpoint; - struct device_node *panel_node; - struct drm_panel *panel; - struct lvds_encoder *lvds_encoder; - - lvds_encoder = devm_kzalloc(dev, sizeof(*lvds_encoder), GFP_KERNEL); - if (!lvds_encoder) - return -ENOMEM; - - lvds_encoder->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown", - GPIOD_OUT_HIGH); - if (IS_ERR(lvds_encoder->powerdown_gpio)) { - int err = PTR_ERR(lvds_encoder->powerdown_gpio); - - if (err != -EPROBE_DEFER) - dev_err(dev, "powerdown GPIO failure: %d\n", err); - return err; - } - - /* Locate the panel DT node. */ - port = of_graph_get_port_by_id(dev->of_node, 1); - if (!port) { - dev_dbg(dev, "port 1 not found\n"); - return -ENXIO; - } - - endpoint = of_get_child_by_name(port, "endpoint"); - of_node_put(port); - if (!endpoint) { - dev_dbg(dev, "no endpoint for port 1\n"); - return -ENXIO; - } - - panel_node = of_graph_get_remote_port_parent(endpoint); - of_node_put(endpoint); - if (!panel_node) { - dev_dbg(dev, "no remote endpoint for port 1\n"); - return -ENXIO; - } - - panel = of_drm_find_panel(panel_node); - of_node_put(panel_node); - if (IS_ERR(panel)) { - dev_dbg(dev, "panel not found, deferring probe\n"); - return PTR_ERR(panel); - } - - lvds_encoder->panel_bridge = - devm_drm_panel_bridge_add_typed(dev, panel, - DRM_MODE_CONNECTOR_LVDS); - if (IS_ERR(lvds_encoder->panel_bridge)) - return PTR_ERR(lvds_encoder->panel_bridge); - - /* The panel_bridge bridge is attached to the panel's of_node, - * but we need a bridge attached to our of_node for our user - * to look up. - */ - lvds_encoder->bridge.of_node = dev->of_node; - lvds_encoder->bridge.funcs = &funcs; - drm_bridge_add(&lvds_encoder->bridge); - - platform_set_drvdata(pdev, lvds_encoder); - - return 0; -} - -static int lvds_encoder_remove(struct platform_device *pdev) -{ - struct lvds_encoder *lvds_encoder = platform_get_drvdata(pdev); - - drm_bridge_remove(&lvds_encoder->bridge); - - return 0; -} - -static const struct of_device_id lvds_encoder_match[] = { - { .compatible = "lvds-encoder" }, - { .compatible = "thine,thc63lvdm83d" }, - {}, -}; -MODULE_DEVICE_TABLE(of, lvds_encoder_match); - -static struct platform_driver lvds_encoder_driver = { - .probe = lvds_encoder_probe, - .remove = lvds_encoder_remove, - .driver = { - .name = "lvds-encoder", - .of_match_table = lvds_encoder_match, - }, -}; -module_platform_driver(lvds_encoder_driver); - -MODULE_AUTHOR("Laurent Pinchart "); -MODULE_DESCRIPTION("Transparent parallel to LVDS encoder"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index f4e293e7cf64268db54339a5f5ae1a5eb3ee8a53..f66777e249687335b9f74c3f2180e9b7d4fc0e45 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c @@ -37,7 +37,7 @@ static int panel_bridge_connector_get_modes(struct drm_connector *connector) struct panel_bridge *panel_bridge = drm_connector_to_panel_bridge(connector); - return drm_panel_get_modes(panel_bridge->panel); + return drm_panel_get_modes(panel_bridge->panel, connector); } static const struct drm_connector_helper_funcs @@ -289,3 +289,21 @@ struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev, return bridge; } EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed); + +/** + * drm_panel_bridge_connector - return the connector for the panel bridge + * + * drm_panel_bridge creates the connector. + * This function gives external access to the connector. + * + * Returns: Pointer to drm_connector + */ +struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge) +{ + struct panel_bridge *panel_bridge; + + panel_bridge = drm_bridge_to_panel_bridge(bridge); + + return &panel_bridge->connector; +} +EXPORT_SYMBOL(drm_panel_bridge_connector); diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c index b7a72dfdcac3c77d04c29576a3d1c0b20facacb3..10c47c008b401e24561832f68dcfc025eb5620a0 100644 --- a/drivers/gpu/drm/bridge/parade-ps8622.c +++ b/drivers/gpu/drm/bridge/parade-ps8622.c @@ -461,7 +461,7 @@ static int ps8622_get_modes(struct drm_connector *connector) ps8622 = connector_to_ps8622(connector); - return drm_panel_get_modes(ps8622->panel); + return drm_panel_get_modes(ps8622->panel, connector); } static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = { diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c index 2b7539701b42249311baa42e78f220ad1fc0b1d1..dd56996fe9c76a822063ee5fc14fc0eadaa1bde9 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c @@ -291,7 +291,7 @@ static irqreturn_t snd_dw_hdmi_irq(int irq, void *data) return IRQ_HANDLED; } -static struct snd_pcm_hardware dw_hdmi_hw = { +static const struct snd_pcm_hardware dw_hdmi_hw = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index b6e793bb653c4dbabf32230638b96d7ef732fe74..b18351b6760adb16691d84dfe51655fcfed09890 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -719,7 +719,15 @@ static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi, static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) { + const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; + struct dw_mipi_dsi_dphy_timing timing; u32 hw_version; + int ret; + + ret = phy_ops->get_timing(dsi->plat_data->priv_data, + dsi->lane_mbps, &timing); + if (ret) + DRM_DEV_ERROR(dsi->dev, "Retrieving phy timings failed\n"); /* * TODO dw drv improvements @@ -732,16 +740,20 @@ static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; if (hw_version >= HWVER_131) { - dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME_V131(0x40) | - PHY_LP2HS_TIME_V131(0x40)); + dsi_write(dsi, DSI_PHY_TMR_CFG, + PHY_HS2LP_TIME_V131(timing.data_hs2lp) | + PHY_LP2HS_TIME_V131(timing.data_lp2hs)); dsi_write(dsi, DSI_PHY_TMR_RD_CFG, MAX_RD_TIME_V131(10000)); } else { - dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40) | - PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000)); + dsi_write(dsi, DSI_PHY_TMR_CFG, + PHY_HS2LP_TIME(timing.data_hs2lp) | + PHY_LP2HS_TIME(timing.data_lp2hs) | + MAX_RD_TIME(10000)); } - dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40) - | PHY_CLKLP2HS_TIME(0x40)); + dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, + PHY_CLKHS2LP_TIME(timing.clk_hs2lp) | + PHY_CLKLP2HS_TIME(timing.clk_lp2hs)); } static void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi) @@ -798,9 +810,6 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge) struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; - if (phy_ops->power_off) - phy_ops->power_off(dsi->plat_data->priv_data); - /* * Switch to command mode before panel-bridge post_disable & * panel unprepare. @@ -817,6 +826,9 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge) */ dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge); + if (phy_ops->power_off) + phy_ops->power_off(dsi->plat_data->priv_data); + if (dsi->slave) { dw_mipi_dsi_disable(dsi->slave); clk_disable_unprepare(dsi->slave->pclk); @@ -883,6 +895,9 @@ static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi, /* Switch to cmd mode for panel-bridge pre_enable & panel prepare */ dw_mipi_dsi_set_mode(dsi, 0); + + if (phy_ops->power_on) + phy_ops->power_on(dsi->plat_data->priv_data); } static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, @@ -899,15 +914,11 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge) { struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); - const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; /* Switch to video mode for panel-bridge enable & panel enable */ dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO); if (dsi->slave) dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO); - - if (phy_ops->power_on) - phy_ops->power_on(dsi->plat_data->priv_data); } static enum drm_mode_status @@ -991,7 +1002,8 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, dsi->dev = dev; dsi->plat_data = plat_data; - if (!plat_data->phy_ops->init || !plat_data->phy_ops->get_lane_mbps) { + if (!plat_data->phy_ops->init || !plat_data->phy_ops->get_lane_mbps || + !plat_data->phy_ops->get_timing) { DRM_ERROR("Phy not properly configured\n"); return ERR_PTR(-ENODEV); } diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c index db298f550a5adfc7d7317c67ae7d7a2b77c5d425..96207fcfde19bda0df94a0f1aadcae95fbcd4d7d 100644 --- a/drivers/gpu/drm/bridge/tc358764.c +++ b/drivers/gpu/drm/bridge/tc358764.c @@ -282,7 +282,7 @@ static int tc358764_get_modes(struct drm_connector *connector) { struct tc358764 *ctx = connector_to_tc358764(connector); - return drm_panel_get_modes(ctx->panel); + return drm_panel_get_modes(ctx->panel, connector); } static const diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 8029478ffebbc6eab05591322782014c6865eb39..3709e5ace7246086b3b4d172bdd5a7218cbf6306 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1346,7 +1346,7 @@ static int tc_connector_get_modes(struct drm_connector *connector) return 0; } - count = drm_panel_get_modes(tc->panel); + count = drm_panel_get_modes(tc->panel, connector); if (count > 0) return count; diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 43abf01ebd4ca00272f3ea781f96597e802a093a..9a2dd986afa58df99392fcaafabaa80a7b4c1b8a 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -206,7 +206,7 @@ static int ti_sn_bridge_connector_get_modes(struct drm_connector *connector) { struct ti_sn_bridge *pdata = connector_to_ti_sn_bridge(connector); - return drm_panel_get_modes(pdata->panel); + return drm_panel_get_modes(pdata->panel, connector); } static enum drm_mode_status diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c index 6e09f27fd9d63cea5c832740dc36104f473644c9..4c7ad46fdd219f59c2830d2d52428763d5e606d2 100644 --- a/drivers/gpu/drm/drm_agpsupport.c +++ b/drivers/gpu/drm/drm_agpsupport.c @@ -212,7 +212,7 @@ int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request) if (!entry) return -ENOMEM; - pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; + pages = DIV_ROUND_UP(request->size, PAGE_SIZE); type = (u32) request->type; memory = agp_allocate_memory(dev->agp->bridge, pages, type); if (!memory) { @@ -325,7 +325,7 @@ int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request) entry = drm_agp_lookup_entry(dev, request->handle); if (!entry || entry->bound) return -EINVAL; - page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE; + page = DIV_ROUND_UP(request->offset, PAGE_SIZE); retcode = drm_bind_agp(entry->memory, page); if (retcode) return retcode; diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 14aeaf736321003c979c6dbf73e0940c4cc6d1d3..bf1b9c37d5152cfeff714ba581022b4002b1c96f 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -251,7 +252,7 @@ EXPORT_SYMBOL(drm_atomic_state_clear); * @ref: This atomic state to deallocate * * This frees all memory associated with an atomic state, including all the - * per-object state for planes, crtcs and connectors. + * per-object state for planes, CRTCs and connectors. */ void __drm_atomic_state_free(struct kref *ref) { @@ -272,12 +273,12 @@ void __drm_atomic_state_free(struct kref *ref) EXPORT_SYMBOL(__drm_atomic_state_free); /** - * drm_atomic_get_crtc_state - get crtc state + * drm_atomic_get_crtc_state - get CRTC state * @state: global atomic state object - * @crtc: crtc to get state object for + * @crtc: CRTC to get state object for * - * This function returns the crtc state for the given crtc, allocating it if - * needed. It will also grab the relevant crtc lock to make sure that the state + * This function returns the CRTC state for the given CRTC, allocating it if + * needed. It will also grab the relevant CRTC lock to make sure that the state * is consistent. * * Returns: @@ -688,10 +689,12 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, * associated state struct &drm_private_state. * * Similar to userspace-exposed objects, private state structures can be - * acquired by calling drm_atomic_get_private_obj_state(). Since this function - * does not take care of locking, drivers should wrap it for each type of - * private state object they have with the required call to drm_modeset_lock() - * for the corresponding &drm_modeset_lock. + * acquired by calling drm_atomic_get_private_obj_state(). This also takes care + * of locking, hence drivers should not have a need to call drm_modeset_lock() + * directly. Sequence of the actual hardware state commit is not handled, + * drivers might need to keep track of struct drm_crtc_commit within subclassed + * structure of &drm_private_state as necessary, e.g. similar to + * &drm_plane_state.commit. See also &drm_atomic_state.fake_commit. * * All private state structures contained in a &drm_atomic_state update can be * iterated using for_each_oldnew_private_obj_in_state(), @@ -1016,14 +1019,52 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, } /** - * drm_atomic_add_affected_connectors - add connectors for crtc + * drm_atomic_add_encoder_bridges - add bridges attached to an encoder * @state: atomic state - * @crtc: DRM crtc + * @encoder: DRM encoder + * + * This function adds all bridges attached to @encoder. This is needed to add + * bridge states to @state and make them available when + * &bridge_funcs.atomic_{check,pre_enable,enable,disable_post_disable}() are + * called + * + * Returns: + * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK + * then the w/w mutex code has detected a deadlock and the entire atomic + * sequence must be restarted. All other errors are fatal. + */ +int +drm_atomic_add_encoder_bridges(struct drm_atomic_state *state, + struct drm_encoder *encoder) +{ + struct drm_bridge_state *bridge_state; + struct drm_bridge *bridge; + + if (!encoder) + return 0; + + DRM_DEBUG_ATOMIC("Adding all bridges for [encoder:%d:%s] to %p\n", + encoder->base.id, encoder->name, state); + + drm_for_each_bridge_in_chain(encoder, bridge) { + bridge_state = drm_atomic_get_bridge_state(state, bridge); + if (IS_ERR(bridge_state)) + return PTR_ERR(bridge_state); + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_add_encoder_bridges); + +/** + * drm_atomic_add_affected_connectors - add connectors for CRTC + * @state: atomic state + * @crtc: DRM CRTC * * This function walks the current configuration and adds all connectors * currently using @crtc to the atomic configuration @state. Note that this * function must acquire the connection mutex. This can potentially cause - * unneeded seralization if the update is just for the planes on one crtc. Hence + * unneeded seralization if the update is just for the planes on one CRTC. Hence * drivers and helpers should only call this when really needed (e.g. when a * full modeset needs to happen due to some change). * @@ -1076,9 +1117,9 @@ drm_atomic_add_affected_connectors(struct drm_atomic_state *state, EXPORT_SYMBOL(drm_atomic_add_affected_connectors); /** - * drm_atomic_add_affected_planes - add planes for crtc + * drm_atomic_add_affected_planes - add planes for CRTC * @state: atomic state - * @crtc: DRM crtc + * @crtc: DRM CRTC * * This function walks the current configuration and adds all planes * currently used by @crtc to the atomic configuration @state. This is useful diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index b191d39c071d85ccdfb87d36f15418055cd197a7..afe14f72a8242ad2c729466ed895d01f2a56bed5 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -150,8 +150,8 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state, * is not set, an error is returned. Userspace can provide a solution * through the atomic ioctl. * - * If the flag is set conflicting connectors are removed from the crtc - * and the crtc is disabled if no encoder is left. This preserves + * If the flag is set conflicting connectors are removed from the CRTC + * and the CRTC is disabled if no encoder is left. This preserves * compatibility with the legacy set_config behavior. */ drm_connector_list_iter_begin(state->dev, &conn_iter); @@ -220,7 +220,7 @@ set_best_encoder(struct drm_atomic_state *state, crtc = conn_state->connector->state->crtc; /* A NULL crtc is an error here because we should have - * duplicated a NULL best_encoder when crtc was NULL. + * duplicated a NULL best_encoder when crtc was NULL. * As an exception restoring duplicated atomic state * during resume is allowed, so don't warn when * best_encoder is equal to encoder we intend to set. @@ -419,6 +419,7 @@ mode_fixup(struct drm_atomic_state *state) for_each_new_connector_in_state(state, connector, new_conn_state, i) { const struct drm_encoder_helper_funcs *funcs; struct drm_encoder *encoder; + struct drm_bridge *bridge; WARN_ON(!!new_conn_state->best_encoder != !!new_conn_state->crtc); @@ -435,11 +436,13 @@ mode_fixup(struct drm_atomic_state *state) encoder = new_conn_state->best_encoder; funcs = encoder->helper_private; - ret = drm_bridge_mode_fixup(encoder->bridge, &new_crtc_state->mode, - &new_crtc_state->adjusted_mode); - if (!ret) { - DRM_DEBUG_ATOMIC("Bridge fixup failed\n"); - return -EINVAL; + bridge = drm_bridge_chain_get_first_bridge(encoder); + ret = drm_atomic_bridge_chain_check(bridge, + new_crtc_state, + new_conn_state); + if (ret) { + DRM_DEBUG_ATOMIC("Bridge atomic check failed\n"); + return ret; } if (funcs && funcs->atomic_check) { @@ -492,6 +495,7 @@ static enum drm_mode_status mode_valid_path(struct drm_connector *connector, struct drm_crtc *crtc, const struct drm_display_mode *mode) { + struct drm_bridge *bridge; enum drm_mode_status ret; ret = drm_encoder_mode_valid(encoder, mode); @@ -501,7 +505,8 @@ static enum drm_mode_status mode_valid_path(struct drm_connector *connector, return ret; } - ret = drm_bridge_mode_valid(encoder->bridge, mode); + bridge = drm_bridge_chain_get_first_bridge(encoder); + ret = drm_bridge_chain_mode_valid(bridge, mode); if (ret != MODE_OK) { DRM_DEBUG_ATOMIC("[BRIDGE] mode_valid() failed\n"); return ret; @@ -556,27 +561,27 @@ mode_valid(struct drm_atomic_state *state) * @state: the driver state object * * Check the state object to see if the requested state is physically possible. - * This does all the crtc and connector related computations for an atomic + * This does all the CRTC and connector related computations for an atomic * update and adds any additional connectors needed for full modesets. It calls * the various per-object callbacks in the follow order: * * 1. &drm_connector_helper_funcs.atomic_best_encoder for determining the new encoder. * 2. &drm_connector_helper_funcs.atomic_check to validate the connector state. - * 3. If it's determined a modeset is needed then all connectors on the affected crtc - * crtc are added and &drm_connector_helper_funcs.atomic_check is run on them. + * 3. If it's determined a modeset is needed then all connectors on the affected + * CRTC are added and &drm_connector_helper_funcs.atomic_check is run on them. * 4. &drm_encoder_helper_funcs.mode_valid, &drm_bridge_funcs.mode_valid and * &drm_crtc_helper_funcs.mode_valid are called on the affected components. * 5. &drm_bridge_funcs.mode_fixup is called on all encoder bridges. * 6. &drm_encoder_helper_funcs.atomic_check is called to validate any encoder state. - * This function is only called when the encoder will be part of a configured crtc, + * This function is only called when the encoder will be part of a configured CRTC, * it must not be used for implementing connector property validation. * If this function is NULL, &drm_atomic_encoder_helper_funcs.mode_fixup is called * instead. - * 7. &drm_crtc_helper_funcs.mode_fixup is called last, to fix up the mode with crtc constraints. + * 7. &drm_crtc_helper_funcs.mode_fixup is called last, to fix up the mode with CRTC constraints. * * &drm_crtc_state.mode_changed is set when the input mode is changed. * &drm_crtc_state.connectors_changed is set when a connector is added or - * removed from the crtc. &drm_crtc_state.active_changed is set when + * removed from the CRTC. &drm_crtc_state.active_changed is set when * &drm_crtc_state.active changes, which is used for DPMS. * See also: drm_atomic_crtc_needs_modeset() * @@ -687,7 +692,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, /* * After all the routing has been prepared we need to add in any - * connector which is itself unchanged, but whose crtc changes its + * connector which is itself unchanged, but whose CRTC changes its * configuration. This must be done before calling mode_fixup in case a * crtc only changed its mode but has the same set of connectors. */ @@ -725,6 +730,26 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, return ret; } + /* + * Iterate over all connectors again, and add all affected bridges to + * the state. + */ + for_each_oldnew_connector_in_state(state, connector, + old_connector_state, + new_connector_state, i) { + struct drm_encoder *encoder; + + encoder = old_connector_state->best_encoder; + ret = drm_atomic_add_encoder_bridges(state, encoder); + if (ret) + return ret; + + encoder = new_connector_state->best_encoder; + ret = drm_atomic_add_encoder_bridges(state, encoder); + if (ret) + return ret; + } + ret = mode_valid(state); if (ret) return ret; @@ -736,13 +761,13 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset); /** * drm_atomic_helper_check_plane_state() - Check plane state for validity * @plane_state: plane state to check - * @crtc_state: crtc state to check + * @crtc_state: CRTC state to check * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point * @can_position: is it legal to position the plane such that it - * doesn't cover the entire crtc? This will generally + * doesn't cover the entire CRTC? This will generally * only be false for primary planes. - * @can_update_disabled: can the plane be updated while the crtc + * @can_update_disabled: can the plane be updated while the CRTC * is disabled? * * Checks that a desired plane update is valid, and updates various @@ -839,7 +864,7 @@ EXPORT_SYMBOL(drm_atomic_helper_check_plane_state); * &drm_crtc_helper_funcs.atomic_check and &drm_plane_helper_funcs.atomic_check * hooks provided by the driver. * - * It also sets &drm_crtc_state.planes_changed to indicate that a crtc has + * It also sets &drm_crtc_state.planes_changed to indicate that a CRTC has * updated planes. * * RETURNS: @@ -903,7 +928,7 @@ EXPORT_SYMBOL(drm_atomic_helper_check_planes); * @state: the driver state object * * Check the state object to see if the requested state is physically possible. - * Only crtcs and planes have check callbacks, so for any additional (global) + * Only CRTCs and planes have check callbacks, so for any additional (global) * checking that a driver needs it can simply wrap that around this function. * Drivers without such needs can directly use this as their * &drm_mode_config_funcs.atomic_check callback. @@ -956,14 +981,14 @@ crtc_needs_disable(struct drm_crtc_state *old_state, struct drm_crtc_state *new_state) { /* - * No new_state means the crtc is off, so the only criteria is whether + * No new_state means the CRTC is off, so the only criteria is whether * it's currently active or in self refresh mode. */ if (!new_state) return drm_atomic_crtc_effectively_active(old_state); /* - * We need to run through the crtc_funcs->disable() function if the crtc + * We need to run through the crtc_funcs->disable() function if the CRTC * is currently on, if it's transitioning to self refresh mode, or if * it's in self refresh mode and needs to be fully disabled. */ @@ -984,6 +1009,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) for_each_oldnew_connector_in_state(old_state, connector, old_conn_state, new_conn_state, i) { const struct drm_encoder_helper_funcs *funcs; struct drm_encoder *encoder; + struct drm_bridge *bridge; /* Shut down everything that's in the changeset and currently * still on. So need to check the old, saved state. */ @@ -1020,7 +1046,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) * Each encoder has at most one connector (since we always steal * it away), so we won't call disable hooks twice. */ - drm_atomic_bridge_disable(encoder->bridge, old_state); + bridge = drm_bridge_chain_get_first_bridge(encoder); + drm_atomic_bridge_chain_disable(bridge, old_state); /* Right function depends upon target state. */ if (funcs) { @@ -1034,7 +1061,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) funcs->dpms(encoder, DRM_MODE_DPMS_OFF); } - drm_atomic_bridge_post_disable(encoder->bridge, old_state); + drm_atomic_bridge_chain_post_disable(bridge, old_state); } for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) { @@ -1080,7 +1107,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) * @old_state: atomic state object with old state structures * * This function updates all the various legacy modeset state pointers in - * connectors, encoders and crtcs. It also updates the timestamping constants + * connectors, encoders and CRTCs. It also updates the timestamping constants * used for precise vblank timestamps by calling * drm_calc_timestamping_constants(). * @@ -1188,6 +1215,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) const struct drm_encoder_helper_funcs *funcs; struct drm_encoder *encoder; struct drm_display_mode *mode, *adjusted_mode; + struct drm_bridge *bridge; if (!new_conn_state->best_encoder) continue; @@ -1215,7 +1243,8 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) funcs->mode_set(encoder, mode, adjusted_mode); } - drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode); + bridge = drm_bridge_chain_get_first_bridge(encoder); + drm_bridge_chain_mode_set(bridge, mode, adjusted_mode); } } @@ -1227,7 +1256,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) * This function shuts down all the outputs that need to be shut down and * prepares them (if required) with the new mode. * - * For compatibility with legacy crtc helpers this should be called before + * For compatibility with legacy CRTC helpers this should be called before * drm_atomic_helper_commit_planes(), which is what the default commit function * does. But drivers with different needs can group the modeset commits together * and do the plane commits at the end. This is useful for drivers doing runtime @@ -1273,7 +1302,7 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev, * This function enables all the outputs with the new configuration which had to * be turned off for the update. * - * For compatibility with legacy crtc helpers this should be called after + * For compatibility with legacy CRTC helpers this should be called after * drm_atomic_helper_commit_planes(), which is what the default commit function * does. But drivers with different needs can group the modeset commits together * and do the plane commits at the end. This is useful for drivers doing runtime @@ -1314,6 +1343,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, for_each_new_connector_in_state(old_state, connector, new_conn_state, i) { const struct drm_encoder_helper_funcs *funcs; struct drm_encoder *encoder; + struct drm_bridge *bridge; if (!new_conn_state->best_encoder) continue; @@ -1332,7 +1362,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, * Each encoder has at most one connector (since we always steal * it away), so we won't call enable hooks twice. */ - drm_atomic_bridge_pre_enable(encoder->bridge, old_state); + bridge = drm_bridge_chain_get_first_bridge(encoder); + drm_atomic_bridge_chain_pre_enable(bridge, old_state); if (funcs) { if (funcs->atomic_enable) @@ -1343,7 +1374,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, funcs->commit(encoder); } - drm_atomic_bridge_enable(encoder->bridge, old_state); + drm_atomic_bridge_chain_enable(bridge, old_state); } drm_atomic_helper_commit_writebacks(dev, old_state); @@ -1403,12 +1434,12 @@ int drm_atomic_helper_wait_for_fences(struct drm_device *dev, EXPORT_SYMBOL(drm_atomic_helper_wait_for_fences); /** - * drm_atomic_helper_wait_for_vblanks - wait for vblank on crtcs + * drm_atomic_helper_wait_for_vblanks - wait for vblank on CRTCs * @dev: DRM device * @old_state: atomic state object with old state structures * - * Helper to, after atomic commit, wait for vblanks on all effected - * crtcs (ie. before cleaning up old framebuffers using + * Helper to, after atomic commit, wait for vblanks on all affected + * CRTCs (ie. before cleaning up old framebuffers using * drm_atomic_helper_cleanup_planes()). It will only wait on CRTCs where the * framebuffers have actually changed to optimize for the legacy cursor and * plane update use-case. @@ -1467,10 +1498,10 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks); * @dev: DRM device * @old_state: atomic state object with old state structures * - * Helper to, after atomic commit, wait for page flips on all effected + * Helper to, after atomic commit, wait for page flips on all affected * crtcs (ie. before cleaning up old framebuffers using * drm_atomic_helper_cleanup_planes()). Compared to - * drm_atomic_helper_wait_for_vblanks() this waits for the completion of on all + * drm_atomic_helper_wait_for_vblanks() this waits for the completion on all * CRTCs, assuming that cursors-only updates are signalling their completion * immediately (or using a different path). * @@ -1834,17 +1865,21 @@ EXPORT_SYMBOL(drm_atomic_helper_commit); /** * DOC: implementing nonblocking commit * - * Nonblocking atomic commits have to be implemented in the following sequence: + * Nonblocking atomic commits should use struct &drm_crtc_commit to sequence + * different operations against each another. Locks, especially struct + * &drm_modeset_lock, should not be held in worker threads or any other + * asynchronous context used to commit the hardware state. + * + * drm_atomic_helper_commit() implements the recommended sequence for + * nonblocking commits, using drm_atomic_helper_setup_commit() internally: * - * 1. Run drm_atomic_helper_prepare_planes() first. This is the only function - * which commit needs to call which can fail, so we want to run it first and + * 1. Run drm_atomic_helper_prepare_planes(). Since this can fail and we + * need to propagate out of memory/VRAM errors to userspace, it must be called * synchronously. * * 2. Synchronize with any outstanding nonblocking commit worker threads which - * might be affected the new state update. This can be done by either cancelling - * or flushing the work items, depending upon whether the driver can deal with - * cancelled updates. Note that it is important to ensure that the framebuffer - * cleanup is still done when cancelling. + * might be affected by the new state update. This is handled by + * drm_atomic_helper_setup_commit(). * * Asynchronous workers need to have sufficient parallelism to be able to run * different atomic commits on different CRTCs in parallel. The simplest way to @@ -1855,21 +1890,29 @@ EXPORT_SYMBOL(drm_atomic_helper_commit); * must be done as one global operation, and enabling or disabling a CRTC can * take a long time. But even that is not required. * + * IMPORTANT: A &drm_atomic_state update for multiple CRTCs is sequenced + * against all CRTCs therein. Therefore for atomic state updates which only flip + * planes the driver must not get the struct &drm_crtc_state of unrelated CRTCs + * in its atomic check code: This would prevent committing of atomic updates to + * multiple CRTCs in parallel. In general, adding additional state structures + * should be avoided as much as possible, because this reduces parallelism in + * (nonblocking) commits, both due to locking and due to commit sequencing + * requirements. + * * 3. The software state is updated synchronously with * drm_atomic_helper_swap_state(). Doing this under the protection of all modeset - * locks means concurrent callers never see inconsistent state. And doing this - * while it's guaranteed that no relevant nonblocking worker runs means that - * nonblocking workers do not need grab any locks. Actually they must not grab - * locks, for otherwise the work flushing will deadlock. + * locks means concurrent callers never see inconsistent state. Note that commit + * workers do not hold any locks; their access is only coordinated through + * ordering. If workers would access state only through the pointers in the + * free-standing state objects (currently not the case for any driver) then even + * multiple pending commits could be in-flight at the same time. * * 4. Schedule a work item to do all subsequent steps, using the split-out * commit helpers: a) pre-plane commit b) plane commit c) post-plane commit and * then cleaning up the framebuffers after the old framebuffer is no longer - * being displayed. - * - * The above scheme is implemented in the atomic helper libraries in - * drm_atomic_helper_commit() using a bunch of helper functions. See - * drm_atomic_helper_setup_commit() for a starting point. + * being displayed. The scheduled work should synchronize against other workers + * using the &drm_crtc_commit infrastructure as needed. See + * drm_atomic_helper_setup_commit() for more details. */ static int stall_checks(struct drm_crtc *crtc, bool nonblock) @@ -2098,7 +2141,7 @@ EXPORT_SYMBOL(drm_atomic_helper_setup_commit); * * This function waits for all preceeding commits that touch the same CRTC as * @old_state to both be committed to the hardware (as signalled by - * drm_atomic_helper_commit_hw_done) and executed by the hardware (as signalled + * drm_atomic_helper_commit_hw_done()) and executed by the hardware (as signalled * by calling drm_crtc_send_vblank_event() on the &drm_crtc_state.event). * * This is part of the atomic helper support for nonblocking commits, see @@ -2185,7 +2228,7 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies); * drm_atomic_helper_fake_vblank - fake VBLANK events if needed * @old_state: atomic state object with old state structures * - * This function walks all CRTCs and fake VBLANK events on those with + * This function walks all CRTCs and fakes VBLANK events on those with * &drm_crtc_state.no_vblank set to true and &drm_crtc_state.event != NULL. * The primary use of this function is writeback connectors working in oneshot * mode and faking VBLANK events. In this case they only fake the VBLANK event @@ -2381,7 +2424,7 @@ static bool plane_crtc_active(const struct drm_plane_state *state) * @flags: flags for committing plane state * * This function commits the new plane state using the plane and atomic helper - * functions for planes and crtcs. It assumes that the atomic state has already + * functions for planes and CRTCs. It assumes that the atomic state has already * been pushed into the relevant object state pointers, since this step can no * longer fail. * @@ -2502,15 +2545,15 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, EXPORT_SYMBOL(drm_atomic_helper_commit_planes); /** - * drm_atomic_helper_commit_planes_on_crtc - commit plane state for a crtc - * @old_crtc_state: atomic state object with the old crtc state + * drm_atomic_helper_commit_planes_on_crtc - commit plane state for a CRTC + * @old_crtc_state: atomic state object with the old CRTC state * * This function commits the new plane state using the plane and atomic helper - * functions for planes on the specific crtc. It assumes that the atomic state + * functions for planes on the specific CRTC. It assumes that the atomic state * has already been pushed into the relevant object state pointers, since this * step can no longer fail. * - * This function is useful when plane updates should be done crtc-by-crtc + * This function is useful when plane updates should be done CRTC-by-CRTC * instead of one global step like drm_atomic_helper_commit_planes() does. * * This function can only be savely used when planes are not allowed to move @@ -2800,10 +2843,10 @@ EXPORT_SYMBOL(drm_atomic_helper_swap_state); * @plane: plane object to update * @crtc: owning CRTC of owning plane * @fb: framebuffer to flip onto plane - * @crtc_x: x offset of primary plane on crtc - * @crtc_y: y offset of primary plane on crtc - * @crtc_w: width of primary plane rectangle on crtc - * @crtc_h: height of primary plane rectangle on crtc + * @crtc_x: x offset of primary plane on @crtc + * @crtc_y: y offset of primary plane on @crtc + * @crtc_w: width of primary plane rectangle on @crtc + * @crtc_h: height of primary plane rectangle on @crtc * @src_x: x offset of @fb for panning * @src_y: y offset of @fb for panning * @src_w: width of source rectangle in @fb @@ -2909,7 +2952,7 @@ EXPORT_SYMBOL(drm_atomic_helper_disable_plane); * @set: mode set configuration * @ctx: lock acquisition context * - * Provides a default crtc set_config handler using the atomic driver interface. + * Provides a default CRTC set_config handler using the atomic driver interface. * * NOTE: For backwards compatibility with old userspace this automatically * resets the "link-status" property to GOOD, to force any link @@ -3322,7 +3365,7 @@ static int page_flip_common(struct drm_atomic_state *state, /** * drm_atomic_helper_page_flip - execute a legacy page flip - * @crtc: DRM crtc + * @crtc: DRM CRTC * @fb: DRM framebuffer * @event: optional DRM event to signal upon completion * @flags: flip flags for non-vblank sync'ed updates @@ -3366,7 +3409,7 @@ EXPORT_SYMBOL(drm_atomic_helper_page_flip); /** * drm_atomic_helper_page_flip_target - do page flip on target vblank period. - * @crtc: DRM crtc + * @crtc: DRM CRTC * @fb: DRM framebuffer * @event: optional DRM event to signal upon completion * @flags: flip flags for non-vblank sync'ed updates diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 0d466d3b08090d756b7bb31343c606cf20b0ac90..a1e5e262bae2d76b432cbd68a870809094e61159 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -160,12 +160,12 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc); /** - * drm_atomic_set_crtc_for_plane - set crtc for plane + * drm_atomic_set_crtc_for_plane - set CRTC for plane * @plane_state: the plane whose incoming state to update - * @crtc: crtc to use for the plane + * @crtc: CRTC to use for the plane * - * Changing the assigned crtc for a plane requires us to grab the lock and state - * for the new crtc, as needed. This function takes care of all these details + * Changing the assigned CRTC for a plane requires us to grab the lock and state + * for the new CRTC, as needed. This function takes care of all these details * besides updating the pointer in the state object itself. * * Returns: @@ -279,12 +279,12 @@ drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state, EXPORT_SYMBOL(drm_atomic_set_fence_for_plane); /** - * drm_atomic_set_crtc_for_connector - set crtc for connector + * drm_atomic_set_crtc_for_connector - set CRTC for connector * @conn_state: atomic state object for the connector - * @crtc: crtc to use for the connector + * @crtc: CRTC to use for the connector * - * Changing the assigned crtc for a connector requires us to grab the lock and - * state for the new crtc, as needed. This function takes care of all these + * Changing the assigned CRTC for a connector requires us to grab the lock and + * state for the new CRTC, as needed. This function takes care of all these * details besides updating the pointer in the state object itself. * * Returns: diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index cba537c99e43720f54b5d946095a2ade9a3230af..37400607e9b739d302d0bb18edc0808487b4963b 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -55,7 +56,7 @@ * just provide additional hooks to get the desired output at the end of the * encoder chain. * - * Bridges can also be chained up using the &drm_bridge.next pointer. + * Bridges can also be chained up using the &drm_bridge.chain_node field. * * Both legacy CRTC helpers and the new atomic modeset helpers support bridges. */ @@ -89,6 +90,74 @@ void drm_bridge_remove(struct drm_bridge *bridge) } EXPORT_SYMBOL(drm_bridge_remove); +static struct drm_bridge_state * +drm_atomic_default_bridge_duplicate_state(struct drm_bridge *bridge) +{ + struct drm_bridge_state *new; + + if (WARN_ON(!bridge->base.state)) + return NULL; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (new) + __drm_atomic_helper_bridge_duplicate_state(bridge, new); + + return new; +} + +static struct drm_private_state * +drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj *obj) +{ + struct drm_bridge *bridge = drm_priv_to_bridge(obj); + struct drm_bridge_state *state; + + if (bridge->funcs->atomic_duplicate_state) + state = bridge->funcs->atomic_duplicate_state(bridge); + else + state = drm_atomic_default_bridge_duplicate_state(bridge); + + return state ? &state->base : NULL; +} + +static void +drm_atomic_default_bridge_destroy_state(struct drm_bridge *bridge, + struct drm_bridge_state *state) +{ + /* Just a simple kfree() for now */ + kfree(state); +} + +static void +drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj, + struct drm_private_state *s) +{ + struct drm_bridge_state *state = drm_priv_to_bridge_state(s); + struct drm_bridge *bridge = drm_priv_to_bridge(obj); + + if (bridge->funcs->atomic_destroy_state) + bridge->funcs->atomic_destroy_state(bridge, state); + else + drm_atomic_default_bridge_destroy_state(bridge, state); +} + +static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = { + .atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state, + .atomic_destroy_state = drm_bridge_atomic_destroy_priv_state, +}; + +static struct drm_bridge_state * +drm_atomic_default_bridge_reset(struct drm_bridge *bridge) +{ + struct drm_bridge_state *bridge_state; + + bridge_state = kzalloc(sizeof(*bridge_state), GFP_KERNEL); + if (!bridge_state) + return ERR_PTR(-ENOMEM); + + __drm_atomic_helper_bridge_reset(bridge, bridge_state); + return bridge_state; +} + /** * drm_bridge_attach - attach the bridge to an encoder's chain * @@ -114,6 +183,7 @@ EXPORT_SYMBOL(drm_bridge_remove); int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, struct drm_bridge *previous) { + struct drm_bridge_state *state; int ret; if (!encoder || !bridge) @@ -128,21 +198,42 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, bridge->dev = encoder->dev; bridge->encoder = encoder; + if (previous) + list_add(&bridge->chain_node, &previous->chain_node); + else + list_add(&bridge->chain_node, &encoder->bridge_chain); + if (bridge->funcs->attach) { ret = bridge->funcs->attach(bridge); - if (ret < 0) { - bridge->dev = NULL; - bridge->encoder = NULL; - return ret; - } + if (ret < 0) + goto err_reset_bridge; } - if (previous) - previous->next = bridge; + if (bridge->funcs->atomic_reset) + state = bridge->funcs->atomic_reset(bridge); else - encoder->bridge = bridge; + state = drm_atomic_default_bridge_reset(bridge); + + if (IS_ERR(state)) { + ret = PTR_ERR(state); + goto err_detach_bridge; + } + + drm_atomic_private_obj_init(bridge->dev, &bridge->base, + &state->base, + &drm_bridge_priv_state_funcs); return 0; + +err_detach_bridge: + if (bridge->funcs->detach) + bridge->funcs->detach(bridge); + +err_reset_bridge: + bridge->dev = NULL; + bridge->encoder = NULL; + list_del(&bridge->chain_node); + return ret; } EXPORT_SYMBOL(drm_bridge_attach); @@ -154,9 +245,12 @@ void drm_bridge_detach(struct drm_bridge *bridge) if (WARN_ON(!bridge->dev)) return; + drm_atomic_private_obj_fini(&bridge->base); + if (bridge->funcs->detach) bridge->funcs->detach(bridge); + list_del(&bridge->chain_node); bridge->dev = NULL; } @@ -172,8 +266,8 @@ void drm_bridge_detach(struct drm_bridge *bridge) */ /** - * drm_bridge_mode_fixup - fixup proposed mode for all bridges in the - * encoder chain + * drm_bridge_chain_mode_fixup - fixup proposed mode for all bridges in the + * encoder chain * @bridge: bridge control structure * @mode: desired mode to be set for the bridge * @adjusted_mode: updated mode that works for this bridge @@ -186,27 +280,31 @@ void drm_bridge_detach(struct drm_bridge *bridge) * RETURNS: * true on success, false on failure */ -bool drm_bridge_mode_fixup(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { - bool ret = true; + struct drm_encoder *encoder; if (!bridge) return true; - if (bridge->funcs->mode_fixup) - ret = bridge->funcs->mode_fixup(bridge, mode, adjusted_mode); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (!bridge->funcs->mode_fixup) + continue; - ret = ret && drm_bridge_mode_fixup(bridge->next, mode, adjusted_mode); + if (!bridge->funcs->mode_fixup(bridge, mode, adjusted_mode)) + return false; + } - return ret; + return true; } -EXPORT_SYMBOL(drm_bridge_mode_fixup); +EXPORT_SYMBOL(drm_bridge_chain_mode_fixup); /** - * drm_bridge_mode_valid - validate the mode against all bridges in the - * encoder chain. + * drm_bridge_chain_mode_valid - validate the mode against all bridges in the + * encoder chain. * @bridge: bridge control structure * @mode: desired mode to be validated * @@ -219,26 +317,33 @@ EXPORT_SYMBOL(drm_bridge_mode_fixup); * RETURNS: * MODE_OK on success, drm_mode_status Enum error code on failure */ -enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge, - const struct drm_display_mode *mode) +enum drm_mode_status +drm_bridge_chain_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode) { - enum drm_mode_status ret = MODE_OK; + struct drm_encoder *encoder; if (!bridge) - return ret; + return MODE_OK; - if (bridge->funcs->mode_valid) - ret = bridge->funcs->mode_valid(bridge, mode); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + enum drm_mode_status ret; - if (ret != MODE_OK) - return ret; + if (!bridge->funcs->mode_valid) + continue; - return drm_bridge_mode_valid(bridge->next, mode); + ret = bridge->funcs->mode_valid(bridge, mode); + if (ret != MODE_OK) + return ret; + } + + return MODE_OK; } -EXPORT_SYMBOL(drm_bridge_mode_valid); +EXPORT_SYMBOL(drm_bridge_chain_mode_valid); /** - * drm_bridge_disable - disables all bridges in the encoder chain + * drm_bridge_chain_disable - disables all bridges in the encoder chain * @bridge: bridge control structure * * Calls &drm_bridge_funcs.disable op for all the bridges in the encoder @@ -247,20 +352,28 @@ EXPORT_SYMBOL(drm_bridge_mode_valid); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_bridge_disable(struct drm_bridge *bridge) +void drm_bridge_chain_disable(struct drm_bridge *bridge) { + struct drm_encoder *encoder; + struct drm_bridge *iter; + if (!bridge) return; - drm_bridge_disable(bridge->next); + encoder = bridge->encoder; + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { + if (iter->funcs->disable) + iter->funcs->disable(iter); - if (bridge->funcs->disable) - bridge->funcs->disable(bridge); + if (iter == bridge) + break; + } } -EXPORT_SYMBOL(drm_bridge_disable); +EXPORT_SYMBOL(drm_bridge_chain_disable); /** - * drm_bridge_post_disable - cleans up after disabling all bridges in the encoder chain + * drm_bridge_chain_post_disable - cleans up after disabling all bridges in the + * encoder chain * @bridge: bridge control structure * * Calls &drm_bridge_funcs.post_disable op for all the bridges in the @@ -269,47 +382,53 @@ EXPORT_SYMBOL(drm_bridge_disable); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_bridge_post_disable(struct drm_bridge *bridge) +void drm_bridge_chain_post_disable(struct drm_bridge *bridge) { + struct drm_encoder *encoder; + if (!bridge) return; - if (bridge->funcs->post_disable) - bridge->funcs->post_disable(bridge); - - drm_bridge_post_disable(bridge->next); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (bridge->funcs->post_disable) + bridge->funcs->post_disable(bridge); + } } -EXPORT_SYMBOL(drm_bridge_post_disable); +EXPORT_SYMBOL(drm_bridge_chain_post_disable); /** - * drm_bridge_mode_set - set proposed mode for all bridges in the - * encoder chain + * drm_bridge_chain_mode_set - set proposed mode for all bridges in the + * encoder chain * @bridge: bridge control structure - * @mode: desired mode to be set for the bridge - * @adjusted_mode: updated mode that works for this bridge + * @mode: desired mode to be set for the encoder chain + * @adjusted_mode: updated mode that works for this encoder chain * * Calls &drm_bridge_funcs.mode_set op for all the bridges in the * encoder chain, starting from the first bridge to the last. * * Note: the bridge passed should be the one closest to the encoder */ -void drm_bridge_mode_set(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - const struct drm_display_mode *adjusted_mode) +void drm_bridge_chain_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { + struct drm_encoder *encoder; + if (!bridge) return; - if (bridge->funcs->mode_set) - bridge->funcs->mode_set(bridge, mode, adjusted_mode); - - drm_bridge_mode_set(bridge->next, mode, adjusted_mode); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (bridge->funcs->mode_set) + bridge->funcs->mode_set(bridge, mode, adjusted_mode); + } } -EXPORT_SYMBOL(drm_bridge_mode_set); +EXPORT_SYMBOL(drm_bridge_chain_mode_set); /** - * drm_bridge_pre_enable - prepares for enabling all - * bridges in the encoder chain + * drm_bridge_chain_pre_enable - prepares for enabling all bridges in the + * encoder chain * @bridge: bridge control structure * * Calls &drm_bridge_funcs.pre_enable op for all the bridges in the encoder @@ -318,20 +437,24 @@ EXPORT_SYMBOL(drm_bridge_mode_set); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_bridge_pre_enable(struct drm_bridge *bridge) +void drm_bridge_chain_pre_enable(struct drm_bridge *bridge) { + struct drm_encoder *encoder; + struct drm_bridge *iter; + if (!bridge) return; - drm_bridge_pre_enable(bridge->next); - - if (bridge->funcs->pre_enable) - bridge->funcs->pre_enable(bridge); + encoder = bridge->encoder; + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { + if (iter->funcs->pre_enable) + iter->funcs->pre_enable(iter); + } } -EXPORT_SYMBOL(drm_bridge_pre_enable); +EXPORT_SYMBOL(drm_bridge_chain_pre_enable); /** - * drm_bridge_enable - enables all bridges in the encoder chain + * drm_bridge_chain_enable - enables all bridges in the encoder chain * @bridge: bridge control structure * * Calls &drm_bridge_funcs.enable op for all the bridges in the encoder @@ -340,22 +463,25 @@ EXPORT_SYMBOL(drm_bridge_pre_enable); * * Note that the bridge passed should be the one closest to the encoder */ -void drm_bridge_enable(struct drm_bridge *bridge) +void drm_bridge_chain_enable(struct drm_bridge *bridge) { + struct drm_encoder *encoder; + if (!bridge) return; - if (bridge->funcs->enable) - bridge->funcs->enable(bridge); - - drm_bridge_enable(bridge->next); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (bridge->funcs->enable) + bridge->funcs->enable(bridge); + } } -EXPORT_SYMBOL(drm_bridge_enable); +EXPORT_SYMBOL(drm_bridge_chain_enable); /** - * drm_atomic_bridge_disable - disables all bridges in the encoder chain + * drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain * @bridge: bridge control structure - * @state: atomic state being committed + * @old_state: old atomic state * * Calls &drm_bridge_funcs.atomic_disable (falls back on * &drm_bridge_funcs.disable) op for all the bridges in the encoder chain, @@ -364,26 +490,42 @@ EXPORT_SYMBOL(drm_bridge_enable); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_atomic_bridge_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, + struct drm_atomic_state *old_state) { + struct drm_encoder *encoder; + struct drm_bridge *iter; + if (!bridge) return; - drm_atomic_bridge_disable(bridge->next, state); + encoder = bridge->encoder; + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { + if (iter->funcs->atomic_disable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + iter); + if (WARN_ON(!old_bridge_state)) + return; + + iter->funcs->atomic_disable(iter, old_bridge_state); + } else if (iter->funcs->disable) { + iter->funcs->disable(iter); + } - if (bridge->funcs->atomic_disable) - bridge->funcs->atomic_disable(bridge, state); - else if (bridge->funcs->disable) - bridge->funcs->disable(bridge); + if (iter == bridge) + break; + } } -EXPORT_SYMBOL(drm_atomic_bridge_disable); +EXPORT_SYMBOL(drm_atomic_bridge_chain_disable); /** - * drm_atomic_bridge_post_disable - cleans up after disabling all bridges in the - * encoder chain + * drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges + * in the encoder chain * @bridge: bridge control structure - * @state: atomic state being committed + * @old_state: old atomic state * * Calls &drm_bridge_funcs.atomic_post_disable (falls back on * &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain, @@ -392,26 +534,39 @@ EXPORT_SYMBOL(drm_atomic_bridge_disable); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_atomic_bridge_post_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, + struct drm_atomic_state *old_state) { + struct drm_encoder *encoder; + if (!bridge) return; - if (bridge->funcs->atomic_post_disable) - bridge->funcs->atomic_post_disable(bridge, state); - else if (bridge->funcs->post_disable) - bridge->funcs->post_disable(bridge); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (bridge->funcs->atomic_post_disable) { + struct drm_bridge_state *old_bridge_state; - drm_atomic_bridge_post_disable(bridge->next, state); + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + bridge); + if (WARN_ON(!old_bridge_state)) + return; + + bridge->funcs->atomic_post_disable(bridge, + old_bridge_state); + } else if (bridge->funcs->post_disable) { + bridge->funcs->post_disable(bridge); + } + } } -EXPORT_SYMBOL(drm_atomic_bridge_post_disable); +EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); /** - * drm_atomic_bridge_pre_enable - prepares for enabling all bridges in the - * encoder chain + * drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in + * the encoder chain * @bridge: bridge control structure - * @state: atomic state being committed + * @old_state: old atomic state * * Calls &drm_bridge_funcs.atomic_pre_enable (falls back on * &drm_bridge_funcs.pre_enable) op for all the bridges in the encoder chain, @@ -420,25 +575,41 @@ EXPORT_SYMBOL(drm_atomic_bridge_post_disable); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_state *old_state) { + struct drm_encoder *encoder; + struct drm_bridge *iter; + if (!bridge) return; - drm_atomic_bridge_pre_enable(bridge->next, state); + encoder = bridge->encoder; + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { + if (iter->funcs->atomic_pre_enable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + iter); + if (WARN_ON(!old_bridge_state)) + return; + + iter->funcs->atomic_pre_enable(iter, old_bridge_state); + } else if (iter->funcs->pre_enable) { + iter->funcs->pre_enable(iter); + } - if (bridge->funcs->atomic_pre_enable) - bridge->funcs->atomic_pre_enable(bridge, state); - else if (bridge->funcs->pre_enable) - bridge->funcs->pre_enable(bridge); + if (iter == bridge) + break; + } } -EXPORT_SYMBOL(drm_atomic_bridge_pre_enable); +EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable); /** - * drm_atomic_bridge_enable - enables all bridges in the encoder chain + * drm_atomic_bridge_chain_enable - enables all bridges in the encoder chain * @bridge: bridge control structure - * @state: atomic state being committed + * @old_state: old atomic state * * Calls &drm_bridge_funcs.atomic_enable (falls back on * &drm_bridge_funcs.enable) op for all the bridges in the encoder chain, @@ -447,20 +618,394 @@ EXPORT_SYMBOL(drm_atomic_bridge_pre_enable); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_atomic_bridge_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, + struct drm_atomic_state *old_state) { + struct drm_encoder *encoder; + if (!bridge) return; - if (bridge->funcs->atomic_enable) - bridge->funcs->atomic_enable(bridge, state); - else if (bridge->funcs->enable) - bridge->funcs->enable(bridge); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (bridge->funcs->atomic_enable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + bridge); + if (WARN_ON(!old_bridge_state)) + return; + + bridge->funcs->atomic_enable(bridge, old_bridge_state); + } else if (bridge->funcs->enable) { + bridge->funcs->enable(bridge); + } + } +} +EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); + +static int drm_atomic_bridge_check(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + if (bridge->funcs->atomic_check) { + struct drm_bridge_state *bridge_state; + int ret; + + bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, + bridge); + if (WARN_ON(!bridge_state)) + return -EINVAL; + + ret = bridge->funcs->atomic_check(bridge, bridge_state, + crtc_state, conn_state); + if (ret) + return ret; + } else if (bridge->funcs->mode_fixup) { + if (!bridge->funcs->mode_fixup(bridge, &crtc_state->mode, + &crtc_state->adjusted_mode)) + return -EINVAL; + } + + return 0; +} + +/** + * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to + * the input end of a bridge + * @bridge: bridge control structure + * @bridge_state: new bridge state + * @crtc_state: new CRTC state + * @conn_state: new connector state + * @output_fmt: tested output bus format + * @num_input_fmts: will contain the size of the returned array + * + * This helper is a pluggable implementation of the + * &drm_bridge_funcs.atomic_get_input_bus_fmts operation for bridges that don't + * modify the bus configuration between their input and their output. It + * returns an array of input formats with a single element set to @output_fmt. + * + * RETURNS: + * a valid format array of size @num_input_fmts, or NULL if the allocation + * failed + */ +u32 * +drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + u32 *input_fmts; + + input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL); + if (!input_fmts) { + *num_input_fmts = 0; + return NULL; + } + + *num_input_fmts = 1; + input_fmts[0] = output_fmt; + return input_fmts; +} +EXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt); + +static int select_bus_fmt_recursive(struct drm_bridge *first_bridge, + struct drm_bridge *cur_bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 out_bus_fmt) +{ + struct drm_bridge_state *cur_state; + unsigned int num_in_bus_fmts, i; + struct drm_bridge *prev_bridge; + u32 *in_bus_fmts; + int ret; + + prev_bridge = drm_bridge_get_prev_bridge(cur_bridge); + cur_state = drm_atomic_get_new_bridge_state(crtc_state->state, + cur_bridge); + if (WARN_ON(!cur_state)) + return -EINVAL; + + /* + * If bus format negotiation is not supported by this bridge, let's + * pass MEDIA_BUS_FMT_FIXED to the previous bridge in the chain and + * hope that it can handle this situation gracefully (by providing + * appropriate default values). + */ + if (!cur_bridge->funcs->atomic_get_input_bus_fmts) { + if (cur_bridge != first_bridge) { + ret = select_bus_fmt_recursive(first_bridge, + prev_bridge, crtc_state, + conn_state, + MEDIA_BUS_FMT_FIXED); + if (ret) + return ret; + } + + cur_state->input_bus_cfg.format = MEDIA_BUS_FMT_FIXED; + cur_state->output_bus_cfg.format = out_bus_fmt; + return 0; + } - drm_atomic_bridge_enable(bridge->next, state); + in_bus_fmts = cur_bridge->funcs->atomic_get_input_bus_fmts(cur_bridge, + cur_state, + crtc_state, + conn_state, + out_bus_fmt, + &num_in_bus_fmts); + if (!num_in_bus_fmts) + return -ENOTSUPP; + else if (!in_bus_fmts) + return -ENOMEM; + + if (first_bridge == cur_bridge) { + cur_state->input_bus_cfg.format = in_bus_fmts[0]; + cur_state->output_bus_cfg.format = out_bus_fmt; + kfree(in_bus_fmts); + return 0; + } + + for (i = 0; i < num_in_bus_fmts; i++) { + ret = select_bus_fmt_recursive(first_bridge, prev_bridge, + crtc_state, conn_state, + in_bus_fmts[i]); + if (ret != -ENOTSUPP) + break; + } + + if (!ret) { + cur_state->input_bus_cfg.format = in_bus_fmts[i]; + cur_state->output_bus_cfg.format = out_bus_fmt; + } + + kfree(in_bus_fmts); + return ret; +} + +/* + * This function is called by &drm_atomic_bridge_chain_check() just before + * calling &drm_bridge_funcs.atomic_check() on all elements of the chain. + * It performs bus format negotiation between bridge elements. The negotiation + * happens in reverse order, starting from the last element in the chain up to + * @bridge. + * + * Negotiation starts by retrieving supported output bus formats on the last + * bridge element and testing them one by one. The test is recursive, meaning + * that for each tested output format, the whole chain will be walked backward, + * and each element will have to choose an input bus format that can be + * transcoded to the requested output format. When a bridge element does not + * support transcoding into a specific output format -ENOTSUPP is returned and + * the next bridge element will have to try a different format. If none of the + * combinations worked, -ENOTSUPP is returned and the atomic modeset will fail. + * + * This implementation is relying on + * &drm_bridge_funcs.atomic_get_output_bus_fmts() and + * &drm_bridge_funcs.atomic_get_input_bus_fmts() to gather supported + * input/output formats. + * + * When &drm_bridge_funcs.atomic_get_output_bus_fmts() is not implemented by + * the last element of the chain, &drm_atomic_bridge_chain_select_bus_fmts() + * tries a single format: &drm_connector.display_info.bus_formats[0] if + * available, MEDIA_BUS_FMT_FIXED otherwise. + * + * When &drm_bridge_funcs.atomic_get_input_bus_fmts() is not implemented, + * &drm_atomic_bridge_chain_select_bus_fmts() skips the negotiation on the + * bridge element that lacks this hook and asks the previous element in the + * chain to try MEDIA_BUS_FMT_FIXED. It's up to bridge drivers to decide what + * to do in that case (fail if they want to enforce bus format negotiation, or + * provide a reasonable default if they need to support pipelines where not + * all elements support bus format negotiation). + */ +static int +drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_connector *conn = conn_state->connector; + struct drm_encoder *encoder = bridge->encoder; + struct drm_bridge_state *last_bridge_state; + unsigned int i, num_out_bus_fmts; + struct drm_bridge *last_bridge; + u32 *out_bus_fmts; + int ret = 0; + + last_bridge = list_last_entry(&encoder->bridge_chain, + struct drm_bridge, chain_node); + last_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, + last_bridge); + if (WARN_ON(!last_bridge_state)) + return -EINVAL; + + if (last_bridge->funcs->atomic_get_output_bus_fmts) { + const struct drm_bridge_funcs *funcs = last_bridge->funcs; + + out_bus_fmts = funcs->atomic_get_output_bus_fmts(last_bridge, + last_bridge_state, + crtc_state, + conn_state, + &num_out_bus_fmts); + if (!num_out_bus_fmts) + return -ENOTSUPP; + else if (!out_bus_fmts) + return -ENOMEM; + } else { + num_out_bus_fmts = 1; + out_bus_fmts = kmalloc(sizeof(*out_bus_fmts), GFP_KERNEL); + if (!out_bus_fmts) + return -ENOMEM; + + if (conn->display_info.num_bus_formats && + conn->display_info.bus_formats) + out_bus_fmts[0] = conn->display_info.bus_formats[0]; + else + out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED; + } + + for (i = 0; i < num_out_bus_fmts; i++) { + ret = select_bus_fmt_recursive(bridge, last_bridge, crtc_state, + conn_state, out_bus_fmts[i]); + if (ret != -ENOTSUPP) + break; + } + + kfree(out_bus_fmts); + + return ret; +} + +static void +drm_atomic_bridge_propagate_bus_flags(struct drm_bridge *bridge, + struct drm_connector *conn, + struct drm_atomic_state *state) +{ + struct drm_bridge_state *bridge_state, *next_bridge_state; + struct drm_bridge *next_bridge; + u32 output_flags; + + bridge_state = drm_atomic_get_new_bridge_state(state, bridge); + next_bridge = drm_bridge_get_next_bridge(bridge); + + /* + * Let's try to apply the most common case here, that is, propagate + * display_info flags for the last bridge, and propagate the input + * flags of the next bridge element to the output end of the current + * bridge when the bridge is not the last one. + * There are exceptions to this rule, like when signal inversion is + * happening at the board level, but that's something drivers can deal + * with from their &drm_bridge_funcs.atomic_check() implementation by + * simply overriding the flags value we've set here. + */ + if (!next_bridge) { + output_flags = conn->display_info.bus_flags; + } else { + next_bridge_state = drm_atomic_get_new_bridge_state(state, + next_bridge); + output_flags = next_bridge_state->input_bus_cfg.flags; + } + + bridge_state->output_bus_cfg.flags = output_flags; + + /* + * Propage the output flags to the input end of the bridge. Again, it's + * not necessarily what all bridges want, but that's what most of them + * do, and by doing that by default we avoid forcing drivers to + * duplicate the "dummy propagation" logic. + */ + bridge_state->input_bus_cfg.flags = output_flags; +} + +/** + * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain + * @bridge: bridge control structure + * @crtc_state: new CRTC state + * @conn_state: new connector state + * + * First trigger a bus format negotiation before calling + * &drm_bridge_funcs.atomic_check() (falls back on + * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain, + * starting from the last bridge to the first. These are called before calling + * &drm_encoder_helper_funcs.atomic_check() + * + * RETURNS: + * 0 on success, a negative error code on failure + */ +int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_connector *conn = conn_state->connector; + struct drm_encoder *encoder = bridge->encoder; + struct drm_bridge *iter; + int ret; + + ret = drm_atomic_bridge_chain_select_bus_fmts(bridge, crtc_state, + conn_state); + if (ret) + return ret; + + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { + int ret; + + /* + * Bus flags are propagated by default. If a bridge needs to + * tweak the input bus flags for any reason, it should happen + * in its &drm_bridge_funcs.atomic_check() implementation such + * that preceding bridges in the chain can propagate the new + * bus flags. + */ + drm_atomic_bridge_propagate_bus_flags(iter, conn, + crtc_state->state); + + ret = drm_atomic_bridge_check(iter, crtc_state, conn_state); + if (ret) + return ret; + + if (iter == bridge) + break; + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_bridge_chain_check); + +/** + * __drm_atomic_helper_bridge_reset() - Initialize a bridge state to its + * default + * @bridge: the bridge this state is refers to + * @state: bridge state to initialize + * + * Initialize the bridge state to default values. This is meant to be* called + * by the bridge &drm_plane_funcs.reset hook for bridges that subclass the + * bridge state. + */ +void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, + struct drm_bridge_state *state) +{ + memset(state, 0, sizeof(*state)); + state->bridge = bridge; +} +EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset); + +/** + * __drm_atomic_helper_bridge_duplicate_state() - Copy atomic bridge state + * @bridge: bridge object + * @state: atomic bridge state + * + * Copies atomic state from a bridge's current state and resets inferred values. + * This is useful for drivers that subclass the bridge state. + */ +void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, + struct drm_bridge_state *state) +{ + __drm_atomic_helper_private_obj_duplicate_state(&bridge->base, + &state->base); + state->bridge = bridge; } -EXPORT_SYMBOL(drm_atomic_bridge_enable); +EXPORT_SYMBOL(__drm_atomic_helper_bridge_duplicate_state); #ifdef CONFIG_OF /** diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index d9a2e3695525c0cceb624b625e595357c489c81b..b031b45aa8efefd7b04a26ad1be0283d30aecd0d 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -150,7 +150,7 @@ void drm_client_release(struct drm_client_dev *client) { struct drm_device *dev = client->dev; - DRM_DEV_DEBUG_KMS(dev->dev, "%s\n", client->name); + drm_dbg_kms(dev, "%s\n", client->name); drm_client_modeset_free(client); drm_client_close(client); @@ -203,7 +203,7 @@ void drm_client_dev_hotplug(struct drm_device *dev) continue; ret = client->funcs->hotplug(client); - DRM_DEV_DEBUG_KMS(dev->dev, "%s: ret=%d\n", client->name, ret); + drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret); } mutex_unlock(&dev->clientlist_mutex); } @@ -223,7 +223,7 @@ void drm_client_dev_restore(struct drm_device *dev) continue; ret = client->funcs->restore(client); - DRM_DEV_DEBUG_KMS(dev->dev, "%s: ret=%d\n", client->name, ret); + drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret); if (!ret) /* The first one to return zero gets the privilege to restore */ break; } @@ -351,8 +351,8 @@ static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer) ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file); if (ret) - DRM_DEV_ERROR(buffer->client->dev->dev, - "Error removing FB:%u (%d)\n", buffer->fb->base.id, ret); + drm_err(buffer->client->dev, + "Error removing FB:%u (%d)\n", buffer->fb->base.id, ret); buffer->fb = NULL; } diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index 4ce5c6d8de99b6f0f177fade0053de15090bb74e..c93123ff7c2186beead154597b21ba58f81c93c9 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -109,28 +109,38 @@ */ /** - * drm_color_lut_extract - clamp and round LUT entries + * drm_color_ctm_s31_32_to_qm_n + * * @user_input: input value - * @bit_precision: number of bits the hw LUT supports + * @m: number of integer bits, only support m <= 32, include the sign-bit + * @n: number of fractional bits, only support n <= 32 + * + * Convert and clamp S31.32 sign-magnitude to Qm.n (signed 2's complement). + * The sign-bit BIT(m+n-1) and above are 0 for positive value and 1 for negative + * the range of value is [-2^(m-1), 2^(m-1) - 2^-n] + * + * For example + * A Q3.12 format number: + * - required bit: 3 + 12 = 15bits + * - range: [-2^2, 2^2 - 2^−15] * - * Extract a degamma/gamma LUT value provided by user (in the form of - * &drm_color_lut entries) and round it to the precision supported by the - * hardware. + * NOTE: the m can be zero if all bit_precision are used to present fractional + * bits like Q0.32 */ -uint32_t drm_color_lut_extract(uint32_t user_input, uint32_t bit_precision) +u64 drm_color_ctm_s31_32_to_qm_n(u64 user_input, u32 m, u32 n) { - uint32_t val = user_input; - uint32_t max = 0xffff >> (16 - bit_precision); + u64 mag = (user_input & ~BIT_ULL(63)) >> (32 - n); + bool negative = !!(user_input & BIT_ULL(63)); + s64 val; - /* Round only if we're not using full precision. */ - if (bit_precision < 16) { - val += 1UL << (16 - bit_precision - 1); - val >>= 16 - bit_precision; - } + WARN_ON(m > 32 || n > 32); + + val = clamp_val(mag, 0, negative ? + BIT_ULL(n + m - 1) : BIT_ULL(n + m - 1) - 1); - return clamp_val(val, 0, max); + return negative ? -val : val; } -EXPORT_SYMBOL(drm_color_lut_extract); +EXPORT_SYMBOL(drm_color_ctm_s31_32_to_qm_n); /** * drm_crtc_enable_color_mgmt - enable color management properties diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 499b05aaccfc2d5536ac2a44bf915c7486a357f7..93a4eec429e8cfda0c15ec4a9ccca29409f53389 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -48,6 +48,8 @@ #include #include +#include "drm_crtc_helper_internal.h" + /** * DOC: overview * diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 273dd80fabf3cadb53d30be128fbd29c69f969aa..e68d23043973ccd7fe3dd51f15b53cdd70e7face 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -76,6 +76,11 @@ static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_branch *mstb); + +static void +drm_dp_send_clear_payload_id_table(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_branch *mstb); + static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_branch *mstb, struct drm_dp_mst_port *port); @@ -517,8 +522,10 @@ drm_dp_decode_sideband_req(const struct drm_dp_sideband_msg_tx *raw, } if (failed) { - for (i = 0; i < r->num_transactions; i++) + for (i = 0; i < r->num_transactions; i++) { + tx = &r->transactions[i]; kfree(tx->bytes); + } return -ENOMEM; } @@ -950,6 +957,8 @@ static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw, case DP_POWER_DOWN_PHY: case DP_POWER_UP_PHY: return drm_dp_sideband_parse_power_updown_phy_ack(raw, msg); + case DP_CLEAR_PAYLOAD_ID_TABLE: + return true; /* since there's nothing to parse */ default: DRM_ERROR("Got unknown reply 0x%02x (%s)\n", msg->req_type, drm_dp_mst_req_type_str(msg->req_type)); @@ -1048,6 +1057,15 @@ static int build_link_address(struct drm_dp_sideband_msg_tx *msg) return 0; } +static int build_clear_payload_id_table(struct drm_dp_sideband_msg_tx *msg) +{ + struct drm_dp_sideband_msg_req_body req; + + req.req_type = DP_CLEAR_PAYLOAD_ID_TABLE; + drm_dp_encode_sideband_req(&req, msg); + return 0; +} + static int build_enum_path_resources(struct drm_dp_sideband_msg_tx *msg, int port_num) { struct drm_dp_sideband_msg_req_body req; @@ -2520,10 +2538,14 @@ static void drm_dp_mst_link_probe_work(struct work_struct *work) struct drm_device *dev = mgr->dev; struct drm_dp_mst_branch *mstb; int ret; + bool clear_payload_id_table; mutex_lock(&mgr->probe_lock); mutex_lock(&mgr->lock); + clear_payload_id_table = !mgr->payload_id_table_cleared; + mgr->payload_id_table_cleared = true; + mstb = mgr->mst_primary; if (mstb) { ret = drm_dp_mst_topology_try_get_mstb(mstb); @@ -2536,6 +2558,19 @@ static void drm_dp_mst_link_probe_work(struct work_struct *work) return; } + /* + * Certain branch devices seem to incorrectly report an available_pbn + * of 0 on downstream sinks, even after clearing the + * DP_PAYLOAD_ALLOCATE_* registers in + * drm_dp_mst_topology_mgr_set_mst(). Namely, the CableMatters USB-C + * 2x DP hub. Sending a CLEAR_PAYLOAD_ID_TABLE message seems to make + * things work again. + */ + if (clear_payload_id_table) { + DRM_DEBUG_KMS("Clearing payload ID table\n"); + drm_dp_send_clear_payload_id_table(mgr, mstb); + } + ret = drm_dp_check_and_send_link_address(mgr, mstb); drm_dp_mst_topology_put_mstb(mstb); @@ -2859,6 +2894,28 @@ out: return ret < 0 ? ret : changed; } +void drm_dp_send_clear_payload_id_table(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_branch *mstb) +{ + struct drm_dp_sideband_msg_tx *txmsg; + int len, ret; + + txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); + if (!txmsg) + return; + + txmsg->dst = mstb; + len = build_clear_payload_id_table(txmsg); + + drm_dp_queue_down_tx(mgr, txmsg); + + ret = drm_dp_mst_wait_tx_reply(mstb, txmsg); + if (ret > 0 && txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) + DRM_DEBUG_KMS("clear payload table id nak received\n"); + + kfree(txmsg); +} + static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_branch *mstb, @@ -3388,6 +3445,7 @@ static int drm_dp_get_vc_payload_bw(u8 dp_link_bw, u8 dp_link_count) int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool mst_state) { int ret = 0; + int i = 0; struct drm_dp_mst_branch *mstb = NULL; mutex_lock(&mgr->lock); @@ -3448,10 +3506,23 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms /* this can fail if the device is gone */ drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, 0); ret = 0; + mutex_lock(&mgr->payload_lock); memset(mgr->payloads, 0, mgr->max_payloads * sizeof(struct drm_dp_payload)); mgr->payload_mask = 0; set_bit(0, &mgr->payload_mask); + for (i = 0; i < mgr->max_payloads; i++) { + struct drm_dp_vcpi *vcpi = mgr->proposed_vcpis[i]; + + if (vcpi) { + vcpi->vcpi = 0; + vcpi->num_slots = 0; + } + mgr->proposed_vcpis[i] = NULL; + } mgr->vcpi_mask = 0; + mutex_unlock(&mgr->payload_lock); + + mgr->payload_id_table_cleared = false; } out_unlock: diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 1b9b40a1c7c98659f1dbb23163a809be9438e745..7c18a980cd4b48d93c12745ecca61b77f2be65e7 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -622,7 +622,8 @@ int drm_dev_init(struct drm_device *dev, return -ENODEV; } - BUG_ON(!parent); + if (WARN_ON(!parent)) + return -EINVAL; kref_init(&dev->ref); dev->dev = get_device(parent); @@ -725,7 +726,7 @@ int devm_drm_dev_init(struct device *parent, { int ret; - if (WARN_ON(!parent || !driver->release)) + if (WARN_ON(!driver->release)) return -EINVAL; ret = drm_dev_init(dev, driver, parent); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 474ac04d5600689393e80041729bdb3358fc17b0..99769d6c9f8462e25d189c78df3990b8519b7b79 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -710,14 +710,11 @@ static const struct minimode extra_modes[] = { }; /* - * Probably taken from CEA-861 spec. - * This table is converted from xorg's hw/xfree86/modes/xf86EdidModes.c. + * From CEA/CTA-861 spec. * - * Index using the VIC. + * Do not access directly, instead always use cea_mode_for_vic(). */ -static const struct drm_display_mode edid_cea_modes[] = { - /* 0 - dummy, VICs start at 1 */ - { }, +static const struct drm_display_mode edid_cea_modes_1[] = { /* 1 - 640x480@60Hz 4:3 */ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, @@ -1380,6 +1377,149 @@ static const struct drm_display_mode edid_cea_modes[] = { .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, }; +/* + * From CEA/CTA-861 spec. + * + * Do not access directly, instead always use cea_mode_for_vic(). + */ +static const struct drm_display_mode edid_cea_modes_193[] = { + /* 193 - 5120x2160@120Hz 64:27 */ + { DRM_MODE("5120x2160", DRM_MODE_TYPE_DRIVER, 1485000, 5120, 5284, + 5372, 5500, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 194 - 7680x4320@24Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10232, + 10408, 11000, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 195 - 7680x4320@25Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10032, + 10208, 10800, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 196 - 7680x4320@30Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 8232, + 8408, 9000, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 197 - 7680x4320@48Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10232, + 10408, 11000, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 48, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 198 - 7680x4320@50Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10032, + 10208, 10800, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 199 - 7680x4320@60Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 8232, + 8408, 9000, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 200 - 7680x4320@100Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 9792, + 9968, 10560, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 201 - 7680x4320@120Hz 16:9 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 8032, + 8208, 8800, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 202 - 7680x4320@24Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10232, + 10408, 11000, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 203 - 7680x4320@25Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10032, + 10208, 10800, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 204 - 7680x4320@30Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 8232, + 8408, 9000, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 205 - 7680x4320@48Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10232, + 10408, 11000, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 48, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 206 - 7680x4320@50Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10032, + 10208, 10800, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 207 - 7680x4320@60Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 8232, + 8408, 9000, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 208 - 7680x4320@100Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 9792, + 9968, 10560, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 209 - 7680x4320@120Hz 64:27 */ + { DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 8032, + 8208, 8800, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 210 - 10240x4320@24Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 1485000, 10240, 11732, + 11908, 12500, 0, 4320, 4336, 4356, 4950, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 211 - 10240x4320@25Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 1485000, 10240, 12732, + 12908, 13500, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 212 - 10240x4320@30Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 1485000, 10240, 10528, + 10704, 11000, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 213 - 10240x4320@48Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 2970000, 10240, 11732, + 11908, 12500, 0, 4320, 4336, 4356, 4950, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 48, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 214 - 10240x4320@50Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 2970000, 10240, 12732, + 12908, 13500, 0, 4320, 4336, 4356, 4400, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 215 - 10240x4320@60Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 2970000, 10240, 10528, + 10704, 11000, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 216 - 10240x4320@100Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 5940000, 10240, 12432, + 12608, 13200, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 217 - 10240x4320@120Hz 64:27 */ + { DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 5940000, 10240, 10528, + 10704, 11000, 0, 4320, 4336, 4356, 4500, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, + /* 218 - 4096x2160@100Hz 256:135 */ + { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 1188000, 4096, 4896, + 4984, 5280, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, + /* 219 - 4096x2160@120Hz 256:135 */ + { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 1188000, 4096, 4184, + 4272, 4400, 0, 2160, 2168, 2178, 2250, 0, + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, +}; + /* * HDMI 1.4 4k modes. Index using the VIC. */ @@ -1391,25 +1531,25 @@ static const struct drm_display_mode edid_4k_modes[] = { 3840, 4016, 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 30, }, + .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 2 - 3840x2160@25Hz */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4896, 4984, 5280, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 25, }, + .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 3 - 3840x2160@24Hz */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 5116, 5204, 5500, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 24, }, + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 4 - 4096x2160@24Hz (SMPTE) */ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 5116, 5204, 5500, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 24, }, + .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, }; /*** DDC fetch and block validation ***/ @@ -3071,6 +3211,30 @@ static u8 *drm_find_cea_extension(const struct edid *edid) return cea; } +static const struct drm_display_mode *cea_mode_for_vic(u8 vic) +{ + BUILD_BUG_ON(1 + ARRAY_SIZE(edid_cea_modes_1) - 1 != 127); + BUILD_BUG_ON(193 + ARRAY_SIZE(edid_cea_modes_193) - 1 != 219); + + if (vic >= 1 && vic < 1 + ARRAY_SIZE(edid_cea_modes_1)) + return &edid_cea_modes_1[vic - 1]; + if (vic >= 193 && vic < 193 + ARRAY_SIZE(edid_cea_modes_193)) + return &edid_cea_modes_193[vic - 193]; + return NULL; +} + +static u8 cea_num_vics(void) +{ + return 193 + ARRAY_SIZE(edid_cea_modes_193); +} + +static u8 cea_next_vic(u8 vic) +{ + if (++vic == 1 + ARRAY_SIZE(edid_cea_modes_1)) + vic = 193; + return vic; +} + /* * Calculate the alternate clock for the CEA mode * (60Hz vs. 59.94Hz etc.) @@ -3108,14 +3272,14 @@ cea_mode_alternate_timings(u8 vic, struct drm_display_mode *mode) * get the other variants by simply increasing the * vertical front porch length. */ - BUILD_BUG_ON(edid_cea_modes[8].vtotal != 262 || - edid_cea_modes[9].vtotal != 262 || - edid_cea_modes[12].vtotal != 262 || - edid_cea_modes[13].vtotal != 262 || - edid_cea_modes[23].vtotal != 312 || - edid_cea_modes[24].vtotal != 312 || - edid_cea_modes[27].vtotal != 312 || - edid_cea_modes[28].vtotal != 312); + BUILD_BUG_ON(cea_mode_for_vic(8)->vtotal != 262 || + cea_mode_for_vic(9)->vtotal != 262 || + cea_mode_for_vic(12)->vtotal != 262 || + cea_mode_for_vic(13)->vtotal != 262 || + cea_mode_for_vic(23)->vtotal != 312 || + cea_mode_for_vic(24)->vtotal != 312 || + cea_mode_for_vic(27)->vtotal != 312 || + cea_mode_for_vic(28)->vtotal != 312); if (((vic == 8 || vic == 9 || vic == 12 || vic == 13) && mode->vtotal < 263) || @@ -3143,8 +3307,8 @@ static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_m if (to_match->picture_aspect_ratio) match_flags |= DRM_MODE_MATCH_ASPECT_RATIO; - for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) { - struct drm_display_mode cea_mode = edid_cea_modes[vic]; + for (vic = 1; vic < cea_num_vics(); vic = cea_next_vic(vic)) { + struct drm_display_mode cea_mode = *cea_mode_for_vic(vic); unsigned int clock1, clock2; /* Check both 60Hz and 59.94Hz */ @@ -3182,8 +3346,8 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match) if (to_match->picture_aspect_ratio) match_flags |= DRM_MODE_MATCH_ASPECT_RATIO; - for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) { - struct drm_display_mode cea_mode = edid_cea_modes[vic]; + for (vic = 1; vic < cea_num_vics(); vic = cea_next_vic(vic)) { + struct drm_display_mode cea_mode = *cea_mode_for_vic(vic); unsigned int clock1, clock2; /* Check both 60Hz and 59.94Hz */ @@ -3206,28 +3370,31 @@ EXPORT_SYMBOL(drm_match_cea_mode); static bool drm_valid_cea_vic(u8 vic) { - return vic > 0 && vic < ARRAY_SIZE(edid_cea_modes); + return cea_mode_for_vic(vic) != NULL; } static enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code) { - return edid_cea_modes[video_code].picture_aspect_ratio; + const struct drm_display_mode *mode = cea_mode_for_vic(video_code); + + if (mode) + return mode->picture_aspect_ratio; + + return HDMI_PICTURE_ASPECT_NONE; +} + +static enum hdmi_picture_aspect drm_get_hdmi_aspect_ratio(const u8 video_code) +{ + return edid_4k_modes[video_code].picture_aspect_ratio; } /* * Calculate the alternate clock for HDMI modes (those from the HDMI vendor * specific block). - * - * It's almost like cea_mode_alternate_clock(), we just need to add an - * exception for the VIC 4 mode (4096x2160@24Hz): no alternate clock for this - * one. */ static unsigned int hdmi_mode_alternate_clock(const struct drm_display_mode *hdmi_mode) { - if (hdmi_mode->vdisplay == 4096 && hdmi_mode->hdisplay == 2160) - return hdmi_mode->clock; - return cea_mode_alternate_clock(hdmi_mode); } @@ -3240,6 +3407,9 @@ static u8 drm_match_hdmi_mode_clock_tolerance(const struct drm_display_mode *to_ if (!to_match->clock) return 0; + if (to_match->picture_aspect_ratio) + match_flags |= DRM_MODE_MATCH_ASPECT_RATIO; + for (vic = 1; vic < ARRAY_SIZE(edid_4k_modes); vic++) { const struct drm_display_mode *hdmi_mode = &edid_4k_modes[vic]; unsigned int clock1, clock2; @@ -3275,6 +3445,9 @@ static u8 drm_match_hdmi_mode(const struct drm_display_mode *to_match) if (!to_match->clock) return 0; + if (to_match->picture_aspect_ratio) + match_flags |= DRM_MODE_MATCH_ASPECT_RATIO; + for (vic = 1; vic < ARRAY_SIZE(edid_4k_modes); vic++) { const struct drm_display_mode *hdmi_mode = &edid_4k_modes[vic]; unsigned int clock1, clock2; @@ -3319,7 +3492,7 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid) unsigned int clock1, clock2; if (drm_valid_cea_vic(vic)) { - cea_mode = &edid_cea_modes[vic]; + cea_mode = cea_mode_for_vic(vic); clock2 = cea_mode_alternate_clock(cea_mode); } else { vic = drm_match_hdmi_mode(mode); @@ -3394,7 +3567,7 @@ drm_display_mode_from_vic_index(struct drm_connector *connector, if (!drm_valid_cea_vic(vic)) return NULL; - newmode = drm_mode_duplicate(dev, &edid_cea_modes[vic]); + newmode = drm_mode_duplicate(dev, cea_mode_for_vic(vic)); if (!newmode) return NULL; @@ -3428,7 +3601,7 @@ static int do_y420vdb_modes(struct drm_connector *connector, if (!drm_valid_cea_vic(vic)) continue; - newmode = drm_mode_duplicate(dev, &edid_cea_modes[vic]); + newmode = drm_mode_duplicate(dev, cea_mode_for_vic(vic)); if (!newmode) break; bitmap_set(hdmi->y420_vdb_modes, vic, 1); @@ -3997,7 +4170,7 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode) vic = drm_match_cea_mode_clock_tolerance(mode, 5); if (drm_valid_cea_vic(vic)) { type = "CEA"; - cea_mode = &edid_cea_modes[vic]; + cea_mode = cea_mode_for_vic(vic); clock1 = cea_mode->clock; clock2 = cea_mode_alternate_clock(cea_mode); } else { @@ -4279,12 +4452,12 @@ int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads) cea = drm_find_cea_extension(edid); if (!cea) { DRM_DEBUG_KMS("SAD: no CEA Extension found\n"); - return -ENOENT; + return 0; } if (cea_revision(cea) < 3) { DRM_DEBUG_KMS("SAD: wrong CEA revision\n"); - return -EOPNOTSUPP; + return 0; } if (cea_db_offsets(cea, &start, &end)) { @@ -4340,12 +4513,12 @@ int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb) cea = drm_find_cea_extension(edid); if (!cea) { DRM_DEBUG_KMS("SAD: no CEA Extension found\n"); - return -ENOENT; + return 0; } if (cea_revision(cea) < 3) { DRM_DEBUG_KMS("SAD: wrong CEA revision\n"); - return -EOPNOTSUPP; + return 0; } if (cea_db_offsets(cea, &start, &end)) { @@ -4573,7 +4746,7 @@ static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, if (scdc->supported) { scdc->scrambling.supported = true; - /* Few sinks support scrambling for cloks < 340M */ + /* Few sinks support scrambling for clocks < 340M */ if ((hf_vsdb[6] & 0x8)) scdc->scrambling.low_rates = true; } @@ -5222,6 +5395,7 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, const struct drm_display_mode *mode) { enum hdmi_picture_aspect picture_aspect; + u8 vic, hdmi_vic; int err; if (!frame || !mode) @@ -5234,7 +5408,8 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, if (mode->flags & DRM_MODE_FLAG_DBLCLK) frame->pixel_repeat = 1; - frame->video_code = drm_mode_cea_vic(connector, mode); + vic = drm_mode_cea_vic(connector, mode); + hdmi_vic = drm_mode_hdmi_vic(connector, mode); frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE; @@ -5248,11 +5423,15 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, /* * Populate picture aspect ratio from either - * user input (if specified) or from the CEA mode list. + * user input (if specified) or from the CEA/HDMI mode lists. */ picture_aspect = mode->picture_aspect_ratio; - if (picture_aspect == HDMI_PICTURE_ASPECT_NONE) - picture_aspect = drm_get_cea_aspect_ratio(frame->video_code); + if (picture_aspect == HDMI_PICTURE_ASPECT_NONE) { + if (vic) + picture_aspect = drm_get_cea_aspect_ratio(vic); + else if (hdmi_vic) + picture_aspect = drm_get_hdmi_aspect_ratio(hdmi_vic); + } /* * The infoframe can't convey anything but none, 4:3 @@ -5260,12 +5439,20 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, * we can only satisfy it by specifying the right VIC. */ if (picture_aspect > HDMI_PICTURE_ASPECT_16_9) { - if (picture_aspect != - drm_get_cea_aspect_ratio(frame->video_code)) + if (vic) { + if (picture_aspect != drm_get_cea_aspect_ratio(vic)) + return -EINVAL; + } else if (hdmi_vic) { + if (picture_aspect != drm_get_hdmi_aspect_ratio(hdmi_vic)) + return -EINVAL; + } else { return -EINVAL; + } + picture_aspect = HDMI_PICTURE_ASPECT_NONE; } + frame->video_code = vic; frame->picture_aspect = picture_aspect; frame->active_aspect = HDMI_ACTIVE_ASPECT_PICTURE; frame->scan_mode = HDMI_SCAN_MODE_UNDERSCAN; diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c index 80d88a55302eca62ebc076785a33ff541754fc49..e555281f43d4b4daf5919e61ccf1549fca90f1d6 100644 --- a/drivers/gpu/drm/drm_encoder.c +++ b/drivers/gpu/drm/drm_encoder.c @@ -140,6 +140,7 @@ int drm_encoder_init(struct drm_device *dev, goto out_put; } + INIT_LIST_HEAD(&encoder->bridge_chain); list_add_tail(&encoder->head, &dev->mode_config.encoder_list); encoder->index = dev->mode_config.num_encoder++; @@ -160,22 +161,16 @@ EXPORT_SYMBOL(drm_encoder_init); void drm_encoder_cleanup(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; + struct drm_bridge *bridge, *next; /* Note that the encoder_list is considered to be static; should we * remove the drm_encoder at runtime we would have to decrement all * the indices on the drm_encoder after us in the encoder_list. */ - if (encoder->bridge) { - struct drm_bridge *bridge = encoder->bridge; - struct drm_bridge *next; - - while (bridge) { - next = bridge->next; - drm_bridge_detach(bridge); - bridge = next; - } - } + list_for_each_entry_safe(bridge, next, &encoder->bridge_chain, + chain_node) + drm_bridge_detach(bridge); drm_mode_object_unregister(dev, &encoder->base); kfree(encoder->name); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 06e0b0075993aaf29f054f7e8d553452bf9f2d56..57f510687b85f0717bf70b88293be891e4eee353 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -95,10 +95,6 @@ static DEFINE_MUTEX(kernel_fb_helper_lock); * It will automatically set up deferred I/O if the driver requires a shadow * buffer. * - * For other drivers, setup fbdev emulation by calling - * drm_fb_helper_fbdev_setup() and tear it down by calling - * drm_fb_helper_fbdev_teardown(). - * * At runtime drivers should restore the fbdev console by using * drm_fb_helper_lastclose() as their &drm_driver.lastclose callback. * They should also notify the fb helper code from updates to the output @@ -195,6 +191,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info) { struct drm_fb_helper *helper = info->par; struct drm_client_dev *client = &helper->client; + struct drm_device *dev = helper->dev; struct drm_crtc *crtc; const struct drm_crtc_helper_funcs *funcs; struct drm_mode_set *mode_set; @@ -213,7 +210,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info) continue; if (!fb) { - DRM_ERROR("no fb to restore??\n"); + drm_err(dev, "no fb to restore?\n"); continue; } @@ -567,8 +564,7 @@ EXPORT_SYMBOL(drm_fb_helper_unregister_fbi); * drm_fb_helper_fini - finialize a &struct drm_fb_helper * @fb_helper: driver-allocated fbdev helper, can be NULL * - * This cleans up all remaining resources associated with @fb_helper. Must be - * called after drm_fb_helper_unlink_fbi() was called. + * This cleans up all remaining resources associated with @fb_helper. */ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) { @@ -608,19 +604,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) } EXPORT_SYMBOL(drm_fb_helper_fini); -/** - * drm_fb_helper_unlink_fbi - wrapper around unlink_framebuffer - * @fb_helper: driver-allocated fbdev helper, can be NULL - * - * A wrapper around unlink_framebuffer implemented by fbdev core - */ -void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper) -{ - if (fb_helper && fb_helper->fbdev) - unlink_framebuffer(fb_helper->fbdev); -} -EXPORT_SYMBOL(drm_fb_helper_unlink_fbi); - static bool drm_fbdev_use_shadow_fb(struct drm_fb_helper *fb_helper) { struct drm_device *dev = fb_helper->dev; @@ -1266,12 +1249,13 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, { struct drm_fb_helper *fb_helper = info->par; struct drm_framebuffer *fb = fb_helper->fb; + struct drm_device *dev = fb_helper->dev; if (in_dbg_master()) return -EINVAL; if (var->pixclock != 0) { - DRM_DEBUG("fbdev emulation doesn't support changing the pixel clock, value of pixclock is ignored\n"); + drm_dbg_kms(dev, "fbdev emulation doesn't support changing the pixel clock, value of pixclock is ignored\n"); var->pixclock = 0; } @@ -1286,7 +1270,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, if (var->bits_per_pixel != fb->format->cpp[0] * 8 || var->xres > fb->width || var->yres > fb->height || var->xres_virtual > fb->width || var->yres_virtual > fb->height) { - DRM_DEBUG("fb requested width/height/bpp can't fit in current fb " + drm_dbg_kms(dev, "fb requested width/height/bpp can't fit in current fb " "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n", var->xres, var->yres, var->bits_per_pixel, var->xres_virtual, var->yres_virtual, @@ -1313,7 +1297,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, * so reject all pixel format changing requests. */ if (!drm_fb_pixel_format_equal(var, &info->var)) { - DRM_DEBUG("fbdev emulation doesn't support changing the pixel format\n"); + drm_dbg_kms(dev, "fbdev emulation doesn't support changing the pixel format\n"); return -EINVAL; } @@ -1338,7 +1322,7 @@ int drm_fb_helper_set_par(struct fb_info *info) return -EBUSY; if (var->pixclock != 0) { - DRM_ERROR("PIXEL CLOCK SET\n"); + drm_err(fb_helper->dev, "PIXEL CLOCK SET\n"); return -EINVAL; } @@ -1448,6 +1432,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, int preferred_bpp) { struct drm_client_dev *client = &fb_helper->client; + struct drm_device *dev = fb_helper->dev; int ret = 0; int crtc_count = 0; struct drm_connector_list_iter conn_iter; @@ -1511,7 +1496,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, struct drm_plane *plane = crtc->primary; int j; - DRM_DEBUG("test CRTC %u primary plane\n", drm_crtc_index(crtc)); + drm_dbg_kms(dev, "test CRTC %u primary plane\n", drm_crtc_index(crtc)); for (j = 0; j < plane->format_count; j++) { const struct drm_format_info *fmt; @@ -1544,7 +1529,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, } } if (sizes.surface_depth != best_depth && best_depth) { - DRM_INFO("requested bpp %d, scaled depth down to %d", + drm_info(dev, "requested bpp %d, scaled depth down to %d", sizes.surface_bpp, best_depth); sizes.surface_depth = best_depth; } @@ -1594,7 +1579,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, mutex_unlock(&client->modeset_mutex); if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { - DRM_INFO("Cannot find any crtc or sizes\n"); + drm_info(dev, "Cannot find any crtc or sizes\n"); /* First time: disable all crtc's.. */ if (!fb_helper->deferred_setup) @@ -1909,7 +1894,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) drm_master_internal_release(fb_helper->dev); - DRM_DEBUG_KMS("\n"); + drm_dbg_kms(fb_helper->dev, "\n"); drm_client_modeset_probe(&fb_helper->client, fb_helper->fb->width, fb_helper->fb->height); drm_setup_crtcs_fb(fb_helper); @@ -1921,108 +1906,6 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) } EXPORT_SYMBOL(drm_fb_helper_hotplug_event); -/** - * drm_fb_helper_fbdev_setup() - Setup fbdev emulation - * @dev: DRM device - * @fb_helper: fbdev helper structure to set up - * @funcs: fbdev helper functions - * @preferred_bpp: Preferred bits per pixel for the device. - * @dev->mode_config.preferred_depth is used if this is zero. - * @max_conn_count: Maximum number of connectors (not used) - * - * This function sets up fbdev emulation and registers fbdev for access by - * userspace. If all connectors are disconnected, setup is deferred to the next - * time drm_fb_helper_hotplug_event() is called. - * The caller must to provide a &drm_fb_helper_funcs->fb_probe callback - * function. - * - * Use drm_fb_helper_fbdev_teardown() to destroy the fbdev. - * - * See also: drm_fb_helper_initial_config(), drm_fbdev_generic_setup(). - * - * Returns: - * Zero on success or negative error code on failure. - */ -int drm_fb_helper_fbdev_setup(struct drm_device *dev, - struct drm_fb_helper *fb_helper, - const struct drm_fb_helper_funcs *funcs, - unsigned int preferred_bpp, - unsigned int max_conn_count) -{ - int ret; - - if (!preferred_bpp) - preferred_bpp = dev->mode_config.preferred_depth; - if (!preferred_bpp) - preferred_bpp = 32; - - drm_fb_helper_prepare(dev, fb_helper, funcs); - - ret = drm_fb_helper_init(dev, fb_helper, 0); - if (ret < 0) { - DRM_DEV_ERROR(dev->dev, "fbdev: Failed to initialize (ret=%d)\n", ret); - return ret; - } - - if (!drm_drv_uses_atomic_modeset(dev)) - drm_helper_disable_unused_functions(dev); - - ret = drm_fb_helper_initial_config(fb_helper, preferred_bpp); - if (ret < 0) { - DRM_DEV_ERROR(dev->dev, "fbdev: Failed to set configuration (ret=%d)\n", ret); - goto err_drm_fb_helper_fini; - } - - return 0; - -err_drm_fb_helper_fini: - drm_fb_helper_fbdev_teardown(dev); - - return ret; -} -EXPORT_SYMBOL(drm_fb_helper_fbdev_setup); - -/** - * drm_fb_helper_fbdev_teardown - Tear down fbdev emulation - * @dev: DRM device - * - * This function unregisters fbdev if not already done and cleans up the - * associated resources including the &drm_framebuffer. - * The driver is responsible for freeing the &drm_fb_helper structure which is - * stored in &drm_device->fb_helper. Do note that this pointer has been cleared - * when this function returns. - * - * In order to support device removal/unplug while file handles are still open, - * drm_fb_helper_unregister_fbi() should be called on device removal and - * drm_fb_helper_fbdev_teardown() in the &drm_driver->release callback when - * file handles are closed. - */ -void drm_fb_helper_fbdev_teardown(struct drm_device *dev) -{ - struct drm_fb_helper *fb_helper = dev->fb_helper; - struct fb_ops *fbops = NULL; - - if (!fb_helper) - return; - - /* Unregister if it hasn't been done already */ - if (fb_helper->fbdev && fb_helper->fbdev->dev) - drm_fb_helper_unregister_fbi(fb_helper); - - if (fb_helper->fbdev && fb_helper->fbdev->fbdefio) { - fb_deferred_io_cleanup(fb_helper->fbdev); - kfree(fb_helper->fbdev->fbdefio); - fbops = fb_helper->fbdev->fbops; - } - - drm_fb_helper_fini(fb_helper); - kfree(fbops); - - if (fb_helper->fb) - drm_framebuffer_remove(fb_helper->fb); -} -EXPORT_SYMBOL(drm_fb_helper_fbdev_teardown); - /** * drm_fb_helper_lastclose - DRM driver lastclose helper for fbdev emulation * @dev: DRM device @@ -2076,7 +1959,6 @@ static int drm_fbdev_fb_release(struct fb_info *info, int user) static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper) { struct fb_info *fbi = fb_helper->fbdev; - struct fb_ops *fbops = NULL; void *shadow = NULL; if (!fb_helper->dev) @@ -2085,15 +1967,11 @@ static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper) if (fbi && fbi->fbdefio) { fb_deferred_io_cleanup(fbi); shadow = fbi->screen_buffer; - fbops = fbi->fbops; } drm_fb_helper_fini(fb_helper); - if (shadow) { - vfree(shadow); - kfree(fbops); - } + vfree(shadow); drm_client_framebuffer_delete(fb_helper->buffer); } @@ -2124,7 +2002,7 @@ static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) return -ENODEV; } -static struct fb_ops drm_fbdev_fb_ops = { +static const struct fb_ops drm_fbdev_fb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, .fb_open = drm_fbdev_fb_open, @@ -2143,32 +2021,26 @@ static struct fb_deferred_io drm_fbdev_defio = { .deferred_io = drm_fb_helper_deferred_io, }; -/** - * drm_fb_helper_generic_probe - Generic fbdev emulation probe helper - * @fb_helper: fbdev helper structure - * @sizes: describes fbdev size and scanout surface size - * +/* * This function uses the client API to create a framebuffer backed by a dumb buffer. * * The _sys_ versions are used for &fb_ops.fb_read, fb_write, fb_fillrect, * fb_copyarea, fb_imageblit. - * - * Returns: - * Zero on success or negative error code on failure. */ -int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, - struct drm_fb_helper_surface_size *sizes) +static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, + struct drm_fb_helper_surface_size *sizes) { struct drm_client_dev *client = &fb_helper->client; + struct drm_device *dev = fb_helper->dev; struct drm_client_buffer *buffer; struct drm_framebuffer *fb; struct fb_info *fbi; u32 format; void *vaddr; - DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n", - sizes->surface_width, sizes->surface_height, - sizes->surface_bpp); + drm_dbg_kms(dev, "surface width(%d), height(%d) and bpp(%d)\n", + sizes->surface_width, sizes->surface_height, + sizes->surface_bpp); format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); buffer = drm_client_framebuffer_create(client, sizes->surface_width, @@ -2191,24 +2063,10 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, drm_fb_helper_fill_info(fbi, fb_helper, sizes); if (drm_fbdev_use_shadow_fb(fb_helper)) { - struct fb_ops *fbops; - void *shadow; - - /* - * fb_deferred_io_cleanup() clears &fbops->fb_mmap so a per - * instance version is necessary. - */ - fbops = kzalloc(sizeof(*fbops), GFP_KERNEL); - shadow = vzalloc(fbi->screen_size); - if (!fbops || !shadow) { - kfree(fbops); - vfree(shadow); + fbi->screen_buffer = vzalloc(fbi->screen_size); + if (!fbi->screen_buffer) return -ENOMEM; - } - *fbops = *fbi->fbops; - fbi->fbops = fbops; - fbi->screen_buffer = shadow; fbi->fbdefio = &drm_fbdev_defio; fb_deferred_io_init(fbi); @@ -2229,7 +2087,6 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, return 0; } -EXPORT_SYMBOL(drm_fb_helper_generic_probe); static const struct drm_fb_helper_funcs drm_fb_helper_generic_funcs = { .fb_probe = drm_fb_helper_generic_probe, @@ -2267,7 +2124,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client) return drm_fb_helper_hotplug_event(dev->fb_helper); if (!dev->mode_config.num_connector) { - DRM_DEV_DEBUG(dev->dev, "No connectors found, will not create framebuffer!\n"); + drm_dbg_kms(dev, "No connectors found, will not create framebuffer!\n"); return 0; } @@ -2292,7 +2149,7 @@ err: fb_helper->dev = NULL; fb_helper->fbdev = NULL; - DRM_DEV_ERROR(dev->dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret); + drm_err(dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret); return ret; } @@ -2311,8 +2168,7 @@ static const struct drm_client_funcs drm_fbdev_client_funcs = { * @dev->mode_config.preferred_depth is used if this is zero. * * This function sets up generic fbdev emulation for drivers that supports - * dumb buffers with a virtual address and that can be mmap'ed. If the driver - * does not support these functions, it could use drm_fb_helper_fbdev_setup(). + * dumb buffers with a virtual address and that can be mmap'ed. * * Restore, hotplug events and teardown are all taken care of. Drivers that do * suspend/resume need to call drm_fb_helper_set_suspend_unlocked() themselves. @@ -2350,7 +2206,7 @@ int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp) ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs); if (ret) { kfree(fb_helper); - DRM_DEV_ERROR(dev->dev, "Failed to register client: %d\n", ret); + drm_err(dev, "Failed to register client: %d\n", ret); return ret; } @@ -2362,7 +2218,7 @@ int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp) ret = drm_fbdev_client_hotplug(&fb_helper->client); if (ret) - DRM_DEV_DEBUG(dev->dev, "client hotplug ret=%d\n", ret); + drm_dbg_kms(dev, "client hotplug ret=%d\n", ret); drm_client_register(&fb_helper->client); diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 4d9385d1bf2da02c79c7f2f281c8e15a53aaaf3d..92d16724f9495c2cf70ef6d608c83da52fad1203 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -287,7 +287,7 @@ static int drm_cpu_valid(void) } /* - * Called whenever a process opens /dev/drm. + * Called whenever a process opens a drm node * * \param filp file pointer. * \param minor acquired minor-object. diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index c630064ccf4168b6dc9094d8c2c44f25ba1ce13d..b234bfaeda060df3baf676dcaf2aa4efd04eb42b 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -253,17 +253,17 @@ const struct drm_format_info *__drm_format_info(u32 format) .char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true }, { .format = DRM_FORMAT_P010, .depth = 0, .num_planes = 2, - .char_per_block = { 2, 4, 0 }, .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 }, + .char_per_block = { 2, 4, 0 }, .block_w = { 1, 1, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true}, { .format = DRM_FORMAT_P012, .depth = 0, .num_planes = 2, - .char_per_block = { 2, 4, 0 }, .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 }, + .char_per_block = { 2, 4, 0 }, .block_w = { 1, 1, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true}, { .format = DRM_FORMAT_P016, .depth = 0, .num_planes = 2, - .char_per_block = { 2, 4, 0 }, .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 }, + .char_per_block = { 2, 4, 0 }, .block_w = { 1, 1, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true}, { .format = DRM_FORMAT_P210, .depth = 0, .num_planes = 2, .char_per_block = { 2, 4, 0 }, - .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 }, .hsub = 2, + .block_w = { 1, 1, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_VUY101010, .depth = 0, .num_planes = 1, .cpp = { 0, 0, 0 }, .hsub = 1, .vsub = 1, diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 000fa4a1899f217d973fe791863c8c3b8df2198d..a9e4a610445ac06dcf29c44829eeef60fa0c020e 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -1114,9 +1114,6 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size, drm_gem_object_get(obj); if (obj->funcs && obj->funcs->mmap) { - /* Remove the fake offset */ - vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node); - ret = obj->funcs->mmap(obj, vma); if (ret) { drm_gem_object_put_unlocked(obj); diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index b9bcd310ca2d83aff42a3f21c78098b7363b68bc..3a7ace19a9021c1dfd7d761e0244725e7c77b429 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -74,8 +74,7 @@ drm_gem_fb_alloc(struct drm_device *dev, ret = drm_framebuffer_init(dev, fb, funcs); if (ret) { - DRM_DEV_ERROR(dev->dev, "Failed to init framebuffer: %d\n", - ret); + drm_err(dev, "Failed to init framebuffer: %d\n", ret); kfree(fb); return ERR_PTR(ret); } @@ -160,7 +159,7 @@ drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file, objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]); if (!objs[i]) { - DRM_DEBUG_KMS("Failed to lookup GEM object\n"); + drm_dbg_kms(dev, "Failed to lookup GEM object\n"); ret = -ENOENT; goto err_gem_object_put; } diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index 0810d3ef6961ccb59f111bc74f692cab0d7bc87b..a421a2eed48ad1b3bcf3cc4523280c49c98a5791 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -528,6 +528,9 @@ int drm_gem_shmem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) struct drm_gem_shmem_object *shmem; int ret; + /* Remove the fake offset */ + vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node); + shmem = to_drm_gem_shmem_obj(obj); ret = drm_gem_shmem_get_pages(shmem); diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index 666cb4c22bb9b12fcfcf63b6d930d3c614143b33..a4863326061a49f802a95b051d80b3d0fc425314 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -92,14 +93,18 @@ static void drm_gem_vram_placement(struct drm_gem_vram_object *gbo, } static int drm_gem_vram_init(struct drm_device *dev, - struct ttm_bo_device *bdev, struct drm_gem_vram_object *gbo, - size_t size, unsigned long pg_align, - bool interruptible) + size_t size, unsigned long pg_align) { + struct drm_vram_mm *vmm = dev->vram_mm; + struct ttm_bo_device *bdev; int ret; size_t acc_size; + if (WARN_ONCE(!vmm, "VRAM MM not initialized")) + return -EINVAL; + bdev = &vmm->bdev; + gbo->bo.base.funcs = &drm_gem_vram_object_funcs; ret = drm_gem_object_init(dev, &gbo->bo.base, size); @@ -112,7 +117,7 @@ static int drm_gem_vram_init(struct drm_device *dev, drm_gem_vram_placement(gbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); ret = ttm_bo_init(bdev, &gbo->bo, size, ttm_bo_type_device, - &gbo->placement, pg_align, interruptible, acc_size, + &gbo->placement, pg_align, false, acc_size, NULL, NULL, ttm_buffer_object_destroy); if (ret) goto err_drm_gem_object_release; @@ -127,29 +132,33 @@ err_drm_gem_object_release: /** * drm_gem_vram_create() - Creates a VRAM-backed GEM object * @dev: the DRM device - * @bdev: the TTM BO device backing the object * @size: the buffer size in bytes * @pg_align: the buffer's alignment in multiples of the page size - * @interruptible: sleep interruptible if waiting for memory * * Returns: * A new instance of &struct drm_gem_vram_object on success, or * an ERR_PTR()-encoded error code otherwise. */ struct drm_gem_vram_object *drm_gem_vram_create(struct drm_device *dev, - struct ttm_bo_device *bdev, size_t size, - unsigned long pg_align, - bool interruptible) + unsigned long pg_align) { struct drm_gem_vram_object *gbo; int ret; - gbo = kzalloc(sizeof(*gbo), GFP_KERNEL); - if (!gbo) - return ERR_PTR(-ENOMEM); + if (dev->driver->gem_create_object) { + struct drm_gem_object *gem = + dev->driver->gem_create_object(dev, size); + if (!gem) + return ERR_PTR(-ENOMEM); + gbo = drm_gem_vram_of_gem(gem); + } else { + gbo = kzalloc(sizeof(*gbo), GFP_KERNEL); + if (!gbo) + return ERR_PTR(-ENOMEM); + } - ret = drm_gem_vram_init(dev, bdev, gbo, size, pg_align, interruptible); + ret = drm_gem_vram_init(dev, gbo, size, pg_align); if (ret < 0) goto err_kfree; @@ -483,9 +492,8 @@ EXPORT_SYMBOL(drm_gem_vram_vunmap); Helper for implementing &struct drm_driver.dumb_create * @file: the DRM file * @dev: the DRM device - * @bdev: the TTM BO device managing the buffer object * @pg_align: the buffer's alignment in multiples of the page size - * @interruptible: sleep interruptible if waiting for memory + * @pitch_align: the scanline's alignment in powers of 2 * @args: the arguments as provided to \ &struct drm_driver.dumb_create * @@ -500,9 +508,8 @@ EXPORT_SYMBOL(drm_gem_vram_vunmap); */ int drm_gem_vram_fill_create_dumb(struct drm_file *file, struct drm_device *dev, - struct ttm_bo_device *bdev, unsigned long pg_align, - bool interruptible, + unsigned long pitch_align, struct drm_mode_create_dumb *args) { size_t pitch, size; @@ -510,14 +517,19 @@ int drm_gem_vram_fill_create_dumb(struct drm_file *file, int ret; u32 handle; - pitch = args->width * ((args->bpp + 7) / 8); + pitch = args->width * DIV_ROUND_UP(args->bpp, 8); + if (pitch_align) { + if (WARN_ON_ONCE(!is_power_of_2(pitch_align))) + return -EINVAL; + pitch = ALIGN(pitch, pitch_align); + } size = pitch * args->height; size = roundup(size, PAGE_SIZE); if (!size) return -EINVAL; - gbo = drm_gem_vram_create(dev, bdev, size, pg_align, interruptible); + gbo = drm_gem_vram_create(dev, size, pg_align); if (IS_ERR(gbo)) return PTR_ERR(gbo); @@ -612,8 +624,7 @@ int drm_gem_vram_driver_dumb_create(struct drm_file *file, if (WARN_ONCE(!dev->vram_mm, "VRAM MM not initialized")) return -EINVAL; - return drm_gem_vram_fill_create_dumb(file, dev, &dev->vram_mm->bdev, 0, - false, args); + return drm_gem_vram_fill_create_dumb(file, dev, 0, 0, args); } EXPORT_SYMBOL(drm_gem_vram_driver_dumb_create); diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 51a2055c8f18af96763f02a60406d9362ce4e9de..6937bf923f05dcaf2bee5b5d00cf581432e367de 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -45,12 +45,34 @@ struct drm_file *drm_file_alloc(struct drm_minor *minor); void drm_file_free(struct drm_file *file); void drm_lastclose(struct drm_device *dev); +#ifdef CONFIG_PCI + /* drm_pci.c */ int drm_irq_by_busid(struct drm_device *dev, void *data, struct drm_file *file_priv); void drm_pci_agp_destroy(struct drm_device *dev); int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master); +#else + +static inline int drm_irq_by_busid(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return -EINVAL; +} + +static inline void drm_pci_agp_destroy(struct drm_device *dev) +{ +} + +static inline int drm_pci_set_busid(struct drm_device *dev, + struct drm_master *master) +{ + return -EINVAL; +} + +#endif + /* drm_prime.c */ int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index fcd728d7cf72279a820160c28fbfd1ea2fefa54f..5afb39688b55c171f4134996506ba6d34fbff1f3 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -652,8 +652,8 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, 0), - DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, 0), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, 0), diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c index e34058c721becd6bd78bdf9da0b59446d9bf51e3..16bff1be4b8ac62225265713f3219a17e0dacf39 100644 --- a/drivers/gpu/drm/drm_mipi_dbi.c +++ b/drivers/gpu/drm/drm_mipi_dbi.c @@ -367,9 +367,9 @@ static void mipi_dbi_blank(struct mipi_dbi_dev *dbidev) memset(dbidev->tx_buf, 0, len); mipi_dbi_command(dbi, MIPI_DCS_SET_COLUMN_ADDRESS, 0, 0, - (width >> 8) & 0xFF, (width - 1) & 0xFF); + ((width - 1) >> 8) & 0xFF, (width - 1) & 0xFF); mipi_dbi_command(dbi, MIPI_DCS_SET_PAGE_ADDRESS, 0, 0, - (height >> 8) & 0xFF, (height - 1) & 0xFF); + ((height - 1) >> 8) & 0xFF, (height - 1) & 0xFF); mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START, (u8 *)dbidev->tx_buf, len); diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 3b570a40493344faa394cc3f27afd37f16726501..08e6eff6a1797b2e0686af7610f061b587ca419d 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "drm_crtc_internal.h" #include "drm_internal.h" @@ -415,6 +416,33 @@ void drm_mode_config_init(struct drm_device *dev) dev->mode_config.num_crtc = 0; dev->mode_config.num_encoder = 0; dev->mode_config.num_total_plane = 0; + + if (IS_ENABLED(CONFIG_LOCKDEP)) { + struct drm_modeset_acquire_ctx modeset_ctx; + struct ww_acquire_ctx resv_ctx; + struct dma_resv resv; + int ret; + + dma_resv_init(&resv); + + drm_modeset_acquire_init(&modeset_ctx, 0); + ret = drm_modeset_lock(&dev->mode_config.connection_mutex, + &modeset_ctx); + if (ret == -EDEADLK) + ret = drm_modeset_backoff(&modeset_ctx); + + ww_acquire_init(&resv_ctx, &reservation_ww_class); + ret = dma_resv_lock(&resv, &resv_ctx); + if (ret == -EDEADLK) + dma_resv_lock_slow(&resv, &resv_ctx); + + dma_resv_unlock(&resv); + ww_acquire_fini(&resv_ctx); + + drm_modeset_drop_locks(&modeset_ctx); + drm_modeset_acquire_fini(&modeset_ctx); + dma_resv_fini(&resv); + } } EXPORT_SYMBOL(drm_mode_config_init); diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c index 6a23e36ed4fea6dcc419ec3d0e742b14afc3b11e..35c2719407a828d00f688fa7e2f336f38e3dabcf 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c @@ -224,12 +224,26 @@ EXPORT_SYMBOL(drm_mode_object_get); * This attaches the given property to the modeset object with the given initial * value. Currently this function cannot fail since the properties are stored in * a statically sized array. + * + * Note that all properties must be attached before the object itself is + * registered and accessible from userspace. */ void drm_object_attach_property(struct drm_mode_object *obj, struct drm_property *property, uint64_t init_val) { int count = obj->properties->count; + struct drm_device *dev = property->dev; + + + if (obj->type == DRM_MODE_OBJECT_CONNECTOR) { + struct drm_connector *connector = obj_to_connector(obj); + + WARN_ON(!dev->driver->load && + connector->registration_state == DRM_CONNECTOR_REGISTERED); + } else { + WARN_ON(!dev->driver->load && dev->registered); + } if (count == DRM_OBJECT_MAX_PROPERTY) { WARN(1, "Failed to attach object property (type: 0x%x). Please " diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 88232698d7a00a95b9317465a6f5fe3ae44a05cd..2a4eb619d7ad0ab3a33ca784e14119a78dd77eff 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1568,33 +1568,76 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length, return 0; } -static int drm_mode_parse_cmdline_options(char *str, size_t len, +static int drm_mode_parse_cmdline_int(const char *delim, unsigned int *int_ret) +{ + const char *value; + char *endp; + + /* + * delim must point to the '=', otherwise it is a syntax error and + * if delim points to the terminating zero, then delim + 1 wil point + * past the end of the string. + */ + if (*delim != '=') + return -EINVAL; + + value = delim + 1; + *int_ret = simple_strtol(value, &endp, 10); + + /* Make sure we have parsed something */ + if (endp == value) + return -EINVAL; + + return 0; +} + +static int drm_mode_parse_panel_orientation(const char *delim, + struct drm_cmdline_mode *mode) +{ + const char *value; + + if (*delim != '=') + return -EINVAL; + + value = delim + 1; + delim = strchr(value, ','); + if (!delim) + delim = value + strlen(value); + + if (!strncmp(value, "normal", delim - value)) + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL; + else if (!strncmp(value, "upside_down", delim - value)) + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP; + else if (!strncmp(value, "left_side_up", delim - value)) + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP; + else if (!strncmp(value, "right_side_up", delim - value)) + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP; + else + return -EINVAL; + + return 0; +} + +static int drm_mode_parse_cmdline_options(const char *str, + bool freestanding, const struct drm_connector *connector, struct drm_cmdline_mode *mode) { - unsigned int rotation = 0; - char *sep = str; + unsigned int deg, margin, rotation = 0; + const char *delim, *option, *sep; - while ((sep = strchr(sep, ','))) { - char *delim, *option; - - option = sep + 1; + option = str; + do { delim = strchr(option, '='); if (!delim) { delim = strchr(option, ','); if (!delim) - delim = str + len; + delim = option + strlen(option); } if (!strncmp(option, "rotate", delim - option)) { - const char *value = delim + 1; - unsigned int deg; - - deg = simple_strtol(value, &sep, 10); - - /* Make sure we have parsed something */ - if (sep == value) + if (drm_mode_parse_cmdline_int(delim, °)) return -EINVAL; switch (deg) { @@ -1619,58 +1662,40 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len, } } else if (!strncmp(option, "reflect_x", delim - option)) { rotation |= DRM_MODE_REFLECT_X; - sep = delim; } else if (!strncmp(option, "reflect_y", delim - option)) { rotation |= DRM_MODE_REFLECT_Y; - sep = delim; } else if (!strncmp(option, "margin_right", delim - option)) { - const char *value = delim + 1; - unsigned int margin; - - margin = simple_strtol(value, &sep, 10); - - /* Make sure we have parsed something */ - if (sep == value) + if (drm_mode_parse_cmdline_int(delim, &margin)) return -EINVAL; mode->tv_margins.right = margin; } else if (!strncmp(option, "margin_left", delim - option)) { - const char *value = delim + 1; - unsigned int margin; - - margin = simple_strtol(value, &sep, 10); - - /* Make sure we have parsed something */ - if (sep == value) + if (drm_mode_parse_cmdline_int(delim, &margin)) return -EINVAL; mode->tv_margins.left = margin; } else if (!strncmp(option, "margin_top", delim - option)) { - const char *value = delim + 1; - unsigned int margin; - - margin = simple_strtol(value, &sep, 10); - - /* Make sure we have parsed something */ - if (sep == value) + if (drm_mode_parse_cmdline_int(delim, &margin)) return -EINVAL; mode->tv_margins.top = margin; } else if (!strncmp(option, "margin_bottom", delim - option)) { - const char *value = delim + 1; - unsigned int margin; - - margin = simple_strtol(value, &sep, 10); - - /* Make sure we have parsed something */ - if (sep == value) + if (drm_mode_parse_cmdline_int(delim, &margin)) return -EINVAL; mode->tv_margins.bottom = margin; + } else if (!strncmp(option, "panel_orientation", delim - option)) { + if (drm_mode_parse_panel_orientation(delim, mode)) + return -EINVAL; } else { return -EINVAL; } - } + sep = strchr(delim, ','); + option = sep + 1; + } while (sep); + + if (rotation && freestanding) + return -EINVAL; mode->rotation_reflection = rotation; @@ -1682,17 +1707,6 @@ static const char * const drm_named_modes_whitelist[] = { "PAL", }; -static bool drm_named_mode_is_in_whitelist(const char *mode, unsigned int size) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) - if (!strncmp(mode, drm_named_modes_whitelist[i], size)) - return true; - - return false; -} - /** * drm_mode_parse_command_line_for_connector - parse command line modeline for connector * @mode_option: optional per connector mode option @@ -1723,72 +1737,30 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, struct drm_cmdline_mode *mode) { const char *name; - bool named_mode = false, parse_extras = false; + bool freestanding = false, parse_extras = false; unsigned int bpp_off = 0, refresh_off = 0, options_off = 0; unsigned int mode_end = 0; - char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL; - char *options_ptr = NULL; + const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL; + const char *options_ptr = NULL; char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL; - int ret; + int i, len, ret; -#ifdef CONFIG_FB - if (!mode_option) - mode_option = fb_mode_option; -#endif + memset(mode, 0, sizeof(*mode)); + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; - if (!mode_option) { - mode->specified = false; + if (!mode_option) return false; - } name = mode_option; - /* - * This is a bit convoluted. To differentiate between the - * named modes and poorly formatted resolutions, we need a - * bunch of things: - * - We need to make sure that the first character (which - * would be our resolution in X) is a digit. - * - If not, then it's either a named mode or a force on/off. - * To distinguish between the two, we need to run the - * extra parsing function, and if not, then we consider it - * a named mode. - * - * If this isn't enough, we should add more heuristics here, - * and matching unit-tests. - */ - if (!isdigit(name[0]) && name[0] != 'x') { - unsigned int namelen = strlen(name); - - /* - * Only the force on/off options can be in that case, - * and they all take a single character. - */ - if (namelen == 1) { - ret = drm_mode_parse_cmdline_extra(name, namelen, true, - connector, mode); - if (!ret) - return true; - } - - named_mode = true; - } - /* Try to locate the bpp and refresh specifiers, if any */ bpp_ptr = strchr(name, '-'); - if (bpp_ptr) { + if (bpp_ptr) bpp_off = bpp_ptr - name; - mode->bpp_specified = true; - } refresh_ptr = strchr(name, '@'); - if (refresh_ptr) { - if (named_mode) - return false; - + if (refresh_ptr) refresh_off = refresh_ptr - name; - mode->refresh_specified = true; - } /* Locate the start of named options */ options_ptr = strchr(name, ','); @@ -1802,33 +1774,58 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, mode_end = refresh_off; } else if (options_ptr) { mode_end = options_off; + parse_extras = true; } else { mode_end = strlen(name); parse_extras = true; } - if (named_mode) { - if (mode_end + 1 > DRM_DISPLAY_MODE_LEN) - return false; + /* First check for a named mode */ + for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) { + ret = str_has_prefix(name, drm_named_modes_whitelist[i]); + if (ret == mode_end) { + if (refresh_ptr) + return false; /* named + refresh is invalid */ - if (!drm_named_mode_is_in_whitelist(name, mode_end)) - return false; + strcpy(mode->name, drm_named_modes_whitelist[i]); + mode->specified = true; + break; + } + } - strscpy(mode->name, name, mode_end + 1); - } else { + /* No named mode? Check for a normal mode argument, e.g. 1024x768 */ + if (!mode->specified && isdigit(name[0])) { ret = drm_mode_parse_cmdline_res_mode(name, mode_end, parse_extras, connector, mode); if (ret) return false; + + mode->specified = true; + } + + /* No mode? Check for freestanding extras and/or options */ + if (!mode->specified) { + unsigned int len = strlen(mode_option); + + if (bpp_ptr || refresh_ptr) + return false; /* syntax error */ + + if (len == 1 || (len >= 2 && mode_option[1] == ',')) + extra_ptr = mode_option; + else + options_ptr = mode_option - 1; + + freestanding = true; } - mode->specified = true; if (bpp_ptr) { ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode); if (ret) return false; + + mode->bpp_specified = true; } if (refresh_ptr) { @@ -1836,6 +1833,8 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, &refresh_end_ptr, mode); if (ret) return false; + + mode->refresh_specified = true; } /* @@ -1849,20 +1848,21 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, else if (refresh_ptr) extra_ptr = refresh_end_ptr; - if (extra_ptr && - extra_ptr != options_ptr) { - int len = strlen(name) - (extra_ptr - name); + if (extra_ptr) { + if (options_ptr) + len = options_ptr - extra_ptr; + else + len = strlen(extra_ptr); - ret = drm_mode_parse_cmdline_extra(extra_ptr, len, false, + ret = drm_mode_parse_cmdline_extra(extra_ptr, len, freestanding, connector, mode); if (ret) return false; } if (options_ptr) { - int len = strlen(name) - (options_ptr - name); - - ret = drm_mode_parse_cmdline_options(options_ptr, len, + ret = drm_mode_parse_cmdline_options(options_ptr + 1, + freestanding, connector, mode); if (ret) return false; diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 0ca58803ba46f207e4227af8eb4c07a7c07b8654..b50b44e7627975522b33b76f2d854c3fe2f3eb2f 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -274,3 +274,119 @@ int drm_of_find_panel_or_bridge(const struct device_node *np, return ret; } EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge); + +enum drm_of_lvds_pixels { + DRM_OF_LVDS_EVEN = BIT(0), + DRM_OF_LVDS_ODD = BIT(1), +}; + +static int drm_of_lvds_get_port_pixels_type(struct device_node *port_node) +{ + bool even_pixels = + of_property_read_bool(port_node, "dual-lvds-even-pixels"); + bool odd_pixels = + of_property_read_bool(port_node, "dual-lvds-odd-pixels"); + + return (even_pixels ? DRM_OF_LVDS_EVEN : 0) | + (odd_pixels ? DRM_OF_LVDS_ODD : 0); +} + +static int drm_of_lvds_get_remote_pixels_type( + const struct device_node *port_node) +{ + struct device_node *endpoint = NULL; + int pixels_type = -EPIPE; + + for_each_child_of_node(port_node, endpoint) { + struct device_node *remote_port; + int current_pt; + + if (!of_node_name_eq(endpoint, "endpoint")) + continue; + + remote_port = of_graph_get_remote_port(endpoint); + if (!remote_port) { + of_node_put(remote_port); + return -EPIPE; + } + + current_pt = drm_of_lvds_get_port_pixels_type(remote_port); + of_node_put(remote_port); + if (pixels_type < 0) + pixels_type = current_pt; + + /* + * Sanity check, ensure that all remote endpoints have the same + * pixel type. We may lift this restriction later if we need to + * support multiple sinks with different dual-link + * configurations by passing the endpoints explicitly to + * drm_of_lvds_get_dual_link_pixel_order(). + */ + if (!current_pt || pixels_type != current_pt) { + of_node_put(remote_port); + return -EINVAL; + } + } + + return pixels_type; +} + +/** + * drm_of_lvds_get_dual_link_pixel_order - Get LVDS dual-link pixel order + * @port1: First DT port node of the Dual-link LVDS source + * @port2: Second DT port node of the Dual-link LVDS source + * + * An LVDS dual-link connection is made of two links, with even pixels + * transitting on one link, and odd pixels on the other link. This function + * returns, for two ports of an LVDS dual-link source, which port shall transmit + * the even and odd pixels, based on the requirements of the connected sink. + * + * The pixel order is determined from the dual-lvds-even-pixels and + * dual-lvds-odd-pixels properties in the sink's DT port nodes. If those + * properties are not present, or if their usage is not valid, this function + * returns -EINVAL. + * + * If either port is not connected, this function returns -EPIPE. + * + * @port1 and @port2 are typically DT sibling nodes, but may have different + * parents when, for instance, two separate LVDS encoders carry the even and odd + * pixels. + * + * Return: + * * DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS - @port1 carries even pixels and @port2 + * carries odd pixels + * * DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS - @port1 carries odd pixels and @port2 + * carries even pixels + * * -EINVAL - @port1 and @port2 are not connected to a dual-link LVDS sink, or + * the sink configuration is invalid + * * -EPIPE - when @port1 or @port2 are not connected + */ +int drm_of_lvds_get_dual_link_pixel_order(const struct device_node *port1, + const struct device_node *port2) +{ + int remote_p1_pt, remote_p2_pt; + + if (!port1 || !port2) + return -EINVAL; + + remote_p1_pt = drm_of_lvds_get_remote_pixels_type(port1); + if (remote_p1_pt < 0) + return remote_p1_pt; + + remote_p2_pt = drm_of_lvds_get_remote_pixels_type(port2); + if (remote_p2_pt < 0) + return remote_p2_pt; + + /* + * A valid dual-lVDS bus is found when one remote port is marked with + * "dual-lvds-even-pixels", and the other remote port is marked with + * "dual-lvds-odd-pixels", bail out if the markers are not right. + */ + if (remote_p1_pt + remote_p2_pt != DRM_OF_LVDS_EVEN + DRM_OF_LVDS_ODD) + return -EINVAL; + + return remote_p1_pt == DRM_OF_LVDS_EVEN ? + DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS : + DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS; +} +EXPORT_SYMBOL_GPL(drm_of_lvds_get_dual_link_pixel_order); diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index ed7985c0535a2dae5311fde445726655bd188a28..8c7bac85a793779bf93476a33b7423142e42c1ad 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -21,11 +21,13 @@ * DEALINGS IN THE SOFTWARE. */ +#include #include #include #include #include +#include static DEFINE_MUTEX(panel_lock); static LIST_HEAD(panel_list); @@ -112,12 +114,6 @@ EXPORT_SYMBOL(drm_panel_remove); */ int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector) { - if (panel->connector) - return -EBUSY; - - panel->connector = connector; - panel->drm = connector->dev; - return 0; } EXPORT_SYMBOL(drm_panel_attach); @@ -134,8 +130,6 @@ EXPORT_SYMBOL(drm_panel_attach); */ void drm_panel_detach(struct drm_panel *panel) { - panel->connector = NULL; - panel->drm = NULL; } EXPORT_SYMBOL(drm_panel_detach); @@ -151,10 +145,13 @@ EXPORT_SYMBOL(drm_panel_detach); */ int drm_panel_prepare(struct drm_panel *panel) { - if (panel && panel->funcs && panel->funcs->prepare) + if (!panel) + return -EINVAL; + + if (panel->funcs && panel->funcs->prepare) return panel->funcs->prepare(panel); - return panel ? -ENOSYS : -EINVAL; + return 0; } EXPORT_SYMBOL(drm_panel_prepare); @@ -171,10 +168,13 @@ EXPORT_SYMBOL(drm_panel_prepare); */ int drm_panel_unprepare(struct drm_panel *panel) { - if (panel && panel->funcs && panel->funcs->unprepare) + if (!panel) + return -EINVAL; + + if (panel->funcs && panel->funcs->unprepare) return panel->funcs->unprepare(panel); - return panel ? -ENOSYS : -EINVAL; + return 0; } EXPORT_SYMBOL(drm_panel_unprepare); @@ -190,10 +190,23 @@ EXPORT_SYMBOL(drm_panel_unprepare); */ int drm_panel_enable(struct drm_panel *panel) { - if (panel && panel->funcs && panel->funcs->enable) - return panel->funcs->enable(panel); + int ret; + + if (!panel) + return -EINVAL; + + if (panel->funcs && panel->funcs->enable) { + ret = panel->funcs->enable(panel); + if (ret < 0) + return ret; + } - return panel ? -ENOSYS : -EINVAL; + ret = backlight_enable(panel->backlight); + if (ret < 0) + DRM_DEV_INFO(panel->dev, "failed to enable backlight: %d\n", + ret); + + return 0; } EXPORT_SYMBOL(drm_panel_enable); @@ -209,16 +222,27 @@ EXPORT_SYMBOL(drm_panel_enable); */ int drm_panel_disable(struct drm_panel *panel) { - if (panel && panel->funcs && panel->funcs->disable) + int ret; + + if (!panel) + return -EINVAL; + + ret = backlight_disable(panel->backlight); + if (ret < 0) + DRM_DEV_INFO(panel->dev, "failed to disable backlight: %d\n", + ret); + + if (panel->funcs && panel->funcs->disable) return panel->funcs->disable(panel); - return panel ? -ENOSYS : -EINVAL; + return 0; } EXPORT_SYMBOL(drm_panel_disable); /** * drm_panel_get_modes - probe the available display modes of a panel * @panel: DRM panel + * @connector: DRM connector * * The modes probed from the panel are automatically added to the connector * that the panel is attached to. @@ -226,12 +250,16 @@ EXPORT_SYMBOL(drm_panel_disable); * Return: The number of modes available from the panel on success or a * negative error code on failure. */ -int drm_panel_get_modes(struct drm_panel *panel) +int drm_panel_get_modes(struct drm_panel *panel, + struct drm_connector *connector) { - if (panel && panel->funcs && panel->funcs->get_modes) - return panel->funcs->get_modes(panel); + if (!panel) + return -EINVAL; - return panel ? -ENOSYS : -EINVAL; + if (panel->funcs && panel->funcs->get_modes) + return panel->funcs->get_modes(panel, connector); + + return -EOPNOTSUPP; } EXPORT_SYMBOL(drm_panel_get_modes); @@ -274,6 +302,45 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np) EXPORT_SYMBOL(of_drm_find_panel); #endif +#if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE) +/** + * drm_panel_of_backlight - use backlight device node for backlight + * @panel: DRM panel + * + * Use this function to enable backlight handling if your panel + * uses device tree and has a backlight phandle. + * + * When the panel is enabled backlight will be enabled after a + * successful call to &drm_panel_funcs.enable() + * + * When the panel is disabled backlight will be disabled before the + * call to &drm_panel_funcs.disable(). + * + * A typical implementation for a panel driver supporting device tree + * will call this function at probe time. Backlight will then be handled + * transparently without requiring any intervention from the driver. + * drm_panel_of_backlight() must be called after the call to drm_panel_init(). + * + * Return: 0 on success or a negative error code on failure. + */ +int drm_panel_of_backlight(struct drm_panel *panel) +{ + struct backlight_device *backlight; + + if (!panel || !panel->dev) + return -EINVAL; + + backlight = devm_of_find_backlight(panel->dev); + + if (IS_ERR(backlight)) + return PTR_ERR(backlight); + + panel->backlight = backlight; + return 0; +} +EXPORT_SYMBOL(drm_panel_of_backlight); +#endif + MODULE_AUTHOR("Thierry Reding "); MODULE_DESCRIPTION("DRM panel infrastructure"); MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index a86a3ab2771c71684dadb542e2628e2b851730e8..f2e43d341980f019a8b3123fefa98349d1846fd0 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -125,8 +125,6 @@ void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) EXPORT_SYMBOL(drm_pci_free); -#ifdef CONFIG_PCI - static int drm_get_pci_domain(struct drm_device *dev) { #ifndef __alpha__ @@ -284,6 +282,8 @@ err_free: } EXPORT_SYMBOL(drm_get_pci_dev); +#ifdef CONFIG_DRM_LEGACY + /** * drm_legacy_pci_init - shadow-attach a legacy DRM PCI driver * @driver: DRM device driver @@ -331,17 +331,6 @@ int drm_legacy_pci_init(struct drm_driver *driver, struct pci_driver *pdriver) } EXPORT_SYMBOL(drm_legacy_pci_init); -#else - -void drm_pci_agp_destroy(struct drm_device *dev) {} - -int drm_irq_by_busid(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - return -EINVAL; -} -#endif - /** * drm_legacy_pci_exit - unregister shadow-attach legacy DRM driver * @driver: DRM device driver @@ -367,3 +356,5 @@ void drm_legacy_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver) DRM_INFO("Module unloaded\n"); } EXPORT_SYMBOL(drm_legacy_pci_exit); + +#endif diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 0814211b0f3f309f1a266b01b1031203e27c88ac..86d9b0e45c8c6325e391be65da146b63357c78fe 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -240,6 +240,7 @@ void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv) struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev, struct dma_buf_export_info *exp_info) { + struct drm_gem_object *obj = exp_info->priv; struct dma_buf *dma_buf; dma_buf = dma_buf_export(exp_info); @@ -247,7 +248,8 @@ struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev, return dma_buf; drm_dev_get(dev); - drm_gem_object_get(exp_info->priv); + drm_gem_object_get(obj); + dma_buf->file->f_mapping = obj->dev->anon_inode->i_mapping; return dma_buf; } @@ -713,6 +715,9 @@ int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) struct file *fil; int ret; + /* Add the fake offset */ + vma->vm_pgoff += drm_vma_node_start(&obj->vma_node); + if (obj->funcs && obj->funcs->mmap) { ret = obj->funcs->mmap(obj, vma); if (ret) @@ -737,8 +742,6 @@ int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) if (ret) goto out; - vma->vm_pgoff += drm_vma_node_start(&obj->vma_node); - ret = obj->dev->driver->fops->mmap(fil, vma); drm_vma_node_revoke(&obj->vma_node, priv); diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index 9a25d73c155c96757d24a5216254e123431f7c07..111b932cf2a9b514cdae82c8ead793d6a937453d 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -37,11 +37,11 @@ #include /* - * drm_debug: Enable debug output. + * __drm_debug: Enable debug output. * Bitmask of DRM_UT_x. See include/drm/drm_print.h for details. */ -unsigned int drm_debug; -EXPORT_SYMBOL(drm_debug); +unsigned int __drm_debug; +EXPORT_SYMBOL(__drm_debug); MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n" "\t\tBit 0 (0x01) will enable CORE messages (drm core code)\n" @@ -52,7 +52,7 @@ MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug cat "\t\tBit 5 (0x20) will enable VBL messages (vblank code)\n" "\t\tBit 7 (0x80) will enable LEASE messages (leasing code)\n" "\t\tBit 8 (0x100) will enable DP messages (displayport code)"); -module_param_named(debug, drm_debug, int, 0600); +module_param_named(debug, __drm_debug, int, 0600); void __drm_puts_coredump(struct drm_printer *p, const char *str) { @@ -256,7 +256,7 @@ void drm_dev_printk(const struct device *dev, const char *level, } EXPORT_SYMBOL(drm_dev_printk); -void drm_dev_dbg(const struct device *dev, unsigned int category, +void drm_dev_dbg(const struct device *dev, enum drm_debug_category category, const char *format, ...) { struct va_format vaf; @@ -280,7 +280,7 @@ void drm_dev_dbg(const struct device *dev, unsigned int category, } EXPORT_SYMBOL(drm_dev_dbg); -void drm_dbg(unsigned int category, const char *format, ...) +void __drm_dbg(enum drm_debug_category category, const char *format, ...) { struct va_format vaf; va_list args; @@ -297,9 +297,9 @@ void drm_dbg(unsigned int category, const char *format, ...) va_end(args); } -EXPORT_SYMBOL(drm_dbg); +EXPORT_SYMBOL(__drm_dbg); -void drm_err(const char *format, ...) +void __drm_err(const char *format, ...) { struct va_format vaf; va_list args; @@ -313,7 +313,7 @@ void drm_err(const char *format, ...) va_end(args); } -EXPORT_SYMBOL(drm_err); +EXPORT_SYMBOL(__drm_err); /** * drm_print_regset32 - print the contents of registers to a diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index a7c87abe88d0b2230efba8b6972271cbf44c4838..576b4b7dcd89c14a0417af74eab6aa78a3b87cb6 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -101,6 +101,7 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode, /* Step 2: Validate against encoders and crtcs */ drm_connector_for_each_possible_encoder(connector, encoder) { + struct drm_bridge *bridge; struct drm_crtc *crtc; ret = drm_encoder_mode_valid(encoder, mode); @@ -112,7 +113,8 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode, continue; } - ret = drm_bridge_mode_valid(encoder->bridge, mode); + bridge = drm_bridge_chain_get_first_bridge(encoder); + ret = drm_bridge_chain_mode_valid(bridge, mode); if (ret != MODE_OK) { /* There is also no point in continuing for crtc check * here. */ diff --git a/drivers/gpu/drm/drm_rect.c b/drivers/gpu/drm/drm_rect.c index b8363aaa9032b79887d4a912a6cbbb03cb92e06a..0460e874896eda69e5449e3212f292327a7748e5 100644 --- a/drivers/gpu/drm/drm_rect.c +++ b/drivers/gpu/drm/drm_rect.c @@ -52,9 +52,17 @@ bool drm_rect_intersect(struct drm_rect *r1, const struct drm_rect *r2) } EXPORT_SYMBOL(drm_rect_intersect); -static u32 clip_scaled(u32 src, u32 dst, u32 clip) +static u32 clip_scaled(int src, int dst, int *clip) { - u64 tmp = mul_u32_u32(src, dst - clip); + u64 tmp; + + if (dst == 0) + return 0; + + /* Only clip what we have. Keeps the result bounded. */ + *clip = min(*clip, dst); + + tmp = mul_u32_u32(src, dst - *clip); /* * Round toward 1.0 when clipping so that we don't accidentally @@ -73,11 +81,13 @@ static u32 clip_scaled(u32 src, u32 dst, u32 clip) * @clip: clip rectangle * * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the - * same amounts multiplied by @hscale and @vscale. + * the corresponding amounts, retaining the vertical and horizontal scaling + * factors from @src to @dst. * * RETURNS: + * * %true if rectangle @dst is still visible after being clipped, - * %false otherwise + * %false otherwise. */ bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst, const struct drm_rect *clip) @@ -87,34 +97,34 @@ bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst, diff = clip->x1 - dst->x1; if (diff > 0) { u32 new_src_w = clip_scaled(drm_rect_width(src), - drm_rect_width(dst), diff); + drm_rect_width(dst), &diff); - src->x1 = clamp_t(int64_t, src->x2 - new_src_w, INT_MIN, INT_MAX); - dst->x1 = clip->x1; + src->x1 = src->x2 - new_src_w; + dst->x1 += diff; } diff = clip->y1 - dst->y1; if (diff > 0) { u32 new_src_h = clip_scaled(drm_rect_height(src), - drm_rect_height(dst), diff); + drm_rect_height(dst), &diff); - src->y1 = clamp_t(int64_t, src->y2 - new_src_h, INT_MIN, INT_MAX); - dst->y1 = clip->y1; + src->y1 = src->y2 - new_src_h; + dst->y1 += diff; } diff = dst->x2 - clip->x2; if (diff > 0) { u32 new_src_w = clip_scaled(drm_rect_width(src), - drm_rect_width(dst), diff); + drm_rect_width(dst), &diff); - src->x2 = clamp_t(int64_t, src->x1 + new_src_w, INT_MIN, INT_MAX); - dst->x2 = clip->x2; + src->x2 = src->x1 + new_src_w; + dst->x2 -= diff; } diff = dst->y2 - clip->y2; if (diff > 0) { u32 new_src_h = clip_scaled(drm_rect_height(src), - drm_rect_height(dst), diff); + drm_rect_height(dst), &diff); - src->y2 = clamp_t(int64_t, src->y1 + new_src_h, INT_MIN, INT_MAX); - dst->y2 = clip->y2; + src->y2 = src->y1 + new_src_h; + dst->y2 -= diff; } return drm_rect_visible(dst); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index aa3e4c3b063a07433f5fb1dbf8807c2d05c07434..3b0afa156d92994ad21aef0d910e95b6f0a45240 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -113,7 +113,7 @@ static void submit_unlock_object(struct etnaviv_gem_submit *submit, int i) if (submit->bos[i].flags & BO_LOCKED) { struct drm_gem_object *obj = &submit->bos[i].obj->base; - ww_mutex_unlock(&obj->resv->lock); + dma_resv_unlock(obj->resv); submit->bos[i].flags &= ~BO_LOCKED; } } @@ -133,8 +133,7 @@ retry: contended = i; if (!(submit->bos[i].flags & BO_LOCKED)) { - ret = ww_mutex_lock_interruptible(&obj->resv->lock, - ticket); + ret = dma_resv_lock_interruptible(obj->resv, ticket); if (ret == -EALREADY) DRM_ERROR("BO at index %u already on submit list\n", i); @@ -161,8 +160,7 @@ fail: obj = &submit->bos[contended].obj->base; /* we lost out in a seqno race, lock and retry.. */ - ret = ww_mutex_lock_slow_interruptible(&obj->resv->lock, - ticket); + ret = dma_resv_lock_slow_interruptible(obj->resv, ticket); if (!ret) { submit->bos[contended].flags |= BO_LOCKED; slow_locked = contended; diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index 1e6aa24bf45eed9f8be1e53ae16fef6a4e5b0426..4785885c0f4f94536d1bb73e759b1ca258a7e3c9 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c @@ -110,7 +110,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data, if (ret) { DRM_DEV_ERROR(dp->dev, "Failed to attach bridge to drm\n"); - bridge->next = NULL; return ret; } } diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 3cebb19ec1c47cfdf80ff059f2ac6d6b1651006f..43fa0f26c052e97bc87248660d827e48c0ac14d8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -43,7 +43,7 @@ exynos_dpi_detect(struct drm_connector *connector, bool force) { struct exynos_dpi *ctx = connector_to_dpi(connector); - if (ctx->panel && !ctx->panel->connector) + if (ctx->panel) drm_panel_attach(ctx->panel, &ctx->connector); return connector_status_connected; @@ -85,7 +85,7 @@ static int exynos_dpi_get_modes(struct drm_connector *connector) } if (ctx->panel) - return ctx->panel->funcs->get_modes(ctx->panel); + return drm_panel_get_modes(ctx->panel, connector); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 72726f2c7a9fb035631d9df9bee2f42a8ee05902..3955f84dc89356b093b0d9749c9fe2a04008347a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -255,6 +255,7 @@ struct exynos_dsi { struct mipi_dsi_host dsi_host; struct drm_connector connector; struct drm_panel *panel; + struct list_head bridge_chain; struct drm_bridge *out_bridge; struct device *dev; @@ -1390,7 +1391,7 @@ static void exynos_dsi_enable(struct drm_encoder *encoder) if (ret < 0) goto err_put_sync; } else { - drm_bridge_pre_enable(dsi->out_bridge); + drm_bridge_chain_pre_enable(dsi->out_bridge); } exynos_dsi_set_display_mode(dsi); @@ -1401,7 +1402,7 @@ static void exynos_dsi_enable(struct drm_encoder *encoder) if (ret < 0) goto err_display_disable; } else { - drm_bridge_enable(dsi->out_bridge); + drm_bridge_chain_enable(dsi->out_bridge); } dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; @@ -1426,10 +1427,10 @@ static void exynos_dsi_disable(struct drm_encoder *encoder) dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE; drm_panel_disable(dsi->panel); - drm_bridge_disable(dsi->out_bridge); + drm_bridge_chain_disable(dsi->out_bridge); exynos_dsi_set_display_enable(dsi, false); drm_panel_unprepare(dsi->panel); - drm_bridge_post_disable(dsi->out_bridge); + drm_bridge_chain_post_disable(dsi->out_bridge); dsi->state &= ~DSIM_STATE_ENABLED; pm_runtime_put_sync(dsi->dev); } @@ -1461,7 +1462,7 @@ static int exynos_dsi_get_modes(struct drm_connector *connector) struct exynos_dsi *dsi = connector_to_dsi(connector); if (dsi->panel) - return dsi->panel->funcs->get_modes(dsi->panel); + return drm_panel_get_modes(dsi->panel, connector); return 0; } @@ -1522,7 +1523,7 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host, if (out_bridge) { drm_bridge_attach(encoder, out_bridge, NULL); dsi->out_bridge = out_bridge; - encoder->bridge = NULL; + list_splice(&encoder->bridge_chain, &dsi->bridge_chain); } else { int ret = exynos_dsi_create_connector(encoder); @@ -1588,6 +1589,7 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host, if (dsi->out_bridge->funcs->detach) dsi->out_bridge->funcs->detach(dsi->out_bridge); dsi->out_bridge = NULL; + INIT_LIST_HEAD(&dsi->bridge_chain); } if (drm->mode_config.poll_enabled) @@ -1735,6 +1737,7 @@ static int exynos_dsi_probe(struct platform_device *pdev) init_completion(&dsi->completed); spin_lock_init(&dsi->transfer_lock); INIT_LIST_HEAD(&dsi->transfer_list); + INIT_LIST_HEAD(&dsi->bridge_chain); dsi->dsi_host.ops = &exynos_dsi_ops; dsi->dsi_host.dev = dev; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index b0877b97291c543fb68a2fd2f5da35e15473f5ac..647a1fd1d815b6135253caa3c70c5fbb15489cf0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -60,7 +60,7 @@ static int exynos_drm_fb_mmap(struct fb_info *info, return 0; } -static struct fb_ops exynos_drm_fb_ops = { +static const struct fb_ops exynos_drm_fb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, .fb_mmap = exynos_drm_fb_mmap, diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 48159d5d22144457d38a1792f7a2c546acdef40b..9ff921f43a9391625ef84299f82d9c69db992add 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -946,8 +946,10 @@ static int hdmi_create_connector(struct drm_encoder *encoder) connector->interlace_allowed = true; connector->polled = DRM_CONNECTOR_POLL_HPD; - ret = drm_connector_init(hdata->drm_dev, connector, - &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); + ret = drm_connector_init_with_ddc(hdata->drm_dev, connector, + &hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA, + hdata->ddc_adpt); if (ret) { DRM_DEV_ERROR(hdata->dev, "Failed to initialize connector with drm\n"); 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 82c972e9c02461b47603b9709071e7ccd335cd2b..9598ee3cc4d293422b37e32042eb08a69d2f0b0f 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c @@ -68,7 +68,7 @@ static int fsl_dcu_drm_connector_get_modes(struct drm_connector *connector) struct fsl_dcu_drm_connector *fsl_connector; fsl_connector = to_fsl_dcu_connector(connector); - return drm_panel_get_modes(fsl_connector->panel); + return drm_panel_get_modes(fsl_connector->panel, connector); } static int fsl_dcu_drm_connector_mode_valid(struct drm_connector *connector, diff --git a/drivers/gpu/drm/gma500/accel_2d.c b/drivers/gpu/drm/gma500/accel_2d.c index 45ad5ffedc937748bcbcef4e1fc868d681dbe825..adc0507545bf7e3596c8519125c3b7be6798e058 100644 --- a/drivers/gpu/drm/gma500/accel_2d.c +++ b/drivers/gpu/drm/gma500/accel_2d.c @@ -21,9 +21,9 @@ #include #include +#include #include -#include "framebuffer.h" #include "psb_drv.h" #include "psb_reg.h" @@ -226,11 +226,10 @@ static int psb_accel_2d_copy(struct drm_psb_private *dev_priv, static void psbfb_copyarea_accel(struct fb_info *info, const struct fb_copyarea *a) { - struct psb_fbdev *fbdev = info->par; - struct psb_framebuffer *psbfb = &fbdev->pfb; - struct drm_device *dev = psbfb->base.dev; - struct drm_framebuffer *fb = fbdev->psb_fb_helper.fb; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_fb_helper *fb_helper = info->par; + struct drm_framebuffer *fb = fb_helper->fb; + struct drm_device *dev; + struct drm_psb_private *dev_priv; uint32_t offset; uint32_t stride; uint32_t src_format; @@ -239,6 +238,8 @@ static void psbfb_copyarea_accel(struct fb_info *info, if (!fb) return; + dev = fb->dev; + dev_priv = dev->dev_private; offset = to_gtt_range(fb->obj[0])->offset; stride = fb->pitches[0]; @@ -309,9 +310,9 @@ void psbfb_copyarea(struct fb_info *info, */ int psbfb_sync(struct fb_info *info) { - struct psb_fbdev *fbdev = info->par; - struct psb_framebuffer *psbfb = &fbdev->pfb; - struct drm_device *dev = psbfb->base.dev; + struct drm_fb_helper *fb_helper = info->par; + struct drm_framebuffer *fb = fb_helper->fb; + struct drm_device *dev = fb->dev; struct drm_psb_private *dev_priv = dev->dev_private; unsigned long _end = jiffies + HZ; int busy = 0; diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c index 8b784947ed3b91940af86f96f8f342cfce46b7bc..1ed854f498b7a2eba99f5e99c1f600fb17497d05 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_display.c +++ b/drivers/gpu/drm/gma500/cdv_intel_display.c @@ -582,8 +582,8 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc, struct gma_clock_t clock; u32 dpll = 0, dspcntr, pipeconf; bool ok; - bool is_crt = false, is_lvds = false, is_tv = false; - bool is_hdmi = false, is_dp = false; + bool is_lvds = false, is_tv = false; + bool is_dp = false; struct drm_mode_config *mode_config = &dev->mode_config; struct drm_connector *connector; const struct gma_limit_t *limit; @@ -607,10 +607,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc, is_tv = true; break; case INTEL_OUTPUT_ANALOG: - is_crt = true; - break; case INTEL_OUTPUT_HDMI: - is_hdmi = true; break; case INTEL_OUTPUT_DISPLAYPORT: is_dp = true; @@ -979,6 +976,7 @@ const struct drm_crtc_funcs cdv_intel_crtc_funcs = { .gamma_set = gma_crtc_gamma_set, .set_config = gma_crtc_set_config, .destroy = gma_crtc_destroy, + .page_flip = gma_crtc_page_flip, }; const struct gma_clock_funcs cdv_clock_funcs = { diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c index 570b59520fd13307600f03ce03f8188bd3517b4e..5772b2dce0d662170731de50b2400ed52feb4c6d 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c @@ -1594,7 +1594,6 @@ cdv_intel_dp_complete_link_train(struct gma_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct cdv_intel_dp *intel_dp = encoder->dev_priv; - bool channel_eq = false; int tries, cr_tries; u32 reg; uint32_t DP = intel_dp->DP; @@ -1602,7 +1601,6 @@ cdv_intel_dp_complete_link_train(struct gma_encoder *encoder) /* channel equalization */ tries = 0; cr_tries = 0; - channel_eq = false; DRM_DEBUG_KMS("\n"); reg = DP | DP_LINK_TRAIN_PAT_2; @@ -1648,7 +1646,6 @@ cdv_intel_dp_complete_link_train(struct gma_encoder *encoder) if (cdv_intel_channel_eq_ok(encoder)) { DRM_DEBUG_KMS("PT2 train is done\n"); - channel_eq = true; break; } diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 218f3bb15276ea16a2c9bc6bf6bf6b440610471f..1459076d1980232b012a6187b57415a9f3c058f5 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -40,8 +40,8 @@ static int psbfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { - struct psb_fbdev *fbdev = info->par; - struct drm_framebuffer *fb = fbdev->psb_fb_helper.fb; + struct drm_fb_helper *fb_helper = info->par; + struct drm_framebuffer *fb = fb_helper->fb; uint32_t v; if (!fb) @@ -77,10 +77,10 @@ static int psbfb_setcolreg(unsigned regno, unsigned red, unsigned green, static int psbfb_pan(struct fb_var_screeninfo *var, struct fb_info *info) { - struct psb_fbdev *fbdev = info->par; - struct psb_framebuffer *psbfb = &fbdev->pfb; - struct drm_device *dev = psbfb->base.dev; - struct gtt_range *gtt = to_gtt_range(psbfb->base.obj[0]); + struct drm_fb_helper *fb_helper = info->par; + struct drm_framebuffer *fb = fb_helper->fb; + struct drm_device *dev = fb->dev; + struct gtt_range *gtt = to_gtt_range(fb->obj[0]); /* * We have to poke our nose in here. The core fb code assumes @@ -99,10 +99,10 @@ static int psbfb_pan(struct fb_var_screeninfo *var, struct fb_info *info) static vm_fault_t psbfb_vm_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; - struct psb_framebuffer *psbfb = vma->vm_private_data; - struct drm_device *dev = psbfb->base.dev; + struct drm_framebuffer *fb = vma->vm_private_data; + struct drm_device *dev = fb->dev; struct drm_psb_private *dev_priv = dev->dev_private; - struct gtt_range *gtt = to_gtt_range(psbfb->base.obj[0]); + struct gtt_range *gtt = to_gtt_range(fb->obj[0]); int page_num; int i; unsigned long address; @@ -145,23 +145,21 @@ static const struct vm_operations_struct psbfb_vm_ops = { static int psbfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { - struct psb_fbdev *fbdev = info->par; - struct psb_framebuffer *psbfb = &fbdev->pfb; + struct drm_fb_helper *fb_helper = info->par; + struct drm_framebuffer *fb = fb_helper->fb; if (vma->vm_pgoff != 0) return -EINVAL; if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; - if (!psbfb->addr_space) - psbfb->addr_space = vma->vm_file->f_mapping; /* * If this is a GEM object then info->screen_base is the virtual * kernel remapping of the object. FIXME: Review if this is * suitable for our mmap work */ vma->vm_ops = &psbfb_vm_ops; - vma->vm_private_data = (void *)psbfb; + vma->vm_private_data = (void *)fb; vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP; return 0; } @@ -209,9 +207,9 @@ static struct fb_ops psbfb_unaccel_ops = { * 0 on success or an error code if we fail. */ static int psb_framebuffer_init(struct drm_device *dev, - struct psb_framebuffer *fb, + struct drm_framebuffer *fb, const struct drm_mode_fb_cmd2 *mode_cmd, - struct gtt_range *gt) + struct drm_gem_object *obj) { const struct drm_format_info *info; int ret; @@ -227,9 +225,9 @@ static int psb_framebuffer_init(struct drm_device *dev, if (mode_cmd->pitches[0] & 63) return -EINVAL; - drm_helper_mode_fill_fb_struct(dev, &fb->base, mode_cmd); - fb->base.obj[0] = >->gem; - ret = drm_framebuffer_init(dev, &fb->base, &psb_fb_funcs); + drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); + fb->obj[0] = obj; + ret = drm_framebuffer_init(dev, fb, &psb_fb_funcs); if (ret) { dev_err(dev->dev, "framebuffer init failed: %d\n", ret); return ret; @@ -252,21 +250,21 @@ static int psb_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer *psb_framebuffer_create (struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, - struct gtt_range *gt) + struct drm_gem_object *obj) { - struct psb_framebuffer *fb; + struct drm_framebuffer *fb; int ret; fb = kzalloc(sizeof(*fb), GFP_KERNEL); if (!fb) return ERR_PTR(-ENOMEM); - ret = psb_framebuffer_init(dev, fb, mode_cmd, gt); + ret = psb_framebuffer_init(dev, fb, mode_cmd, obj); if (ret) { kfree(fb); return ERR_PTR(ret); } - return &fb->base; + return fb; } /** @@ -300,14 +298,13 @@ static struct gtt_range *psbfb_alloc(struct drm_device *dev, int aligned_size) * * Create a framebuffer to the specifications provided */ -static int psbfb_create(struct psb_fbdev *fbdev, +static int psbfb_create(struct drm_fb_helper *fb_helper, struct drm_fb_helper_surface_size *sizes) { - struct drm_device *dev = fbdev->psb_fb_helper.dev; + struct drm_device *dev = fb_helper->dev; struct drm_psb_private *dev_priv = dev->dev_private; struct fb_info *info; struct drm_framebuffer *fb; - struct psb_framebuffer *psbfb = &fbdev->pfb; struct drm_mode_fb_cmd2 mode_cmd; int size; int ret; @@ -372,7 +369,7 @@ static int psbfb_create(struct psb_fbdev *fbdev, memset(dev_priv->vram_addr + backing->offset, 0, size); - info = drm_fb_helper_alloc_fbi(&fbdev->psb_fb_helper); + info = drm_fb_helper_alloc_fbi(fb_helper); if (IS_ERR(info)) { ret = PTR_ERR(info); goto out; @@ -380,14 +377,13 @@ static int psbfb_create(struct psb_fbdev *fbdev, mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth); - ret = psb_framebuffer_init(dev, psbfb, &mode_cmd, backing); - if (ret) + fb = psb_framebuffer_create(dev, &mode_cmd, &backing->gem); + if (IS_ERR(fb)) { + ret = PTR_ERR(fb); goto out; + } - fb = &psbfb->base; - psbfb->fbdev = info; - - fbdev->psb_fb_helper.fb = fb; + fb_helper->fb = fb; if (dev_priv->ops->accel_2d && pitch_lines > 8) /* 2D engine */ info->fbops = &psbfb_ops; @@ -411,15 +407,14 @@ static int psbfb_create(struct psb_fbdev *fbdev, info->apertures->ranges[0].size = dev_priv->gtt.stolen_size; } - drm_fb_helper_fill_info(info, &fbdev->psb_fb_helper, sizes); + drm_fb_helper_fill_info(info, fb_helper, sizes); info->fix.mmio_start = pci_resource_start(dev->pdev, 0); info->fix.mmio_len = pci_resource_len(dev->pdev, 0); /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ - dev_dbg(dev->dev, "allocated %dx%d fb\n", - psbfb->base.width, psbfb->base.height); + dev_dbg(dev->dev, "allocated %dx%d fb\n", fb->width, fb->height); return 0; out: @@ -439,7 +434,6 @@ static struct drm_framebuffer *psb_user_framebuffer_create (struct drm_device *dev, struct drm_file *filp, const struct drm_mode_fb_cmd2 *cmd) { - struct gtt_range *r; struct drm_gem_object *obj; /* @@ -451,17 +445,15 @@ static struct drm_framebuffer *psb_user_framebuffer_create return ERR_PTR(-ENOENT); /* Let the core code do all the work */ - r = container_of(obj, struct gtt_range, gem); - return psb_framebuffer_create(dev, cmd, r); + return psb_framebuffer_create(dev, cmd, obj); } -static int psbfb_probe(struct drm_fb_helper *helper, +static int psbfb_probe(struct drm_fb_helper *fb_helper, struct drm_fb_helper_surface_size *sizes) { - struct psb_fbdev *psb_fbdev = - container_of(helper, struct psb_fbdev, psb_fb_helper); - struct drm_device *dev = psb_fbdev->psb_fb_helper.dev; + struct drm_device *dev = fb_helper->dev; struct drm_psb_private *dev_priv = dev->dev_private; + unsigned int fb_size; int bytespp; bytespp = sizes->surface_bpp / 8; @@ -471,72 +463,77 @@ static int psbfb_probe(struct drm_fb_helper *helper, /* If the mode will not fit in 32bit then switch to 16bit to get a console on full resolution. The X mode setting server will allocate its own 32bit GEM framebuffer */ - if (ALIGN(sizes->fb_width * bytespp, 64) * sizes->fb_height > - dev_priv->vram_stolen_size) { + fb_size = ALIGN(sizes->surface_width * bytespp, 64) * + sizes->surface_height; + fb_size = ALIGN(fb_size, PAGE_SIZE); + + if (fb_size > dev_priv->vram_stolen_size) { sizes->surface_bpp = 16; sizes->surface_depth = 16; } - return psbfb_create(psb_fbdev, sizes); + return psbfb_create(fb_helper, sizes); } static const struct drm_fb_helper_funcs psb_fb_helper_funcs = { .fb_probe = psbfb_probe, }; -static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev) +static int psb_fbdev_destroy(struct drm_device *dev, + struct drm_fb_helper *fb_helper) { - struct psb_framebuffer *psbfb = &fbdev->pfb; + struct drm_framebuffer *fb = fb_helper->fb; + + drm_fb_helper_unregister_fbi(fb_helper); - drm_fb_helper_unregister_fbi(&fbdev->psb_fb_helper); + drm_fb_helper_fini(fb_helper); + drm_framebuffer_unregister_private(fb); + drm_framebuffer_cleanup(fb); - drm_fb_helper_fini(&fbdev->psb_fb_helper); - drm_framebuffer_unregister_private(&psbfb->base); - drm_framebuffer_cleanup(&psbfb->base); + if (fb->obj[0]) + drm_gem_object_put_unlocked(fb->obj[0]); + kfree(fb); - if (psbfb->base.obj[0]) - drm_gem_object_put_unlocked(psbfb->base.obj[0]); return 0; } int psb_fbdev_init(struct drm_device *dev) { - struct psb_fbdev *fbdev; + struct drm_fb_helper *fb_helper; struct drm_psb_private *dev_priv = dev->dev_private; int ret; - fbdev = kzalloc(sizeof(struct psb_fbdev), GFP_KERNEL); - if (!fbdev) { + fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL); + if (!fb_helper) { dev_err(dev->dev, "no memory\n"); return -ENOMEM; } - dev_priv->fbdev = fbdev; + dev_priv->fb_helper = fb_helper; - drm_fb_helper_prepare(dev, &fbdev->psb_fb_helper, &psb_fb_helper_funcs); + drm_fb_helper_prepare(dev, fb_helper, &psb_fb_helper_funcs); - ret = drm_fb_helper_init(dev, &fbdev->psb_fb_helper, - INTELFB_CONN_LIMIT); + ret = drm_fb_helper_init(dev, fb_helper, INTELFB_CONN_LIMIT); if (ret) goto free; - ret = drm_fb_helper_single_add_all_connectors(&fbdev->psb_fb_helper); + ret = drm_fb_helper_single_add_all_connectors(fb_helper); if (ret) goto fini; /* disable all the possible outputs/crtcs before entering KMS mode */ drm_helper_disable_unused_functions(dev); - ret = drm_fb_helper_initial_config(&fbdev->psb_fb_helper, 32); + ret = drm_fb_helper_initial_config(fb_helper, 32); if (ret) goto fini; return 0; fini: - drm_fb_helper_fini(&fbdev->psb_fb_helper); + drm_fb_helper_fini(fb_helper); free: - kfree(fbdev); + kfree(fb_helper); return ret; } @@ -544,12 +541,12 @@ static void psb_fbdev_fini(struct drm_device *dev) { struct drm_psb_private *dev_priv = dev->dev_private; - if (!dev_priv->fbdev) + if (!dev_priv->fb_helper) return; - psb_fbdev_destroy(dev, dev_priv->fbdev); - kfree(dev_priv->fbdev); - dev_priv->fbdev = NULL; + psb_fbdev_destroy(dev, dev_priv->fb_helper); + kfree(dev_priv->fb_helper); + dev_priv->fb_helper = NULL; } static const struct drm_mode_config_funcs psb_mode_funcs = { diff --git a/drivers/gpu/drm/gma500/framebuffer.h b/drivers/gpu/drm/gma500/framebuffer.h index ae8a02639fd99a1ac8cbcda623c2a0988d3f7d44..2fbba4b48841667de719eee83b20001b479870b1 100644 --- a/drivers/gpu/drm/gma500/framebuffer.h +++ b/drivers/gpu/drm/gma500/framebuffer.h @@ -9,23 +9,8 @@ #ifndef _FRAMEBUFFER_H_ #define _FRAMEBUFFER_H_ -#include - #include "psb_drv.h" -struct psb_framebuffer { - struct drm_framebuffer base; - struct address_space *addr_space; - struct fb_info *fbdev; -}; - -struct psb_fbdev { - struct drm_fb_helper psb_fb_helper; /* must be first */ - struct psb_framebuffer pfb; -}; - -#define to_psb_fb(x) container_of(x, struct psb_framebuffer, base) - extern int gma_connector_clones(struct drm_device *dev, int type_mask); #endif diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index e20ccb5d10fde9225b0d62d535dc5c3b2e992cd6..17f136985d21456b1ec4228e8946cfd5228f4fa4 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -255,6 +255,8 @@ void gma_crtc_dpms(struct drm_crtc *crtc, int mode) /* Give the overlay scaler a chance to enable * if it's on this pipe */ /* psb_intel_crtc_dpms_video(crtc, true); TODO */ + + drm_crtc_vblank_on(crtc); break; case DRM_MODE_DPMS_OFF: if (!gma_crtc->active) @@ -501,6 +503,52 @@ void gma_crtc_destroy(struct drm_crtc *crtc) kfree(gma_crtc); } +int gma_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t page_flip_flags, + struct drm_modeset_acquire_ctx *ctx) +{ + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + struct drm_framebuffer *current_fb = crtc->primary->fb; + struct drm_framebuffer *old_fb = crtc->primary->old_fb; + const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + struct drm_device *dev = crtc->dev; + unsigned long flags; + int ret; + + if (!crtc_funcs->mode_set_base) + return -EINVAL; + + /* Using mode_set_base requires the new fb to be set already. */ + crtc->primary->fb = fb; + + if (event) { + spin_lock_irqsave(&dev->event_lock, flags); + + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + + gma_crtc->page_flip_event = event; + + /* Call this locked if we want an event at vblank interrupt. */ + ret = crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y, old_fb); + if (ret) { + gma_crtc->page_flip_event = NULL; + drm_crtc_vblank_put(crtc); + } + + spin_unlock_irqrestore(&dev->event_lock, flags); + } else { + ret = crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y, old_fb); + } + + /* Restore previous fb in case of failure. */ + if (ret) + crtc->primary->fb = current_fb; + + return ret; +} + int gma_crtc_set_config(struct drm_mode_set *set, struct drm_modeset_acquire_ctx *ctx) { diff --git a/drivers/gpu/drm/gma500/gma_display.h b/drivers/gpu/drm/gma500/gma_display.h index fdbd7ecaa59ca2c21208f9f01754e3ed9249e721..7bd6c1ee8b21a948d45229a5facbc093ff0ceffa 100644 --- a/drivers/gpu/drm/gma500/gma_display.h +++ b/drivers/gpu/drm/gma500/gma_display.h @@ -11,6 +11,7 @@ #define _GMA_DISPLAY_H_ #include +#include struct drm_encoder; struct drm_mode_set; @@ -71,6 +72,11 @@ extern void gma_crtc_prepare(struct drm_crtc *crtc); extern void gma_crtc_commit(struct drm_crtc *crtc); extern void gma_crtc_disable(struct drm_crtc *crtc); extern void gma_crtc_destroy(struct drm_crtc *crtc); +extern int gma_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t page_flip_flags, + struct drm_modeset_acquire_ctx *ctx); extern int gma_crtc_set_config(struct drm_mode_set *set, struct drm_modeset_acquire_ctx *ctx); diff --git a/drivers/gpu/drm/gma500/mdfld_intel_display.c b/drivers/gpu/drm/gma500/mdfld_intel_display.c index b8bfb96008b8dcc2c0b725f9f0cf78291ce38ca4..4fff110c492124e8629cf0c979c61e0dd1c30b72 100644 --- a/drivers/gpu/drm/gma500/mdfld_intel_display.c +++ b/drivers/gpu/drm/gma500/mdfld_intel_display.c @@ -113,27 +113,6 @@ static int psb_intel_panel_fitter_pipe(struct drm_device *dev) return (pfit_control >> 29) & 0x3; } -static struct drm_device globle_dev; - -void mdfld__intel_plane_set_alpha(int enable) -{ - struct drm_device *dev = &globle_dev; - int dspcntr_reg = DSPACNTR; - u32 dspcntr; - - dspcntr = REG_READ(dspcntr_reg); - - if (enable) { - dspcntr &= ~DISPPLANE_32BPP_NO_ALPHA; - dspcntr |= DISPPLANE_32BPP; - } else { - dspcntr &= ~DISPPLANE_32BPP; - dspcntr |= DISPPLANE_32BPP_NO_ALPHA; - } - - REG_WRITE(dspcntr_reg, dspcntr); -} - static int check_fb(struct drm_framebuffer *fb) { if (!fb) @@ -164,8 +143,6 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, u32 dspcntr; int ret; - memcpy(&globle_dev, dev, sizeof(struct drm_device)); - dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe); /* no fb bound */ diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c index f4c520893ceb627a5c779357a883dcd99a6e29ec..f4370232767d3d70ce7e65f8ae7af2d622f60419 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c @@ -159,9 +159,7 @@ static void oaktrail_hdmi_audio_disable(struct drm_device *dev) static unsigned int htotal_calculate(struct drm_display_mode *mode) { - u32 htotal, new_crtc_htotal; - - htotal = (mode->crtc_hdisplay - 1) | ((mode->crtc_htotal - 1) << 16); + u32 new_crtc_htotal; /* * 1024 x 768 new_crtc_htotal = 0x1024; diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c index 7390403ea1b72de3347fd9fd61a96b7b3c96fbd2..582e095975002de841d032a5f53f364ceebf6bc0 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c @@ -117,6 +117,7 @@ static void oaktrail_lvds_mode_set(struct drm_encoder *encoder, if (!connector) { DRM_ERROR("Couldn't find connector when setting mode"); + gma_power_end(dev); return; } diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 7005f8f69c683749a0e7493c001d929e7c1fa091..52591416f8fe1ea49562fa57418051e23716151e 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -19,10 +19,10 @@ #include #include +#include #include #include #include -#include #include #include @@ -426,14 +426,48 @@ static long psb_unlocked_ioctl(struct file *filp, unsigned int cmd, static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - return drm_get_pci_dev(pdev, ent, &driver); -} + struct drm_device *dev; + int ret; + + ret = pci_enable_device(pdev); + if (ret) + return ret; + + dev = drm_dev_alloc(&driver, &pdev->dev); + if (IS_ERR(dev)) { + ret = PTR_ERR(dev); + goto err_pci_disable_device; + } + + dev->pdev = pdev; + pci_set_drvdata(pdev, dev); + + ret = psb_driver_load(dev, ent->driver_data); + if (ret) + goto err_drm_dev_put; + ret = drm_dev_register(dev, ent->driver_data); + if (ret) + goto err_psb_driver_unload; + + return 0; + +err_psb_driver_unload: + psb_driver_unload(dev); +err_drm_dev_put: + drm_dev_put(dev); +err_pci_disable_device: + pci_disable_device(pdev); + return ret; +} static void psb_pci_remove(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - drm_put_dev(dev); + + drm_dev_unregister(dev); + psb_driver_unload(dev); + drm_dev_put(dev); } static const struct dev_pm_ops psb_pm_ops = { @@ -466,8 +500,6 @@ static const struct file_operations psb_gem_fops = { static struct drm_driver driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM, - .load = psb_driver_load, - .unload = psb_driver_unload, .lastclose = drm_fb_helper_lastclose, .num_ioctls = ARRAY_SIZE(psb_ioctls), diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index 9b3c03f4a38d2ff3c457209e01a3172c1a1cd8c6..3d4ef3071d45d8e6afa8ccba2a6e902e2e2cf8d5 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -229,6 +229,8 @@ enum { #define KSEL_BYPASS_25 6 #define KSEL_BYPASS_83_100 7 +struct drm_fb_helper; + struct opregion_header; struct opregion_acpi; struct opregion_swsci; @@ -432,7 +434,7 @@ struct drm_psb_private { struct pci_dev *lpc_pdev; /* Currently only used by mrst */ const struct psb_ops *ops; const struct psb_offset *regmap; - + struct child_device_config *child_dev; int child_dev_num; @@ -540,7 +542,7 @@ struct drm_psb_private { /* Oaktrail HDMI state */ struct oaktrail_hdmi_dev *hdmi_priv; - + /* Register state */ struct psb_save_area regs; @@ -572,7 +574,7 @@ struct drm_psb_private { uint32_t blc_adj1; uint32_t blc_adj2; - void *fbdev; + struct drm_fb_helper *fb_helper; /* 2D acceleration */ spinlock_t lock_2d; diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c index 4256410535f06636370226d8c2d2189dcd173913..fed3b563e62e62673add13ead9a2f27a443400ca 100644 --- a/drivers/gpu/drm/gma500/psb_intel_display.c +++ b/drivers/gpu/drm/gma500/psb_intel_display.c @@ -432,6 +432,7 @@ const struct drm_crtc_funcs psb_intel_crtc_funcs = { .gamma_set = gma_crtc_gamma_set, .set_config = gma_crtc_set_config, .destroy = gma_crtc_destroy, + .page_flip = gma_crtc_page_flip, }; const struct gma_clock_funcs psb_clock_funcs = { diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index cdf10333d1c22c9ea681f56b05263f3b4f3789af..16c6136f778b07c32bc7642e4ad2bb79a0b28e74 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "gma_display.h" @@ -182,6 +183,8 @@ struct gma_crtc { struct psb_intel_crtc_state *crtc_state; const struct gma_clock_funcs *clock_funcs; + + struct drm_pending_vblank_event *page_flip_event; }; #define to_gma_crtc(x) \ diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c index e6265fb85626ee67e4c2075a5bd4c2f838209833..40a37e400b023fcc6d4398ae8a37418a9bb6b1e2 100644 --- a/drivers/gpu/drm/gma500/psb_irq.c +++ b/drivers/gpu/drm/gma500/psb_irq.c @@ -165,11 +165,23 @@ static void mid_pipe_event_handler(struct drm_device *dev, int pipe) "%s, can't clear status bits for pipe %d, its value = 0x%x.\n", __func__, pipe, PSB_RVDC32(pipe_stat_reg)); - if (pipe_stat_val & PIPE_VBLANK_STATUS) - drm_handle_vblank(dev, pipe); + if (pipe_stat_val & PIPE_VBLANK_STATUS || + (IS_MFLD(dev) && pipe_stat_val & PIPE_TE_STATUS)) { + struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + unsigned long flags; - if (pipe_stat_val & PIPE_TE_STATUS) drm_handle_vblank(dev, pipe); + + spin_lock_irqsave(&dev->event_lock, flags); + if (gma_crtc->page_flip_event) { + drm_crtc_send_vblank_event(crtc, + gma_crtc->page_flip_event); + gma_crtc->page_flip_event = NULL; + drm_crtc_vblank_put(crtc); + } + spin_unlock_irqrestore(&dev->event_lock, flags); + } } /* @@ -194,7 +206,6 @@ static void psb_sgx_interrupt(struct drm_device *dev, u32 stat_1, u32 stat_2) { struct drm_psb_private *dev_priv = dev->dev_private; u32 val, addr; - int error = false; if (stat_1 & _PSB_CE_TWOD_COMPLETE) val = PSB_RSGX32(PSB_CR_2D_BLIT_STATUS); @@ -229,7 +240,6 @@ static void psb_sgx_interrupt(struct drm_device *dev, u32 stat_1, u32 stat_2) DRM_ERROR("\tMMU failing address is 0x%08x.\n", (unsigned int)addr); - error = true; } } diff --git a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c index 7de3ce637c7f71aa16c6a6be4322f5e5d390392e..9e8224456ea29ac9ff62ba1747c28e118e2a57b9 100644 --- a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c +++ b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include @@ -36,6 +36,11 @@ static struct i2c_client *tc35876x_client; static struct i2c_client *cmi_lcd_i2c_client; +/* Panel GPIOs */ +static struct gpio_desc *bridge_reset; +static struct gpio_desc *bridge_bl_enable; +static struct gpio_desc *backlight_voltage; + #define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) #define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) @@ -316,27 +321,23 @@ static int tc35876x_regr(struct i2c_client *client, u16 reg, u32 *value) void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state) { - struct tc35876x_platform_data *pdata; - if (WARN(!tc35876x_client, "%s called before probe", __func__)) return; dev_dbg(&tc35876x_client->dev, "%s: state %d\n", __func__, state); - pdata = dev_get_platdata(&tc35876x_client->dev); - - if (pdata->gpio_bridge_reset == -1) + if (!bridge_reset) return; if (state) { - gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0); + gpiod_set_value_cansleep(bridge_reset, 0); mdelay(10); } else { /* Pull MIPI Bridge reset pin to Low */ - gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0); + gpiod_set_value_cansleep(bridge_reset, 0); mdelay(20); /* Pull MIPI Bridge reset pin to High */ - gpio_set_value_cansleep(pdata->gpio_bridge_reset, 1); + gpiod_set_value_cansleep(bridge_reset, 1); mdelay(40); } } @@ -510,25 +511,20 @@ void tc35876x_brightness_control(struct drm_device *dev, int level) void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev) { - struct tc35876x_platform_data *pdata; - if (WARN(!tc35876x_client, "%s called before probe", __func__)) return; dev_dbg(&tc35876x_client->dev, "%s\n", __func__); - pdata = dev_get_platdata(&tc35876x_client->dev); - - if (pdata->gpio_panel_bl_en != -1) - gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 0); + if (bridge_bl_enable) + gpiod_set_value_cansleep(bridge_bl_enable, 0); - if (pdata->gpio_panel_vadd != -1) - gpio_set_value_cansleep(pdata->gpio_panel_vadd, 0); + if (backlight_voltage) + gpiod_set_value_cansleep(backlight_voltage, 0); } void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev) { - struct tc35876x_platform_data *pdata; struct drm_psb_private *dev_priv = dev->dev_private; if (WARN(!tc35876x_client, "%s called before probe", __func__)) @@ -536,10 +532,8 @@ void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev) dev_dbg(&tc35876x_client->dev, "%s\n", __func__); - pdata = dev_get_platdata(&tc35876x_client->dev); - - if (pdata->gpio_panel_vadd != -1) { - gpio_set_value_cansleep(pdata->gpio_panel_vadd, 1); + if (backlight_voltage) { + gpiod_set_value_cansleep(backlight_voltage, 1); msleep(260); } @@ -571,8 +565,8 @@ void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev) "i2c write failed (%d)\n", ret); } - if (pdata->gpio_panel_bl_en != -1) - gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 1); + if (bridge_bl_enable) + gpiod_set_value_cansleep(bridge_bl_enable, 1); tc35876x_brightness_control(dev, dev_priv->brightness_adjusted); } @@ -635,8 +629,6 @@ static int tc35876x_get_panel_info(struct drm_device *dev, int pipe, static int tc35876x_bridge_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct tc35876x_platform_data *pdata; - dev_info(&client->dev, "%s\n", __func__); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { @@ -645,26 +637,23 @@ static int tc35876x_bridge_probe(struct i2c_client *client, return -ENODEV; } - pdata = dev_get_platdata(&client->dev); - if (!pdata) { - dev_err(&client->dev, "%s: no platform data\n", __func__); - return -ENODEV; - } + bridge_reset = devm_gpiod_get_optional(&client->dev, "bridge-reset", GPIOD_OUT_LOW); + if (IS_ERR(bridge_reset)) + return PTR_ERR(bridge_reset); + if (bridge_reset) + gpiod_set_consumer_name(bridge_reset, "tc35876x bridge reset"); - if (pdata->gpio_bridge_reset != -1) { - gpio_request(pdata->gpio_bridge_reset, "tc35876x bridge reset"); - gpio_direction_output(pdata->gpio_bridge_reset, 0); - } - - if (pdata->gpio_panel_bl_en != -1) { - gpio_request(pdata->gpio_panel_bl_en, "tc35876x panel bl en"); - gpio_direction_output(pdata->gpio_panel_bl_en, 0); - } + bridge_bl_enable = devm_gpiod_get_optional(&client->dev, "bl-en", GPIOD_OUT_LOW); + if (IS_ERR(bridge_bl_enable)) + return PTR_ERR(bridge_bl_enable); + if (bridge_bl_enable) + gpiod_set_consumer_name(bridge_bl_enable, "tc35876x panel bl en"); - if (pdata->gpio_panel_vadd != -1) { - gpio_request(pdata->gpio_panel_vadd, "tc35876x panel vadd"); - gpio_direction_output(pdata->gpio_panel_vadd, 0); - } + backlight_voltage = devm_gpiod_get_optional(&client->dev, "vadd", GPIOD_OUT_LOW); + if (IS_ERR(backlight_voltage)) + return PTR_ERR(backlight_voltage); + if (backlight_voltage) + gpiod_set_consumer_name(backlight_voltage, "tc35876x panel vadd"); tc35876x_client = client; @@ -673,19 +662,8 @@ static int tc35876x_bridge_probe(struct i2c_client *client, static int tc35876x_bridge_remove(struct i2c_client *client) { - struct tc35876x_platform_data *pdata = dev_get_platdata(&client->dev); - dev_dbg(&client->dev, "%s\n", __func__); - if (pdata->gpio_bridge_reset != -1) - gpio_free(pdata->gpio_bridge_reset); - - if (pdata->gpio_panel_bl_en != -1) - gpio_free(pdata->gpio_panel_bl_en); - - if (pdata->gpio_panel_vadd != -1) - gpio_free(pdata->gpio_panel_vadd); - tc35876x_client = NULL; return 0; diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile index 0c2d4296bccd1b0f57983d15490615f78a0b1776..f991327155976b7ac19a2f092d3e5e160dc563cc 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_ttm.o +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_ttm.o obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c index 6527a97f68a3cc003e8b0a9da017cc2c9a8ca847..7fa7d4933f6031b2210aaabe06fd19dd40344313 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c @@ -99,14 +99,12 @@ static void hibmc_plane_atomic_update(struct drm_plane *plane, s64 gpu_addr = 0; unsigned int line_l; struct hibmc_drm_private *priv = plane->dev->dev_private; - struct hibmc_framebuffer *hibmc_fb; struct drm_gem_vram_object *gbo; if (!state->fb) return; - hibmc_fb = to_hibmc_framebuffer(state->fb); - gbo = drm_gem_vram_of_gem(hibmc_fb->obj); + gbo = drm_gem_vram_of_gem(state->fb->obj[0]); gpu_addr = drm_gem_vram_offset(gbo); if (WARN_ON_ONCE(gpu_addr < 0)) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index 2fd4ca91a62d938c7a79e6076cc816982273434d..11d1b0761c9a7ddef4b6cb95083d75219b89fdea 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -54,6 +55,7 @@ static struct drm_driver hibmc_driver = { .desc = "hibmc drm driver", .major = 1, .minor = 0, + .debugfs_init = drm_vram_mm_debugfs_init, .dumb_create = hibmc_dumb_create, .dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset, .gem_prime_mmap = drm_gem_prime_mmap, @@ -247,8 +249,6 @@ static int hibmc_unload(struct drm_device *dev) { struct hibmc_drm_private *priv = dev->dev_private; - hibmc_fbdev_fini(priv); - drm_atomic_helper_shutdown(dev); if (dev->irq_enabled) @@ -307,7 +307,7 @@ static int hibmc_load(struct drm_device *dev) /* reset all the states of crtc/plane/encoder/connector */ drm_mode_config_reset(dev); - ret = hibmc_fbdev_init(priv); + ret = drm_fbdev_generic_setup(dev, 16); if (ret) { DRM_ERROR("failed to initialize fbdev: %d\n", ret); goto err; diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h index e58ecd7edcf82da2df4abcb72fb46696aa46da00..50a0c1f9d21138c3defd0fcbe00ca97877e32be0 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h @@ -18,18 +18,6 @@ #include struct drm_device; -struct drm_gem_object; - -struct hibmc_framebuffer { - struct drm_framebuffer fb; - struct drm_gem_object *obj; -}; - -struct hibmc_fbdev { - struct drm_fb_helper helper; /* must be first */ - struct hibmc_framebuffer *fb; - int size; -}; struct hibmc_drm_private { /* hw */ @@ -42,13 +30,8 @@ struct hibmc_drm_private { /* drm */ struct drm_device *dev; bool mode_config_initialized; - - /* fbdev */ - struct hibmc_fbdev *fbdev; }; -#define to_hibmc_framebuffer(x) container_of(x, struct hibmc_framebuffer, fb) - void hibmc_set_power_mode(struct hibmc_drm_private *priv, unsigned int power_mode); void hibmc_set_current_gate(struct hibmc_drm_private *priv, @@ -56,15 +39,6 @@ void hibmc_set_current_gate(struct hibmc_drm_private *priv, int hibmc_de_init(struct hibmc_drm_private *priv); int hibmc_vdac_init(struct hibmc_drm_private *priv); -int hibmc_fbdev_init(struct hibmc_drm_private *priv); -void hibmc_fbdev_fini(struct hibmc_drm_private *priv); - -int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel, - struct drm_gem_object **obj); -struct hibmc_framebuffer * -hibmc_framebuffer_init(struct drm_device *dev, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj); int hibmc_mm_init(struct hibmc_drm_private *hibmc); void hibmc_mm_fini(struct hibmc_drm_private *hibmc); diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c deleted file mode 100644 index b4c1cea051e8fd848d02e03a4dcbdf4ce409cf05..0000000000000000000000000000000000000000 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c +++ /dev/null @@ -1,240 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* Hisilicon Hibmc SoC drm driver - * - * Based on the bochs drm driver. - * - * Copyright (c) 2016 Huawei Limited. - * - * Author: - * Rongrong Zou - * Rongrong Zou - * Jianhua Li - */ - -#include -#include -#include -#include -#include - -#include "hibmc_drm_drv.h" - -static int hibmcfb_create_object( - struct hibmc_drm_private *priv, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object **gobj_p) -{ - struct drm_gem_object *gobj; - struct drm_device *dev = priv->dev; - u32 size; - int ret = 0; - - size = mode_cmd->pitches[0] * mode_cmd->height; - ret = hibmc_gem_create(dev, size, true, &gobj); - if (ret) - return ret; - - *gobj_p = gobj; - return ret; -} - -static struct fb_ops hibmc_drm_fb_ops = { - .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, -}; - -static int hibmc_drm_fb_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct hibmc_fbdev *hi_fbdev = - container_of(helper, struct hibmc_fbdev, helper); - struct hibmc_drm_private *priv = helper->dev->dev_private; - struct fb_info *info; - struct drm_mode_fb_cmd2 mode_cmd; - struct drm_gem_object *gobj = NULL; - int ret = 0; - size_t size; - unsigned int bytes_per_pixel; - struct drm_gem_vram_object *gbo = NULL; - void *base; - - DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n", - sizes->surface_width, sizes->surface_height, - sizes->surface_bpp); - - bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8); - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - mode_cmd.pitches[0] = mode_cmd.width * bytes_per_pixel; - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - size = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height); - - ret = hibmcfb_create_object(priv, &mode_cmd, &gobj); - if (ret) { - DRM_ERROR("failed to create fbcon backing object: %d\n", ret); - return -ENOMEM; - } - - gbo = drm_gem_vram_of_gem(gobj); - - ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); - if (ret) { - DRM_ERROR("failed to pin fbcon: %d\n", ret); - goto out_unref_gem; - } - - base = drm_gem_vram_kmap(gbo, true, NULL); - if (IS_ERR(base)) { - ret = PTR_ERR(base); - DRM_ERROR("failed to kmap fbcon: %d\n", ret); - goto out_unpin_bo; - } - - info = drm_fb_helper_alloc_fbi(helper); - if (IS_ERR(info)) { - ret = PTR_ERR(info); - DRM_ERROR("failed to allocate fbi: %d\n", ret); - goto out_release_fbi; - } - - hi_fbdev->fb = hibmc_framebuffer_init(priv->dev, &mode_cmd, gobj); - if (IS_ERR(hi_fbdev->fb)) { - ret = PTR_ERR(hi_fbdev->fb); - hi_fbdev->fb = NULL; - DRM_ERROR("failed to initialize framebuffer: %d\n", ret); - goto out_release_fbi; - } - - priv->fbdev->size = size; - hi_fbdev->helper.fb = &hi_fbdev->fb->fb; - - info->fbops = &hibmc_drm_fb_ops; - - drm_fb_helper_fill_info(info, &priv->fbdev->helper, sizes); - - info->screen_base = base; - info->screen_size = size; - - info->fix.smem_start = gbo->bo.mem.bus.offset + gbo->bo.mem.bus.base; - info->fix.smem_len = size; - return 0; - -out_release_fbi: - drm_gem_vram_kunmap(gbo); -out_unpin_bo: - drm_gem_vram_unpin(gbo); -out_unref_gem: - drm_gem_object_put_unlocked(gobj); - - return ret; -} - -static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev) -{ - struct hibmc_framebuffer *gfb = fbdev->fb; - struct drm_fb_helper *fbh = &fbdev->helper; - - drm_fb_helper_unregister_fbi(fbh); - - drm_fb_helper_fini(fbh); - - if (gfb) - drm_framebuffer_put(&gfb->fb); -} - -static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = { - .fb_probe = hibmc_drm_fb_create, -}; - -int hibmc_fbdev_init(struct hibmc_drm_private *priv) -{ - int ret; - struct fb_var_screeninfo *var; - struct fb_fix_screeninfo *fix; - struct hibmc_fbdev *hifbdev; - - hifbdev = devm_kzalloc(priv->dev->dev, sizeof(*hifbdev), GFP_KERNEL); - if (!hifbdev) { - DRM_ERROR("failed to allocate hibmc_fbdev\n"); - return -ENOMEM; - } - - priv->fbdev = hifbdev; - drm_fb_helper_prepare(priv->dev, &hifbdev->helper, - &hibmc_fbdev_helper_funcs); - - /* Now just one crtc and one channel */ - ret = drm_fb_helper_init(priv->dev, &hifbdev->helper, 1); - if (ret) { - DRM_ERROR("failed to initialize fb helper: %d\n", ret); - return ret; - } - - ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper); - if (ret) { - DRM_ERROR("failed to add all connectors: %d\n", ret); - goto fini; - } - - ret = drm_fb_helper_initial_config(&hifbdev->helper, 16); - if (ret) { - DRM_ERROR("failed to setup initial conn config: %d\n", ret); - goto fini; - } - - var = &hifbdev->helper.fbdev->var; - fix = &hifbdev->helper.fbdev->fix; - - DRM_DEBUG_DRIVER("Member of info->var is :\n" - "xres=%d\n" - "yres=%d\n" - "xres_virtual=%d\n" - "yres_virtual=%d\n" - "xoffset=%d\n" - "yoffset=%d\n" - "bits_per_pixel=%d\n" - "...\n", var->xres, var->yres, var->xres_virtual, - var->yres_virtual, var->xoffset, var->yoffset, - var->bits_per_pixel); - DRM_DEBUG_DRIVER("Member of info->fix is :\n" - "smem_start=%lx\n" - "smem_len=%d\n" - "type=%d\n" - "type_aux=%d\n" - "visual=%d\n" - "xpanstep=%d\n" - "ypanstep=%d\n" - "ywrapstep=%d\n" - "line_length=%d\n" - "accel=%d\n" - "capabilities=%d\n" - "...\n", fix->smem_start, fix->smem_len, fix->type, - fix->type_aux, fix->visual, fix->xpanstep, - fix->ypanstep, fix->ywrapstep, fix->line_length, - fix->accel, fix->capabilities); - - return 0; - -fini: - drm_fb_helper_fini(&hifbdev->helper); - return ret; -} - -void hibmc_fbdev_fini(struct hibmc_drm_private *priv) -{ - if (!priv->fbdev) - return; - - hibmc_fbdev_destroy(priv->fbdev); - priv->fbdev = NULL; -} diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c index 21b684eab5c9c6785550774a37dd19b8242a4997..50b988fdd5cc1e4cd9399eb483c317583ee2ff11 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -46,125 +47,14 @@ void hibmc_mm_fini(struct hibmc_drm_private *hibmc) drm_vram_helper_release_mm(hibmc->dev); } -int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel, - struct drm_gem_object **obj) -{ - struct drm_gem_vram_object *gbo; - int ret; - - *obj = NULL; - - size = roundup(size, PAGE_SIZE); - if (size == 0) - return -EINVAL; - - gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev, size, 0, false); - if (IS_ERR(gbo)) { - ret = PTR_ERR(gbo); - if (ret != -ERESTARTSYS) - DRM_ERROR("failed to allocate GEM object: %d\n", ret); - return ret; - } - *obj = &gbo->bo.base; - return 0; -} - int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { - struct drm_gem_object *gobj; - u32 handle; - int ret; - - args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 16); - args->size = args->pitch * args->height; - - ret = hibmc_gem_create(dev, args->size, false, - &gobj); - if (ret) { - DRM_ERROR("failed to create GEM object: %d\n", ret); - return ret; - } - - ret = drm_gem_handle_create(file, gobj, &handle); - drm_gem_object_put_unlocked(gobj); - if (ret) { - DRM_ERROR("failed to unreference GEM object: %d\n", ret); - return ret; - } - - args->handle = handle; - return 0; -} - -static void hibmc_user_framebuffer_destroy(struct drm_framebuffer *fb) -{ - struct hibmc_framebuffer *hibmc_fb = to_hibmc_framebuffer(fb); - - drm_gem_object_put_unlocked(hibmc_fb->obj); - drm_framebuffer_cleanup(fb); - kfree(hibmc_fb); -} - -static const struct drm_framebuffer_funcs hibmc_fb_funcs = { - .destroy = hibmc_user_framebuffer_destroy, -}; - -struct hibmc_framebuffer * -hibmc_framebuffer_init(struct drm_device *dev, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj) -{ - struct hibmc_framebuffer *hibmc_fb; - int ret; - - hibmc_fb = kzalloc(sizeof(*hibmc_fb), GFP_KERNEL); - if (!hibmc_fb) { - DRM_ERROR("failed to allocate hibmc_fb\n"); - return ERR_PTR(-ENOMEM); - } - - drm_helper_mode_fill_fb_struct(dev, &hibmc_fb->fb, mode_cmd); - hibmc_fb->obj = obj; - ret = drm_framebuffer_init(dev, &hibmc_fb->fb, &hibmc_fb_funcs); - if (ret) { - DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); - kfree(hibmc_fb); - return ERR_PTR(ret); - } - - return hibmc_fb; -} - -static struct drm_framebuffer * -hibmc_user_framebuffer_create(struct drm_device *dev, - struct drm_file *filp, - const struct drm_mode_fb_cmd2 *mode_cmd) -{ - struct drm_gem_object *obj; - struct hibmc_framebuffer *hibmc_fb; - - DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n", - mode_cmd->width, mode_cmd->height, - (mode_cmd->pixel_format) & 0xff, - (mode_cmd->pixel_format >> 8) & 0xff, - (mode_cmd->pixel_format >> 16) & 0xff, - (mode_cmd->pixel_format >> 24) & 0xff); - - obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]); - if (!obj) - return ERR_PTR(-ENOENT); - - hibmc_fb = hibmc_framebuffer_init(dev, mode_cmd, obj); - if (IS_ERR(hibmc_fb)) { - drm_gem_object_put_unlocked(obj); - return ERR_PTR((long)hibmc_fb); - } - return &hibmc_fb->fb; + return drm_gem_vram_fill_create_dumb(file, dev, 0, 16, args); } const struct drm_mode_config_funcs hibmc_mode_funcs = { .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, - .fb_create = hibmc_user_framebuffer_create, + .fb_create = drm_gem_fb_create, }; diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c index e66c38332df473422e39b7b9fb5a846d28380ca5..b88c3d5f92b4598e22447f5756db6438229cba69 100644 --- a/drivers/gpu/drm/i810/i810_dma.c +++ b/drivers/gpu/drm/i810/i810_dma.c @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -39,7 +40,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/i810/i810_drv.c b/drivers/gpu/drm/i810/i810_drv.c index 5dd26a06ee0ed2e164b5df1f040c178688fc1a3d..0e53a066d4dbc2bbb7e6c7b5b1f55c94ee794df5 100644 --- a/drivers/gpu/drm/i810/i810_drv.c +++ b/drivers/gpu/drm/i810/i810_drv.c @@ -31,11 +31,12 @@ */ #include "i810_drv.h" + #include +#include #include #include -#include #include #include diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 85cdd7b317ef5ecda0b36a7f4857a30fa7ec83d8..59c37587918606450035e1c264217ffe5a117a98 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -12714,7 +12714,7 @@ static void intel_dump_infoframe(struct drm_i915_private *dev_priv, const union hdmi_infoframe *frame) { - if ((drm_debug & DRM_UT_KMS) == 0) + if (!drm_debug_enabled(DRM_UT_KMS)) return; hdmi_infoframe_log(KERN_DEBUG, dev_priv->drm.dev, frame); @@ -13312,7 +13312,7 @@ pipe_config_infoframe_mismatch(struct drm_i915_private *dev_priv, const union hdmi_infoframe *b) { if (fastset) { - if ((drm_debug & DRM_UT_KMS) == 0) + if (!drm_debug_enabled(DRM_UT_KMS)) return; DRM_DEBUG_KMS("fastset mismatch in %s infoframe\n", name); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index afec172ca9e4a082d95886ca2816dddcd93f9282..b689b69aafc2a8090af1318549cdf0e690f813ad 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1814,7 +1814,7 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp) { char str[128]; /* FIXME: too big for stack? */ - if ((drm_debug & DRM_UT_KMS) == 0) + if (!drm_debug_enabled(DRM_UT_KMS)) return; snprintf_int_array(str, sizeof(str), diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 48c960ca12fb2b20c46a13e7ca974df42416093a..1e98e432c9fae9e8ce72ffbbc7e26de5b86a18d9 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -100,7 +100,7 @@ static int intel_fbdev_pan_display(struct fb_var_screeninfo *var, return ret; } -static struct fb_ops intelfb_ops = { +static const struct fb_ops intelfb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, .fb_set_par = intel_fbdev_set_par, diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c index eaea49d08eb5a35d373e040e9bc09947cf5fa928..372b57ca0efc91b60296213b2d4eb17ae0d73bf6 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c @@ -93,40 +93,6 @@ static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) i915_gem_object_unpin_map(obj); } -static void *i915_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num) -{ - struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); - struct page *page; - - if (page_num >= obj->base.size >> PAGE_SHIFT) - return NULL; - - if (!i915_gem_object_has_struct_page(obj)) - return NULL; - - if (i915_gem_object_pin_pages(obj)) - return NULL; - - /* Synchronisation is left to the caller (via .begin_cpu_access()) */ - page = i915_gem_object_get_page(obj, page_num); - if (IS_ERR(page)) - goto err_unpin; - - return kmap(page); - -err_unpin: - i915_gem_object_unpin_pages(obj); - return NULL; -} - -static void i915_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num, void *addr) -{ - struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); - - kunmap(virt_to_page(addr)); - i915_gem_object_unpin_pages(obj); -} - static int i915_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) { struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); @@ -195,8 +161,6 @@ static const struct dma_buf_ops i915_dmabuf_ops = { .map_dma_buf = i915_gem_map_dma_buf, .unmap_dma_buf = i915_gem_unmap_dma_buf, .release = drm_gem_dmabuf_release, - .map = i915_gem_dmabuf_kmap, - .unmap = i915_gem_dmabuf_kunmap, .mmap = i915_gem_dmabuf_mmap, .vmap = i915_gem_dmabuf_vmap, .vunmap = i915_gem_dmabuf_vunmap, diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c index d85d1ce273ca873f1c8fff45cff8e8e195cb1541..2a52b92586b9f049fd73ac8c90bea59cdeeeb904 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c @@ -254,106 +254,6 @@ err_obj: return err; } -static int igt_dmabuf_export_kmap(void *arg) -{ - struct drm_i915_private *i915 = arg; - struct drm_i915_gem_object *obj; - struct dma_buf *dmabuf; - void *ptr; - int err; - - obj = i915_gem_object_create_shmem(i915, 2 * PAGE_SIZE); - if (IS_ERR(obj)) - return PTR_ERR(obj); - - dmabuf = i915_gem_prime_export(&obj->base, 0); - i915_gem_object_put(obj); - if (IS_ERR(dmabuf)) { - err = PTR_ERR(dmabuf); - pr_err("i915_gem_prime_export failed with err=%d\n", err); - return err; - } - - ptr = dma_buf_kmap(dmabuf, 0); - if (!ptr) { - pr_err("dma_buf_kmap failed\n"); - err = -ENOMEM; - goto err; - } - - if (memchr_inv(ptr, 0, PAGE_SIZE)) { - dma_buf_kunmap(dmabuf, 0, ptr); - pr_err("Exported page[0] not initialiased to zero!\n"); - err = -EINVAL; - goto err; - } - - memset(ptr, 0xc5, PAGE_SIZE); - dma_buf_kunmap(dmabuf, 0, ptr); - - ptr = i915_gem_object_pin_map(obj, I915_MAP_WB); - if (IS_ERR(ptr)) { - err = PTR_ERR(ptr); - pr_err("i915_gem_object_pin_map failed with err=%d\n", err); - goto err; - } - memset(ptr + PAGE_SIZE, 0xaa, PAGE_SIZE); - i915_gem_object_flush_map(obj); - i915_gem_object_unpin_map(obj); - - ptr = dma_buf_kmap(dmabuf, 1); - if (!ptr) { - pr_err("dma_buf_kmap failed\n"); - err = -ENOMEM; - goto err; - } - - if (memchr_inv(ptr, 0xaa, PAGE_SIZE)) { - dma_buf_kunmap(dmabuf, 1, ptr); - pr_err("Exported page[1] not set to 0xaa!\n"); - err = -EINVAL; - goto err; - } - - memset(ptr, 0xc5, PAGE_SIZE); - dma_buf_kunmap(dmabuf, 1, ptr); - - ptr = dma_buf_kmap(dmabuf, 0); - if (!ptr) { - pr_err("dma_buf_kmap failed\n"); - err = -ENOMEM; - goto err; - } - if (memchr_inv(ptr, 0xc5, PAGE_SIZE)) { - dma_buf_kunmap(dmabuf, 0, ptr); - pr_err("Exported page[0] did not retain 0xc5!\n"); - err = -EINVAL; - goto err; - } - dma_buf_kunmap(dmabuf, 0, ptr); - - ptr = dma_buf_kmap(dmabuf, 2); - if (ptr) { - pr_err("Erroneously kmapped beyond the end of the object!\n"); - dma_buf_kunmap(dmabuf, 2, ptr); - err = -EINVAL; - goto err; - } - - ptr = dma_buf_kmap(dmabuf, -1); - if (ptr) { - pr_err("Erroneously kmapped before the start of the object!\n"); - dma_buf_kunmap(dmabuf, -1, ptr); - err = -EINVAL; - goto err; - } - - err = 0; -err: - dma_buf_put(dmabuf); - return err; -} - int i915_gem_dmabuf_mock_selftests(void) { static const struct i915_subtest tests[] = { @@ -362,7 +262,6 @@ int i915_gem_dmabuf_mock_selftests(void) SUBTEST(igt_dmabuf_import), SUBTEST(igt_dmabuf_import_ownership), SUBTEST(igt_dmabuf_export_vmap), - SUBTEST(igt_dmabuf_export_kmap), }; struct drm_i915_private *i915; int err; diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c index b9e059d4328a54d933107d78d4c244d6c6bcfab1..9272bef57092be40012c2be12c815b7e72f1b1fd 100644 --- a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c @@ -76,20 +76,6 @@ static void mock_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) vm_unmap_ram(vaddr, mock->npages); } -static void *mock_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num) -{ - struct mock_dmabuf *mock = to_mock(dma_buf); - - return kmap(mock->pages[page_num]); -} - -static void mock_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num, void *addr) -{ - struct mock_dmabuf *mock = to_mock(dma_buf); - - return kunmap(mock->pages[page_num]); -} - static int mock_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) { return -ENODEV; @@ -99,8 +85,6 @@ static const struct dma_buf_ops mock_dmabuf_ops = { .map_dma_buf = mock_map_dma_buf, .unmap_dma_buf = mock_unmap_dma_buf, .release = mock_dmabuf_release, - .map = mock_dmabuf_kmap, - .unmap = mock_dmabuf_kunmap, .mmap = mock_dmabuf_mmap, .vmap = mock_dmabuf_vmap, .vunmap = mock_dmabuf_vunmap, diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index fde5487925a271bb206b857072f2282931cde51c..f7385abdd74bc5540247c603300366e465ffa2bc 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1394,7 +1394,7 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv) static void i915_welcome_messages(struct drm_i915_private *dev_priv) { - if (drm_debug & DRM_UT_DRIVER) { + if (drm_debug_enabled(DRM_UT_DRIVER)) { struct drm_printer p = drm_debug_printer("i915 device info:"); drm_printf(&p, "pciid=0x%04x rev=0x%02x platform=%s (subplatform=0x%x) gen=%i\n", diff --git a/drivers/gpu/drm/i915/i915_gem.h b/drivers/gpu/drm/i915/i915_gem.h index 78a99d7c4e78a901bca7092d49a48ee2c3a81330..1753c84d6c0d37ca65b5d8750d135bac5dc11595 100644 --- a/drivers/gpu/drm/i915/i915_gem.h +++ b/drivers/gpu/drm/i915/i915_gem.h @@ -36,7 +36,7 @@ struct drm_i915_private; #ifdef CONFIG_DRM_I915_DEBUG_GEM -#define GEM_SHOW_DEBUG() (drm_debug & DRM_UT_DRIVER) +#define GEM_SHOW_DEBUG() drm_debug_enabled(DRM_UT_DRIVER) #define GEM_BUG_ON(condition) do { if (unlikely((condition))) { \ GEM_TRACE_ERR("%s:%d GEM_BUG_ON(%s)\n", \ diff --git a/drivers/gpu/drm/i915/i915_utils.c b/drivers/gpu/drm/i915/i915_utils.c index 0348c6d0ef5f3062a668f20ccc9287428c3ed7cf..c47261ae86eab09b1341059a3ec9cb36db6767a8 100644 --- a/drivers/gpu/drm/i915/i915_utils.c +++ b/drivers/gpu/drm/i915/i915_utils.c @@ -23,7 +23,7 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level, struct va_format vaf; va_list args; - if (is_debug && !(drm_debug & DRM_UT_DRIVER)) + if (is_debug && !drm_debug_enabled(DRM_UT_DRIVER)) return; va_start(args, fmt); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8ef41b8fc5c5b87c8094ace62e0379687ad8c658..148ac455dfa767f855282d379f6025b15b25b731 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5249,7 +5249,7 @@ skl_print_wm_changes(struct intel_atomic_state *state) struct intel_crtc *crtc; int i; - if ((drm_debug & DRM_UT_KMS) == 0) + if (!drm_debug_enabled(DRM_UT_KMS)) return; for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 208069faf183dd46622f0f6789ab6992bb07ccce..8cb2665b2c7425b1cab030e58db9a8f63965d7cb 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -127,7 +127,7 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector); int num_modes; - num_modes = drm_panel_get_modes(imx_ldb_ch->panel); + num_modes = drm_panel_get_modes(imx_ldb_ch->panel, connector); if (num_modes > 0) return num_modes; diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 35518e5de356d7b0adb16a01266db15cf4307979..3dca424059f769c129d19454f7e41b589da75728 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -50,7 +50,7 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) struct device_node *np = imxpd->dev->of_node; int num_modes; - num_modes = drm_panel_get_modes(imxpd->panel); + num_modes = drm_panel_get_modes(imxpd->panel, connector); if (num_modes > 0) return num_modes; diff --git a/drivers/gpu/drm/ingenic/ingenic-drm.c b/drivers/gpu/drm/ingenic/ingenic-drm.c index ec32e1c673350cd6ad1b628cf7aba1c7a03c87c7..6d47ef7b148c3dcd5f6236a0b40c472ffb72082d 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm.c @@ -153,6 +153,7 @@ struct ingenic_dma_hwdesc { struct jz_soc_info { bool needs_dev_clk; + unsigned int max_width, max_height; }; struct ingenic_drm { @@ -164,6 +165,7 @@ struct ingenic_drm { struct device *dev; struct regmap *map; struct clk *lcd_clk, *pix_clk; + const struct jz_soc_info *soc_info; struct ingenic_dma_hwdesc *dma_hwdesc; dma_addr_t dma_hwdesc_phys; @@ -326,6 +328,10 @@ static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc, if (!drm_atomic_crtc_needs_modeset(state)) return 0; + if (state->mode.hdisplay > priv->soc_info->max_height || + state->mode.vdisplay > priv->soc_info->max_width) + return -EINVAL; + rate = clk_round_rate(priv->pix_clk, state->adjusted_mode.clock * 1000); if (rate < 0) @@ -372,14 +378,18 @@ static void ingenic_drm_plane_atomic_update(struct drm_plane *plane, struct ingenic_drm *priv = drm_plane_get_priv(plane); struct drm_plane_state *state = plane->state; unsigned int width, height, cpp; + dma_addr_t addr; - width = state->crtc->state->adjusted_mode.hdisplay; - height = state->crtc->state->adjusted_mode.vdisplay; - cpp = state->fb->format->cpp[plane->index]; + if (state && state->fb) { + addr = drm_fb_cma_get_gem_addr(state->fb, state, 0); + width = state->src_w >> 16; + height = state->src_h >> 16; + cpp = state->fb->format->cpp[plane->index]; - priv->dma_hwdesc->addr = drm_fb_cma_get_gem_addr(state->fb, state, 0); - priv->dma_hwdesc->cmd = width * height * cpp / 4; - priv->dma_hwdesc->cmd |= JZ_LCD_CMD_EOF_IRQ; + priv->dma_hwdesc->addr = addr; + priv->dma_hwdesc->cmd = width * height * cpp / 4; + priv->dma_hwdesc->cmd |= JZ_LCD_CMD_EOF_IRQ; + } } static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder, @@ -617,6 +627,7 @@ static int ingenic_drm_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + priv->soc_info = soc_info; priv->dev = dev; drm = &priv->drm; drm->dev_private = priv; @@ -632,8 +643,8 @@ static int ingenic_drm_probe(struct platform_device *pdev) drm_mode_config_init(drm); drm->mode_config.min_width = 0; drm->mode_config.min_height = 0; - drm->mode_config.max_width = 800; - drm->mode_config.max_height = 600; + drm->mode_config.max_width = soc_info->max_width; + drm->mode_config.max_height = 4095; drm->mode_config.funcs = &ingenic_drm_mode_config_funcs; base = devm_platform_ioremap_resource(pdev, 0); @@ -810,15 +821,26 @@ static int ingenic_drm_remove(struct platform_device *pdev) static const struct jz_soc_info jz4740_soc_info = { .needs_dev_clk = true, + .max_width = 800, + .max_height = 600, }; static const struct jz_soc_info jz4725b_soc_info = { .needs_dev_clk = false, + .max_width = 800, + .max_height = 600, +}; + +static const struct jz_soc_info jz4770_soc_info = { + .needs_dev_clk = false, + .max_width = 1280, + .max_height = 720, }; static const struct of_device_id ingenic_drm_of_match[] = { { .compatible = "ingenic,jz4740-lcd", .data = &jz4740_soc_info }, { .compatible = "ingenic,jz4725b-lcd", .data = &jz4725b_soc_info }, + { .compatible = "ingenic,jz4770-lcd", .data = &jz4770_soc_info }, { /* sentinel */ }, }; diff --git a/drivers/gpu/drm/lima/Kconfig b/drivers/gpu/drm/lima/Kconfig index 571dc369a7e95259e9218957c6aa6af2218e8c5e..d589f09d04d97f1ee80417764b47b2befa9095f4 100644 --- a/drivers/gpu/drm/lima/Kconfig +++ b/drivers/gpu/drm/lima/Kconfig @@ -11,4 +11,4 @@ config DRM_LIMA select DRM_SCHED select DRM_GEM_SHMEM_HELPER help - DRM driver for ARM Mali 400/450 GPUs. + DRM driver for ARM Mali 400/450 GPUs. diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c index 751454ae3cd10e473978393426dd1922d9e84d7e..e59907e688541a2ff5dfc6904e2a9980908d376f 100644 --- a/drivers/gpu/drm/mcde/mcde_display.c +++ b/drivers/gpu/drm/mcde/mcde_display.c @@ -498,24 +498,20 @@ static void mcde_configure_channel(struct mcde *mcde, enum mcde_channel ch, } /* Set up channel 0 sync (based on chnl_update_registers()) */ - if (mcde->te_sync) { - /* - * Turn on hardware TE0 synchronization - */ + if (mcde->video_mode || mcde->te_sync) val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; - val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0 - << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; - } else { - /* - * Set up sync source to software, out sync formatter - * Code mostly from mcde_hw.c chnl_update_registers() - */ + else val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SOFTWARE << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; + + if (mcde->te_sync) + val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0 + << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; + else val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_FORMATTER << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; - } + writel(val, mcde->regs + sync); /* Set up pixels per line and lines per frame */ @@ -934,10 +930,17 @@ 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); - - drm_crtc_vblank_on(crtc); } + 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. + */ + mcde_enable_fifo(mcde, MCDE_FIFO_A); + dev_info(drm->dev, "MCDE display is enabled\n"); } @@ -946,13 +949,22 @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe) struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; struct mcde *mcde = drm->dev_private; + struct drm_pending_vblank_event *event; - if (mcde->te_sync) - drm_crtc_vblank_off(crtc); + drm_crtc_vblank_off(crtc); /* Disable FIFO A flow */ mcde_disable_fifo(mcde, MCDE_FIFO_A, true); + event = crtc->state->event; + if (event) { + crtc->state->event = NULL; + + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, event); + spin_unlock_irq(&crtc->dev->event_lock); + } + dev_info(drm->dev, "MCDE display is disabled\n"); } @@ -1048,8 +1060,9 @@ 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)); - /* Send a single frame using software sync */ - mcde_display_send_one_frame(mcde); + if (!mcde->video_mode) + /* Send a single frame using software sync */ + mcde_display_send_one_frame(mcde); dev_info_once(mcde->dev, "sent first display update\n"); } else { /* @@ -1097,6 +1110,8 @@ static struct drm_simple_display_pipe_funcs mcde_display_funcs = { .enable = mcde_display_enable, .disable = mcde_display_disable, .update = mcde_display_update, + .enable_vblank = mcde_display_enable_vblank, + .disable_vblank = mcde_display_disable_vblank, .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, }; @@ -1123,12 +1138,6 @@ int mcde_display_init(struct drm_device *drm) DRM_FORMAT_YUV422, }; - /* Provide vblank only when we have TE enabled */ - if (mcde->te_sync) { - mcde_display_funcs.enable_vblank = mcde_display_enable_vblank; - mcde_display_funcs.disable_vblank = mcde_display_disable_vblank; - } - ret = drm_simple_display_pipe_init(drm, &mcde->pipe, &mcde_display_funcs, formats, ARRAY_SIZE(formats), diff --git a/drivers/gpu/drm/mcde/mcde_drm.h b/drivers/gpu/drm/mcde/mcde_drm.h index dab4db021231323b6c26e1353044ae18f1f8ad04..80edd6628979c0d4d9224a6e145a2a5c7d6d97fe 100644 --- a/drivers/gpu/drm/mcde/mcde_drm.h +++ b/drivers/gpu/drm/mcde/mcde_drm.h @@ -19,6 +19,7 @@ struct mcde { struct mipi_dsi_device *mdsi; s16 stride; bool te_sync; + bool video_mode; bool oneshot_mode; unsigned int flow_active; spinlock_t flow_lock; /* Locks the channel flow control */ diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c index 5649887d2b90126d17ea37c89fd699ab1b3d6777..9008ddcfc528ca63ee6a957e10cc26c9d7acfd0d 100644 --- a/drivers/gpu/drm/mcde/mcde_drv.c +++ b/drivers/gpu/drm/mcde/mcde_drv.c @@ -179,18 +179,10 @@ static int mcde_modeset_init(struct drm_device *drm) mode_config->min_height = 1; mode_config->max_height = 1080; - /* - * Currently we only support vblank handling on the DSI bridge, using - * TE synchronization. If TE sync is not set up, it is still possible - * to push out a single update on demand, but this is hard for DRM to - * exploit. - */ - if (mcde->te_sync) { - ret = drm_vblank_init(drm, 1); - if (ret) { - dev_err(drm->dev, "failed to init vblank\n"); - goto out_config; - } + ret = drm_vblank_init(drm, 1); + if (ret) { + dev_err(drm->dev, "failed to init vblank\n"); + goto out_config; } ret = mcde_display_init(drm); @@ -339,8 +331,6 @@ static int mcde_probe(struct platform_device *pdev) drm->dev_private = mcde; platform_set_drvdata(pdev, drm); - /* Enable use of the TE signal and interrupt */ - mcde->te_sync = true; /* Enable continuous updates: this is what Linux' framebuffer expects */ mcde->oneshot_mode = false; drm->dev_private = mcde; diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c index d6214d3c8b337b5b6ab4c1f19fb17fbca003f41c..bb6528b01cd07e0c42432a739a8ccc2c8e781d46 100644 --- a/drivers/gpu/drm/mcde/mcde_dsi.c +++ b/drivers/gpu/drm/mcde/mcde_dsi.c @@ -39,7 +39,6 @@ struct mcde_dsi { struct device *dev; struct mcde *mcde; struct drm_bridge bridge; - struct drm_connector connector; struct drm_panel *panel; struct drm_bridge *bridge_out; struct mipi_dsi_host dsi_host; @@ -64,11 +63,6 @@ static inline struct mcde_dsi *host_to_mcde_dsi(struct mipi_dsi_host *h) return container_of(h, struct mcde_dsi, dsi_host); } -static inline struct mcde_dsi *connector_to_mcde_dsi(struct drm_connector *c) -{ - return container_of(c, struct mcde_dsi, connector); -} - bool mcde_dsi_irq(struct mipi_dsi_device *mdsi) { struct mcde_dsi *d; @@ -124,12 +118,41 @@ bool mcde_dsi_irq(struct mipi_dsi_device *mdsi) val = readl(d->regs + DSI_VID_MODE_STS_FLAG); if (val) - dev_err(d->dev, "some video mode error status\n"); + dev_dbg(d->dev, "DSI_VID_MODE_STS_FLAG = %08x\n", val); + if (val & DSI_VID_MODE_STS_VSG_RUNNING) + dev_dbg(d->dev, "VID mode VSG running\n"); + if (val & DSI_VID_MODE_STS_ERR_MISSING_DATA) + dev_err(d->dev, "VID mode missing data\n"); + if (val & DSI_VID_MODE_STS_ERR_MISSING_HSYNC) + dev_err(d->dev, "VID mode missing HSYNC\n"); + if (val & DSI_VID_MODE_STS_ERR_MISSING_VSYNC) + dev_err(d->dev, "VID mode missing VSYNC\n"); + if (val & DSI_VID_MODE_STS_REG_ERR_SMALL_LENGTH) + dev_err(d->dev, "VID mode less bytes than expected between two HSYNC\n"); + if (val & DSI_VID_MODE_STS_REG_ERR_SMALL_HEIGHT) + dev_err(d->dev, "VID mode less lines than expected between two VSYNC\n"); + if (val & (DSI_VID_MODE_STS_ERR_BURSTWRITE | + DSI_VID_MODE_STS_ERR_LINEWRITE | + DSI_VID_MODE_STS_ERR_LONGREAD)) + dev_err(d->dev, "VID mode read/write error\n"); + if (val & DSI_VID_MODE_STS_ERR_VRS_WRONG_LENGTH) + dev_err(d->dev, "VID mode received packets differ from expected size\n"); + if (val & DSI_VID_MODE_STS_VSG_RECOVERY) + dev_err(d->dev, "VID mode VSG in recovery mode\n"); writel(val, d->regs + DSI_VID_MODE_STS_CLR); return te_received; } +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; +} + static int mcde_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *mdsi) { @@ -148,7 +171,7 @@ static int mcde_dsi_host_attach(struct mipi_dsi_host *host, d->mdsi = mdsi; if (d->mcde) - d->mcde->mdsi = mdsi; + mcde_dsi_attach_to_mcde(d); return 0; } @@ -223,25 +246,25 @@ static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host, if (txlen > 0) { val = 0; for (i = 0; i < 4 && i < txlen; i++) - val |= tx[i] << (i & 3) * 8; + 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 & 3) * 8; + 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 & 3) * 8; + 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 & 3) * 8; + val |= tx[i + 12] << (i * 8); writel(val, d->regs + DSI_DIRECT_CMD_WRDAT3); } @@ -336,7 +359,7 @@ void mcde_dsi_te_request(struct mipi_dsi_device *mdsi) val |= 0 << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID_SHIFT; val |= 2 << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE_SHIFT; val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN; - val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_SHORT_WRITE_1 << + val |= MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SHIFT; writel(val, d->regs + DSI_DIRECT_CMD_MAIN_SETTINGS); @@ -365,13 +388,14 @@ void mcde_dsi_te_request(struct mipi_dsi_device *mdsi) static void mcde_dsi_setup_video_mode(struct mcde_dsi *d, const struct drm_display_mode *mode) { - u8 bpp = mipi_dsi_pixel_format_to_bpp(d->mdsi->format); + /* cpp, characters per pixel, number of bytes per pixel */ + u8 cpp = mipi_dsi_pixel_format_to_bpp(d->mdsi->format) / 8; + u64 pclk; u64 bpl; - u32 hfp; - u32 hbp; - u32 hsa; + int hfp; + int hbp; + int hsa; u32 blkline_pck, line_duration; - u32 blkeol_pck, blkeol_duration; u32 val; val = 0; @@ -408,11 +432,21 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d, return; } - /* TODO: TVG could be enabled here */ + /* TODO: TVG (test video generator) could be enabled here */ - /* Send blanking packet */ + /* + * During vertical blanking: go to LP mode + * Like with the EOL setting, if this is not set, the EOL area will be + * filled with NULL or blanking packets in the vblank area. + * FIXME: some Samsung phones and display panels such as s6e63m0 use + * DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_BLANKING here instead, + * figure out how to properly configure that from the panel. + */ val |= DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_LP_0; - /* Send EOL packet */ + /* + * During EOL: go to LP mode. If this is not set, the EOL area will be + * filled with NULL or blanking packets. + */ val |= DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0; /* Recovery mode 1 */ val |= 1 << DSI_VID_MAIN_CTL_RECOVERY_MODE_SHIFT; @@ -420,13 +454,13 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d, writel(val, d->regs + DSI_VID_MAIN_CTL); /* Vertical frame parameters are pretty straight-forward */ - val = mode->vdisplay << DSI_VID_VSIZE_VSA_LENGTH_SHIFT; + val = mode->vdisplay << DSI_VID_VSIZE_VACT_LENGTH_SHIFT; /* vertical front porch */ val |= (mode->vsync_start - mode->vdisplay) << DSI_VID_VSIZE_VFP_LENGTH_SHIFT; /* vertical sync active */ val |= (mode->vsync_end - mode->vsync_start) - << DSI_VID_VSIZE_VACT_LENGTH_SHIFT; + << DSI_VID_VSIZE_VSA_LENGTH_SHIFT; /* vertical back porch */ val |= (mode->vtotal - mode->vsync_end) << DSI_VID_VSIZE_VBP_LENGTH_SHIFT; @@ -434,36 +468,54 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d, /* * Horizontal frame parameters: - * horizontal resolution is given in pixels and must be re-calculated - * into bytes since this is what the hardware expects. + * horizontal resolution is given in pixels but must be re-calculated + * into bytes since this is what the hardware expects, these registers + * define the payload size of the packet. + * + * hfp = horizontal front porch in bytes + * hbp = horizontal back porch in bytes + * hsa = horizontal sync active in bytes * * 6 + 2 is HFP header + checksum */ - hfp = (mode->hsync_start - mode->hdisplay) * bpp - 6 - 2; + hfp = (mode->hsync_start - mode->hdisplay) * cpp - 6 - 2; if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { /* + * Use sync pulse for sync: explicit HSA time * 6 is HBP header + checksum * 4 is RGB header + checksum */ - hbp = (mode->htotal - mode->hsync_end) * bpp - 4 - 6; + hbp = (mode->htotal - mode->hsync_end) * cpp - 4 - 6; /* * 6 is HBP header + checksum * 4 is HSW packet bytes * 4 is RGB header + checksum */ - hsa = (mode->hsync_end - mode->hsync_start) * bpp - 4 - 4 - 6; + hsa = (mode->hsync_end - mode->hsync_start) * cpp - 4 - 4 - 6; } else { /* - * HBP includes both back porch and sync + * Use event for sync: HBP includes both back porch and sync * 6 is HBP header + checksum * 4 is HSW packet bytes * 4 is RGB header + checksum */ - hbp = (mode->htotal - mode->hsync_start) * bpp - 4 - 4 - 6; - /* HSA is not considered in this mode and set to 0 */ + hbp = (mode->htotal - mode->hsync_start) * cpp - 4 - 4 - 6; + /* HSA is not present in this mode and set to 0 */ hsa = 0; } - dev_dbg(d->dev, "hfp: %u, hbp: %u, hsa: %u\n", + if (hfp < 0) { + dev_info(d->dev, "hfp negative, set to 0\n"); + hfp = 0; + } + if (hbp < 0) { + dev_info(d->dev, "hbp negative, set to 0\n"); + hbp = 0; + } + if (hsa < 0) { + dev_info(d->dev, "hsa negative, set to 0\n"); + hsa = 0; + } + dev_dbg(d->dev, "hfp: %u, hbp: %u, hsa: %u bytes\n", hfp, hbp, hsa); /* Frame parameters: horizontal sync active */ @@ -474,91 +526,185 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d, val |= hfp << DSI_VID_HSIZE1_HFP_LENGTH_SHIFT; writel(val, d->regs + DSI_VID_HSIZE1); - /* RGB data length (bytes on one scanline) */ - val = mode->hdisplay * (bpp / 8); + /* RGB data length (visible bytes on one scanline) */ + val = mode->hdisplay * cpp; writel(val, d->regs + DSI_VID_HSIZE2); + dev_dbg(d->dev, "RGB length, visible area on a line: %u bytes\n", val); - /* TODO: further adjustments for TVG mode here */ + /* + * Calculate the time between two pixels in picoseconds using + * the supplied refresh rate and total resolution including + * porches and sync. + */ + /* (ps/s) / (pixels/s) = ps/pixels */ + pclk = DIV_ROUND_UP_ULL(1000000000000, + (mode->vrefresh * mode->htotal * mode->vtotal)); + dev_dbg(d->dev, "picoseconds between two pixels: %llu\n", + pclk); /* - * EOL packet length from bits per line calculations: pixel clock - * is given in kHz, calculate the time between two pixels in - * picoseconds. + * How many bytes per line will this update frequency yield? + * + * Calculate the number of picoseconds for one scanline (1), then + * divide by 1000000000000 (2) to get in pixels per second we + * want to output. + * + * Multiply with number of bytes per second at this video display + * frequency (3) to get number of bytes transferred during this + * time. Notice that we use the frequency the display wants, + * not what we actually get from the DSI PLL, which is hs_freq. + * + * These arithmetics are done in a different order to avoid + * overflow. */ - bpl = mode->clock * mode->htotal; - bpl *= (d->hs_freq / 8); - do_div(bpl, 1000000); /* microseconds */ - do_div(bpl, 1000000); /* seconds */ + bpl = pclk * mode->htotal; /* (1) picoseconds per line */ + dev_dbg(d->dev, "picoseconds per line: %llu\n", bpl); + /* Multiply with bytes per second (3) */ + bpl *= (d->mdsi->hs_rate / 8); + /* Pixels per second (2) */ + bpl = DIV_ROUND_DOWN_ULL(bpl, 1000000); /* microseconds */ + bpl = DIV_ROUND_DOWN_ULL(bpl, 1000000); /* seconds */ + /* parallel transactions in all lanes */ bpl *= d->mdsi->lanes; - dev_dbg(d->dev, "calculated bytes per line: %llu\n", bpl); + dev_dbg(d->dev, + "calculated bytes per line: %llu @ %d Hz with HS %lu Hz\n", + bpl, mode->vrefresh, d->mdsi->hs_rate); + /* * 6 is header + checksum, header = 4 bytes, checksum = 2 bytes * 4 is short packet for vsync/hsync */ if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { - /* Fixme: isn't the hsync width in pixels? */ + /* Set the event packet size to 0 (not used) */ + writel(0, d->regs + DSI_VID_BLKSIZE1); + /* + * FIXME: isn't the hsync width in pixels? The porch and + * sync area size is in pixels here, but this -6 + * seems to be for bytes. It looks like this in the vendor + * code though. Is it completely untested? + */ blkline_pck = bpl - (mode->hsync_end - mode->hsync_start) - 6; val = blkline_pck << DSI_VID_BLKSIZE2_BLKLINE_PULSE_PCK_SHIFT; writel(val, d->regs + DSI_VID_BLKSIZE2); } else { + /* Set the sync pulse packet size to 0 (not used) */ + writel(0, d->regs + DSI_VID_BLKSIZE2); + /* Specifying payload size in bytes (-4-6 from manual) */ blkline_pck = bpl - 4 - 6; + if (blkline_pck > 0x1FFF) + dev_err(d->dev, "blkline_pck too big %d bytes\n", + blkline_pck); val = blkline_pck << DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_SHIFT; + val &= DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_MASK; writel(val, d->regs + DSI_VID_BLKSIZE1); } - line_duration = (blkline_pck + 6) / d->mdsi->lanes; - dev_dbg(d->dev, "line duration %u\n", line_duration); + /* + * The line duration is used to scale back the frequency from + * the max frequency supported by the HS clock to the desired + * update frequency in vrefresh. + */ + line_duration = blkline_pck + 6; + /* + * The datasheet contains this complex condition to decreasing + * the line duration by 1 under very specific circumstances. + * Here we also imply that LP is used during burst EOL. + */ + if (d->mdsi->lanes == 2 && (hsa & 0x01) && (hfp & 0x01) + && (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)) + line_duration--; + line_duration = DIV_ROUND_CLOSEST(line_duration, d->mdsi->lanes); + dev_dbg(d->dev, "line duration %u bytes\n", line_duration); val = line_duration << DSI_VID_DPHY_TIME_REG_LINE_DURATION_SHIFT; /* * This is the time to perform LP->HS on D-PHY * FIXME: nowhere to get this from: DT property on the DSI? + * The manual says this is "system dependent". + * values like 48 and 72 seen in the vendor code. */ - val |= 0 << DSI_VID_DPHY_TIME_REG_WAKEUP_TIME_SHIFT; + val |= 48 << DSI_VID_DPHY_TIME_REG_WAKEUP_TIME_SHIFT; writel(val, d->regs + DSI_VID_DPHY_TIME); - /* Calculate block end of line */ - blkeol_pck = bpl - mode->hdisplay * bpp - 6; - blkeol_duration = (blkeol_pck + 6) / d->mdsi->lanes; - dev_dbg(d->dev, "blkeol pck: %u, duration: %u\n", - blkeol_pck, blkeol_duration); - + /* + * See the manual figure 657 page 2203 for understanding the impact + * of the different burst mode settings. + */ if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) { - /* Set up EOL clock for burst mode */ + int blkeol_pck, blkeol_duration; + /* + * Packet size at EOL for burst mode, this is only used + * if DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0 is NOT set, + * but we instead send NULL or blanking packets at EOL. + * This is given in number of bytes. + * + * See the manual page 2198 for the 13 reg_blkeol_pck bits. + */ + blkeol_pck = bpl - (mode->htotal * cpp) - 6; + if (blkeol_pck < 0) { + dev_err(d->dev, "video block does not fit on line!\n"); + dev_err(d->dev, + "calculated bytes per line: %llu @ %d Hz\n", + bpl, mode->vrefresh); + dev_err(d->dev, + "bytes per line (blkline_pck) %u bytes\n", + blkline_pck); + dev_err(d->dev, + "blkeol_pck becomes %d bytes\n", blkeol_pck); + return; + } + dev_dbg(d->dev, "BLKEOL packet: %d bytes\n", blkeol_pck); + val = readl(d->regs + DSI_VID_BLKSIZE1); + val &= ~DSI_VID_BLKSIZE1_BLKEOL_PCK_MASK; val |= blkeol_pck << DSI_VID_BLKSIZE1_BLKEOL_PCK_SHIFT; writel(val, d->regs + DSI_VID_BLKSIZE1); - writel(blkeol_pck, d->regs + DSI_VID_VCA_SETTING2); - - writel(blkeol_duration, d->regs + DSI_VID_PCK_TIME); - writel(blkeol_duration - 6, d->regs + DSI_VID_VCA_SETTING1); + /* Use the same value for exact burst limit */ + val = blkeol_pck << + DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_SHIFT; + val &= DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_MASK; + writel(val, d->regs + DSI_VID_VCA_SETTING2); + /* + * This BLKEOL duration is claimed to be the duration in clock + * cycles of the BLLP end-of-line (EOL) period for each line if + * DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0 is set. + * + * It is hard to trust the manuals' claim that this is in clock + * cycles as we mimic the behaviour of the vendor code, which + * appears to write a number of bytes that would have been + * transferred on a single lane. + * + * See the manual figure 657 page 2203 and page 2198 for the 13 + * reg_blkeol_duration bits. + * + * FIXME: should this also be set up also for non-burst mode + * according to figure 565 page 2202? + */ + blkeol_duration = DIV_ROUND_CLOSEST(blkeol_pck + 6, + d->mdsi->lanes); + dev_dbg(d->dev, "BLKEOL duration: %d clock cycles\n", + blkeol_duration); + + val = readl(d->regs + DSI_VID_PCK_TIME); + val &= ~DSI_VID_PCK_TIME_BLKEOL_DURATION_MASK; + val |= blkeol_duration << + DSI_VID_PCK_TIME_BLKEOL_DURATION_SHIFT; + writel(val, d->regs + DSI_VID_PCK_TIME); + + /* Max burst limit, this is given in bytes */ + val = readl(d->regs + DSI_VID_VCA_SETTING1); + val &= ~DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT_MASK; + val |= (blkeol_pck - 6) << + DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT_SHIFT; + writel(val, d->regs + DSI_VID_VCA_SETTING1); } /* Maximum line limit */ val = readl(d->regs + DSI_VID_VCA_SETTING2); - val |= blkline_pck << - DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_SHIFT; + val &= ~DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT_MASK; + val |= (blkline_pck - 6) << + DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT_SHIFT; writel(val, d->regs + DSI_VID_VCA_SETTING2); - - /* Put IF1 into video mode */ - val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL); - val |= DSI_MCTL_MAIN_DATA_CTL_IF1_MODE; - writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL); - - /* Disable command mode on IF1 */ - val = readl(d->regs + DSI_CMD_MODE_CTL); - val &= ~DSI_CMD_MODE_CTL_IF1_LP_EN; - writel(val, d->regs + DSI_CMD_MODE_CTL); - - /* Enable some error interrupts */ - val = readl(d->regs + DSI_VID_MODE_STS_CTL); - 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); + dev_dbg(d->dev, "blkline pck: %d bytes\n", blkline_pck - 6); } static void mcde_dsi_start(struct mcde_dsi *d) @@ -670,30 +816,25 @@ static void mcde_dsi_start(struct mcde_dsi *d) 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_mode_set(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - const struct drm_display_mode *adj) +static void mcde_dsi_bridge_pre_enable(struct drm_bridge *bridge) { struct mcde_dsi *d = bridge_to_mcde_dsi(bridge); - unsigned long pixel_clock_hz = mode->clock * 1000; unsigned long hs_freq, lp_freq; u32 val; int ret; - if (!d->mdsi) { - dev_err(d->dev, "no DSI device attached to encoder!\n"); - return; - } - - dev_info(d->dev, "set DSI master to %dx%d %lu Hz %s mode\n", - mode->hdisplay, mode->vdisplay, pixel_clock_hz, - (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? "VIDEO" : "CMD" - ); - /* Copy maximum clock frequencies */ if (d->mdsi->lp_rate) lp_freq = d->mdsi->lp_rate; @@ -732,7 +873,21 @@ static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge, d->hs_freq); if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) { - mcde_dsi_setup_video_mode(d, mode); + /* Put IF1 into video mode */ + val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL); + val |= DSI_MCTL_MAIN_DATA_CTL_IF1_MODE; + writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL); + + /* Disable command mode on IF1 */ + val = readl(d->regs + DSI_CMD_MODE_CTL); + val &= ~DSI_CMD_MODE_CTL_IF1_LP_EN; + writel(val, d->regs + DSI_CMD_MODE_CTL); + + /* Enable some error interrupts */ + val = readl(d->regs + DSI_VID_MODE_STS_CTL); + 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); } else { /* Command mode, clear IF1 ID */ val = readl(d->regs + DSI_CMD_MODE_CTL); @@ -746,6 +901,26 @@ static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge, } } +static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adj) +{ + struct mcde_dsi *d = bridge_to_mcde_dsi(bridge); + + if (!d->mdsi) { + dev_err(d->dev, "no DSI device attached to encoder!\n"); + return; + } + + 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) { u32 val; @@ -811,67 +986,23 @@ static void mcde_dsi_bridge_disable(struct drm_bridge *bridge) clk_disable_unprepare(d->lp_clk); } -/* - * This connector needs no special handling, just use the default - * helpers for everything. It's pretty dummy. - */ -static const struct drm_connector_funcs mcde_dsi_connector_funcs = { - .reset = drm_atomic_helper_connector_reset, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = drm_connector_cleanup, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static int mcde_dsi_get_modes(struct drm_connector *connector) -{ - struct mcde_dsi *d = connector_to_mcde_dsi(connector); - - /* Just pass the question to the panel */ - if (d->panel) - return drm_panel_get_modes(d->panel); - - /* TODO: deal with bridges */ - - return 0; -} - -static const struct drm_connector_helper_funcs -mcde_dsi_connector_helper_funcs = { - .get_modes = mcde_dsi_get_modes, -}; - static int mcde_dsi_bridge_attach(struct drm_bridge *bridge) { struct mcde_dsi *d = bridge_to_mcde_dsi(bridge); struct drm_device *drm = bridge->dev; int ret; - drm_connector_helper_add(&d->connector, - &mcde_dsi_connector_helper_funcs); - if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) { dev_err(d->dev, "we need atomic updates\n"); return -ENOTSUPP; } - ret = drm_connector_init(drm, &d->connector, - &mcde_dsi_connector_funcs, - DRM_MODE_CONNECTOR_DSI); - if (ret) { - dev_err(d->dev, "failed to initialize DSI bridge connector\n"); - return ret; - } - d->connector.polled = DRM_CONNECTOR_POLL_CONNECT; - /* The encoder in the bridge attached to the DSI bridge */ - drm_connector_attach_encoder(&d->connector, bridge->encoder); - /* Then we attach the DSI bridge to the output (panel etc) bridge */ + /* Attach the DSI bridge to the output (panel etc) bridge */ ret = drm_bridge_attach(bridge->encoder, d->bridge_out, bridge); if (ret) { dev_err(d->dev, "failed to attach the DSI bridge\n"); return ret; } - d->connector.status = connector_status_connected; return 0; } @@ -881,6 +1012,7 @@ static const struct drm_bridge_funcs mcde_dsi_bridge_funcs = { .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, @@ -901,7 +1033,7 @@ static int mcde_dsi_bind(struct device *dev, struct device *master, d->mcde = mcde; /* If the display attached before binding, set this up */ if (d->mdsi) - d->mcde->mdsi = d->mdsi; + mcde_dsi_attach_to_mcde(d); /* Obtain the clocks */ d->hs_clk = devm_clk_get(dev, "hs"); @@ -935,11 +1067,13 @@ static int mcde_dsi_bind(struct device *dev, struct device *master, for_each_available_child_of_node(dev->of_node, child) { panel = of_drm_find_panel(child); if (IS_ERR(panel)) { - dev_err(dev, "failed to find panel try bridge (%lu)\n", + dev_err(dev, "failed to find panel try bridge (%ld)\n", PTR_ERR(panel)); + panel = NULL; + bridge = of_drm_find_bridge(child); if (IS_ERR(bridge)) { - dev_err(dev, "failed to find bridge (%lu)\n", + dev_err(dev, "failed to find bridge (%ld)\n", PTR_ERR(bridge)); return PTR_ERR(bridge); } diff --git a/drivers/gpu/drm/mcde/mcde_dsi_regs.h b/drivers/gpu/drm/mcde/mcde_dsi_regs.h index c9253321a3be438a0464e8f716fffb92d0fd8bda..16551af1089e44972d871f3f0e9ccd1a5b0e97b2 100644 --- a/drivers/gpu/drm/mcde/mcde_dsi_regs.h +++ b/drivers/gpu/drm/mcde/mcde_dsi_regs.h @@ -123,17 +123,6 @@ #define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT BIT(3) #define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SHIFT 8 #define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_MASK 0x00003F00 -#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_TURN_ON_PERIPHERAL 50 -#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SHUT_DOWN_PERIPHERAL 34 -#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_GENERIC_SHORT_WRITE_0 3 -#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_GENERIC_SHORT_WRITE_1 19 -#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_GENERIC_SHORT_WRITE_2 35 -#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_GENERIC_LONG_WRITE 41 -#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_SHORT_WRITE_0 5 -#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_SHORT_WRITE_1 21 -#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_LONG_WRITE 57 -#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_READ 6 -#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SET_MAX_PKT_SIZE 55 #define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID_SHIFT 14 #define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE_SHIFT 16 #define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN BIT(21) @@ -239,6 +228,7 @@ #define DSI_VID_PCK_TIME 0x000000A8 #define DSI_VID_PCK_TIME_BLKEOL_DURATION_SHIFT 0 +#define DSI_VID_PCK_TIME_BLKEOL_DURATION_MASK 0x00000FFF #define DSI_VID_DPHY_TIME 0x000000AC #define DSI_VID_DPHY_TIME_REG_LINE_DURATION_SHIFT 0 @@ -248,6 +238,16 @@ #define DSI_VID_MODE_STS 0x000000BC #define DSI_VID_MODE_STS_VSG_RUNNING BIT(0) +#define DSI_VID_MODE_STS_ERR_MISSING_DATA BIT(1) +#define DSI_VID_MODE_STS_ERR_MISSING_HSYNC BIT(2) +#define DSI_VID_MODE_STS_ERR_MISSING_VSYNC BIT(3) +#define DSI_VID_MODE_STS_REG_ERR_SMALL_LENGTH BIT(4) +#define DSI_VID_MODE_STS_REG_ERR_SMALL_HEIGHT BIT(5) +#define DSI_VID_MODE_STS_ERR_BURSTWRITE BIT(6) +#define DSI_VID_MODE_STS_ERR_LINEWRITE BIT(7) +#define DSI_VID_MODE_STS_ERR_LONGREAD BIT(8) +#define DSI_VID_MODE_STS_ERR_VRS_WRONG_LENGTH BIT(9) +#define DSI_VID_MODE_STS_VSG_RECOVERY BIT(10) #define DSI_VID_VCA_SETTING1 0x000000C0 #define DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT_SHIFT 0 diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile index 8067a4be831151d96ed36aba362701f0936fa082..5044dfb8e3d62609a9b87d82b501cca4f7b60375 100644 --- a/drivers/gpu/drm/mediatek/Makefile +++ b/drivers/gpu/drm/mediatek/Makefile @@ -7,7 +7,6 @@ mediatek-drm-y := mtk_disp_color.o \ mtk_drm_ddp.o \ mtk_drm_ddp_comp.o \ mtk_drm_drv.o \ - mtk_drm_fb.o \ mtk_drm_gem.o \ mtk_drm_plane.o \ mtk_dsi.o \ diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 84d14213d992596713249a5370e7a243b75447a3..2b1c122066eab97fe869ad6bdfb4930c9caa9db3 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -16,8 +16,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -27,7 +29,6 @@ #include "mtk_drm_ddp.h" #include "mtk_drm_ddp_comp.h" #include "mtk_drm_drv.h" -#include "mtk_drm_fb.h" #include "mtk_drm_gem.h" #define DRIVER_NAME "mediatek" @@ -115,6 +116,19 @@ static int mtk_atomic_commit(struct drm_device *drm, return 0; } +static struct drm_framebuffer * +mtk_drm_mode_fb_create(struct drm_device *dev, + struct drm_file *file, + const struct drm_mode_fb_cmd2 *cmd) +{ + const struct drm_format_info *info = drm_get_format_info(dev, cmd); + + if (info->num_planes != 1) + return ERR_PTR(-EINVAL); + + return drm_gem_fb_create(dev, file, cmd); +} + static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = { .fb_create = mtk_drm_mode_fb_create, .atomic_check = drm_atomic_helper_check, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_fb.c b/drivers/gpu/drm/mediatek/mtk_drm_fb.c deleted file mode 100644 index 3f230a28a2dce6b3e25b488a254ff34379c64ebb..0000000000000000000000000000000000000000 --- a/drivers/gpu/drm/mediatek/mtk_drm_fb.c +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2015 MediaTek Inc. - */ - -#include -#include - -#include -#include -#include -#include -#include - -#include "mtk_drm_drv.h" -#include "mtk_drm_fb.h" -#include "mtk_drm_gem.h" - -static const struct drm_framebuffer_funcs mtk_drm_fb_funcs = { - .create_handle = drm_gem_fb_create_handle, - .destroy = drm_gem_fb_destroy, -}; - -static struct drm_framebuffer *mtk_drm_framebuffer_init(struct drm_device *dev, - const struct drm_mode_fb_cmd2 *mode, - struct drm_gem_object *obj) -{ - const struct drm_format_info *info = drm_get_format_info(dev, mode); - struct drm_framebuffer *fb; - int ret; - - if (info->num_planes != 1) - return ERR_PTR(-EINVAL); - - fb = kzalloc(sizeof(*fb), GFP_KERNEL); - if (!fb) - return ERR_PTR(-ENOMEM); - - drm_helper_mode_fill_fb_struct(dev, fb, mode); - - fb->obj[0] = obj; - - ret = drm_framebuffer_init(dev, fb, &mtk_drm_fb_funcs); - if (ret) { - DRM_ERROR("failed to initialize framebuffer\n"); - kfree(fb); - return ERR_PTR(ret); - } - - return fb; -} - -struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev, - struct drm_file *file, - const struct drm_mode_fb_cmd2 *cmd) -{ - const struct drm_format_info *info = drm_get_format_info(dev, cmd); - struct drm_framebuffer *fb; - struct drm_gem_object *gem; - unsigned int width = cmd->width; - unsigned int height = cmd->height; - unsigned int size, bpp; - int ret; - - if (info->num_planes != 1) - return ERR_PTR(-EINVAL); - - gem = drm_gem_object_lookup(file, cmd->handles[0]); - if (!gem) - return ERR_PTR(-ENOENT); - - bpp = info->cpp[0]; - size = (height - 1) * cmd->pitches[0] + width * bpp; - size += cmd->offsets[0]; - - if (gem->size < size) { - ret = -EINVAL; - goto unreference; - } - - fb = mtk_drm_framebuffer_init(dev, cmd, gem); - if (IS_ERR(fb)) { - ret = PTR_ERR(fb); - goto unreference; - } - - return fb; - -unreference: - drm_gem_object_put_unlocked(gem); - return ERR_PTR(ret); -} diff --git a/drivers/gpu/drm/mediatek/mtk_drm_fb.h b/drivers/gpu/drm/mediatek/mtk_drm_fb.h deleted file mode 100644 index eb64d26001c66d73f54105952213263f70dba16f..0000000000000000000000000000000000000000 --- a/drivers/gpu/drm/mediatek/mtk_drm_fb.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2015 MediaTek Inc. - */ - -#ifndef MTK_DRM_FB_H -#define MTK_DRM_FB_H - -struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev, - struct drm_file *file, - const struct drm_mode_fb_cmd2 *cmd); - -#endif /* MTK_DRM_FB_H */ diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index 3b0cc91c7023aa91c62631c09145631449c717fa..f0b0325381e0e9d98469278986533bf728f096a5 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -13,7 +13,6 @@ #include "mtk_drm_crtc.h" #include "mtk_drm_ddp_comp.h" #include "mtk_drm_drv.h" -#include "mtk_drm_fb.h" #include "mtk_drm_gem.h" #include "mtk_drm_plane.h" @@ -95,7 +94,7 @@ static int mtk_plane_atomic_check(struct drm_plane *plane, if (!fb) return 0; - if (!state->crtc) + if (WARN_ON(!state->crtc)) return 0; ret = mtk_drm_crtc_plane_check(state->crtc, plane, diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index e9931bbbe846478efce7b294e001d1b916ed4493..3b5e016d16c48095b6fb2b0b589d77f045a270c7 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -821,7 +821,7 @@ static int mtk_dsi_connector_get_modes(struct drm_connector *connector) { struct mtk_dsi *dsi = connector_to_dsi(connector); - return drm_panel_get_modes(dsi->panel); + return drm_panel_get_modes(dsi->panel, connector); } static const struct drm_encoder_helper_funcs mtk_dsi_encoder_helper_funcs = { diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index c79b1f855d89559584e0ee5ff6c1d30091c1482f..5e4a4dbda443f92c76b63a6906aa0a47b238c5e4 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -1238,17 +1238,19 @@ static int mtk_hdmi_conn_mode_valid(struct drm_connector *conn, struct drm_display_mode *mode) { struct mtk_hdmi *hdmi = hdmi_ctx_from_conn(conn); + struct drm_bridge *next_bridge; dev_dbg(hdmi->dev, "xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n", mode->hdisplay, mode->vdisplay, mode->vrefresh, !!(mode->flags & DRM_MODE_FLAG_INTERLACE), mode->clock * 1000); - if (hdmi->bridge.next) { + next_bridge = drm_bridge_get_next_bridge(&hdmi->bridge); + if (next_bridge) { struct drm_display_mode adjusted_mode; drm_mode_copy(&adjusted_mode, mode); - if (!drm_bridge_mode_fixup(hdmi->bridge.next, mode, - &adjusted_mode)) + if (!drm_bridge_chain_mode_fixup(next_bridge, mode, + &adjusted_mode)) return MODE_BAD; } @@ -1300,9 +1302,10 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge) struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge); int ret; - ret = drm_connector_init(bridge->encoder->dev, &hdmi->conn, - &mtk_hdmi_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA); + ret = drm_connector_init_with_ddc(bridge->encoder->dev, &hdmi->conn, + &mtk_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA, + hdmi->ddc_adpt); if (ret) { dev_err(hdmi->dev, "Failed to initialize connector: %d\n", ret); return ret; diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile index c389e2399133231d6664ba12c0d32c153e106b22..28a519cdf66b82a6522122b9559f042092e42420 100644 --- a/drivers/gpu/drm/meson/Makefile +++ b/drivers/gpu/drm/meson/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_overlay.o +meson-drm-y += meson_rdma.o meson_osd_afbcd.o obj-$(CONFIG_DRM_MESON) += meson-drm.o obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c index 57ae1c13d1e6d1f33486441f784d0eb0b306a65c..e66b6271ff58a75990e79fda9309cde659abe931 100644 --- a/drivers/gpu/drm/meson/meson_crtc.c +++ b/drivers/gpu/drm/meson/meson_crtc.c @@ -23,7 +23,9 @@ #include "meson_registers.h" #include "meson_venc.h" #include "meson_viu.h" +#include "meson_rdma.h" #include "meson_vpp.h" +#include "meson_osd_afbcd.h" #define MESON_G12A_VIU_OFFSET 0x5ec0 @@ -35,7 +37,11 @@ struct meson_crtc { struct meson_drm *priv; void (*enable_osd1)(struct meson_drm *priv); void (*enable_vd1)(struct meson_drm *priv); + void (*enable_osd1_afbc)(struct meson_drm *priv); + void (*disable_osd1_afbc)(struct meson_drm *priv); unsigned int viu_offset; + bool vsync_forced; + bool vsync_disabled; }; #define to_meson_crtc(x) container_of(x, struct meson_crtc, base) @@ -46,6 +52,7 @@ static int meson_crtc_enable_vblank(struct drm_crtc *crtc) struct meson_crtc *meson_crtc = to_meson_crtc(crtc); struct meson_drm *priv = meson_crtc->priv; + meson_crtc->vsync_disabled = false; meson_venc_enable_vsync(priv); return 0; @@ -56,7 +63,10 @@ static void meson_crtc_disable_vblank(struct drm_crtc *crtc) struct meson_crtc *meson_crtc = to_meson_crtc(crtc); struct meson_drm *priv = meson_crtc->priv; - meson_venc_disable_vsync(priv); + if (!meson_crtc->vsync_forced) { + meson_crtc->vsync_disabled = true; + meson_venc_disable_vsync(priv); + } } static const struct drm_crtc_funcs meson_crtc_funcs = { @@ -236,6 +246,26 @@ static void meson_crtc_enable_osd1(struct meson_drm *priv) priv->io_base + _REG(VPP_MISC)); } +static void meson_crtc_g12a_enable_osd1_afbc(struct meson_drm *priv) +{ + writel_relaxed(priv->viu.osd1_blk2_cfg4, + priv->io_base + _REG(VIU_OSD1_BLK2_CFG_W4)); + + writel_bits_relaxed(OSD_MEM_LINEAR_ADDR, OSD_MEM_LINEAR_ADDR, + priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); + + writel_relaxed(priv->viu.osd1_blk1_cfg4, + priv->io_base + _REG(VIU_OSD1_BLK1_CFG_W4)); + + meson_viu_g12a_enable_osd1_afbc(priv); + + writel_bits_relaxed(OSD_MEM_LINEAR_ADDR, OSD_MEM_LINEAR_ADDR, + priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); + + writel_bits_relaxed(OSD_MALI_SRC_EN, OSD_MALI_SRC_EN, + priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0)); +} + static void meson_g12a_crtc_enable_osd1(struct meson_drm *priv) { writel_relaxed(priv->viu.osd_blend_din0_scope_h, @@ -281,6 +311,8 @@ void meson_crtc_irq(struct meson_drm *priv) if (priv->viu.osd1_enabled && priv->viu.osd1_commit) { writel_relaxed(priv->viu.osd1_ctrl_stat, priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); + writel_relaxed(priv->viu.osd1_ctrl_stat2, + priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); writel_relaxed(priv->viu.osd1_blk0_cfg[0], priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0)); writel_relaxed(priv->viu.osd1_blk0_cfg[1], @@ -291,6 +323,20 @@ void meson_crtc_irq(struct meson_drm *priv) priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W3)); writel_relaxed(priv->viu.osd1_blk0_cfg[4], priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W4)); + + if (priv->viu.osd1_afbcd) { + if (meson_crtc->enable_osd1_afbc) + meson_crtc->enable_osd1_afbc(priv); + } else { + if (meson_crtc->disable_osd1_afbc) + meson_crtc->disable_osd1_afbc(priv); + if (priv->afbcd.ops) { + priv->afbcd.ops->reset(priv); + priv->afbcd.ops->disable(priv); + } + meson_crtc->vsync_forced = false; + } + writel_relaxed(priv->viu.osd_sc_ctrl0, priv->io_base + _REG(VPP_OSD_SC_CTRL0)); writel_relaxed(priv->viu.osd_sc_i_wh_m1, @@ -312,15 +358,25 @@ void meson_crtc_irq(struct meson_drm *priv) writel_relaxed(priv->viu.osd_sc_v_ctrl0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0)); - meson_canvas_config(priv->canvas, priv->canvas_id_osd1, - priv->viu.osd1_addr, priv->viu.osd1_stride, - priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, - MESON_CANVAS_BLKMODE_LINEAR, 0); + if (!priv->viu.osd1_afbcd) + meson_canvas_config(priv->canvas, priv->canvas_id_osd1, + priv->viu.osd1_addr, + priv->viu.osd1_stride, + priv->viu.osd1_height, + MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, 0); /* Enable OSD1 */ if (meson_crtc->enable_osd1) meson_crtc->enable_osd1(priv); + if (priv->viu.osd1_afbcd) { + priv->afbcd.ops->reset(priv); + priv->afbcd.ops->setup(priv); + priv->afbcd.ops->enable(priv); + meson_crtc->vsync_forced = true; + } + priv->viu.osd1_commit = false; } @@ -357,7 +413,7 @@ void meson_crtc_irq(struct meson_drm *priv) MESON_CANVAS_WRAP_NONE, MESON_CANVAS_BLKMODE_LINEAR, MESON_CANVAS_ENDIAN_SWAP64); - }; + } writel_relaxed(priv->viu.vd1_if0_gen_reg, priv->io_base + meson_crtc->viu_offset + @@ -543,6 +599,9 @@ void meson_crtc_irq(struct meson_drm *priv) priv->viu.vd1_commit = false; } + if (meson_crtc->vsync_disabled) + return; + drm_crtc_handle_vblank(priv->crtc); spin_lock_irqsave(&priv->drm->event_lock, flags); @@ -579,10 +638,20 @@ int meson_crtc_create(struct meson_drm *priv) meson_crtc->enable_osd1 = meson_g12a_crtc_enable_osd1; meson_crtc->enable_vd1 = meson_g12a_crtc_enable_vd1; meson_crtc->viu_offset = MESON_G12A_VIU_OFFSET; + meson_crtc->enable_osd1_afbc = + meson_crtc_g12a_enable_osd1_afbc; + meson_crtc->disable_osd1_afbc = + meson_viu_g12a_disable_osd1_afbc; drm_crtc_helper_add(crtc, &meson_g12a_crtc_helper_funcs); } else { meson_crtc->enable_osd1 = meson_crtc_enable_osd1; meson_crtc->enable_vd1 = meson_crtc_enable_vd1; + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) { + meson_crtc->enable_osd1_afbc = + meson_viu_gxm_enable_osd1_afbc; + meson_crtc->disable_osd1_afbc = + meson_viu_gxm_disable_osd1_afbc; + } drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs); } diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 397c33182f4f83325d066bf5454d0ebd1cc5b14c..b5f5eb7b4bb904b311f5994750e5830026a8ae1b 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -28,10 +28,12 @@ #include "meson_drv.h" #include "meson_overlay.h" #include "meson_plane.h" +#include "meson_osd_afbcd.h" #include "meson_registers.h" #include "meson_venc_cvbs.h" #include "meson_viu.h" #include "meson_vpp.h" +#include "meson_rdma.h" #define DRIVER_NAME "meson" #define DRIVER_DESC "Amlogic Meson DRM driver" @@ -184,6 +186,7 @@ static void meson_remove_framebuffers(void) static int meson_drv_bind_master(struct device *dev, bool has_components) { struct platform_device *pdev = to_platform_device(dev); + const struct meson_drm_match_data *match; struct meson_drm *priv; struct drm_device *drm; struct resource *res; @@ -196,6 +199,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) return -ENODEV; } + match = of_device_get_match_data(dev); + if (!match) + return -ENODEV; + drm = drm_dev_alloc(&meson_driver, dev); if (IS_ERR(drm)) return PTR_ERR(drm); @@ -208,8 +215,8 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) drm->dev_private = priv; priv->drm = drm; priv->dev = dev; - - priv->compat = (enum vpu_compatible)of_device_get_match_data(priv->dev); + priv->compat = match->compat; + priv->afbcd.ops = match->afbcd_ops; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu"); regs = devm_ioremap_resource(dev, res); @@ -289,6 +296,11 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) meson_venc_init(priv); meson_vpp_init(priv); meson_viu_init(priv); + if (priv->afbcd.ops) { + ret = priv->afbcd.ops->init(priv); + if (ret) + return ret; + } /* Encoder Initialization */ @@ -359,12 +371,16 @@ static void meson_drv_unbind(struct device *dev) meson_canvas_free(priv->canvas, priv->canvas_id_vd1_2); } + if (priv->afbcd.ops) { + priv->afbcd.ops->reset(priv); + meson_rdma_free(priv); + } + drm_dev_unregister(drm); drm_irq_uninstall(drm); drm_kms_helper_poll_fini(drm); drm_mode_config_cleanup(drm); drm_dev_put(drm); - } static const struct component_master_ops meson_drv_master_ops = { @@ -393,6 +409,8 @@ static int __maybe_unused meson_drv_pm_resume(struct device *dev) meson_venc_init(priv); meson_vpp_init(priv); meson_viu_init(priv); + if (priv->afbcd.ops) + priv->afbcd.ops->init(priv); drm_mode_config_helper_resume(priv->drm); @@ -481,15 +499,33 @@ static int meson_drv_probe(struct platform_device *pdev) return 0; }; +static struct meson_drm_match_data meson_drm_gxbb_data = { + .compat = VPU_COMPATIBLE_GXBB, +}; + +static struct meson_drm_match_data meson_drm_gxl_data = { + .compat = VPU_COMPATIBLE_GXL, +}; + +static struct meson_drm_match_data meson_drm_gxm_data = { + .compat = VPU_COMPATIBLE_GXM, + .afbcd_ops = &meson_afbcd_gxm_ops, +}; + +static struct meson_drm_match_data meson_drm_g12a_data = { + .compat = VPU_COMPATIBLE_G12A, + .afbcd_ops = &meson_afbcd_g12a_ops, +}; + static const struct of_device_id dt_match[] = { { .compatible = "amlogic,meson-gxbb-vpu", - .data = (void *)VPU_COMPATIBLE_GXBB }, + .data = (void *)&meson_drm_gxbb_data }, { .compatible = "amlogic,meson-gxl-vpu", - .data = (void *)VPU_COMPATIBLE_GXL }, + .data = (void *)&meson_drm_gxl_data }, { .compatible = "amlogic,meson-gxm-vpu", - .data = (void *)VPU_COMPATIBLE_GXM }, + .data = (void *)&meson_drm_gxm_data }, { .compatible = "amlogic,meson-g12a-vpu", - .data = (void *)VPU_COMPATIBLE_G12A }, + .data = (void *)&meson_drm_g12a_data }, {} }; MODULE_DEVICE_TABLE(of, dt_match); diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h index 820d07bdd42aefa621cbc1a34295a8e583bf4a08..f9a0c8e9d4d06cba183659c26a9a321d30f2c912 100644 --- a/drivers/gpu/drm/meson/meson_drv.h +++ b/drivers/gpu/drm/meson/meson_drv.h @@ -16,6 +16,7 @@ struct drm_crtc; struct drm_device; struct drm_plane; struct meson_drm; +struct meson_afbcd_ops; enum vpu_compatible { VPU_COMPATIBLE_GXBB = 0, @@ -24,6 +25,11 @@ enum vpu_compatible { VPU_COMPATIBLE_G12A = 3, }; +struct meson_drm_match_data { + enum vpu_compatible compat; + struct meson_afbcd_ops *afbcd_ops; +}; + struct meson_drm { struct device *dev; enum vpu_compatible compat; @@ -47,11 +53,16 @@ struct meson_drm { bool osd1_enabled; bool osd1_interlace; bool osd1_commit; + bool osd1_afbcd; uint32_t osd1_ctrl_stat; + uint32_t osd1_ctrl_stat2; uint32_t osd1_blk0_cfg[5]; + uint32_t osd1_blk1_cfg4; + uint32_t osd1_blk2_cfg4; uint32_t osd1_addr; uint32_t osd1_stride; uint32_t osd1_height; + uint32_t osd1_width; uint32_t osd_sc_ctrl0; uint32_t osd_sc_i_wh_m1; uint32_t osd_sc_o_h_start_end; @@ -122,6 +133,18 @@ struct meson_drm { bool venc_repeat; bool hdmi_use_enci; } venc; + + struct { + dma_addr_t addr_phys; + uint32_t *addr; + unsigned int offset; + } rdma; + + struct { + struct meson_afbcd_ops *ops; + u64 modifier; + u32 format; + } afbcd; }; static inline int meson_vpu_is_compatible(struct meson_drm *priv, diff --git a/drivers/gpu/drm/meson/meson_osd_afbcd.c b/drivers/gpu/drm/meson/meson_osd_afbcd.c new file mode 100644 index 0000000000000000000000000000000000000000..f12e0271f16655fae972a331c7e7fdd9eb6c59e8 --- /dev/null +++ b/drivers/gpu/drm/meson/meson_osd_afbcd.c @@ -0,0 +1,389 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include + +#include +#include + +#include "meson_drv.h" +#include "meson_registers.h" +#include "meson_viu.h" +#include "meson_rdma.h" +#include "meson_osd_afbcd.h" + +/* + * DOC: Driver for the ARM FrameBuffer Compression Decoders + * + * The Amlogic GXM and G12A SoC families embeds an AFBC Decoder, + * to decode compressed buffers generated by the ARM Mali GPU. + * + * For the GXM Family, Amlogic designed their own Decoder, named in + * the vendor source as "MESON_AFBC", and a single decoder is available + * for the 2 OSD planes. + * This decoder is compatible with the AFBC 1.0 specifications and the + * Mali T820 GPU capabilities. + * It supports : + * - basic AFBC buffer for RGB32 only, thus YTR feature is mandatory + * - SPARSE layout and SPLIT layout + * - only 16x16 superblock + * + * The decoder reads the data from the SDRAM, decodes and sends the + * decoded pixel stream to the OSD1 Plane pixel composer. + * + * For the G12A Family, Amlogic integrated an ARM AFBC Decoder, named + * in the vendor source as "MALI_AFBC", and the decoder can decode up + * to 4 surfaces, one for each of the 4 available OSDs. + * This decoder is compatible with the AFBC 1.2 specifications for the + * Mali G31 and G52 GPUs. + * Is supports : + * - basic AFBC buffer for multiple RGB and YUV pixel formats + * - SPARSE layout and SPLIT layout + * - 16x16 and 32x8 "wideblk" superblocks + * - Tiled header + * + * The ARM AFBC Decoder independent from the VPU Pixel Pipeline, so + * the ARM AFBC Decoder reads the data from the SDRAM then decodes + * into a private internal physical address where the OSD1 Plane pixel + * composer unpacks the decoded data. + */ + +/* Amlogic AFBC Decoder for GXM Family */ + +#define OSD1_AFBCD_RGB32 0x15 + +static int meson_gxm_afbcd_pixel_fmt(u64 modifier, uint32_t format) +{ + switch (format) { + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + return OSD1_AFBCD_RGB32; + /* TOFIX support mode formats */ + default: + DRM_DEBUG("unsupported afbc format[%08x]\n", format); + return -EINVAL; + } +} + +static bool meson_gxm_afbcd_supported_fmt(u64 modifier, uint32_t format) +{ + if (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_32x8) + return false; + + if (!(modifier & AFBC_FORMAT_MOD_YTR)) + return false; + + return meson_gxm_afbcd_pixel_fmt(modifier, format) >= 0; +} + +static int meson_gxm_afbcd_init(struct meson_drm *priv) +{ + return 0; +} + +static int meson_gxm_afbcd_reset(struct meson_drm *priv) +{ + writel_relaxed(VIU_SW_RESET_OSD1_AFBCD, + priv->io_base + _REG(VIU_SW_RESET)); + writel_relaxed(0, priv->io_base + _REG(VIU_SW_RESET)); + + return 0; +} + +static int meson_gxm_afbcd_enable(struct meson_drm *priv) +{ + writel_relaxed(FIELD_PREP(OSD1_AFBCD_ID_FIFO_THRD, 0x40) | + OSD1_AFBCD_DEC_ENABLE, + priv->io_base + _REG(OSD1_AFBCD_ENABLE)); + + return 0; +} + +static int meson_gxm_afbcd_disable(struct meson_drm *priv) +{ + writel_bits_relaxed(OSD1_AFBCD_DEC_ENABLE, 0, + priv->io_base + _REG(OSD1_AFBCD_ENABLE)); + + return 0; +} + +static int meson_gxm_afbcd_setup(struct meson_drm *priv) +{ + u32 conv_lbuf_len; + u32 mode = FIELD_PREP(OSD1_AFBCD_MIF_URGENT, 3) | + FIELD_PREP(OSD1_AFBCD_HOLD_LINE_NUM, 4) | + FIELD_PREP(OSD1_AFBCD_RGBA_EXCHAN_CTRL, 0x34) | + meson_gxm_afbcd_pixel_fmt(priv->afbcd.modifier, + priv->afbcd.format); + + if (priv->afbcd.modifier & AFBC_FORMAT_MOD_SPARSE) + mode |= OSD1_AFBCD_HREG_HALF_BLOCK; + + if (priv->afbcd.modifier & AFBC_FORMAT_MOD_SPLIT) + mode |= OSD1_AFBCD_HREG_BLOCK_SPLIT; + + writel_relaxed(mode, priv->io_base + _REG(OSD1_AFBCD_MODE)); + + writel_relaxed(FIELD_PREP(OSD1_AFBCD_HREG_VSIZE_IN, + priv->viu.osd1_width) | + FIELD_PREP(OSD1_AFBCD_HREG_HSIZE_IN, + priv->viu.osd1_height), + priv->io_base + _REG(OSD1_AFBCD_SIZE_IN)); + + writel_relaxed(priv->viu.osd1_addr >> 4, + priv->io_base + _REG(OSD1_AFBCD_HDR_PTR)); + writel_relaxed(priv->viu.osd1_addr >> 4, + priv->io_base + _REG(OSD1_AFBCD_FRAME_PTR)); + /* TOFIX: bits 31:24 are not documented, nor the meaning of 0xe4 */ + writel_relaxed((0xe4 << 24) | (priv->viu.osd1_addr & 0xffffff), + priv->io_base + _REG(OSD1_AFBCD_CHROMA_PTR)); + + if (priv->viu.osd1_width <= 128) + conv_lbuf_len = 32; + else if (priv->viu.osd1_width <= 256) + conv_lbuf_len = 64; + else if (priv->viu.osd1_width <= 512) + conv_lbuf_len = 128; + else if (priv->viu.osd1_width <= 1024) + conv_lbuf_len = 256; + else if (priv->viu.osd1_width <= 2048) + conv_lbuf_len = 512; + else + conv_lbuf_len = 1024; + + writel_relaxed(conv_lbuf_len, + priv->io_base + _REG(OSD1_AFBCD_CONV_CTRL)); + + writel_relaxed(FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_BGN_H, 0) | + FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_END_H, + priv->viu.osd1_width - 1), + priv->io_base + _REG(OSD1_AFBCD_PIXEL_HSCOPE)); + + writel_relaxed(FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_BGN_V, 0) | + FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_END_V, + priv->viu.osd1_height - 1), + priv->io_base + _REG(OSD1_AFBCD_PIXEL_VSCOPE)); + + return 0; +} + +struct meson_afbcd_ops meson_afbcd_gxm_ops = { + .init = meson_gxm_afbcd_init, + .reset = meson_gxm_afbcd_reset, + .enable = meson_gxm_afbcd_enable, + .disable = meson_gxm_afbcd_disable, + .setup = meson_gxm_afbcd_setup, + .supported_fmt = meson_gxm_afbcd_supported_fmt, +}; + +/* ARM AFBC Decoder for G12A Family */ + +/* Amlogic G12A Mali AFBC Decoder supported formats */ +enum { + MAFBC_FMT_RGB565 = 0, + MAFBC_FMT_RGBA5551, + MAFBC_FMT_RGBA1010102, + MAFBC_FMT_YUV420_10B, + MAFBC_FMT_RGB888, + MAFBC_FMT_RGBA8888, + MAFBC_FMT_RGBA4444, + MAFBC_FMT_R8, + MAFBC_FMT_RG88, + MAFBC_FMT_YUV420_8B, + MAFBC_FMT_YUV422_8B = 11, + MAFBC_FMT_YUV422_10B = 14, +}; + +static int meson_g12a_afbcd_pixel_fmt(u64 modifier, uint32_t format) +{ + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + /* YTR is forbidden for non XBGR formats */ + if (modifier & AFBC_FORMAT_MOD_YTR) + return -EINVAL; + /* fall through */ + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + return MAFBC_FMT_RGBA8888; + case DRM_FORMAT_RGB888: + /* YTR is forbidden for non XBGR formats */ + if (modifier & AFBC_FORMAT_MOD_YTR) + return -EINVAL; + return MAFBC_FMT_RGB888; + case DRM_FORMAT_RGB565: + /* YTR is forbidden for non XBGR formats */ + if (modifier & AFBC_FORMAT_MOD_YTR) + return -EINVAL; + return MAFBC_FMT_RGB565; + /* TOFIX support mode formats */ + default: + DRM_DEBUG("unsupported afbc format[%08x]\n", format); + return -EINVAL; + } +} + +static int meson_g12a_afbcd_bpp(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + return 32; + case DRM_FORMAT_RGB888: + return 24; + case DRM_FORMAT_RGB565: + return 16; + /* TOFIX support mode formats */ + default: + DRM_ERROR("unsupported afbc format[%08x]\n", format); + return 0; + } +} + +static int meson_g12a_afbcd_fmt_to_blk_mode(u64 modifier, uint32_t format) +{ + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + return OSD_MALI_COLOR_MODE_RGBA8888; + case DRM_FORMAT_RGB888: + return OSD_MALI_COLOR_MODE_RGB888; + case DRM_FORMAT_RGB565: + return OSD_MALI_COLOR_MODE_RGB565; + /* TOFIX support mode formats */ + default: + DRM_DEBUG("unsupported afbc format[%08x]\n", format); + return -EINVAL; + } +} + +static bool meson_g12a_afbcd_supported_fmt(u64 modifier, uint32_t format) +{ + return meson_g12a_afbcd_pixel_fmt(modifier, format) >= 0; +} + +static int meson_g12a_afbcd_init(struct meson_drm *priv) +{ + int ret; + + ret = meson_rdma_init(priv); + if (ret) + return ret; + + meson_rdma_setup(priv); + + /* Handle AFBC Decoder reset manually */ + writel_bits_relaxed(MALI_AFBCD_MANUAL_RESET, MALI_AFBCD_MANUAL_RESET, + priv->io_base + _REG(MALI_AFBCD_TOP_CTRL)); + + return 0; +} + +static int meson_g12a_afbcd_reset(struct meson_drm *priv) +{ + meson_rdma_reset(priv); + + meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB | + VIU_SW_RESET_G12A_OSD1_AFBCD, + VIU_SW_RESET); + meson_rdma_writel_sync(priv, 0, VIU_SW_RESET); + + return 0; +} + +static int meson_g12a_afbcd_enable(struct meson_drm *priv) +{ + meson_rdma_writel_sync(priv, VPU_MAFBC_IRQ_SURFACES_COMPLETED | + VPU_MAFBC_IRQ_CONFIGURATION_SWAPPED | + VPU_MAFBC_IRQ_DECODE_ERROR | + VPU_MAFBC_IRQ_DETILING_ERROR, + VPU_MAFBC_IRQ_MASK); + + meson_rdma_writel_sync(priv, VPU_MAFBC_S0_ENABLE, + VPU_MAFBC_SURFACE_CFG); + + meson_rdma_writel_sync(priv, VPU_MAFBC_DIRECT_SWAP, + VPU_MAFBC_COMMAND); + + /* This will enable the RDMA replaying the register writes on vsync */ + meson_rdma_flush(priv); + + return 0; +} + +static int meson_g12a_afbcd_disable(struct meson_drm *priv) +{ + writel_bits_relaxed(VPU_MAFBC_S0_ENABLE, 0, + priv->io_base + _REG(VPU_MAFBC_SURFACE_CFG)); + + return 0; +} + +static int meson_g12a_afbcd_setup(struct meson_drm *priv) +{ + u32 format = meson_g12a_afbcd_pixel_fmt(priv->afbcd.modifier, + priv->afbcd.format); + + if (priv->afbcd.modifier & AFBC_FORMAT_MOD_YTR) + format |= VPU_MAFBC_YUV_TRANSFORM; + + if (priv->afbcd.modifier & AFBC_FORMAT_MOD_SPLIT) + format |= VPU_MAFBC_BLOCK_SPLIT; + + if (priv->afbcd.modifier & AFBC_FORMAT_MOD_TILED) + format |= VPU_MAFBC_TILED_HEADER_EN; + + if ((priv->afbcd.modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) == + AFBC_FORMAT_MOD_BLOCK_SIZE_32x8) + format |= FIELD_PREP(VPU_MAFBC_SUPER_BLOCK_ASPECT, 1); + + meson_rdma_writel_sync(priv, format, + VPU_MAFBC_FORMAT_SPECIFIER_S0); + + meson_rdma_writel_sync(priv, priv->viu.osd1_addr, + VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0); + meson_rdma_writel_sync(priv, 0, + VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0); + + meson_rdma_writel_sync(priv, priv->viu.osd1_width, + VPU_MAFBC_BUFFER_WIDTH_S0); + meson_rdma_writel_sync(priv, ALIGN(priv->viu.osd1_height, 32), + VPU_MAFBC_BUFFER_HEIGHT_S0); + + meson_rdma_writel_sync(priv, 0, + VPU_MAFBC_BOUNDING_BOX_X_START_S0); + meson_rdma_writel_sync(priv, priv->viu.osd1_width - 1, + VPU_MAFBC_BOUNDING_BOX_X_END_S0); + meson_rdma_writel_sync(priv, 0, + VPU_MAFBC_BOUNDING_BOX_Y_START_S0); + meson_rdma_writel_sync(priv, priv->viu.osd1_height - 1, + VPU_MAFBC_BOUNDING_BOX_Y_END_S0); + + meson_rdma_writel_sync(priv, MESON_G12A_AFBCD_OUT_ADDR, + VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0); + meson_rdma_writel_sync(priv, 0, + VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0); + + meson_rdma_writel_sync(priv, priv->viu.osd1_width * + (meson_g12a_afbcd_bpp(priv->afbcd.format) / 8), + VPU_MAFBC_OUTPUT_BUF_STRIDE_S0); + + return 0; +} + +struct meson_afbcd_ops meson_afbcd_g12a_ops = { + .init = meson_g12a_afbcd_init, + .reset = meson_g12a_afbcd_reset, + .enable = meson_g12a_afbcd_enable, + .disable = meson_g12a_afbcd_disable, + .setup = meson_g12a_afbcd_setup, + .fmt_to_blk_mode = meson_g12a_afbcd_fmt_to_blk_mode, + .supported_fmt = meson_g12a_afbcd_supported_fmt, +}; diff --git a/drivers/gpu/drm/meson/meson_osd_afbcd.h b/drivers/gpu/drm/meson/meson_osd_afbcd.h new file mode 100644 index 0000000000000000000000000000000000000000..5e5523304f42f95c305a850bcde238fc57988ca5 --- /dev/null +++ b/drivers/gpu/drm/meson/meson_osd_afbcd.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2019 BayLibre, SAS + * Author: Neil Armstrong + */ + +#ifndef __MESON_OSD_AFBCD_H +#define __MESON_OSD_AFBCD_H + +#include "meson_drv.h" + +/* This is an internal address used to transfer pixel from AFBC to the VIU */ +#define MESON_G12A_AFBCD_OUT_ADDR 0x1000000 + +struct meson_afbcd_ops { + int (*init)(struct meson_drm *priv); + int (*reset)(struct meson_drm *priv); + int (*enable)(struct meson_drm *priv); + int (*disable)(struct meson_drm *priv); + int (*setup)(struct meson_drm *priv); + int (*fmt_to_blk_mode)(u64 modifier, uint32_t format); + bool (*supported_fmt)(u64 modifier, uint32_t format); +}; + +extern struct meson_afbcd_ops meson_afbcd_gxm_ops; +extern struct meson_afbcd_ops meson_afbcd_g12a_ops; + +#endif /* __MESON_OSD_AFBCD_H */ diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index ed543227b00dd9c60f39c46a0b9369fe57f093df..d5cbc47835bfa021252383e0ecacaf30dd66a279 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -23,6 +23,7 @@ #include "meson_plane.h" #include "meson_registers.h" #include "meson_viu.h" +#include "meson_osd_afbcd.h" /* OSD_SCI_WH_M1 */ #define SCI_WH_M1_W(w) FIELD_PREP(GENMASK(28, 16), w) @@ -92,12 +93,38 @@ static int meson_plane_atomic_check(struct drm_plane *plane, false, true); } +#define MESON_MOD_AFBC_VALID_BITS (AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | \ + AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | \ + AFBC_FORMAT_MOD_YTR | \ + AFBC_FORMAT_MOD_SPARSE | \ + AFBC_FORMAT_MOD_SPLIT) + /* Takes a fixed 16.16 number and converts it to integer. */ static inline int64_t fixed16_to_int(int64_t value) { return value >> 16; } +static u32 meson_g12a_afbcd_line_stride(struct meson_drm *priv) +{ + u32 line_stride = 0; + + switch (priv->afbcd.format) { + case DRM_FORMAT_RGB565: + line_stride = ((priv->viu.osd1_width << 4) + 127) >> 7; + break; + case DRM_FORMAT_RGB888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + line_stride = ((priv->viu.osd1_width << 5) + 127) >> 7; + break; + } + + return ((line_stride + 1) >> 1) << 1; +} + static void meson_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { @@ -126,59 +153,91 @@ static void meson_plane_atomic_update(struct drm_plane *plane, */ spin_lock_irqsave(&priv->drm->event_lock, flags); + /* Check if AFBC decoder is required for this buffer */ + if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) && + fb->modifier & DRM_FORMAT_MOD_ARM_AFBC(MESON_MOD_AFBC_VALID_BITS)) + priv->viu.osd1_afbcd = true; + else + priv->viu.osd1_afbcd = false; + /* Enable OSD and BLK0, set max global alpha */ priv->viu.osd1_ctrl_stat = OSD_ENABLE | (0xFF << OSD_GLOBAL_ALPHA_SHIFT) | OSD_BLK0_ENABLE; + priv->viu.osd1_ctrl_stat2 = readl(priv->io_base + + _REG(VIU_OSD1_CTRL_STAT2)); + canvas_id_osd1 = priv->canvas_id_osd1; /* Set up BLK0 to point to the right canvas */ - priv->viu.osd1_blk0_cfg[0] = ((canvas_id_osd1 << OSD_CANVAS_SEL) | - OSD_ENDIANNESS_LE); + priv->viu.osd1_blk0_cfg[0] = canvas_id_osd1 << OSD_CANVAS_SEL; + + if (priv->viu.osd1_afbcd) { + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + /* This is the internal decoding memory address */ + priv->viu.osd1_blk1_cfg4 = MESON_G12A_AFBCD_OUT_ADDR; + priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_BE; + priv->viu.osd1_ctrl_stat2 |= OSD_PENDING_STAT_CLEAN; + priv->viu.osd1_ctrl_stat |= VIU_OSD1_CFG_SYN_EN; + } + + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) { + priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_LE; + priv->viu.osd1_ctrl_stat2 |= OSD_DPATH_MALI_AFBCD; + } + } else { + priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_LE; + + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) + priv->viu.osd1_ctrl_stat2 &= ~OSD_DPATH_MALI_AFBCD; + } /* On GXBB, Use the old non-HDR RGB2YUV converter */ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) priv->viu.osd1_blk0_cfg[0] |= OSD_OUTPUT_COLOR_RGB; + if (priv->viu.osd1_afbcd && + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + priv->viu.osd1_blk0_cfg[0] |= OSD_MALI_SRC_EN | + priv->afbcd.ops->fmt_to_blk_mode(fb->modifier, + fb->format->format); + } else { + switch (fb->format->format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | + OSD_COLOR_MATRIX_32_ARGB; + break; + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | + OSD_COLOR_MATRIX_32_ABGR; + break; + case DRM_FORMAT_RGB888: + priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_24 | + OSD_COLOR_MATRIX_24_RGB; + break; + case DRM_FORMAT_RGB565: + priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_16 | + OSD_COLOR_MATRIX_16_RGB565; + break; + }; + } + switch (fb->format->format) { case DRM_FORMAT_XRGB8888: - /* For XRGB, replace the pixel's alpha by 0xFF */ - writel_bits_relaxed(OSD_REPLACE_EN, OSD_REPLACE_EN, - priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); - priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | - OSD_COLOR_MATRIX_32_ARGB; - break; case DRM_FORMAT_XBGR8888: /* For XRGB, replace the pixel's alpha by 0xFF */ - writel_bits_relaxed(OSD_REPLACE_EN, OSD_REPLACE_EN, - priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); - priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | - OSD_COLOR_MATRIX_32_ABGR; + priv->viu.osd1_ctrl_stat2 |= OSD_REPLACE_EN; break; case DRM_FORMAT_ARGB8888: - /* For ARGB, use the pixel's alpha */ - writel_bits_relaxed(OSD_REPLACE_EN, 0, - priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); - priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | - OSD_COLOR_MATRIX_32_ARGB; - break; case DRM_FORMAT_ABGR8888: /* For ARGB, use the pixel's alpha */ - writel_bits_relaxed(OSD_REPLACE_EN, 0, - priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); - priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | - OSD_COLOR_MATRIX_32_ABGR; + priv->viu.osd1_ctrl_stat2 &= ~OSD_REPLACE_EN; break; - case DRM_FORMAT_RGB888: - priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_24 | - OSD_COLOR_MATRIX_24_RGB; - break; - case DRM_FORMAT_RGB565: - priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_16 | - OSD_COLOR_MATRIX_16_RGB565; - break; - }; + } /* Default scaler parameters */ vsc_bot_rcv_num = 0; @@ -305,6 +364,17 @@ static void meson_plane_atomic_update(struct drm_plane *plane, priv->viu.osd1_addr = gem->paddr; priv->viu.osd1_stride = fb->pitches[0]; priv->viu.osd1_height = fb->height; + priv->viu.osd1_width = fb->width; + + if (priv->viu.osd1_afbcd) { + priv->afbcd.modifier = fb->modifier; + priv->afbcd.format = fb->format->format; + + /* Calculate decoder write stride */ + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) + priv->viu.osd1_blk2_cfg4 = + meson_g12a_afbcd_line_stride(priv); + } if (!meson_plane->enabled) { /* Reset OSD1 before enabling it on GXL+ SoCs */ @@ -326,6 +396,11 @@ static void meson_plane_atomic_disable(struct drm_plane *plane, struct meson_plane *meson_plane = to_meson_plane(plane); struct meson_drm *priv = meson_plane->priv; + if (priv->afbcd.ops) { + priv->afbcd.ops->reset(priv); + priv->afbcd.ops->disable(priv); + } + /* Disable OSD1 */ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) writel_bits_relaxed(VIU_OSD1_POSTBLD_SRC_OSD1, 0, @@ -345,6 +420,42 @@ static const struct drm_plane_helper_funcs meson_plane_helper_funcs = { .prepare_fb = drm_gem_fb_prepare_fb, }; +static bool meson_plane_format_mod_supported(struct drm_plane *plane, + u32 format, u64 modifier) +{ + struct meson_plane *meson_plane = to_meson_plane(plane); + struct meson_drm *priv = meson_plane->priv; + int i; + + if (modifier == DRM_FORMAT_MOD_INVALID) + return false; + + if (modifier == DRM_FORMAT_MOD_LINEAR) + return true; + + if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) && + !meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) + return false; + + if (modifier & ~DRM_FORMAT_MOD_ARM_AFBC(MESON_MOD_AFBC_VALID_BITS)) + return false; + + for (i = 0 ; i < plane->modifier_count ; ++i) + if (plane->modifiers[i] == modifier) + break; + + if (i == plane->modifier_count) { + DRM_DEBUG_KMS("Unsupported modifier\n"); + return false; + } + + if (priv->afbcd.ops && priv->afbcd.ops->supported_fmt) + return priv->afbcd.ops->supported_fmt(modifier, format); + + DRM_DEBUG_KMS("AFBC Unsupported\n"); + return false; +} + static const struct drm_plane_funcs meson_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, @@ -352,6 +463,7 @@ static const struct drm_plane_funcs meson_plane_funcs = { .reset = drm_atomic_helper_plane_reset, .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, + .format_mod_supported = meson_plane_format_mod_supported, }; static const uint32_t supported_drm_formats[] = { @@ -363,10 +475,60 @@ static const uint32_t supported_drm_formats[] = { DRM_FORMAT_RGB565, }; +static const uint64_t format_modifiers_afbc_gxm[] = { + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | + AFBC_FORMAT_MOD_SPARSE | + AFBC_FORMAT_MOD_YTR), + /* SPLIT mandates SPARSE, RGB modes mandates YTR */ + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | + AFBC_FORMAT_MOD_YTR | + AFBC_FORMAT_MOD_SPARSE | + AFBC_FORMAT_MOD_SPLIT), + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID, +}; + +static const uint64_t format_modifiers_afbc_g12a[] = { + /* + * - TOFIX Support AFBC modifiers for YUV formats (16x16 + TILED) + * - SPLIT is mandatory for performances reasons when in 16x16 + * block size + * - 32x8 block size + SPLIT is mandatory with 4K frame size + * for performances reasons + */ + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | + AFBC_FORMAT_MOD_SPARSE | + AFBC_FORMAT_MOD_SPLIT), + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | + AFBC_FORMAT_MOD_YTR | + AFBC_FORMAT_MOD_SPARSE | + AFBC_FORMAT_MOD_SPLIT), + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | + AFBC_FORMAT_MOD_SPARSE), + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | + AFBC_FORMAT_MOD_YTR | + AFBC_FORMAT_MOD_SPARSE), + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | + AFBC_FORMAT_MOD_SPARSE | + AFBC_FORMAT_MOD_SPLIT), + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | + AFBC_FORMAT_MOD_YTR | + AFBC_FORMAT_MOD_SPARSE | + AFBC_FORMAT_MOD_SPLIT), + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID, +}; + +static const uint64_t format_modifiers_default[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID, +}; + int meson_plane_create(struct meson_drm *priv) { struct meson_plane *meson_plane; struct drm_plane *plane; + const uint64_t *format_modifiers = format_modifiers_default; meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane), GFP_KERNEL); @@ -376,11 +538,16 @@ int meson_plane_create(struct meson_drm *priv) meson_plane->priv = priv; plane = &meson_plane->base; + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) + format_modifiers = format_modifiers_afbc_gxm; + else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) + format_modifiers = format_modifiers_afbc_g12a; + drm_universal_plane_init(priv->drm, plane, 0xFF, &meson_plane_funcs, supported_drm_formats, ARRAY_SIZE(supported_drm_formats), - NULL, + format_modifiers, DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane"); drm_plane_helper_add(plane, &meson_plane_helper_funcs); diff --git a/drivers/gpu/drm/meson/meson_rdma.c b/drivers/gpu/drm/meson/meson_rdma.c new file mode 100644 index 0000000000000000000000000000000000000000..25b34b1e72a7abb075f9564f560b41685570a17e --- /dev/null +++ b/drivers/gpu/drm/meson/meson_rdma.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include +#include + +#include "meson_drv.h" +#include "meson_registers.h" +#include "meson_rdma.h" + +/* + * The VPU embeds a "Register DMA" that can write a sequence of registers + * on the VPU AHB bus, either manually or triggered by an internal IRQ + * event like VSYNC or a line input counter. + * The initial implementation handles a single channel (over 8), triggered + * by the VSYNC irq and does not handle the RDMA irq. + */ + +#define RDMA_DESC_SIZE (sizeof(uint32_t) * 2) + +int meson_rdma_init(struct meson_drm *priv) +{ + if (!priv->rdma.addr) { + /* Allocate a PAGE buffer */ + priv->rdma.addr = + dma_alloc_coherent(priv->dev, SZ_4K, + &priv->rdma.addr_phys, + GFP_KERNEL); + if (!priv->rdma.addr) + return -ENOMEM; + } + + priv->rdma.offset = 0; + + writel_relaxed(RDMA_CTRL_SW_RESET, + priv->io_base + _REG(RDMA_CTRL)); + writel_relaxed(RDMA_DEFAULT_CONFIG | + FIELD_PREP(RDMA_CTRL_AHB_WR_BURST, 3) | + FIELD_PREP(RDMA_CTRL_AHB_RD_BURST, 0), + priv->io_base + _REG(RDMA_CTRL)); + + return 0; +} + +void meson_rdma_free(struct meson_drm *priv) +{ + if (!priv->rdma.addr && !priv->rdma.addr_phys) + return; + + meson_rdma_stop(priv); + + dma_free_coherent(priv->dev, SZ_4K, + priv->rdma.addr, priv->rdma.addr_phys); + + priv->rdma.addr = NULL; + priv->rdma.addr_phys = (dma_addr_t)NULL; +} + +void meson_rdma_setup(struct meson_drm *priv) +{ + /* Channel 1: Write Flag, No Address Increment */ + writel_bits_relaxed(RDMA_ACCESS_RW_FLAG_CHAN1 | + RDMA_ACCESS_ADDR_INC_CHAN1, + RDMA_ACCESS_RW_FLAG_CHAN1, + priv->io_base + _REG(RDMA_ACCESS_AUTO)); +} + +void meson_rdma_stop(struct meson_drm *priv) +{ + writel_bits_relaxed(RDMA_IRQ_CLEAR_CHAN1, + RDMA_IRQ_CLEAR_CHAN1, + priv->io_base + _REG(RDMA_CTRL)); + + /* Stop Channel 1 */ + writel_bits_relaxed(RDMA_ACCESS_TRIGGER_CHAN1, + FIELD_PREP(RDMA_ACCESS_ADDR_INC_CHAN1, + RDMA_ACCESS_TRIGGER_STOP), + priv->io_base + _REG(RDMA_ACCESS_AUTO)); +} + +void meson_rdma_reset(struct meson_drm *priv) +{ + meson_rdma_stop(priv); + + priv->rdma.offset = 0; +} + +static void meson_rdma_writel(struct meson_drm *priv, uint32_t val, + uint32_t reg) +{ + if (priv->rdma.offset >= (SZ_4K / RDMA_DESC_SIZE)) { + dev_warn_once(priv->dev, "%s: overflow\n", __func__); + return; + } + + priv->rdma.addr[priv->rdma.offset++] = reg; + priv->rdma.addr[priv->rdma.offset++] = val; +} + +/* + * This will add the register to the RDMA buffer and write it to the + * hardware at the same time. + * When meson_rdma_flush is called, the RDMA will replay the register + * writes in order. + */ +void meson_rdma_writel_sync(struct meson_drm *priv, uint32_t val, uint32_t reg) +{ + meson_rdma_writel(priv, val, reg); + + writel_relaxed(val, priv->io_base + _REG(reg)); +} + +void meson_rdma_flush(struct meson_drm *priv) +{ + meson_rdma_stop(priv); + + /* Start of Channel 1 register writes buffer */ + writel(priv->rdma.addr_phys, + priv->io_base + _REG(RDMA_AHB_START_ADDR_1)); + + /* Last byte on Channel 1 register writes buffer */ + writel(priv->rdma.addr_phys + (priv->rdma.offset * RDMA_DESC_SIZE) - 1, + priv->io_base + _REG(RDMA_AHB_END_ADDR_1)); + + /* Trigger Channel 1 on VSYNC event */ + writel_bits_relaxed(RDMA_ACCESS_TRIGGER_CHAN1, + FIELD_PREP(RDMA_ACCESS_TRIGGER_CHAN1, + RDMA_ACCESS_TRIGGER_VSYNC), + priv->io_base + _REG(RDMA_ACCESS_AUTO)); + + priv->rdma.offset = 0; +} diff --git a/drivers/gpu/drm/meson/meson_rdma.h b/drivers/gpu/drm/meson/meson_rdma.h new file mode 100644 index 0000000000000000000000000000000000000000..3870bff7b47fad9d4adbc70db8f2bfa955532d07 --- /dev/null +++ b/drivers/gpu/drm/meson/meson_rdma.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2019 BayLibre, SAS + * Author: Neil Armstrong + */ + +#ifndef __MESON_RDMA_H +#define __MESON_RDMA_H + +#include "meson_drv.h" + +int meson_rdma_init(struct meson_drm *priv); +void meson_rdma_free(struct meson_drm *priv); +void meson_rdma_setup(struct meson_drm *priv); +void meson_rdma_reset(struct meson_drm *priv); +void meson_rdma_stop(struct meson_drm *priv); + +void meson_rdma_writel_sync(struct meson_drm *priv, uint32_t val, uint32_t reg); +void meson_rdma_flush(struct meson_drm *priv); + +#endif /* __MESON_RDMA_H */ diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h index 05fce48ceee0df57eba349df48aa92031b3c6427..8ea00546cd4e29187ee29ed9889505a258532a3e 100644 --- a/drivers/gpu/drm/meson/meson_registers.h +++ b/drivers/gpu/drm/meson/meson_registers.h @@ -138,19 +138,25 @@ #define VIU_ADDR_START 0x1a00 #define VIU_ADDR_END 0x1aff #define VIU_SW_RESET 0x1a01 +#define VIU_SW_RESET_OSD1_AFBCD BIT(31) +#define VIU_SW_RESET_G12A_OSD1_AFBCD BIT(21) +#define VIU_SW_RESET_G12A_AFBC_ARB BIT(19) #define VIU_SW_RESET_OSD1 BIT(0) #define VIU_MISC_CTRL0 0x1a06 #define VIU_CTRL0_VD1_AFBC_MASK 0x170000 #define VIU_MISC_CTRL1 0x1a07 +#define MALI_AFBC_MISC GENMASK(15, 8) #define D2D3_INTF_LENGTH 0x1a08 #define D2D3_INTF_CTRL0 0x1a09 #define VIU_OSD1_CTRL_STAT 0x1a10 #define VIU_OSD1_OSD_BLK_ENABLE BIT(0) +#define VIU_OSD1_OSD_MEM_MODE_LINEAR BIT(2) #define VIU_OSD1_POSTBLD_SRC_VD1 (1 << 8) #define VIU_OSD1_POSTBLD_SRC_VD2 (2 << 8) #define VIU_OSD1_POSTBLD_SRC_OSD1 (3 << 8) #define VIU_OSD1_POSTBLD_SRC_OSD2 (4 << 8) #define VIU_OSD1_OSD_ENABLE BIT(21) +#define VIU_OSD1_CFG_SYN_EN BIT(31) #define VIU_OSD1_CTRL_STAT2 0x1a2d #define VIU_OSD1_COLOR_ADDR 0x1a11 #define VIU_OSD1_COLOR 0x1a12 @@ -181,6 +187,16 @@ #define VIU_OSD1_FIFO_CTRL_STAT 0x1a2b #define VIU_OSD1_TEST_RDDATA 0x1a2c #define VIU_OSD1_PROT_CTRL 0x1a2e +#define VIU_OSD1_MALI_UNPACK_CTRL 0x1a2f +#define VIU_OSD1_MALI_UNPACK_EN BIT(31) +#define VIU_OSD1_MALI_AFBCD_R_REORDER GENMASK(15, 12) +#define VIU_OSD1_MALI_AFBCD_G_REORDER GENMASK(11, 8) +#define VIU_OSD1_MALI_AFBCD_B_REORDER GENMASK(7, 4) +#define VIU_OSD1_MALI_AFBCD_A_REORDER GENMASK(3, 0) +#define VIU_OSD1_MALI_REORDER_R 1 +#define VIU_OSD1_MALI_REORDER_G 2 +#define VIU_OSD1_MALI_REORDER_B 3 +#define VIU_OSD1_MALI_REORDER_A 4 #define VIU_OSD2_CTRL_STAT 0x1a30 #define VIU_OSD2_CTRL_STAT2 0x1a4d #define VIU_OSD2_COLOR_ADDR 0x1a31 @@ -1195,11 +1211,59 @@ #define RDMA_AHB_START_ADDR_7 0x110e #define RDMA_AHB_END_ADDR_7 0x110f #define RDMA_ACCESS_AUTO 0x1110 +#define RDMA_ACCESS_TRIGGER_CHAN3 GENMASK(31, 24) +#define RDMA_ACCESS_TRIGGER_CHAN2 GENMASK(23, 16) +#define RDMA_ACCESS_TRIGGER_CHAN1 GENMASK(15, 8) +#define RDMA_ACCESS_TRIGGER_STOP 0 +#define RDMA_ACCESS_TRIGGER_VSYNC 1 +#define RDMA_ACCESS_TRIGGER_LINE 32 +#define RDMA_ACCESS_RW_FLAG_CHAN3 BIT(7) +#define RDMA_ACCESS_RW_FLAG_CHAN2 BIT(6) +#define RDMA_ACCESS_RW_FLAG_CHAN1 BIT(5) +#define RDMA_ACCESS_ADDR_INC_CHAN3 BIT(3) +#define RDMA_ACCESS_ADDR_INC_CHAN2 BIT(2) +#define RDMA_ACCESS_ADDR_INC_CHAN1 BIT(1) #define RDMA_ACCESS_AUTO2 0x1111 +#define RDMA_ACCESS_RW_FLAG_CHAN7 BIT(7) +#define RDMA_ACCESS_RW_FLAG_CHAN6 BIT(6) +#define RDMA_ACCESS_RW_FLAG_CHAN5 BIT(5) +#define RDMA_ACCESS_RW_FLAG_CHAN4 BIT(4) +#define RDMA_ACCESS_ADDR_INC_CHAN7 BIT(3) +#define RDMA_ACCESS_ADDR_INC_CHAN6 BIT(2) +#define RDMA_ACCESS_ADDR_INC_CHAN5 BIT(1) +#define RDMA_ACCESS_ADDR_INC_CHAN4 BIT(0) #define RDMA_ACCESS_AUTO3 0x1112 +#define RDMA_ACCESS_TRIGGER_CHAN7 GENMASK(31, 24) +#define RDMA_ACCESS_TRIGGER_CHAN6 GENMASK(23, 16) +#define RDMA_ACCESS_TRIGGER_CHAN5 GENMASK(15, 8) +#define RDMA_ACCESS_TRIGGER_CHAN4 GENMASK(7, 0) #define RDMA_ACCESS_MAN 0x1113 +#define RDMA_ACCESS_MAN_RW_FLAG BIT(2) +#define RDMA_ACCESS_MAN_ADDR_INC BIT(1) +#define RDMA_ACCESS_MAN_START BIT(0) #define RDMA_CTRL 0x1114 +#define RDMA_IRQ_CLEAR_CHAN7 BIT(31) +#define RDMA_IRQ_CLEAR_CHAN6 BIT(30) +#define RDMA_IRQ_CLEAR_CHAN5 BIT(29) +#define RDMA_IRQ_CLEAR_CHAN4 BIT(28) +#define RDMA_IRQ_CLEAR_CHAN3 BIT(27) +#define RDMA_IRQ_CLEAR_CHAN2 BIT(26) +#define RDMA_IRQ_CLEAR_CHAN1 BIT(25) +#define RDMA_IRQ_CLEAR_CHAN_MAN BIT(24) +#define RDMA_DEFAULT_CONFIG (BIT(7) | BIT(6)) +#define RDMA_CTRL_AHB_WR_BURST GENMASK(5, 4) +#define RDMA_CTRL_AHB_RD_BURST GENMASK(3, 2) +#define RDMA_CTRL_SW_RESET BIT(1) +#define RDMA_CTRL_FREE_CLK_EN BIT(0) #define RDMA_STATUS 0x1115 +#define RDMA_IRQ_STAT_CHAN7 BIT(31) +#define RDMA_IRQ_STAT_CHAN6 BIT(30) +#define RDMA_IRQ_STAT_CHAN5 BIT(29) +#define RDMA_IRQ_STAT_CHAN4 BIT(28) +#define RDMA_IRQ_STAT_CHAN3 BIT(27) +#define RDMA_IRQ_STAT_CHAN2 BIT(26) +#define RDMA_IRQ_STAT_CHAN1 BIT(25) +#define RDMA_IRQ_STAT_CHAN_MAN BIT(24) #define RDMA_STATUS2 0x1116 #define RDMA_STATUS3 0x1117 #define L_GAMMA_CNTL_PORT 0x1400 @@ -1595,15 +1659,33 @@ /* osd afbcd on gxtvbb */ #define OSD1_AFBCD_ENABLE 0x31a0 +#define OSD1_AFBCD_ID_FIFO_THRD GENMASK(15, 9) +#define OSD1_AFBCD_DEC_ENABLE BIT(8) +#define OSD1_AFBCD_FRM_START BIT(0) #define OSD1_AFBCD_MODE 0x31a1 +#define OSD1_AFBCD_SOFT_RESET BIT(31) +#define OSD1_AFBCD_AXI_REORDER_MODE BIT(28) +#define OSD1_AFBCD_MIF_URGENT GENMASK(25, 24) +#define OSD1_AFBCD_HOLD_LINE_NUM GENMASK(22, 16) +#define OSD1_AFBCD_RGBA_EXCHAN_CTRL GENMASK(15, 8) +#define OSD1_AFBCD_HREG_BLOCK_SPLIT BIT(6) +#define OSD1_AFBCD_HREG_HALF_BLOCK BIT(5) +#define OSD1_AFBCD_HREG_PIXEL_PACKING_FMT GENMASK(4, 0) #define OSD1_AFBCD_SIZE_IN 0x31a2 +#define OSD1_AFBCD_HREG_VSIZE_IN GENMASK(31, 16) +#define OSD1_AFBCD_HREG_HSIZE_IN GENMASK(15, 0) #define OSD1_AFBCD_HDR_PTR 0x31a3 #define OSD1_AFBCD_FRAME_PTR 0x31a4 #define OSD1_AFBCD_CHROMA_PTR 0x31a5 #define OSD1_AFBCD_CONV_CTRL 0x31a6 +#define OSD1_AFBCD_CONV_LBUF_LEN GENMASK(15, 0) #define OSD1_AFBCD_STATUS 0x31a8 #define OSD1_AFBCD_PIXEL_HSCOPE 0x31a9 +#define OSD1_AFBCD_DEC_PIXEL_BGN_H GENMASK(31, 16) +#define OSD1_AFBCD_DEC_PIXEL_END_H GENMASK(15, 0) #define OSD1_AFBCD_PIXEL_VSCOPE 0x31aa +#define OSD1_AFBCD_DEC_PIXEL_BGN_V GENMASK(31, 16) +#define OSD1_AFBCD_DEC_PIXEL_END_V GENMASK(15, 0) /* add for gxm and 962e dv core2 */ #define DOLBY_CORE2A_SWAP_CTRL1 0x3434 @@ -1615,12 +1697,34 @@ #define VPU_MAFBC_IRQ_CLEAR 0x3a02 #define VPU_MAFBC_IRQ_MASK 0x3a03 #define VPU_MAFBC_IRQ_STATUS 0x3a04 +#define VPU_MAFBC_IRQ_SECURE_ID_ERROR BIT(5) +#define VPU_MAFBC_IRQ_AXI_ERROR BIT(4) +#define VPU_MAFBC_IRQ_DETILING_ERROR BIT(3) +#define VPU_MAFBC_IRQ_DECODE_ERROR BIT(2) +#define VPU_MAFBC_IRQ_CONFIGURATION_SWAPPED BIT(1) +#define VPU_MAFBC_IRQ_SURFACES_COMPLETED BIT(0) #define VPU_MAFBC_COMMAND 0x3a05 +#define VPU_MAFBC_PENDING_SWAP BIT(1) +#define VPU_MAFBC_DIRECT_SWAP BIT(0) #define VPU_MAFBC_STATUS 0x3a06 +#define VPU_MAFBC_ERROR BIT(2) +#define VPU_MAFBC_SWAPPING BIT(1) +#define VPU_MAFBC_ACTIVE BIT(0) #define VPU_MAFBC_SURFACE_CFG 0x3a07 +#define VPU_MAFBC_CONTINUOUS_DECODING_ENABLE BIT(16) +#define VPU_MAFBC_S3_ENABLE BIT(3) +#define VPU_MAFBC_S2_ENABLE BIT(2) +#define VPU_MAFBC_S1_ENABLE BIT(1) +#define VPU_MAFBC_S0_ENABLE BIT(0) #define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0 0x3a10 #define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0 0x3a11 #define VPU_MAFBC_FORMAT_SPECIFIER_S0 0x3a12 +#define VPU_MAFBC_PAYLOAD_LIMIT_EN BIT(19) +#define VPU_MAFBC_TILED_HEADER_EN BIT(18) +#define VPU_MAFBC_SUPER_BLOCK_ASPECT GENMASK(17, 16) +#define VPU_MAFBC_BLOCK_SPLIT BIT(9) +#define VPU_MAFBC_YUV_TRANSFORM BIT(8) +#define VPU_MAFBC_PIXEL_FORMAT GENMASK(3, 0) #define VPU_MAFBC_BUFFER_WIDTH_S0 0x3a13 #define VPU_MAFBC_BUFFER_HEIGHT_S0 0x3a14 #define VPU_MAFBC_BOUNDING_BOX_X_START_S0 0x3a15 @@ -1631,6 +1735,8 @@ #define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0 0x3a1a #define VPU_MAFBC_OUTPUT_BUF_STRIDE_S0 0x3a1b #define VPU_MAFBC_PREFETCH_CFG_S0 0x3a1c +#define VPU_MAFBC_PREFETCH_READ_DIRECTION_Y BIT(1) +#define VPU_MAFBC_PREFETCH_READ_DIRECTION_X BIT(0) #define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S1 0x3a30 #define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S1 0x3a31 @@ -1677,7 +1783,11 @@ #define DOLBY_PATH_CTRL 0x1a0c #define DOLBY_BYPASS_EN(val) (val & 0xf) #define OSD_PATH_MISC_CTRL 0x1a0e +#define OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD BIT(4) +#define OSD_PATH_OSD_AXI_SEL_OSD2_AFBCD BIT(5) +#define OSD_PATH_OSD_AXI_SEL_OSD3_AFBCD BIT(6) #define MALI_AFBCD_TOP_CTRL 0x1a0f +#define MALI_AFBCD_MANUAL_RESET BIT(23) #define VIU_OSD_BLEND_CTRL 0x39b0 #define VIU_OSD_BLEND_REORDER(dest, src) ((src) << (dest * 4)) diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c index 9ab27aecfcf313b04d7158d6dc6de230b9a7b91c..1bd6b6d15ffb304d38c9cb3bfb718e2964e7a75f 100644 --- a/drivers/gpu/drm/meson/meson_venc_cvbs.c +++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c @@ -64,6 +64,25 @@ struct meson_cvbs_mode meson_cvbs_modes[MESON_CVBS_MODES_COUNT] = { }, }; +static const struct meson_cvbs_mode * +meson_cvbs_get_mode(const struct drm_display_mode *req_mode) +{ + int i; + + for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) { + struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i]; + + if (drm_mode_match(req_mode, &meson_mode->mode, + DRM_MODE_MATCH_TIMINGS | + DRM_MODE_MATCH_CLOCK | + DRM_MODE_MATCH_FLAGS | + DRM_MODE_MATCH_3D_FLAGS)) + return meson_mode; + } + + return NULL; +} + /* Connector */ static void meson_cvbs_connector_destroy(struct drm_connector *connector) @@ -136,14 +155,8 @@ static int meson_venc_cvbs_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { - int i; - - for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) { - struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i]; - - if (drm_mode_equal(&crtc_state->mode, &meson_mode->mode)) - return 0; - } + if (meson_cvbs_get_mode(&crtc_state->mode)) + return 0; return -EINVAL; } @@ -191,24 +204,17 @@ static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + const struct meson_cvbs_mode *meson_mode = meson_cvbs_get_mode(mode); struct meson_venc_cvbs *meson_venc_cvbs = encoder_to_meson_venc_cvbs(encoder); struct meson_drm *priv = meson_venc_cvbs->priv; - int i; - for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) { - struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i]; + if (meson_mode) { + meson_venci_cvbs_mode_set(priv, meson_mode->enci); - if (drm_mode_equal(mode, &meson_mode->mode)) { - meson_venci_cvbs_mode_set(priv, - meson_mode->enci); - - /* Setup 27MHz vclk2 for ENCI and VDAC */ - meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS, - MESON_VCLK_CVBS, MESON_VCLK_CVBS, - MESON_VCLK_CVBS, true); - break; - } + /* Setup 27MHz vclk2 for ENCI and VDAC */ + meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS, MESON_VCLK_CVBS, + MESON_VCLK_CVBS, MESON_VCLK_CVBS, true); } } diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c index 68cf2c2eca5fe4ab5153b0d7faca33550748ba4c..304f8ff1339cb6c35acb5e239de5f08b4481ed5b 100644 --- a/drivers/gpu/drm/meson/meson_viu.c +++ b/drivers/gpu/drm/meson/meson_viu.c @@ -7,6 +7,9 @@ */ #include +#include + +#include #include "meson_drv.h" #include "meson_viu.h" @@ -335,6 +338,79 @@ void meson_viu_osd1_reset(struct meson_drm *priv) meson_viu_load_matrix(priv); } +#define OSD1_MALI_ORDER_ABGR \ + (FIELD_PREP(VIU_OSD1_MALI_AFBCD_A_REORDER, \ + VIU_OSD1_MALI_REORDER_A) | \ + FIELD_PREP(VIU_OSD1_MALI_AFBCD_B_REORDER, \ + VIU_OSD1_MALI_REORDER_B) | \ + FIELD_PREP(VIU_OSD1_MALI_AFBCD_G_REORDER, \ + VIU_OSD1_MALI_REORDER_G) | \ + FIELD_PREP(VIU_OSD1_MALI_AFBCD_R_REORDER, \ + VIU_OSD1_MALI_REORDER_R)) + +#define OSD1_MALI_ORDER_ARGB \ + (FIELD_PREP(VIU_OSD1_MALI_AFBCD_A_REORDER, \ + VIU_OSD1_MALI_REORDER_A) | \ + FIELD_PREP(VIU_OSD1_MALI_AFBCD_B_REORDER, \ + VIU_OSD1_MALI_REORDER_R) | \ + FIELD_PREP(VIU_OSD1_MALI_AFBCD_G_REORDER, \ + VIU_OSD1_MALI_REORDER_G) | \ + FIELD_PREP(VIU_OSD1_MALI_AFBCD_R_REORDER, \ + VIU_OSD1_MALI_REORDER_B)) + +void meson_viu_g12a_enable_osd1_afbc(struct meson_drm *priv) +{ + u32 afbc_order = OSD1_MALI_ORDER_ARGB; + + /* Enable Mali AFBC Unpack */ + writel_bits_relaxed(VIU_OSD1_MALI_UNPACK_EN, + VIU_OSD1_MALI_UNPACK_EN, + priv->io_base + _REG(VIU_OSD1_MALI_UNPACK_CTRL)); + + switch (priv->afbcd.format) { + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + afbc_order = OSD1_MALI_ORDER_ABGR; + break; + } + + /* Setup RGBA Reordering */ + writel_bits_relaxed(VIU_OSD1_MALI_AFBCD_A_REORDER | + VIU_OSD1_MALI_AFBCD_B_REORDER | + VIU_OSD1_MALI_AFBCD_G_REORDER | + VIU_OSD1_MALI_AFBCD_R_REORDER, + afbc_order, + priv->io_base + _REG(VIU_OSD1_MALI_UNPACK_CTRL)); + + /* Select AFBCD path for OSD1 */ + writel_bits_relaxed(OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD, + OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD, + priv->io_base + _REG(OSD_PATH_MISC_CTRL)); +} + +void meson_viu_g12a_disable_osd1_afbc(struct meson_drm *priv) +{ + /* Disable AFBCD path for OSD1 */ + writel_bits_relaxed(OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD, 0, + priv->io_base + _REG(OSD_PATH_MISC_CTRL)); + + /* Disable AFBCD unpack */ + writel_bits_relaxed(VIU_OSD1_MALI_UNPACK_EN, 0, + priv->io_base + _REG(VIU_OSD1_MALI_UNPACK_CTRL)); +} + +void meson_viu_gxm_enable_osd1_afbc(struct meson_drm *priv) +{ + writel_bits_relaxed(MALI_AFBC_MISC, FIELD_PREP(MALI_AFBC_MISC, 0x90), + priv->io_base + _REG(VIU_MISC_CTRL1)); +} + +void meson_viu_gxm_disable_osd1_afbc(struct meson_drm *priv) +{ + writel_bits_relaxed(MALI_AFBC_MISC, FIELD_PREP(MALI_AFBC_MISC, 0x00), + priv->io_base + _REG(VIU_MISC_CTRL1)); +} + static inline uint32_t meson_viu_osd_burst_length_reg(uint32_t length) { uint32_t val = (((length & 0x80) % 24) / 12); @@ -362,7 +438,7 @@ void meson_viu_init(struct meson_drm *priv) /* Initialize OSD1 fifo control register */ reg = VIU_OSD_DDR_PRIORITY_URGENT | - VIU_OSD_HOLD_FIFO_LINES(4) | + VIU_OSD_HOLD_FIFO_LINES(31) | VIU_OSD_FIFO_DEPTH_VAL(32) | /* fifo_depth_val: 32*8=256 */ VIU_OSD_WORDS_PER_BURST(4) | /* 4 words in 1 burst */ VIU_OSD_FIFO_LIMITS(2); /* fifo_lim: 2*16=32 */ @@ -420,8 +496,13 @@ void meson_viu_init(struct meson_drm *priv) writel_bits_relaxed(DOLBY_BYPASS_EN(0xc), DOLBY_BYPASS_EN(0xc), priv->io_base + _REG(DOLBY_PATH_CTRL)); + + meson_viu_g12a_disable_osd1_afbc(priv); } + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) + meson_viu_gxm_disable_osd1_afbc(priv); + priv->viu.osd1_enabled = false; priv->viu.osd1_commit = false; priv->viu.osd1_interlace = false; diff --git a/drivers/gpu/drm/meson/meson_viu.h b/drivers/gpu/drm/meson/meson_viu.h index a112e8d18850c7978d9e5db0e4d66bf690b018f2..e4a2f24d7c384d1bc4dcd59ccc2b056f5f978ff7 100644 --- a/drivers/gpu/drm/meson/meson_viu.h +++ b/drivers/gpu/drm/meson/meson_viu.h @@ -10,6 +10,8 @@ #define __MESON_VIU_H /* OSDx_BLKx_CFG */ +#define OSD_MALI_SRC_EN BIT(30) + #define OSD_CANVAS_SEL 16 #define OSD_ENDIANNESS_LE BIT(15) @@ -33,21 +35,38 @@ #define OSD_COLOR_MATRIX_16_RGB655 (0x00 << 2) #define OSD_COLOR_MATRIX_16_RGB565 (0x04 << 2) +#define OSD_MALI_COLOR_MODE_R8 (0 << 8) +#define OSD_MALI_COLOR_MODE_YUV422 (1 << 8) +#define OSD_MALI_COLOR_MODE_RGB565 (2 << 8) +#define OSD_MALI_COLOR_MODE_RGBA5551 (3 << 8) +#define OSD_MALI_COLOR_MODE_RGBA4444 (4 << 8) +#define OSD_MALI_COLOR_MODE_RGBA8888 (5 << 8) +#define OSD_MALI_COLOR_MODE_RGB888 (7 << 8) +#define OSD_MALI_COLOR_MODE_YUV422_10B (8 << 8) +#define OSD_MALI_COLOR_MODE_RGBA1010102 (9 << 8) + #define OSD_INTERLACE_ENABLED BIT(1) #define OSD_INTERLACE_ODD BIT(0) #define OSD_INTERLACE_EVEN (0) /* OSDx_CTRL_STAT */ #define OSD_ENABLE BIT(21) +#define OSD_MEM_LINEAR_ADDR BIT(2) #define OSD_BLK0_ENABLE BIT(0) #define OSD_GLOBAL_ALPHA_SHIFT 12 /* OSDx_CTRL_STAT2 */ +#define OSD_DPATH_MALI_AFBCD BIT(15) #define OSD_REPLACE_EN BIT(14) #define OSD_REPLACE_SHIFT 6 +#define OSD_PENDING_STAT_CLEAN BIT(1) void meson_viu_osd1_reset(struct meson_drm *priv); +void meson_viu_g12a_enable_osd1_afbc(struct meson_drm *priv); +void meson_viu_g12a_disable_osd1_afbc(struct meson_drm *priv); +void meson_viu_gxm_enable_osd1_afbc(struct meson_drm *priv); +void meson_viu_gxm_disable_osd1_afbc(struct meson_drm *priv); void meson_viu_init(struct meson_drm *priv); #endif /* __MESON_VIU_H */ diff --git a/drivers/gpu/drm/mga/mga_drv.h b/drivers/gpu/drm/mga/mga_drv.h index d5deecb93975304ea5c160c07d460344a08156cd..66df5160789683d715a55f590d75343c1b438127 100644 --- a/drivers/gpu/drm/mga/mga_drv.h +++ b/drivers/gpu/drm/mga/mga_drv.h @@ -32,6 +32,7 @@ #define __MGA_DRV_H__ #include +#include #include #include @@ -40,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/mgag200/Kconfig b/drivers/gpu/drm/mgag200/Kconfig index aed11f4f4c55e84c4d769f7ae1a62c1dd6ba40b4..d60aa4b9ccd470d94f95737b73a76be4994e3f1d 100644 --- a/drivers/gpu/drm/mgag200/Kconfig +++ b/drivers/gpu/drm/mgag200/Kconfig @@ -8,8 +8,8 @@ config DRM_MGAG200 select DRM_TTM_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. + 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. diff --git a/drivers/gpu/drm/mgag200/mgag200_cursor.c b/drivers/gpu/drm/mgag200/mgag200_cursor.c index 79711dbb5b03231558c47b34f190007822762e1f..d491edd317ff31c6ab97baecf47d253f4e4c4237 100644 --- a/drivers/gpu/drm/mgag200/mgag200_cursor.c +++ b/drivers/gpu/drm/mgag200/mgag200_cursor.c @@ -5,7 +5,7 @@ * Author: Christopher Harvey */ -#include +#include #include "mgag200_drv.h" @@ -208,8 +208,7 @@ int mgag200_cursor_init(struct mga_device *mdev) return -ENOMEM; for (i = 0; i < ncursors; ++i) { - gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev, - size, 0, false); + gbo = drm_gem_vram_create(dev, size, 0); if (IS_ERR(gbo)) { ret = PTR_ERR(gbo); goto err_drm_gem_vram_put; diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index d43951caeea02b43cd740ee95c491b63d09c4e37..7a5bad2f57d70bbe838a46c8e29f800e4466f313 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -6,13 +6,13 @@ * Dave Airlie */ -#include #include +#include +#include #include #include #include -#include #include #include "mgag200_drv.h" @@ -27,12 +27,15 @@ int mgag200_modeset = -1; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, mgag200_modeset, int, 0400); +int mgag200_hw_bug_no_startadd = -1; +MODULE_PARM_DESC(modeset, "HW does not interpret scanout-buffer start address correctly"); +module_param_named(hw_bug_no_startadd, mgag200_hw_bug_no_startadd, int, 0400); + static struct drm_driver driver; static const struct pci_device_id pciidlist[] = { - { PCI_VENDOR_ID_MATROX, 0x522, PCI_VENDOR_ID_SUN, 0x4852, 0, 0, + { 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, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_A }, { PCI_VENDOR_ID_MATROX, 0x524, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_B }, { PCI_VENDOR_ID_MATROX, 0x530, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EV }, { PCI_VENDOR_ID_MATROX, 0x532, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_WB }, @@ -48,22 +51,66 @@ MODULE_DEVICE_TABLE(pci, pciidlist); static int mga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + struct drm_device *dev; + int ret; + drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "mgag200drmfb"); - return drm_get_pci_dev(pdev, ent, &driver); + ret = pci_enable_device(pdev); + if (ret) + return ret; + + dev = drm_dev_alloc(&driver, &pdev->dev); + if (IS_ERR(dev)) { + ret = PTR_ERR(dev); + goto err_pci_disable_device; + } + + dev->pdev = pdev; + pci_set_drvdata(pdev, dev); + + ret = mgag200_driver_load(dev, ent->driver_data); + if (ret) + goto err_drm_dev_put; + + ret = drm_dev_register(dev, ent->driver_data); + if (ret) + goto err_mgag200_driver_unload; + + return 0; + +err_mgag200_driver_unload: + mgag200_driver_unload(dev); +err_drm_dev_put: + drm_dev_put(dev); +err_pci_disable_device: + pci_disable_device(pdev); + return ret; } static void mga_pci_remove(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); - drm_put_dev(dev); + drm_dev_unregister(dev); + mgag200_driver_unload(dev); + drm_dev_put(dev); } DEFINE_DRM_GEM_FOPS(mgag200_driver_fops); static bool mgag200_pin_bo_at_0(const struct mga_device *mdev) { + if (mgag200_hw_bug_no_startadd > 0) { + DRM_WARN_ONCE("Option hw_bug_no_startradd is enabled. Please " + "report the output of 'lspci -vvnn' to " + " if this " + "option is required to make mgag200 work " + "correctly on your system.\n"); + return true; + } else if (!mgag200_hw_bug_no_startadd) { + return false; + } return mdev->flags & MGAG200_FLAG_HW_BUG_NO_STARTADD; } @@ -87,14 +134,11 @@ int mgag200_driver_dumb_create(struct drm_file *file, if (mgag200_pin_bo_at_0(mdev)) pg_align = PFN_UP(mdev->mc.vram_size); - return drm_gem_vram_fill_create_dumb(file, dev, &dev->vram_mm->bdev, - pg_align, false, args); + return drm_gem_vram_fill_create_dumb(file, dev, pg_align, 0, args); } static struct drm_driver driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET, - .load = mgag200_driver_load, - .unload = mgag200_driver_unload, .fops = &mgag200_driver_fops, .name = DRIVER_NAME, .desc = DRIVER_DESC, diff --git a/drivers/gpu/drm/mgag200/mgag200_i2c.c b/drivers/gpu/drm/mgag200/mgag200_i2c.c index 51d4037f00d4a4b236fed2110ad6b1b2ee6a0ec7..9f4635916d32252833af5664e02fdf7716a97d32 100644 --- a/drivers/gpu/drm/mgag200/mgag200_i2c.c +++ b/drivers/gpu/drm/mgag200/mgag200_i2c.c @@ -29,8 +29,7 @@ #include #include #include - -#include +#include #include "mgag200_drv.h" diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c index e1bc5b0aa7742661407881aa9adbd4843471a4bf..e278b6a547bde6fb8e3b8e3b5f7b93f9e8348d56 100644 --- a/drivers/gpu/drm/mgag200/mgag200_main.c +++ b/drivers/gpu/drm/mgag200/mgag200_main.c @@ -8,9 +8,10 @@ * Dave Airlie */ +#include + #include #include -#include #include "mgag200_drv.h" @@ -118,8 +119,11 @@ static int mgag200_device_init(struct drm_device *dev, return -ENOMEM; /* stash G200 SE model number for later use */ - if (IS_G200_SE(mdev)) + if (IS_G200_SE(mdev)) { mdev->unique_rev_id = RREG32(0x1e24); + DRM_DEBUG("G200 SE unique revision id is 0x%x\n", + mdev->unique_rev_id); + } ret = mga_vram_init(mdev); if (ret) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 5ec697148fc177de5868087b27cb1aa60412d11b..62a8e9ccb16dcc8ce226224c17030b4b170ebea9 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -9,10 +9,10 @@ */ #include +#include #include #include -#include #include #include diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index 99997d73736225df671cfcc46d89a394b0d18353..e89657630ea711ad5596e3f2fcdfb8d5a165daa8 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -26,7 +26,7 @@ * Authors: Dave Airlie */ -#include +#include #include "mgag200_drv.h" 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 9262ed2dc8c3631b3917c24c090b85786fa6e7bb..c7df71e2fafca2df22773b77e020295d92ee6f4c 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c @@ -53,7 +53,7 @@ static int mdp4_lvds_connector_get_modes(struct drm_connector *connector) if (panel) { drm_panel_attach(panel, connector); - ret = panel->funcs->get_modes(panel); + ret = drm_panel_get_modes(panel, connector); drm_panel_detach(panel); } diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 271aa7bbca925fd95de80964aed83c0cd9fce240..0fc29f1be8cc6ddb4b02aac6be4bc66b8aec3741 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -329,7 +329,7 @@ static int dsi_mgr_connector_get_modes(struct drm_connector *connector) * attached to the drm_panel. */ drm_panel_attach(panel, connector); - num = drm_panel_get_modes(panel); + num = drm_panel_get_modes(panel, connector); if (!num) return 0; diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c index 2950bba4aca98ebcc2700e521148610669af9733..b65b5cc2dba2d8a14d00ddf5863fd4ba15a28c92 100644 --- a/drivers/gpu/drm/msm/edp/edp_bridge.c +++ b/drivers/gpu/drm/msm/edp/edp_bridge.c @@ -55,8 +55,14 @@ static void edp_bridge_mode_set(struct drm_bridge *bridge, DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if ((connector->encoder != NULL) && - (connector->encoder->bridge == bridge)) { + struct drm_encoder *encoder = connector->encoder; + struct drm_bridge *first_bridge; + + if (!connector->encoder) + continue; + + first_bridge = drm_bridge_chain_get_first_bridge(encoder); + if (bridge == first_bridge) { msm_edp_ctrl_timing_cfg(edp->ctrl, adjusted_mode, &connector->display_info); break; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c index 839822d894d0f866ce25105fce257d4067cbaa3e..59702684d576c3a7eb49f7542188705b938b35cb 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c @@ -433,8 +433,10 @@ struct drm_connector *msm_hdmi_connector_init(struct hdmi *hdmi) connector = &hdmi_connector->base; - drm_connector_init(hdmi->dev, connector, &hdmi_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA); + drm_connector_init_with_ddc(hdmi->dev, connector, + &hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA, + hdmi->i2c); drm_connector_helper_add(connector, &msm_hdmi_connector_helper_funcs); connector->polled = DRM_CONNECTOR_POLL_CONNECT | diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index cff198b2f47001453177184316b65d5f19f62c2c..db48867df47dd2a785b273bc4ead0b7aa7ec7ec5 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -26,7 +26,7 @@ struct msm_fbdev { struct drm_framebuffer *fb; }; -static struct fb_ops msm_fb_ops = { +static const struct fb_ops msm_fb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index be5327af16faaa267756c9559b2591a20bec2650..385d4965a8d0755c917a1466e793190db0656a9e 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -54,7 +54,6 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, INIT_LIST_HEAD(&submit->node); INIT_LIST_HEAD(&submit->bo_list); - ww_acquire_init(&submit->ticket, &reservation_ww_class); return submit; } @@ -158,7 +157,7 @@ static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, msm_gem_unpin_iova(&msm_obj->base, submit->aspace); if (submit->bos[i].flags & BO_LOCKED) - ww_mutex_unlock(&msm_obj->base.resv->lock); + dma_resv_unlock(msm_obj->base.resv); if (backoff && !(submit->bos[i].flags & BO_VALID)) submit->bos[i].iova = 0; @@ -181,8 +180,8 @@ retry: contended = i; if (!(submit->bos[i].flags & BO_LOCKED)) { - ret = ww_mutex_lock_interruptible(&msm_obj->base.resv->lock, - &submit->ticket); + ret = dma_resv_lock_interruptible(msm_obj->base.resv, + &submit->ticket); if (ret) goto fail; submit->bos[i].flags |= BO_LOCKED; @@ -203,8 +202,8 @@ fail: if (ret == -EDEADLK) { struct msm_gem_object *msm_obj = submit->bos[contended].obj; /* we lost out in a seqno race, lock and retry.. */ - ret = ww_mutex_lock_slow_interruptible(&msm_obj->base.resv->lock, - &submit->ticket); + ret = dma_resv_lock_slow_interruptible(msm_obj->base.resv, + &submit->ticket); if (!ret) { submit->bos[contended].flags |= BO_LOCKED; slow_locked = contended; @@ -390,8 +389,6 @@ static void submit_cleanup(struct msm_gem_submit *submit) list_del_init(&msm_obj->submit_entry); drm_gem_object_put(&msm_obj->base); } - - ww_acquire_fini(&submit->ticket); } int msm_ioctl_gem_submit(struct drm_device *dev, void *data, @@ -408,6 +405,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct msm_ringbuffer *ring; int out_fence_fd = -1; struct pid *pid = get_pid(task_pid(current)); + bool has_ww_ticket = false; unsigned i; int ret, submitid; if (!gpu) @@ -489,6 +487,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (ret) goto out; + /* copy_*_user while holding a ww ticket upsets lockdep */ + ww_acquire_init(&submit->ticket, &reservation_ww_class); + has_ww_ticket = true; ret = submit_lock_objects(submit); if (ret) goto out; @@ -588,6 +589,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, out: submit_cleanup(submit); + if (has_ww_ticket) + ww_acquire_fini(&submit->ticket); if (ret) msm_gem_submit_free(submit); out_unlock: diff --git a/drivers/gpu/drm/mxsfb/mxsfb_out.c b/drivers/gpu/drm/mxsfb/mxsfb_out.c index 4eb94744c526322000098bcac69e01f28820e232..9eca1605d11d69f37b2613de989ea01271d09e09 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_out.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_out.c @@ -31,7 +31,7 @@ static int mxsfb_panel_get_modes(struct drm_connector *connector) drm_connector_to_mxsfb_drm_private(connector); if (mxsfb->panel) - return drm_panel_get_modes(mxsfb->panel); + return drm_panel_get_modes(mxsfb->panel, connector); return 0; } diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index 3558df043592c0a29ca7b88fcf61826400ae6a26..9c990266e8768674dc18c8fdf0bd0343265a9044 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -2,7 +2,7 @@ config DRM_NOUVEAU tristate "Nouveau (NVIDIA) cards" depends on DRM && PCI && MMU - select FW_LOADER + select FW_LOADER select DRM_KMS_HELPER select DRM_TTM select BACKLIGHT_CLASS_DEVICE if DRM_NOUVEAU_BACKLIGHT diff --git a/drivers/gpu/drm/nouveau/dispnv50/atom.h b/drivers/gpu/drm/nouveau/dispnv50/atom.h index 43df86c38f58bcf061491cb718f66e215db40a7c..24f7700768dab9a7d715ff1b2de867eef4f4f9b7 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/atom.h +++ b/drivers/gpu/drm/nouveau/dispnv50/atom.h @@ -114,6 +114,7 @@ struct nv50_head_atom { u8 nhsync:1; u8 nvsync:1; u8 depth:4; + u8 bpc; } or; /* Currently only used for MST */ diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 549486f1d93760a51c28bf10948e62a86613c428..63425e24601896cb31238ddbcba0b9b7fae03e41 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -326,9 +326,9 @@ nv50_outp_atomic_check_view(struct drm_encoder *encoder, * same size as the native one (e.g. different * refresh rate) */ - if (adjusted_mode->hdisplay == native_mode->hdisplay && - adjusted_mode->vdisplay == native_mode->vdisplay && - adjusted_mode->type & DRM_MODE_TYPE_DRIVER) + if (mode->hdisplay == native_mode->hdisplay && + mode->vdisplay == native_mode->vdisplay && + mode->type & DRM_MODE_TYPE_DRIVER) break; mode = native_mode; asyc->scaler.full = true; @@ -353,10 +353,20 @@ nv50_outp_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { - struct nouveau_connector *nv_connector = - nouveau_connector(conn_state->connector); - return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, - nv_connector->native_mode); + struct drm_connector *connector = conn_state->connector; + struct nouveau_connector *nv_connector = nouveau_connector(connector); + struct nv50_head_atom *asyh = nv50_head_atom(crtc_state); + int ret; + + ret = nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, + nv_connector->native_mode); + if (ret) + return ret; + + if (crtc_state->mode_changed || crtc_state->connectors_changed) + asyh->or.bpc = connector->display_info.bpc; + + return 0; } /****************************************************************************** @@ -770,32 +780,54 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, struct nv50_mstm *mstm = mstc->mstm; struct nv50_head_atom *asyh = nv50_head_atom(crtc_state); int slots; + int ret; + + ret = nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, + mstc->native); + if (ret) + return ret; + + if (!crtc_state->mode_changed && !crtc_state->connectors_changed) + return 0; + + /* + * When restoring duplicated states, we need to make sure that the bw + * remains the same and avoid recalculating it, as the connector's bpc + * may have changed after the state was duplicated + */ + if (!state->duplicated) { + const int clock = crtc_state->adjusted_mode.clock; - if (crtc_state->mode_changed || crtc_state->connectors_changed) { /* - * When restoring duplicated states, we need to make sure that - * the bw remains the same and avoid recalculating it, as the - * connector's bpc may have changed after the state was - * duplicated + * XXX: Since we don't use HDR in userspace quite yet, limit + * the bpc to 8 to save bandwidth on the topology. In the + * future, we'll want to properly fix this by dynamically + * selecting the highest possible bpc that would fit in the + * topology */ - if (!state->duplicated) { - const int bpp = connector->display_info.bpc * 3; - const int clock = crtc_state->adjusted_mode.clock; + asyh->or.bpc = min(connector->display_info.bpc, 8U); + asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3); + } - asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, bpp); - } + slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, mstc->port, + asyh->dp.pbn); + if (slots < 0) + return slots; - slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, - mstc->port, - asyh->dp.pbn); - if (slots < 0) - return slots; + asyh->dp.tu = slots; - asyh->dp.tu = slots; - } + return 0; +} - return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, - mstc->native); +static u8 +nv50_dp_bpc_to_depth(unsigned int bpc) +{ + switch (bpc) { + case 6: return 0x2; + case 8: return 0x5; + case 10: /* fall-through */ + default: return 0x6; + } } static void @@ -808,7 +840,7 @@ nv50_msto_enable(struct drm_encoder *encoder) struct nv50_mstm *mstm = NULL; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; - u8 proto, depth; + u8 proto; bool r; drm_connector_list_iter_begin(encoder->dev, &conn_iter); @@ -837,14 +869,8 @@ nv50_msto_enable(struct drm_encoder *encoder) else proto = 0x9; - switch (mstc->connector.display_info.bpc) { - case 6: depth = 0x2; break; - case 8: depth = 0x5; break; - case 10: - default: depth = 0x6; break; - } - - mstm->outp->update(mstm->outp, head->base.index, armh, proto, depth); + mstm->outp->update(mstm->outp, head->base.index, armh, proto, + nv50_dp_bpc_to_depth(armh->or.bpc)); msto->head = head; msto->mstc = mstc; @@ -1498,20 +1524,14 @@ nv50_sor_enable(struct drm_encoder *encoder) lvds.lvds.script |= 0x0200; } - if (nv_connector->base.display_info.bpc == 8) + if (asyh->or.bpc == 8) lvds.lvds.script |= 0x0200; } nvif_mthd(&disp->disp->object, 0, &lvds, sizeof(lvds)); break; case DCB_OUTPUT_DP: - if (nv_connector->base.display_info.bpc == 6) - depth = 0x2; - else - if (nv_connector->base.display_info.bpc == 8) - depth = 0x5; - else - depth = 0x6; + depth = nv50_dp_bpc_to_depth(asyh->or.bpc); if (nv_encoder->link & 1) proto = 0x8; @@ -1662,7 +1682,7 @@ nv50_pior_enable(struct drm_encoder *encoder) nv50_outp_acquire(nv_encoder); nv_connector = nouveau_encoder_connector_get(nv_encoder); - switch (nv_connector->base.display_info.bpc) { + switch (asyh->or.bpc) { case 10: asyh->or.depth = 0x6; break; case 8: asyh->or.depth = 0x5; break; case 6: asyh->or.depth = 0x2; break; diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.h b/drivers/gpu/drm/nouveau/dispnv50/disp.h index 7c41b0599d1ac10791b71245e4a2b67a957d1169..c0a79531b0873d4242291981ce0ca94840e1258a 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.h +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.h @@ -78,14 +78,14 @@ void evo_kick(u32 *, struct nv50_dmac *); #define evo_mthd(p, m, s) do { \ const u32 _m = (m), _s = (s); \ - if (drm_debug & DRM_UT_KMS) \ + if (drm_debug_enabled(DRM_UT_KMS)) \ pr_err("%04x %d %s\n", _m, _s, __func__); \ *((p)++) = ((_s << 18) | _m); \ } while(0) #define evo_data(p, d) do { \ const u32 _d = (d); \ - if (drm_debug & DRM_UT_KMS) \ + if (drm_debug_enabled(DRM_UT_KMS)) \ pr_err("\t%08x\n", _d); \ *((p)++) = _d; \ } while(0) diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c index 71c23bf1fe25915534fc0b61c46a760f500ce921..c9692df2b76cca51604c0fb008643ff26a972be0 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head.c @@ -81,18 +81,17 @@ nv50_head_atomic_check_dither(struct nv50_head_atom *armh, struct nv50_head_atom *asyh, struct nouveau_conn_atom *asyc) { - struct drm_connector *connector = asyc->state.connector; u32 mode = 0x00; if (asyc->dither.mode == DITHERING_MODE_AUTO) { - if (asyh->base.depth > connector->display_info.bpc * 3) + if (asyh->base.depth > asyh->or.bpc * 3) mode = DITHERING_MODE_DYNAMIC2X2; } else { mode = asyc->dither.mode; } if (asyc->dither.depth == DITHERING_DEPTH_AUTO) { - if (connector->display_info.bpc >= 8) + if (asyh->or.bpc >= 8) mode |= DITHERING_DEPTH_8BPC; } else { mode |= asyc->dither.depth; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 5b413588b82303f805d9093a254655dad91f4d74..9a9a7f5003d3f370fe5f23926a836fd7ad0a6f37 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -245,14 +245,22 @@ nouveau_conn_atomic_duplicate_state(struct drm_connector *connector) void nouveau_conn_reset(struct drm_connector *connector) { + struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_conn_atom *asyc; - if (WARN_ON(!(asyc = kzalloc(sizeof(*asyc), GFP_KERNEL)))) - return; + if (drm_drv_uses_atomic_modeset(connector->dev)) { + if (WARN_ON(!(asyc = kzalloc(sizeof(*asyc), GFP_KERNEL)))) + return; + + if (connector->state) + nouveau_conn_atomic_destroy_state(connector, + connector->state); + + __drm_atomic_helper_connector_reset(connector, &asyc->state); + } else { + asyc = &nv_connector->properties_state; + } - if (connector->state) - nouveau_conn_atomic_destroy_state(connector, connector->state); - __drm_atomic_helper_connector_reset(connector, &asyc->state); asyc->dither.mode = DITHERING_MODE_AUTO; asyc->dither.depth = DITHERING_DEPTH_AUTO; asyc->scaler.mode = DRM_MODE_SCALE_NONE; @@ -276,8 +284,14 @@ void nouveau_conn_attach_properties(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct nouveau_conn_atom *armc = nouveau_conn_atom(connector->state); struct nouveau_display *disp = nouveau_display(dev); + struct nouveau_connector *nv_connector = nouveau_connector(connector); + struct nouveau_conn_atom *armc; + + if (drm_drv_uses_atomic_modeset(connector->dev)) + armc = nouveau_conn_atom(connector->state); + else + armc = &nv_connector->properties_state; /* Init DVI-I specific properties. */ if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) @@ -748,9 +762,9 @@ static int nouveau_connector_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t value) { - struct nouveau_conn_atom *asyc = nouveau_conn_atom(connector->state); struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; + struct nouveau_conn_atom *asyc = &nv_connector->properties_state; struct drm_encoder *encoder = to_drm_encoder(nv_encoder); int ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index f43a8d63aef86e07c7078501ff4bad0e33ba937b..de84fb4708c7ab22f4e5abbf1aa5918500b3bc63 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -29,6 +29,7 @@ #include +#include #include #include #include @@ -44,6 +45,60 @@ struct dcb_output; struct nouveau_backlight; #endif +#define nouveau_conn_atom(p) \ + container_of((p), struct nouveau_conn_atom, state) + +struct nouveau_conn_atom { + struct drm_connector_state state; + + struct { + /* The enum values specifically defined here match nv50/gf119 + * hw values, and the code relies on this. + */ + enum { + DITHERING_MODE_OFF = 0x00, + DITHERING_MODE_ON = 0x01, + DITHERING_MODE_DYNAMIC2X2 = 0x10 | DITHERING_MODE_ON, + DITHERING_MODE_STATIC2X2 = 0x18 | DITHERING_MODE_ON, + DITHERING_MODE_TEMPORAL = 0x20 | DITHERING_MODE_ON, + DITHERING_MODE_AUTO + } mode; + enum { + DITHERING_DEPTH_6BPC = 0x00, + DITHERING_DEPTH_8BPC = 0x02, + DITHERING_DEPTH_AUTO + } depth; + } dither; + + struct { + int mode; /* DRM_MODE_SCALE_* */ + struct { + enum { + UNDERSCAN_OFF, + UNDERSCAN_ON, + UNDERSCAN_AUTO, + } mode; + u32 hborder; + u32 vborder; + } underscan; + bool full; + } scaler; + + struct { + int color_vibrance; + int vibrant_hue; + } procamp; + + union { + struct { + bool dither:1; + bool scaler:1; + bool procamp:1; + }; + u8 mask; + } set; +}; + struct nouveau_connector { struct drm_connector base; enum dcb_connector_type type; @@ -63,6 +118,12 @@ struct nouveau_connector { #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT struct nouveau_backlight *backlight; #endif + /* + * Our connector property code expects a nouveau_conn_atom struct + * even on pre-nv50 where we do not support atomic. This embedded + * version gets used in the non atomic modeset case. + */ + struct nouveau_conn_atom properties_state; }; static inline struct nouveau_connector *nouveau_connector( @@ -121,61 +182,6 @@ extern int nouveau_ignorelid; extern int nouveau_duallink; extern int nouveau_hdmimhz; -#include -#define nouveau_conn_atom(p) \ - container_of((p), struct nouveau_conn_atom, state) - -struct nouveau_conn_atom { - struct drm_connector_state state; - - struct { - /* The enum values specifically defined here match nv50/gf119 - * hw values, and the code relies on this. - */ - enum { - DITHERING_MODE_OFF = 0x00, - DITHERING_MODE_ON = 0x01, - DITHERING_MODE_DYNAMIC2X2 = 0x10 | DITHERING_MODE_ON, - DITHERING_MODE_STATIC2X2 = 0x18 | DITHERING_MODE_ON, - DITHERING_MODE_TEMPORAL = 0x20 | DITHERING_MODE_ON, - DITHERING_MODE_AUTO - } mode; - enum { - DITHERING_DEPTH_6BPC = 0x00, - DITHERING_DEPTH_8BPC = 0x02, - DITHERING_DEPTH_AUTO - } depth; - } dither; - - struct { - int mode; /* DRM_MODE_SCALE_* */ - struct { - enum { - UNDERSCAN_OFF, - UNDERSCAN_ON, - UNDERSCAN_AUTO, - } mode; - u32 hborder; - u32 vborder; - } underscan; - bool full; - } scaler; - - struct { - int color_vibrance; - int vibrant_hue; - } procamp; - - union { - struct { - bool dither:1; - bool scaler:1; - bool procamp:1; - }; - u8 mask; - } set; -}; - void nouveau_conn_attach_properties(struct drm_connector *); void nouveau_conn_reset(struct drm_connector *); struct drm_connector_state * diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 70f34cacc552cbd3617abe2a22cb9111a0171eea..da8c46e0994316b11612227aef899d8f96d240d1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -248,11 +248,11 @@ void nouveau_drm_device_remove(struct drm_device *dev); #define NV_INFO(drm,f,a...) NV_PRINTK(info, &(drm)->client, f, ##a) #define NV_DEBUG(drm,f,a...) do { \ - if (unlikely(drm_debug & DRM_UT_DRIVER)) \ + if (drm_debug_enabled(DRM_UT_DRIVER)) \ NV_PRINTK(info, &(drm)->client, f, ##a); \ } while(0) #define NV_ATOMIC(drm,f,a...) do { \ - if (unlikely(drm_debug & DRM_UT_ATOMIC)) \ + if (drm_debug_enabled(DRM_UT_ATOMIC)) \ NV_PRINTK(info, &(drm)->client, f, ##a); \ } while(0) diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index f439f0a5b43a5a619550fa6977efd340c05bafba..0c5cdda3c336508eb74aba563decad1db63f9b84 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -203,7 +203,7 @@ nouveau_fbcon_release(struct fb_info *info, int user) return 0; } -static struct fb_ops nouveau_fbcon_ops = { +static const struct fb_ops nouveau_fbcon_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, .fb_open = nouveau_fbcon_open, @@ -214,7 +214,7 @@ static struct fb_ops nouveau_fbcon_ops = { .fb_sync = nouveau_fbcon_sync, }; -static struct fb_ops nouveau_fbcon_sw_ops = { +static const struct fb_ops nouveau_fbcon_sw_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, .fb_open = nouveau_fbcon_open, diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 1324c19f4e5cfa4ea10a966ab4a5d1f08c434d82..05ec8edd6a8b787213b3c2b4628c4aad33d360a4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -484,12 +484,9 @@ retry: static int validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli, - struct list_head *list, struct drm_nouveau_gem_pushbuf_bo *pbbo, - uint64_t user_pbbo_ptr) + struct list_head *list, struct drm_nouveau_gem_pushbuf_bo *pbbo) { struct nouveau_drm *drm = chan->drm; - struct drm_nouveau_gem_pushbuf_bo __user *upbbo = - (void __force __user *)(uintptr_t)user_pbbo_ptr; struct nouveau_bo *nvbo; int ret, relocs = 0; @@ -533,10 +530,6 @@ validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli, b->presumed.offset = nvbo->bo.offset; b->presumed.valid = 0; relocs++; - - if (copy_to_user(&upbbo[nvbo->pbbo_index].presumed, - &b->presumed, sizeof(b->presumed))) - return -EFAULT; } } @@ -547,8 +540,8 @@ static int nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, struct drm_file *file_priv, struct drm_nouveau_gem_pushbuf_bo *pbbo, - uint64_t user_buffers, int nr_buffers, - struct validate_op *op, int *apply_relocs) + int nr_buffers, + struct validate_op *op, bool *apply_relocs) { struct nouveau_cli *cli = nouveau_cli(file_priv); int ret; @@ -565,7 +558,7 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, return ret; } - ret = validate_list(chan, cli, &op->list, pbbo, user_buffers); + ret = validate_list(chan, cli, &op->list, pbbo); if (unlikely(ret < 0)) { if (ret != -ERESTARTSYS) NV_PRINTK(err, cli, "validating bo list\n"); @@ -605,16 +598,12 @@ u_memcpya(uint64_t user, unsigned nmemb, unsigned size) static int nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, struct drm_nouveau_gem_pushbuf *req, + struct drm_nouveau_gem_pushbuf_reloc *reloc, struct drm_nouveau_gem_pushbuf_bo *bo) { - struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL; int ret = 0; unsigned i; - reloc = u_memcpya(req->relocs, req->nr_relocs, sizeof(*reloc)); - if (IS_ERR(reloc)) - return PTR_ERR(reloc); - for (i = 0; i < req->nr_relocs; i++) { struct drm_nouveau_gem_pushbuf_reloc *r = &reloc[i]; struct drm_nouveau_gem_pushbuf_bo *b; @@ -693,11 +682,13 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, struct nouveau_drm *drm = nouveau_drm(dev); struct drm_nouveau_gem_pushbuf *req = data; struct drm_nouveau_gem_pushbuf_push *push; + struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL; struct drm_nouveau_gem_pushbuf_bo *bo; struct nouveau_channel *chan = NULL; struct validate_op op; struct nouveau_fence *fence = NULL; - int i, j, ret = 0, do_reloc = 0; + int i, j, ret = 0; + bool do_reloc = false; if (unlikely(!abi16)) return -ENOMEM; @@ -755,7 +746,8 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, } /* Validate buffer list */ - ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers, +revalidate: + ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->nr_buffers, &op, &do_reloc); if (ret) { if (ret != -ERESTARTSYS) @@ -765,7 +757,18 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, /* Apply any relocations that are required */ if (do_reloc) { - ret = nouveau_gem_pushbuf_reloc_apply(cli, req, bo); + if (!reloc) { + validate_fini(&op, chan, NULL, bo); + reloc = u_memcpya(req->relocs, req->nr_relocs, sizeof(*reloc)); + if (IS_ERR(reloc)) { + ret = PTR_ERR(reloc); + goto out_prevalid; + } + + goto revalidate; + } + + ret = nouveau_gem_pushbuf_reloc_apply(cli, req, reloc, bo); if (ret) { NV_PRINTK(err, cli, "reloc apply: %d\n", ret); goto out; @@ -851,6 +854,22 @@ out: validate_fini(&op, chan, fence, bo); nouveau_fence_unref(&fence); + if (do_reloc) { + struct drm_nouveau_gem_pushbuf_bo __user *upbbo = + u64_to_user_ptr(req->buffers); + + for (i = 0; i < req->nr_buffers; i++) { + if (bo[i].presumed.valid) + continue; + + if (copy_to_user(&upbbo[i].presumed, &bo[i].presumed, + sizeof(bo[i].presumed))) { + ret = -EFAULT; + break; + } + } + u_free(reloc); + } out_prevalid: u_free(bo); u_free(push); diff --git a/drivers/gpu/drm/omapdrm/displays/Kconfig b/drivers/gpu/drm/omapdrm/displays/Kconfig index 240dda1028459ac7e85f3ffd9e96539347e1f410..b562a8cd61bfaec12d6e8e9d85ee1c56a33741a0 100644 --- a/drivers/gpu/drm/omapdrm/displays/Kconfig +++ b/drivers/gpu/drm/omapdrm/displays/Kconfig @@ -8,18 +8,18 @@ config DRM_OMAP_ENCODER_OPA362 through a GPIO. config DRM_OMAP_ENCODER_TPD12S015 - tristate "TPD12S015 HDMI ESD protection and level shifter" + tristate "TPD12S015 HDMI ESD protection and level shifter" help Driver for TPD12S015, which offers HDMI ESD protection and level shifting. config DRM_OMAP_CONNECTOR_HDMI - tristate "HDMI Connector" + tristate "HDMI Connector" help Driver for a generic HDMI connector. config DRM_OMAP_CONNECTOR_ANALOG_TV - tristate "Analog TV Connector" + tristate "Analog TV Connector" help Driver for a generic analog TV connector. diff --git a/drivers/gpu/drm/omapdrm/dss/Kconfig b/drivers/gpu/drm/omapdrm/dss/Kconfig index 956f23e1452d8c2e2e6d9e72a13e922c35f7c7b2..72ae79c0c9b4173322c056c524a2f02697c68e6b 100644 --- a/drivers/gpu/drm/omapdrm/dss/Kconfig +++ b/drivers/gpu/drm/omapdrm/dss/Kconfig @@ -6,12 +6,12 @@ config OMAP_DSS_BASE tristate menuconfig OMAP2_DSS - tristate "OMAP2+ Display Subsystem support" + tristate "OMAP2+ Display Subsystem support" select OMAP_DSS_BASE select VIDEOMODE_HELPERS select OMAP2_DSS_INIT select HDMI - help + help OMAP2+ Display Subsystem support. if OMAP2_DSS @@ -52,7 +52,7 @@ config OMAP2_DSS_DPI config OMAP2_DSS_VENC bool "VENC support" - default y + default y help OMAP Video Encoder support for S-Video and composite TV-out. @@ -61,7 +61,7 @@ config OMAP2_DSS_HDMI_COMMON config OMAP4_DSS_HDMI bool "HDMI support for OMAP4" - default y + default y select OMAP2_DSS_HDMI_COMMON help HDMI support for OMAP4 based SoCs. @@ -85,7 +85,7 @@ config OMAP5_DSS_HDMI config OMAP2_DSS_SDI bool "SDI support" - default n + default n help SDI (Serial Display Interface) support. @@ -94,7 +94,7 @@ config OMAP2_DSS_SDI config OMAP2_DSS_DSI bool "DSI support" - default n + default n help MIPI DSI (Display Serial Interface) support. diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index 5b8799c69f684936a96034665c38b2aef84a6408..94cded3871746e8f367e823cb7968a61c861a8f2 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -229,7 +229,8 @@ static int omap_connector_get_modes(struct drm_connector *connector) * operation to the panel API. */ if (omap_connector->output->panel) - return drm_panel_get_modes(omap_connector->output->panel); + return drm_panel_get_modes(omap_connector->output->panel, + connector); /* * We can't retrieve modes, which can happen for instance for a DVI or diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index b3e22c890c51d97eb855acdcd8a1678cf92fdcca..d2750f60f519249831e5a519d1f185873ac1bd94 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -217,8 +217,8 @@ static int omap_display_id(struct omap_dss_device *output) } else if (output->bridge) { struct drm_bridge *bridge = output->bridge; - while (bridge->next) - bridge = bridge->next; + while (drm_bridge_get_next_bridge(bridge)) + bridge = drm_bridge_get_next_bridge(bridge); node = bridge->of_node; } else if (output->panel) { diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index 24bbe9f2a32ec696fcd2ec6cae339c51371d5068..4f2165a37795f717810ffdb8660bdef65e2284ba 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -126,7 +126,8 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, for (dssdev = output; dssdev; dssdev = dssdev->next) omap_encoder_update_videomode_flags(&vm, dssdev->bus_flags); - for (bridge = output->bridge; bridge; bridge = bridge->next) { + for (bridge = output->bridge; bridge; + bridge = drm_bridge_get_next_bridge(bridge)) { if (!bridge->timings) continue; diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 58f53946ee4d42e5334e826ee08d40b293dbaeb9..b06e5cbfd03afcef4a9f0e74a329490efcdf03dc 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -70,7 +70,7 @@ fallback: return drm_fb_helper_pan_display(var, fbi); } -static struct fb_ops omap_fb_ops = { +static const struct fb_ops omap_fb_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index 7344bb61936c8070313639dd9913c7fa5f1b427a..b319fe7f23718bbc8adccbe45478942376a3dabe 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c @@ -85,25 +85,6 @@ static int omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer, return 0; } -static void *omap_gem_dmabuf_kmap(struct dma_buf *buffer, - unsigned long page_num) -{ - struct drm_gem_object *obj = buffer->priv; - struct page **pages; - omap_gem_get_pages(obj, &pages, false); - omap_gem_cpu_sync_page(obj, page_num); - return kmap(pages[page_num]); -} - -static void omap_gem_dmabuf_kunmap(struct dma_buf *buffer, - unsigned long page_num, void *addr) -{ - struct drm_gem_object *obj = buffer->priv; - struct page **pages; - omap_gem_get_pages(obj, &pages, false); - kunmap(pages[page_num]); -} - static int omap_gem_dmabuf_mmap(struct dma_buf *buffer, struct vm_area_struct *vma) { @@ -123,8 +104,6 @@ static const struct dma_buf_ops omap_dmabuf_ops = { .release = drm_gem_dmabuf_release, .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access, .end_cpu_access = omap_gem_dmabuf_end_cpu_access, - .map = omap_gem_dmabuf_kmap, - .unmap = omap_gem_dmabuf_kunmap, .mmap = omap_gem_dmabuf_mmap, }; diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index f152bc4eeb535efde0e4005bf514b9c3e3ea4a2e..41f796b28dd5e406f319d66f2e4ac013e00fcb90 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -18,6 +18,17 @@ config DRM_PANEL_ARM_VERSATILE reference designs. The panel is detected using special registers in the Versatile family syscon registers. +config DRM_PANEL_BOE_HIMAX8279D + tristate "Boe Himax8279d 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 Boe Himax8279d + TFT-LCD modules. The panel has a 1200x1920 resolution and uses + 24 bit RGB per pixel. It provides a MIPI DSI interface to + the host and has a built-in LED backlight. + config DRM_PANEL_LVDS tristate "Generic LVDS panel driver" depends on OF @@ -98,6 +109,17 @@ config DRM_PANEL_KINGDISPLAY_KD097D04 24 bit RGB per pixel. It provides a MIPI DSI interface to the host and has a built-in LED backlight. +config DRM_PANEL_LEADTEK_LTK500HD1829 + tristate "Leadtek LTK500HD1829 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 Kingdisplay kd097d04 + TFT-LCD modules. The panel has a 1536x2048 resolution and uses + 24 bit RGB per pixel. It provides a MIPI DSI interface to + the host and has a built-in LED backlight. + config DRM_PANEL_SAMSUNG_LD9040 tristate "Samsung LD9040 RGB/SPI panel" depends on OF && SPI @@ -355,4 +377,14 @@ config DRM_PANEL_TRULY_NT35597_WQXGA help Say Y here if you want to enable support for Truly NT35597 WQXGA Dual DSI Video Mode panel + +config DRM_PANEL_XINPENG_XPP055C272 + tristate "Xinpeng XPP055C272 panel driver" + 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 Xinpeng + XPP055C272 controller for 720x1280 LCD panels with MIPI/RGB/SPI + system interfaces. endmenu diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index b6cd39fe0f206c9177ffd87a68bd591f0895eb10..4dc7acff21b90f26342a668ca64b0864224f5c11 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o +obj-$(CONFIG_DRM_PANEL_BOE_HIMAX8279D) += panel-boe-himax8279d.o obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o @@ -8,6 +9,7 @@ obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o +obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o @@ -38,3 +40,4 @@ obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o +obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o diff --git a/drivers/gpu/drm/panel/panel-arm-versatile.c b/drivers/gpu/drm/panel/panel-arm-versatile.c index a0574dc03e16fd9275ca64fbfbc1be861082170e..41444a73c9807828c5d6f43f8bea67c43a0711fb 100644 --- a/drivers/gpu/drm/panel/panel-arm-versatile.c +++ b/drivers/gpu/drm/panel/panel-arm-versatile.c @@ -260,9 +260,9 @@ static int versatile_panel_enable(struct drm_panel *panel) return 0; } -static int versatile_panel_get_modes(struct drm_panel *panel) +static int versatile_panel_get_modes(struct drm_panel *panel, + struct drm_connector *connector) { - struct drm_connector *connector = panel->connector; struct versatile_panel *vpanel = to_versatile_panel(panel); struct drm_display_mode *mode; @@ -270,7 +270,7 @@ static int versatile_panel_get_modes(struct drm_panel *panel) connector->display_info.height_mm = vpanel->panel_type->height_mm; connector->display_info.bus_flags = vpanel->panel_type->bus_flags; - mode = drm_mode_duplicate(panel->drm, &vpanel->panel_type->mode); + mode = drm_mode_duplicate(connector->dev, &vpanel->panel_type->mode); drm_mode_set_name(mode); mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; diff --git a/drivers/gpu/drm/panel/panel-boe-himax8279d.c b/drivers/gpu/drm/panel/panel-boe-himax8279d.c new file mode 100644 index 0000000000000000000000000000000000000000..74d58ee7d04c8a7c5a48eb0acd8f71cddb8ed75a --- /dev/null +++ b/drivers/gpu/drm/panel/panel-boe-himax8279d.c @@ -0,0 +1,978 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019, Huaqin Telecom Technology Co., Ltd + * + * Author: Jerry Han + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include