drm-misc-next for 5.10: UAPI Changes: Cross-subsystem Changes: Core Changes: - ttm: various cleanups and reworks of the API Driver Changes: - ast: various cleanups - gma500: A few fixes, conversion to GPIOd API - hisilicon: Change of maintainer, various reworks - ingenic: Clock handling and formats support improvements - mcde: improvements to the DSI support - mgag200: Support G200 desktop cards - mxsfb: Support the i.MX7 and i.MX8M and the alpha plane - panfrost: support devfreq - ps8640: Retrieve the EDID from eDP control, misc improvements - tidss: Add a workaround for AM65xx YUV formats handling - virtio: a few cleanups, support for virtio-gpu exported resources - bridges: Support the chained bridges on more drivers, new bridges: Toshiba TC358762, Toshiba TC358775, Lontium LT9611 - panels: Convert to dev_ based logging, read orientation from the DT, various fixes, new panels: Mantix MLAF057WE51-X, Chefree CH101OLHLWH-002, Powertip PH800480T013, KingDisplay KD116N21-30NV-A010 Signed-off-by: Dave Airlie <airlied@redhat.com>
Unified · Split
| @@ -0,0 +1,176 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/display/bridge/lontium,lt9611.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Lontium LT9611 2 Port MIPI to HDMI Bridge | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Vinod Koul <vkoul@kernel.org> | |
| 11 | + | |
| 12 | +description: | | |
| 13 | + The LT9611 is a bridge device which converts DSI to HDMI | |
| 14 | + | |
| 15 | +properties: | |
| 16 | + compatible: | |
| 17 | + enum: | |
| 18 | + - lontium,lt9611 | |
| 19 | + | |
| 20 | + reg: | |
| 21 | + maxItems: 1 | |
| 22 | + | |
| 23 | + "#sound-dai-cells": | |
| 24 | + const: 1 | |
| 25 | + | |
| 26 | + interrupts: | |
| 27 | + maxItems: 1 | |
| 28 | + | |
| 29 | + reset-gpios: | |
| 30 | + maxItems: 1 | |
| 31 | + description: GPIO connected to active high RESET pin. | |
| 32 | + | |
| 33 | + vdd-supply: | |
| 34 | + description: Regulator for 1.8V MIPI phy power. | |
| 35 | + | |
| 36 | + vcc-supply: | |
| 37 | + description: Regulator for 3.3V IO power. | |
| 38 | + | |
| 39 | + ports: | |
| 40 | + type: object | |
| 41 | + | |
| 42 | + properties: | |
| 43 | + "#address-cells": | |
| 44 | + const: 1 | |
| 45 | + | |
| 46 | + "#size-cells": | |
| 47 | + const: 0 | |
| 48 | + | |
| 49 | + port@0: | |
| 50 | + type: object | |
| 51 | + description: | | |
| 52 | + Primary MIPI port-1 for MIPI input | |
| 53 | + | |
| 54 | + properties: | |
| 55 | + reg: | |
| 56 | + const: 0 | |
| 57 | + | |
| 58 | + patternProperties: | |
| 59 | + "^endpoint(@[0-9])$": | |
| 60 | + type: object | |
| 61 | + additionalProperties: false | |
| 62 | + | |
| 63 | + properties: | |
| 64 | + remote-endpoint: | |
| 65 | + $ref: /schemas/types.yaml#/definitions/phandle | |
| 66 | + | |
| 67 | + required: | |
| 68 | + - reg | |
| 69 | + | |
| 70 | + port@1: | |
| 71 | + type: object | |
| 72 | + description: | | |
| 73 | + Additional MIPI port-2 for MIPI input, used in combination | |
| 74 | + with primary MIPI port-1 to drive higher resolution displays | |
| 75 | + | |
| 76 | + properties: | |
| 77 | + reg: | |
| 78 | + const: 1 | |
| 79 | + | |
| 80 | + patternProperties: | |
| 81 | + "^endpoint(@[0-9])$": | |
| 82 | + type: object | |
| 83 | + additionalProperties: false | |
| 84 | + | |
| 85 | + properties: | |
| 86 | + remote-endpoint: | |
| 87 | + $ref: /schemas/types.yaml#/definitions/phandle | |
| 88 | + | |
| 89 | + required: | |
| 90 | + - reg | |
| 91 | + | |
| 92 | + port@2: | |
| 93 | + type: object | |
| 94 | + description: | | |
| 95 | + HDMI port for HDMI output | |
| 96 | + | |
| 97 | + properties: | |
| 98 | + reg: | |
| 99 | + const: 2 | |
| 100 | + | |
| 101 | + patternProperties: | |
| 102 | + "^endpoint(@[0-9])$": | |
| 103 | + type: object | |
| 104 | + additionalProperties: false | |
| 105 | + | |
| 106 | + properties: | |
| 107 | + remote-endpoint: | |
| 108 | + $ref: /schemas/types.yaml#/definitions/phandle | |
| 109 | + | |
| 110 | + required: | |
| 111 | + - reg | |
| 112 | + | |
| 113 | + required: | |
| 114 | + - "#address-cells" | |
| 115 | + - "#size-cells" | |
| 116 | + - port@0 | |
| 117 | + - port@2 | |
| 118 | + | |
| 119 | +required: | |
| 120 | + - compatible | |
| 121 | + - reg | |
| 122 | + - interrupts | |
| 123 | + - vdd-supply | |
| 124 | + - vcc-supply | |
| 125 | + - ports | |
| 126 | + | |
| 127 | +additionalProperties: false | |
| 128 | + | |
| 129 | +examples: | |
| 130 | + - | | |
| 131 | + #include <dt-bindings/gpio/gpio.h> | |
| 132 | + #include <dt-bindings/interrupt-controller/irq.h> | |
| 133 | + | |
| 134 | + i2c10 { | |
| 135 | + #address-cells = <1>; | |
| 136 | + #size-cells = <0>; | |
| 137 | + | |
| 138 | + hdmi-bridge@3b { | |
| 139 | + compatible = "lontium,lt9611"; | |
| 140 | + reg = <0x3b>; | |
| 141 | + | |
| 142 | + reset-gpios = <&tlmm 128 GPIO_ACTIVE_HIGH>; | |
| 143 | + interrupts-extended = <&tlmm 84 IRQ_TYPE_EDGE_FALLING>; | |
| 144 | + | |
| 145 | + vdd-supply = <<9611_1v8>; | |
| 146 | + vcc-supply = <<9611_3v3>; | |
| 147 | + | |
| 148 | + ports { | |
| 149 | + #address-cells = <1>; | |
| 150 | + #size-cells = <0>; | |
| 151 | + | |
| 152 | + port@0 { | |
| 153 | + reg = <0>; | |
| 154 | + lt9611_a: endpoint { | |
| 155 | + remote-endpoint = <&dsi0_out>; | |
| 156 | + }; | |
| 157 | + }; | |
| 158 | + | |
| 159 | + port@1 { | |
| 160 | + reg = <1>; | |
| 161 | + lt9611_b: endpoint { | |
| 162 | + remote-endpoint = <&dsi1_out>; | |
| 163 | + }; | |
| 164 | + }; | |
| 165 | + | |
| 166 | + port@2 { | |
| 167 | + reg = <2>; | |
| 168 | + lt9611_out: endpoint { | |
| 169 | + remote-endpoint = <&hdmi_con>; | |
| 170 | + }; | |
| 171 | + }; | |
| 172 | + }; | |
| 173 | + }; | |
| 174 | + }; | |
| 175 | + | |
| 176 | +... | |
| @@ -0,0 +1,127 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/display/bridge/toshiba,tc358762.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Toshiba TC358762 MIPI DSI to MIPI DPI bridge | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Marek Vasut <marex@denx.de> | |
| 11 | + | |
| 12 | +description: | | |
| 13 | + The TC358762 is bridge device which converts MIPI DSI to MIPI DPI. | |
| 14 | + | |
| 15 | +properties: | |
| 16 | + compatible: | |
| 17 | + enum: | |
| 18 | + - toshiba,tc358762 | |
| 19 | + | |
| 20 | + reg: | |
| 21 | + maxItems: 1 | |
| 22 | + description: virtual channel number of a DSI peripheral | |
| 23 | + | |
| 24 | + vddc-supply: | |
| 25 | + description: Regulator for 1.2V internal core power. | |
| 26 | + | |
| 27 | + ports: | |
| 28 | + type: object | |
| 29 | + | |
| 30 | + properties: | |
| 31 | + "#address-cells": | |
| 32 | + const: 1 | |
| 33 | + | |
| 34 | + "#size-cells": | |
| 35 | + const: 0 | |
| 36 | + | |
| 37 | + port@0: | |
| 38 | + type: object | |
| 39 | + additionalProperties: false | |
| 40 | + | |
| 41 | + description: | | |
| 42 | + Video port for MIPI DSI input | |
| 43 | + | |
| 44 | + properties: | |
| 45 | + reg: | |
| 46 | + const: 0 | |
| 47 | + | |
| 48 | + patternProperties: | |
| 49 | + endpoint: | |
| 50 | + type: object | |
| 51 | + additionalProperties: false | |
| 52 | + | |
| 53 | + properties: | |
| 54 | + remote-endpoint: true | |
| 55 | + | |
| 56 | + required: | |
| 57 | + - reg | |
| 58 | + | |
| 59 | + port@1: | |
| 60 | + type: object | |
| 61 | + additionalProperties: false | |
| 62 | + | |
| 63 | + description: | | |
| 64 | + Video port for MIPI DPI output (panel or connector). | |
| 65 | + | |
| 66 | + properties: | |
| 67 | + reg: | |
| 68 | + const: 1 | |
| 69 | + | |
| 70 | + patternProperties: | |
| 71 | + endpoint: | |
| 72 | + type: object | |
| 73 | + additionalProperties: false | |
| 74 | + | |
| 75 | + properties: | |
| 76 | + remote-endpoint: true | |
| 77 | + | |
| 78 | + required: | |
| 79 | + - reg | |
| 80 | + | |
| 81 | + required: | |
| 82 | + - "#address-cells" | |
| 83 | + - "#size-cells" | |
| 84 | + - port@0 | |
| 85 | + - port@1 | |
| 86 | + | |
| 87 | +required: | |
| 88 | + - compatible | |
| 89 | + - reg | |
| 90 | + - vddc-supply | |
| 91 | + - ports | |
| 92 | + | |
| 93 | +additionalProperties: false | |
| 94 | + | |
| 95 | +examples: | |
| 96 | + - | | |
| 97 | + i2c1 { | |
| 98 | + #address-cells = <1>; | |
| 99 | + #size-cells = <0>; | |
| 100 | + | |
| 101 | + bridge@0 { | |
| 102 | + reg = <0>; | |
| 103 | + compatible = "toshiba,tc358762"; | |
| 104 | + vddc-supply = <&vcc_1v2_reg>; | |
| 105 | + | |
| 106 | + ports { | |
| 107 | + #address-cells = <1>; | |
| 108 | + #size-cells = <0>; | |
| 109 | + | |
| 110 | + port@0 { | |
| 111 | + reg = <0>; | |
| 112 | + bridge_in: endpoint { | |
| 113 | + remote-endpoint = <&dsi_out>; | |
| 114 | + }; | |
| 115 | + }; | |
| 116 | + | |
| 117 | + port@1 { | |
| 118 | + reg = <1>; | |
| 119 | + bridge_out: endpoint { | |
| 120 | + remote-endpoint = <&panel_in>; | |
| 121 | + }; | |
| 122 | + }; | |
| 123 | + }; | |
| 124 | + }; | |
| 125 | + }; | |
| 126 | + | |
| 127 | +... | |
| @@ -0,0 +1,215 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/display/bridge/toshiba,tc358775.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Toshiba TC358775 DSI to LVDS bridge bindings | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Vinay Simha BN <simhavcs@gmail.com> | |
| 11 | + | |
| 12 | +description: | | |
| 13 | + This binding supports DSI to LVDS bridge TC358775 | |
| 14 | + | |
| 15 | + MIPI DSI-RX Data 4-lane, CLK 1-lane with data rates up to 800 Mbps/lane. | |
| 16 | + Video frame size: | |
| 17 | + Up to 1600x1200 24-bit/pixel resolution for single-link LVDS display panel | |
| 18 | + limited by 135 MHz LVDS speed | |
| 19 | + Up to WUXGA (1920x1200 24-bit pixels) resolution for dual-link LVDS display | |
| 20 | + panel, limited by 270 MHz LVDS speed. | |
| 21 | + | |
| 22 | +properties: | |
| 23 | + compatible: | |
| 24 | + const: toshiba,tc358775 | |
| 25 | + | |
| 26 | + reg: | |
| 27 | + maxItems: 1 | |
| 28 | + description: i2c address of the bridge, 0x0f | |
| 29 | + | |
| 30 | + vdd-supply: | |
| 31 | + maxItems: 1 | |
| 32 | + description: 1.2V LVDS Power Supply | |
| 33 | + | |
| 34 | + vddio-supply: | |
| 35 | + maxItems: 1 | |
| 36 | + description: 1.8V IO Power Supply | |
| 37 | + | |
| 38 | + stby-gpios: | |
| 39 | + maxItems: 1 | |
| 40 | + description: Standby pin, Low active | |
| 41 | + | |
| 42 | + reset-gpios: | |
| 43 | + maxItems: 1 | |
| 44 | + description: Hardware reset, Low active | |
| 45 | + | |
| 46 | + ports: | |
| 47 | + type: object | |
| 48 | + description: | |
| 49 | + A node containing input and output port nodes with endpoint definitions | |
| 50 | + as documented in | |
| 51 | + Documentation/devicetree/bindings/media/video-interfaces.txt | |
| 52 | + properties: | |
| 53 | + "#address-cells": | |
| 54 | + const: 1 | |
| 55 | + | |
| 56 | + "#size-cells": | |
| 57 | + const: 0 | |
| 58 | + | |
| 59 | + port@0: | |
| 60 | + type: object | |
| 61 | + description: | | |
| 62 | + DSI Input. The remote endpoint phandle should be a | |
| 63 | + reference to a valid mipi_dsi_host device node. | |
| 64 | + | |
| 65 | + port@1: | |
| 66 | + type: object | |
| 67 | + description: | | |
| 68 | + Video port for LVDS output (panel or connector). | |
| 69 | + | |
| 70 | + port@2: | |
| 71 | + type: object | |
| 72 | + description: | | |
| 73 | + Video port for Dual link LVDS output (panel or connector). | |
| 74 | + | |
| 75 | + required: | |
| 76 | + - port@0 | |
| 77 | + - port@1 | |
| 78 | + | |
| 79 | +required: | |
| 80 | + - compatible | |
| 81 | + - reg | |
| 82 | + - vdd-supply | |
| 83 | + - vddio-supply | |
| 84 | + - stby-gpios | |
| 85 | + - reset-gpios | |
| 86 | + - ports | |
| 87 | + | |
| 88 | +examples: | |
| 89 | + - | | |
| 90 | + #include <dt-bindings/gpio/gpio.h> | |
| 91 | + | |
| 92 | + /* For single-link LVDS display panel */ | |
| 93 | + | |
| 94 | + i2c@78b8000 { | |
| 95 | + /* On High speed expansion */ | |
| 96 | + label = "HS-I2C2"; | |
| 97 | + reg = <0x078b8000 0x500>; | |
| 98 | + clock-frequency = <400000>; /* fastmode operation */ | |
| 99 | + #address-cells = <1>; | |
| 100 | + #size-cells = <0>; | |
| 101 | + | |
| 102 | + tc_bridge: bridge@f { | |
| 103 | + compatible = "toshiba,tc358775"; | |
| 104 | + reg = <0x0f>; | |
| 105 | + | |
| 106 | + vdd-supply = <&pm8916_l2>; | |
| 107 | + vddio-supply = <&pm8916_l6>; | |
| 108 | + | |
| 109 | + stby-gpios = <&msmgpio 99 GPIO_ACTIVE_LOW>; | |
| 110 | + reset-gpios = <&msmgpio 72 GPIO_ACTIVE_LOW>; | |
| 111 | + | |
| 112 | + ports { | |
| 113 | + #address-cells = <1>; | |
| 114 | + #size-cells = <0>; | |
| 115 | + | |
| 116 | + port@0 { | |
| 117 | + reg = <0>; | |
| 118 | + d2l_in_test: endpoint { | |
| 119 | + remote-endpoint = <&dsi0_out>; | |
| 120 | + }; | |
| 121 | + }; | |
| 122 | + | |
| 123 | + port@1 { | |
| 124 | + reg = <1>; | |
| 125 | + lvds_out: endpoint { | |
| 126 | + remote-endpoint = <&panel_in>; | |
| 127 | + }; | |
| 128 | + }; | |
| 129 | + }; | |
| 130 | + }; | |
| 131 | + }; | |
| 132 | + | |
| 133 | + dsi@1a98000 { | |
| 134 | + reg = <0x1a98000 0x25c>; | |
| 135 | + reg-names = "dsi_ctrl"; | |
| 136 | + | |
| 137 | + ports { | |
| 138 | + #address-cells = <1>; | |
| 139 | + #size-cells = <0>; | |
| 140 | + port@1 { | |
| 141 | + reg = <1>; | |
| 142 | + dsi0_out: endpoint { | |
| 143 | + remote-endpoint = <&d2l_in_test>; | |
| 144 | + data-lanes = <0 1 2 3>; | |
| 145 | + }; | |
| 146 | + }; | |
| 147 | + }; | |
| 148 | + }; | |
| 149 | + | |
| 150 | + - | | |
| 151 | + /* For dual-link LVDS display panel */ | |
| 152 | + | |
| 153 | + i2c@78b8000 { | |
| 154 | + /* On High speed expansion */ | |
| 155 | + label = "HS-I2C2"; | |
| 156 | + reg = <0x078b8000 0x500>; | |
| 157 | + clock-frequency = <400000>; /* fastmode operation */ | |
| 158 | + #address-cells = <1>; | |
| 159 | + #size-cells = <0>; | |
| 160 | + | |
| 161 | + tc_bridge_dual: bridge@f { | |
| 162 | + compatible = "toshiba,tc358775"; | |
| 163 | + reg = <0x0f>; | |
| 164 | + | |
| 165 | + vdd-supply = <&pm8916_l2>; | |
| 166 | + vddio-supply = <&pm8916_l6>; | |
| 167 | + | |
| 168 | + stby-gpios = <&msmgpio 99 GPIO_ACTIVE_LOW>; | |
| 169 | + reset-gpios = <&msmgpio 72 GPIO_ACTIVE_LOW>; | |
| 170 | + | |
| 171 | + ports { | |
| 172 | + #address-cells = <1>; | |
| 173 | + #size-cells = <0>; | |
| 174 | + | |
| 175 | + port@0 { | |
| 176 | + reg = <0>; | |
| 177 | + d2l_in_dual: endpoint { | |
| 178 | + remote-endpoint = <&dsi0_out_dual>; | |
| 179 | + }; | |
| 180 | + }; | |
| 181 | + | |
| 182 | + port@1 { | |
| 183 | + reg = <1>; | |
| 184 | + lvds0_out: endpoint { | |
| 185 | + remote-endpoint = <&panel_in0>; | |
| 186 | + }; | |
| 187 | + }; | |
| 188 | + | |
| 189 | + port@2 { | |
| 190 | + reg = <2>; | |
| 191 | + lvds1_out: endpoint { | |
| 192 | + remote-endpoint = <&panel_in1>; | |
| 193 | + }; | |
| 194 | + }; | |
| 195 | + }; | |
| 196 | + }; | |
| 197 | + }; | |
| 198 | + | |
| 199 | + dsi@1a98000 { | |
| 200 | + reg = <0x1a98000 0x25c>; | |
| 201 | + reg-names = "dsi_ctrl"; | |
| 202 | + | |
| 203 | + ports { | |
| 204 | + #address-cells = <1>; | |
| 205 | + #size-cells = <0>; | |
| 206 | + port@1 { | |
| 207 | + reg = <1>; | |
| 208 | + dsi0_out_dual: endpoint { | |
| 209 | + remote-endpoint = <&d2l_in_dual>; | |
| 210 | + data-lanes = <0 1 2 3>; | |
| 211 | + }; | |
| 212 | + }; | |
| 213 | + }; | |
| 214 | + }; | |
| 215 | +... | |
| @@ -13,7 +13,9 @@ properties: · 12 unmodified lines | ||
| 13 | 13 | compatible: |
| 14 | 14 | items: |
| 15 | 15 | - enum: |
| 16 | − - bananapi,lhr050h41 | |
| 16 | + - bananapi,lhr050h41 | |
| 17 | + - feixin,k101-im2byl02 | |
| 18 | + | |
| 17 | 19 | - const: ilitek,ili9881c |
| 18 | 20 | |
| 19 | 21 | backlight: true |
| @@ -0,0 +1,70 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/display/panel/mantix,mlaf057we51-x.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Mantix MLAF057WE51-X 5.7" 720x1440 TFT LCD panel | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Guido Günther <agx@sigxcpu.org> | |
| 11 | + | |
| 12 | +description: | |
| 13 | + Mantix MLAF057WE51 X is a 720x1440 TFT LCD panel connected using | |
| 14 | + a MIPI-DSI video interface. | |
| 15 | + | |
| 16 | +allOf: | |
| 17 | + - $ref: panel-common.yaml# | |
| 18 | + | |
| 19 | +properties: | |
| 20 | + compatible: | |
| 21 | + enum: | |
| 22 | + - mantix,mlaf057we51-x | |
| 23 | + | |
| 24 | + port: true | |
| 25 | + reg: | |
| 26 | + maxItems: 1 | |
| 27 | + description: DSI virtual channel | |
| 28 | + | |
| 29 | + avdd-supply: | |
| 30 | + description: Positive analog power supply | |
| 31 | + | |
| 32 | + avee-supply: | |
| 33 | + description: Negative analog power supply | |
| 34 | + | |
| 35 | + vddi-supply: | |
| 36 | + description: 1.8V I/O voltage supply | |
| 37 | + | |
| 38 | + reset-gpios: true | |
| 39 | + | |
| 40 | + backlight: true | |
| 41 | + | |
| 42 | +required: | |
| 43 | + - compatible | |
| 44 | + - reg | |
| 45 | + - avdd-supply | |
| 46 | + - avee-supply | |
| 47 | + - vddi-supply | |
| 48 | + - reset-gpios | |
| 49 | + | |
| 50 | +additionalProperties: false | |
| 51 | + | |
| 52 | +examples: | |
| 53 | + - | | |
| 54 | + #include <dt-bindings/gpio/gpio.h> | |
| 55 | + | |
| 56 | + dsi { | |
| 57 | + #address-cells = <1>; | |
| 58 | + #size-cells = <0>; | |
| 59 | + panel@0 { | |
| 60 | + compatible = "mantix,mlaf057we51-x"; | |
| 61 | + reg = <0>; | |
| 62 | + avdd-supply = <®_avdd>; | |
| 63 | + avee-supply = <®_avee>; | |
| 64 | + vddi-supply = <®_1v8_p>; | |
| 65 | + reset-gpios = <&gpio1 29 GPIO_ACTIVE_LOW>; | |
| 66 | + backlight = <&backlight>; | |
| 67 | + }; | |
| 68 | + }; | |
| 69 | + | |
| 70 | +... | |
| @@ -87,6 +87,8 @@ properties: · 86 unmodified lines | ||
| 87 | 87 | - cdtech,s070swv29hg-dc44 |
| 88 | 88 | # CDTech(H.K.) Electronics Limited 7" 800x480 color TFT-LCD panel |
| 89 | 89 | - cdtech,s070wv95-ct16 |
| 90 | + # Chefree CH101OLHLWH-002 10.1" (1280x800) color TFT LCD panel | |
| 91 | + - chefree,ch101olhlwh-002 | |
| 90 | 92 | # Chunghwa Picture Tubes Ltd. 7" WXGA TFT LCD panel |
| 91 | 93 | - chunghwa,claa070wp03xg |
| 92 | 94 | # Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel |
| @@ -159,6 +161,8 @@ properties: · 66 unmodified lines | ||
| 159 | 161 | - innolux,n156bge-l21 |
| 160 | 162 | # Innolux Corporation 7.0" WSVGA (1024x600) TFT LCD panel |
| 161 | 163 | - innolux,zj070na-01p |
| 164 | + # King & Display KD116N21-30NV-A010 eDP TFT LCD panel | |
| 165 | + - kingdisplay,kd116n21-30nv-a010 | |
| 162 | 166 | # Kaohsiung Opto-Electronics Inc. 5.7" QVGA (320 x 240) TFT LCD panel |
| 163 | 167 | - koe,tx14d24vm1bpa |
| 164 | 168 | # Kaohsiung Opto-Electronics Inc. 10.1" WUXGA (1920 x 1200) LVDS TFT LCD panel |
| @@ -219,6 +223,8 @@ properties: · 54 unmodified lines | ||
| 219 | 223 | - osddisplays,osd070t1718-19ts |
| 220 | 224 | # One Stop Displays OSD101T2045-53TS 10.1" 1920x1200 panel |
| 221 | 225 | - osddisplays,osd101t2045-53ts |
| 226 | + # POWERTIP PH800480T013-IDF2 7.0" WVGA TFT LCD panel | |
| 227 | + - powertip,ph800480t013-idf02 | |
| 222 | 228 | # QiaoDian XianShi Corporation 4"3 TFT LCD panel |
| 223 | 229 | - qiaodian,qd43003c0-40 |
| 224 | 230 | # Rocktech Displays Ltd. RK101II01D-CT 10.1" TFT 1280x800 |
| @@ -8,10 +8,11 @@ title: Rocktech JH057N00900 5.5" 720x1440 TFT LCD panel · 7 unmodified lines | ||
| 8 | 8 | |
| 9 | 9 | maintainers: |
| 10 | 10 | - Ondrej Jirman <megi@xff.cz> |
| 11 | + - Guido Gŭnther <agx@sigxcpu.org> | |
| 11 | 12 | |
| 12 | −description: | | |
| 13 | − Rocktech JH057N00900 is a 720x1440 TFT LCD panel | |
| 14 | − connected using a MIPI-DSI video interface. | |
| 13 | +description: | |
| 14 | + Rocktech JH057N00900 is a 720x1440 TFT LCD panel | |
| 15 | + connected using a MIPI-DSI video interface. | |
| 15 | 16 | |
| 16 | 17 | allOf: |
| 17 | 18 | - $ref: panel-common.yaml# |
| @@ -19,9 +20,9 @@ allOf: · 1 unmodified line | ||
| 19 | 20 | properties: |
| 20 | 21 | compatible: |
| 21 | 22 | enum: |
| 22 | − # Rocktech JH057N00900 5.5" 720x1440 TFT LCD panel | |
| 23 | + # Rocktech JH057N00900 5.5" 720x1440 TFT LCD panel | |
| 23 | 24 | - rocktech,jh057n00900 |
| 24 | − # Xingbangda XBD599 5.99" 720x1440 TFT LCD panel | |
| 25 | + # Xingbangda XBD599 5.99" 720x1440 TFT LCD panel | |
| 25 | 26 | - xingbangda,xbd599 |
| 26 | 27 | |
| 27 | 28 | port: true |
| @@ -35,13 +36,9 @@ properties: · 7 unmodified lines | ||
| 35 | 36 | iovcc-supply: |
| 36 | 37 | description: I/O voltage supply |
| 37 | 38 | |
| 38 | − reset-gpios: | |
| 39 | − description: GPIO used for the reset pin | |
| 40 | − maxItems: 1 | |
| 39 | + reset-gpios: true | |
| 41 | 40 | |
| 42 | − backlight: | |
| 43 | − description: Backlight used by the panel | |
| 44 | − $ref: "/schemas/types.yaml#/definitions/phandle" | |
| 41 | + backlight: true | |
| 45 | 42 | |
| 46 | 43 | required: |
| 47 | 44 | - compatible |
| @@ -57,15 +54,16 @@ examples: · 9 unmodified lines | ||
| 57 | 54 | #include <dt-bindings/gpio/gpio.h> |
| 58 | 55 | |
| 59 | 56 | dsi { |
| 60 | − #address-cells = <1>; | |
| 61 | − #size-cells = <0>; | |
| 62 | − panel@0 { | |
| 63 | − compatible = "rocktech,jh057n00900"; | |
| 64 | − reg = <0>; | |
| 65 | − vcc-supply = <®_2v8_p>; | |
| 66 | − iovcc-supply = <®_1v8_p>; | |
| 67 | − reset-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>; | |
| 68 | − backlight = <&backlight>; | |
| 69 | − }; | |
| 57 | + #address-cells = <1>; | |
| 58 | + #size-cells = <0>; | |
| 59 | + panel@0 { | |
| 60 | + compatible = "rocktech,jh057n00900"; | |
| 61 | + reg = <0>; | |
| 62 | + vcc-supply = <®_2v8_p>; | |
| 63 | + iovcc-supply = <®_1v8_p>; | |
| 64 | + reset-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>; | |
| 65 | + backlight = <&backlight>; | |
| 66 | + }; | |
| 70 | 67 | }; |
| 68 | + | |
| 71 | 69 | ... |
| @@ -197,6 +197,8 @@ patternProperties: · 196 unmodified lines | ||
| 197 | 197 | description: Ceva, Inc. |
| 198 | 198 | "^checkpoint,.*": |
| 199 | 199 | description: Check Point Software Technologies Ltd. |
| 200 | + "^chefree,.*": | |
| 201 | + description: Chefree Technology Corp. | |
| 200 | 202 | "^chipidea,.*": |
| 201 | 203 | description: Chipidea, Inc |
| 202 | 204 | "^chipone,.*": |
| @@ -601,6 +603,8 @@ patternProperties: · 398 unmodified lines | ||
| 601 | 603 | description: Logic Technologies Limited |
| 602 | 604 | "^longcheer,.*": |
| 603 | 605 | description: Longcheer Technology (Shanghai) Co., Ltd. |
| 606 | + "^lontium,.*": | |
| 607 | + description: Lontium Semiconductor Corporation | |
| 604 | 608 | "^loongson,.*": |
| 605 | 609 | description: Loongson Technology Corporation Limited |
| 606 | 610 | "^lsi,.*": |
| @@ -611,6 +615,8 @@ patternProperties: · 4 unmodified lines | ||
| 611 | 615 | description: Linux Automation GmbH |
| 612 | 616 | "^macnica,.*": |
| 613 | 617 | description: Macnica Americas |
| 618 | + "^mantix,.*": | |
| 619 | + description: Mantix Display Technology Co.,Ltd. | |
| 614 | 620 | "^mapleboard,.*": |
| 615 | 621 | description: Mapleboard.org |
| 616 | 622 | "^marvell,.*": |
| @@ -830,6 +836,8 @@ patternProperties: · 213 unmodified lines | ||
| 830 | 836 | description: Poslab Technology Co., Ltd. |
| 831 | 837 | "^pov,.*": |
| 832 | 838 | description: Point of View International B.V. |
| 839 | + "^powertip,.*": | |
| 840 | + description: Powertip Tech. Corp. | |
| 833 | 841 | "^powervr,.*": |
| 834 | 842 | description: PowerVR (deprecated, use img) |
| 835 | 843 | "^primux,.*": |
| @@ -1,3 +1,5 @@ | ||
| 1 | +.. Copyright 2020 DisplayLink (UK) Ltd. | |
| 2 | + | |
| 1 | 3 | =================== |
| 2 | 4 | Userland interfaces |
| 3 | 5 | =================== |
| @@ -162,6 +164,116 @@ other hand, a driver requires shared state between clients which is · 158 unmodified lines | ||
| 162 | 164 | visible to user-space and accessible beyond open-file boundaries, they |
| 163 | 165 | cannot support render nodes. |
| 164 | 166 | |
| 167 | +Device Hot-Unplug | |
| 168 | +================= | |
| 169 | + | |
| 170 | +.. note:: | |
| 171 | + The following is the plan. Implementation is not there yet | |
| 172 | + (2020 May). | |
| 173 | + | |
| 174 | +Graphics devices (display and/or render) may be connected via USB (e.g. | |
| 175 | +display adapters or docking stations) or Thunderbolt (e.g. eGPU). An end | |
| 176 | +user is able to hot-unplug this kind of devices while they are being | |
| 177 | +used, and expects that the very least the machine does not crash. Any | |
| 178 | +damage from hot-unplugging a DRM device needs to be limited as much as | |
| 179 | +possible and userspace must be given the chance to handle it if it wants | |
| 180 | +to. Ideally, unplugging a DRM device still lets a desktop continue to | |
| 181 | +run, but that is going to need explicit support throughout the whole | |
| 182 | +graphics stack: from kernel and userspace drivers, through display | |
| 183 | +servers, via window system protocols, and in applications and libraries. | |
| 184 | + | |
| 185 | +Other scenarios that should lead to the same are: unrecoverable GPU | |
| 186 | +crash, PCI device disappearing off the bus, or forced unbind of a driver | |
| 187 | +from the physical device. | |
| 188 | + | |
| 189 | +In other words, from userspace perspective everything needs to keep on | |
| 190 | +working more or less, until userspace stops using the disappeared DRM | |
| 191 | +device and closes it completely. Userspace will learn of the device | |
| 192 | +disappearance from the device removed uevent, ioctls returning ENODEV | |
| 193 | +(or driver-specific ioctls returning driver-specific things), or open() | |
| 194 | +returning ENXIO. | |
| 195 | + | |
| 196 | +Only after userspace has closed all relevant DRM device and dmabuf file | |
| 197 | +descriptors and removed all mmaps, the DRM driver can tear down its | |
| 198 | +instance for the device that no longer exists. If the same physical | |
| 199 | +device somehow comes back in the mean time, it shall be a new DRM | |
| 200 | +device. | |
| 201 | + | |
| 202 | +Similar to PIDs, chardev minor numbers are not recycled immediately. A | |
| 203 | +new DRM device always picks the next free minor number compared to the | |
| 204 | +previous one allocated, and wraps around when minor numbers are | |
| 205 | +exhausted. | |
| 206 | + | |
| 207 | +The goal raises at least the following requirements for the kernel and | |
| 208 | +drivers. | |
| 209 | + | |
| 210 | +Requirements for KMS UAPI | |
| 211 | +------------------------- | |
| 212 | + | |
| 213 | +- KMS connectors must change their status to disconnected. | |
| 214 | + | |
| 215 | +- Legacy modesets and pageflips, and atomic commits, both real and | |
| 216 | + TEST_ONLY, and any other ioctls either fail with ENODEV or fake | |
| 217 | + success. | |
| 218 | + | |
| 219 | +- Pending non-blocking KMS operations deliver the DRM events userspace | |
| 220 | + is expecting. This applies also to ioctls that faked success. | |
| 221 | + | |
| 222 | +- open() on a device node whose underlying device has disappeared will | |
| 223 | + fail with ENXIO. | |
| 224 | + | |
| 225 | +- Attempting to create a DRM lease on a disappeared DRM device will | |
| 226 | + fail with ENODEV. Existing DRM leases remain and work as listed | |
| 227 | + above. | |
| 228 | + | |
| 229 | +Requirements for Render and Cross-Device UAPI | |
| 230 | +--------------------------------------------- | |
| 231 | + | |
| 232 | +- All GPU jobs that can no longer run must have their fences | |
| 233 | + force-signalled to avoid inflicting hangs on userspace. | |
| 234 | + The associated error code is ENODEV. | |
| 235 | + | |
| 236 | +- Some userspace APIs already define what should happen when the device | |
| 237 | + disappears (OpenGL, GL ES: `GL_KHR_robustness`_; `Vulkan`_: | |
| 238 | + VK_ERROR_DEVICE_LOST; etc.). DRM drivers are free to implement this | |
| 239 | + behaviour the way they see best, e.g. returning failures in | |
| 240 | + driver-specific ioctls and handling those in userspace drivers, or | |
| 241 | + rely on uevents, and so on. | |
| 242 | + | |
| 243 | +- dmabuf which point to memory that has disappeared will either fail to | |
| 244 | + import with ENODEV or continue to be successfully imported if it would | |
| 245 | + have succeeded before the disappearance. See also about memory maps | |
| 246 | + below for already imported dmabufs. | |
| 247 | + | |
| 248 | +- Attempting to import a dmabuf to a disappeared device will either fail | |
| 249 | + with ENODEV or succeed if it would have succeeded without the | |
| 250 | + disappearance. | |
| 251 | + | |
| 252 | +- open() on a device node whose underlying device has disappeared will | |
| 253 | + fail with ENXIO. | |
| 254 | + | |
| 255 | +.. _GL_KHR_robustness: https://www.khronos.org/registry/OpenGL/extensions/KHR/KHR_robustness.txt | |
| 256 | +.. _Vulkan: https://www.khronos.org/vulkan/ | |
| 257 | + | |
| 258 | +Requirements for Memory Maps | |
| 259 | +---------------------------- | |
| 260 | + | |
| 261 | +Memory maps have further requirements that apply to both existing maps | |
| 262 | +and maps created after the device has disappeared. If the underlying | |
| 263 | +memory disappears, the map is created or modified such that reads and | |
| 264 | +writes will still complete successfully but the result is undefined. | |
| 265 | +This applies to both userspace mmap()'d memory and memory pointed to by | |
| 266 | +dmabuf which might be mapped to other devices (cross-device dmabuf | |
| 267 | +imports). | |
| 268 | + | |
| 269 | +Raising SIGBUS is not an option, because userspace cannot realistically | |
| 270 | +handle it. Signal handlers are global, which makes them extremely | |
| 271 | +difficult to use correctly from libraries like those that Mesa produces. | |
| 272 | +Signal handlers are not composable, you can't have different handlers | |
| 273 | +for GPU1 and GPU2 from different vendors, and a third handler for | |
| 274 | +mmapped regular files. Threads cause additional pain with signal | |
| 275 | +handling as well. | |
| 276 | + | |
| 165 | 277 | .. _drm_driver_ioctl: |
| 166 | 278 | |
| 167 | 279 | IOCTL Support on Device Nodes |
| @@ -199,7 +311,7 @@ EPERM/EACCES: · 31 unmodified lines | ||
| 199 | 311 | difference between EACCES and EPERM. |
| 200 | 312 | |
| 201 | 313 | ENODEV: |
| 202 | − The device is not (yet) present or fully initialized. | |
| 314 | + The device is not present anymore or is not yet fully initialized. | |
| 203 | 315 | |
| 204 | 316 | EOPNOTSUPP: |
| 205 | 317 | Feature (like PRIME, modesetting, GEM) is not supported by the driver. |
| @@ -1,6 +1,6 @@ | ||
| 1 | −========================================== | |
| 2 | − drm/pl111 ARM PrimeCell PL111 CLCD Driver | |
| 3 | −========================================== | |
| 1 | +==================================================== | |
| 2 | + drm/pl111 ARM PrimeCell PL110 and PL111 CLCD Driver | |
| 3 | +==================================================== | |
| 4 | 4 | |
| 5 | 5 | .. kernel-doc:: drivers/gpu/drm/pl111/pl111_drv.c |
| 6 | − :doc: ARM PrimeCell PL111 CLCD Driver | |
| 6 | + :doc: ARM PrimeCell PL110 and PL111 CLCD Driver | |
| @@ -403,6 +403,52 @@ Contact: Emil Velikov, respective driver maintainers · 402 unmodified lines | ||
| 403 | 403 | |
| 404 | 404 | Level: Intermediate |
| 405 | 405 | |
| 406 | +Plumb drm_atomic_state all over | |
| 407 | +------------------------------- | |
| 408 | + | |
| 409 | +Currently various atomic functions take just a single or a handful of | |
| 410 | +object states (eg. plane state). While that single object state can | |
| 411 | +suffice for some simple cases, we often have to dig out additional | |
| 412 | +object states for dealing with various dependencies between the individual | |
| 413 | +objects or the hardware they represent. The process of digging out the | |
| 414 | +additional states is rather non-intuitive and error prone. | |
| 415 | + | |
| 416 | +To fix that most functions should rather take the overall | |
| 417 | +drm_atomic_state as one of their parameters. The other parameters | |
| 418 | +would generally be the object(s) we mainly want to interact with. | |
| 419 | + | |
| 420 | +For example, instead of | |
| 421 | + | |
| 422 | +.. code-block:: c | |
| 423 | + | |
| 424 | + int (*atomic_check)(struct drm_plane *plane, struct drm_plane_state *state); | |
| 425 | + | |
| 426 | +we would have something like | |
| 427 | + | |
| 428 | +.. code-block:: c | |
| 429 | + | |
| 430 | + int (*atomic_check)(struct drm_plane *plane, struct drm_atomic_state *state); | |
| 431 | + | |
| 432 | +The implementation can then trivially gain access to any required object | |
| 433 | +state(s) via drm_atomic_get_plane_state(), drm_atomic_get_new_plane_state(), | |
| 434 | +drm_atomic_get_old_plane_state(), and their equivalents for | |
| 435 | +other object types. | |
| 436 | + | |
| 437 | +Additionally many drivers currently access the object->state pointer | |
| 438 | +directly in their commit functions. That is not going to work if we | |
| 439 | +eg. want to allow deeper commit pipelines as those pointers could | |
| 440 | +then point to the states corresponding to a future commit instead of | |
| 441 | +the current commit we're trying to process. Also non-blocking commits | |
| 442 | +execute locklessly so there are serious concerns with dereferencing | |
| 443 | +the object->state pointers without holding the locks that protect them. | |
| 444 | +Use of drm_atomic_get_new_plane_state(), drm_atomic_get_old_plane_state(), | |
| 445 | +etc. avoids these problems as well since they relate to a specific | |
| 446 | +commit via the passed in drm_atomic_state. | |
| 447 | + | |
| 448 | +Contact: Ville Syrjälä, Daniel Vetter | |
| 449 | + | |
| 450 | +Level: Intermediate | |
| 451 | + | |
| 406 | 452 | |
| 407 | 453 | Core refactorings |
| 408 | 454 | ================= |
| @@ -5474,12 +5474,19 @@ S: Maintained · 5473 unmodified lines | ||
| 5474 | 5474 | F: drivers/gpu/drm/panel/panel-lvds.c |
| 5475 | 5475 | F: Documentation/devicetree/bindings/display/panel/lvds.yaml |
| 5476 | 5476 | |
| 5477 | +DRM DRIVER FOR MANTIX MLAF057WE51 PANELS | |
| 5478 | +M: Guido Günther <agx@sigxcpu.org> | |
| 5479 | +R: Purism Kernel Team <kernel@puri.sm> | |
| 5480 | +S: Maintained | |
| 5481 | +F: Documentation/devicetree/bindings/display/panel/mantix,mlaf057we51-x.yaml | |
| 5482 | +F: drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c | |
| 5483 | + | |
| 5477 | 5484 | DRM DRIVER FOR MATROX G200/G400 GRAPHICS CARDS |
| 5478 | 5485 | S: Orphan / Obsolete |
| 5479 | 5486 | F: drivers/gpu/drm/mga/ |
| 5480 | 5487 | F: include/uapi/drm/mga_drm.h |
| 5481 | 5488 | |
| 5482 | −DRM DRIVER FOR MGA G200 SERVER GRAPHICS CHIPS | |
| 5489 | +DRM DRIVER FOR MGA G200 GRAPHICS CHIPS | |
| 5483 | 5490 | M: Dave Airlie <airlied@redhat.com> |
| 5484 | 5491 | S: Odd Fixes |
| 5485 | 5492 | F: drivers/gpu/drm/mgag200/ |
| @@ -5767,7 +5774,7 @@ F: drivers/gpu/drm/gma500/ · 281 unmodified lines | ||
| 5767 | 5774 | |
| 5768 | 5775 | DRM DRIVERS FOR HISILICON |
| 5769 | 5776 | M: Xinliang Liu <xinliang.liu@linaro.org> |
| 5770 | −M: Rongrong Zou <zourongrong@gmail.com> | |
| 5777 | +M: Tian Tao <tiantao6@hisilicon.com> | |
| 5771 | 5778 | R: John Stultz <john.stultz@linaro.org> |
| 5772 | 5779 | R: Xinwei Kong <kong.kongxinwei@hisilicon.com> |
| 5773 | 5780 | R: Chen Feng <puck.chen@hisilicon.com> |
| @@ -517,8 +517,9 @@ out_put: · 516 unmodified lines | ||
| 517 | 517 | uint64_t amdgpu_amdkfd_get_vram_usage(struct kgd_dev *kgd) |
| 518 | 518 | { |
| 519 | 519 | struct amdgpu_device *adev = (struct amdgpu_device *)kgd; |
| 520 | + struct ttm_resource_manager *vram_man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); | |
| 520 | 521 | |
| 521 | − return amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); | |
| 522 | + return amdgpu_vram_mgr_usage(vram_man); | |
| 522 | 523 | } |
| 523 | 524 | |
| 524 | 525 | uint64_t amdgpu_amdkfd_get_hive_id(struct kgd_dev *kgd) |
| @@ -562,7 +562,7 @@ static int init_user_pages(struct kgd_mem *mem, uint64_t user_addr) · 561 unmodified lines | ||
| 562 | 562 | |
| 563 | 563 | mutex_lock(&process_info->lock); |
| 564 | 564 | |
| 565 | − ret = amdgpu_ttm_tt_set_userptr(bo->tbo.ttm, user_addr, 0); | |
| 565 | + ret = amdgpu_ttm_tt_set_userptr(&bo->tbo, user_addr, 0); | |
| 566 | 566 | if (ret) { |
| 567 | 567 | pr_err("%s: Failed to set userptr: %d\n", __func__, ret); |
| 568 | 568 | goto out; |
| @@ -26,6 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | |
| 27 | 27 | #include <drm/drm_edid.h> |
| 28 | 28 | #include <drm/drm_fb_helper.h> |
| 29 | +#include <drm/drm_dp_helper.h> | |
| 29 | 30 | #include <drm/drm_probe_helper.h> |
| 30 | 31 | #include <drm/amdgpu_drm.h> |
| 31 | 32 | #include "amdgpu.h" |
| @@ -1413,6 +1414,10 @@ out: · 1381 unmodified lines | ||
| 1413 | 1414 | pm_runtime_put_autosuspend(connector->dev->dev); |
| 1414 | 1415 | } |
| 1415 | 1416 | |
| 1417 | + drm_dp_set_subconnector_property(&amdgpu_connector->base, | |
| 1418 | + ret, | |
| 1419 | + amdgpu_dig_connector->dpcd, | |
| 1420 | + amdgpu_dig_connector->downstream_ports); | |
| 1416 | 1421 | return ret; |
| 1417 | 1422 | } |
| 1418 | 1423 | |
| @@ -1959,6 +1964,11 @@ amdgpu_connector_add(struct amdgpu_device *adev, · 540 unmodified lines | ||
| 1959 | 1964 | if (has_aux) |
| 1960 | 1965 | amdgpu_atombios_dp_aux_init(amdgpu_connector); |
| 1961 | 1966 | |
| 1967 | + if (connector_type == DRM_MODE_CONNECTOR_DisplayPort || | |
| 1968 | + connector_type == DRM_MODE_CONNECTOR_eDP) { | |
| 1969 | + drm_connector_attach_dp_subconnector_property(&amdgpu_connector->base); | |
| 1970 | + } | |
| 1971 | + | |
| 1962 | 1972 | return; |
| 1963 | 1973 | |
| 1964 | 1974 | failed: |
| @@ -299,7 +299,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev, · 298 unmodified lines | ||
| 299 | 299 | { |
| 300 | 300 | s64 time_us, increment_us; |
| 301 | 301 | u64 free_vram, total_vram, used_vram; |
| 302 | − | |
| 302 | + struct ttm_resource_manager *vram_man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); | |
| 303 | 303 | /* Allow a maximum of 200 accumulated ms. This is basically per-IB |
| 304 | 304 | * throttling. |
| 305 | 305 | * |
| @@ -316,7 +316,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev, · 10 unmodified lines | ||
| 316 | 316 | } |
| 317 | 317 | |
| 318 | 318 | total_vram = adev->gmc.real_vram_size - atomic64_read(&adev->vram_pin_size); |
| 319 | − used_vram = amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); | |
| 319 | + used_vram = amdgpu_vram_mgr_usage(vram_man); | |
| 320 | 320 | free_vram = used_vram >= total_vram ? 0 : total_vram - used_vram; |
| 321 | 321 | |
| 322 | 322 | spin_lock(&adev->mm_stats.lock); |
| @@ -363,7 +363,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev, · 40 unmodified lines | ||
| 363 | 363 | if (!amdgpu_gmc_vram_full_visible(&adev->gmc)) { |
| 364 | 364 | u64 total_vis_vram = adev->gmc.visible_vram_size; |
| 365 | 365 | u64 used_vis_vram = |
| 366 | − amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); | |
| 366 | + amdgpu_vram_mgr_vis_usage(vram_man); | |
| 367 | 367 | |
| 368 | 368 | if (used_vis_vram < total_vis_vram) { |
| 369 | 369 | u64 free_vis_vram = total_vis_vram - used_vis_vram; |
| @@ -3882,7 +3882,7 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev, · 3881 unmodified lines | ||
| 3882 | 3882 | |
| 3883 | 3883 | amdgpu_virt_init_data_exchange(adev); |
| 3884 | 3884 | /* we need recover gart prior to run SMC/CP/SDMA resume */ |
| 3885 | − amdgpu_gtt_mgr_recover(&adev->mman.bdev.man[TTM_PL_TT]); | |
| 3885 | + amdgpu_gtt_mgr_recover(ttm_manager_type(&adev->mman.bdev, TTM_PL_TT)); | |
| 3886 | 3886 | |
| 3887 | 3887 | r = amdgpu_device_fw_loading(adev); |
| 3888 | 3888 | if (r) |
| @@ -4081,8 +4081,7 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, · 192 unmodified lines | ||
| 4081 | 4081 | amdgpu_inc_vram_lost(tmp_adev); |
| 4082 | 4082 | } |
| 4083 | 4083 | |
| 4084 | − r = amdgpu_gtt_mgr_recover( | |
| 4085 | − &tmp_adev->mman.bdev.man[TTM_PL_TT]); | |
| 4084 | + r = amdgpu_gtt_mgr_recover(ttm_manager_type(&tmp_adev->mman.bdev, TTM_PL_TT)); | |
| 4086 | 4085 | if (r) |
| 4087 | 4086 | goto out; |
| 4088 | 4087 | |
| @@ -393,12 +393,12 @@ MODULE_PARM_DESC(sched_hw_submission, "the max number of HW submissions (default · 392 unmodified lines | ||
| 393 | 393 | module_param_named(sched_hw_submission, amdgpu_sched_hw_submission, int, 0444); |
| 394 | 394 | |
| 395 | 395 | /** |
| 396 | − * DOC: ppfeaturemask (uint) | |
| 396 | + * DOC: ppfeaturemask (hexint) | |
| 397 | 397 | * Override power features enabled. See enum PP_FEATURE_MASK in drivers/gpu/drm/amd/include/amd_shared.h. |
| 398 | 398 | * The default is the current set of stable power features. |
| 399 | 399 | */ |
| 400 | 400 | MODULE_PARM_DESC(ppfeaturemask, "all power features enabled (default))"); |
| 401 | −module_param_named(ppfeaturemask, amdgpu_pp_feature_mask, uint, 0444); | |
| 401 | +module_param_named(ppfeaturemask, amdgpu_pp_feature_mask, hexint, 0444); | |
| 402 | 402 | |
| 403 | 403 | /** |
| 404 | 404 | * DOC: forcelongtraining (uint) |
| @@ -332,7 +332,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data, · 331 unmodified lines | ||
| 332 | 332 | bo = gem_to_amdgpu_bo(gobj); |
| 333 | 333 | bo->preferred_domains = AMDGPU_GEM_DOMAIN_GTT; |
| 334 | 334 | bo->allowed_domains = AMDGPU_GEM_DOMAIN_GTT; |
| 335 | − r = amdgpu_ttm_tt_set_userptr(bo->tbo.ttm, args->addr, args->flags); | |
| 335 | + r = amdgpu_ttm_tt_set_userptr(&bo->tbo, args->addr, args->flags); | |
| 336 | 336 | if (r) |
| 337 | 337 | goto release_object; |
| 338 | 338 | |
| @@ -24,11 +24,10 @@ · 23 unmodified lines | ||
| 24 | 24 | |
| 25 | 25 | #include "amdgpu.h" |
| 26 | 26 | |
| 27 | −struct amdgpu_gtt_mgr { | |
| 28 | − struct drm_mm mm; | |
| 29 | − spinlock_t lock; | |
| 30 | − atomic64_t available; | |
| 31 | −}; | |
| 27 | +static inline struct amdgpu_gtt_mgr *to_gtt_mgr(struct ttm_resource_manager *man) | |
| 28 | +{ | |
| 29 | + return container_of(man, struct amdgpu_gtt_mgr, manager); | |
| 30 | +} | |
| 32 | 31 | |
| 33 | 32 | struct amdgpu_gtt_node { |
| 34 | 33 | struct drm_mm_node node; |
| @@ -48,9 +47,9 @@ static ssize_t amdgpu_mem_info_gtt_total_show(struct device *dev, · 13 unmodified lines | ||
| 48 | 47 | { |
| 49 | 48 | struct drm_device *ddev = dev_get_drvdata(dev); |
| 50 | 49 | struct amdgpu_device *adev = ddev->dev_private; |
| 51 | − | |
| 50 | + struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); | |
| 52 | 51 | return snprintf(buf, PAGE_SIZE, "%llu\n", |
| 53 | − (adev->mman.bdev.man[TTM_PL_TT].size) * PAGE_SIZE); | |
| 52 | + man->size * PAGE_SIZE); | |
| 54 | 53 | } |
| 55 | 54 | |
| 56 | 55 | /** |
| @@ -66,9 +65,9 @@ static ssize_t amdgpu_mem_info_gtt_used_show(struct device *dev, · 9 unmodified lines | ||
| 66 | 65 | { |
| 67 | 66 | struct drm_device *ddev = dev_get_drvdata(dev); |
| 68 | 67 | struct amdgpu_device *adev = ddev->dev_private; |
| 69 | − | |
| 68 | + struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); | |
| 70 | 69 | return snprintf(buf, PAGE_SIZE, "%llu\n", |
| 71 | − amdgpu_gtt_mgr_usage(&adev->mman.bdev.man[TTM_PL_TT])); | |
| 70 | + amdgpu_gtt_mgr_usage(man)); | |
| 72 | 71 | } |
| 73 | 72 | |
| 74 | 73 | static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO, |
| @@ -76,6 +75,7 @@ static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO, · 1 unmodified line | ||
| 76 | 75 | static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO, |
| 77 | 76 | amdgpu_mem_info_gtt_used_show, NULL); |
| 78 | 77 | |
| 78 | +static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func; | |
| 79 | 79 | /** |
| 80 | 80 | * amdgpu_gtt_mgr_init - init GTT manager and DRM MM |
| 81 | 81 | * |
| @@ -84,24 +84,25 @@ static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO, · 2 unmodified lines | ||
| 84 | 84 | * |
| 85 | 85 | * Allocate and initialize the GTT manager. |
| 86 | 86 | */ |
| 87 | −static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man, | |
| 88 | − unsigned long p_size) | |
| 87 | +int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size) | |
| 89 | 88 | { |
| 90 | − struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); | |
| 91 | − struct amdgpu_gtt_mgr *mgr; | |
| 89 | + struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr; | |
| 90 | + struct ttm_resource_manager *man = &mgr->manager; | |
| 92 | 91 | uint64_t start, size; |
| 93 | 92 | int ret; |
| 94 | 93 | |
| 95 | − mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); | |
| 96 | − if (!mgr) | |
| 97 | − return -ENOMEM; | |
| 94 | + man->use_tt = true; | |
| 95 | + man->func = &amdgpu_gtt_mgr_func; | |
| 96 | + man->available_caching = TTM_PL_MASK_CACHING; | |
| 97 | + man->default_caching = TTM_PL_FLAG_CACHED; | |
| 98 | + | |
| 99 | + ttm_resource_manager_init(man, gtt_size >> PAGE_SHIFT); | |
| 98 | 100 | |
| 99 | 101 | start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS; |
| 100 | 102 | size = (adev->gmc.gart_size >> PAGE_SHIFT) - start; |
| 101 | 103 | drm_mm_init(&mgr->mm, start, size); |
| 102 | 104 | spin_lock_init(&mgr->lock); |
| 103 | − atomic64_set(&mgr->available, p_size); | |
| 104 | − man->priv = mgr; | |
| 105 | + atomic64_set(&mgr->available, gtt_size >> PAGE_SHIFT); | |
| 105 | 106 | |
| 106 | 107 | ret = device_create_file(adev->dev, &dev_attr_mem_info_gtt_total); |
| 107 | 108 | if (ret) { |
| @@ -114,6 +115,8 @@ static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man, · 6 unmodified lines | ||
| 114 | 115 | return ret; |
| 115 | 116 | } |
| 116 | 117 | |
| 118 | + ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, &mgr->manager); | |
| 119 | + ttm_resource_manager_set_used(man, true); | |
| 117 | 120 | return 0; |
| 118 | 121 | } |
| 119 | 122 | |
| @@ -125,20 +128,27 @@ static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man, · 5 unmodified lines | ||
| 125 | 128 | * Destroy and free the GTT manager, returns -EBUSY if ranges are still |
| 126 | 129 | * allocated inside it. |
| 127 | 130 | */ |
| 128 | −static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man) | |
| 131 | +void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev) | |
| 129 | 132 | { |
| 130 | − struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); | |
| 131 | − struct amdgpu_gtt_mgr *mgr = man->priv; | |
| 133 | + struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr; | |
| 134 | + struct ttm_resource_manager *man = &mgr->manager; | |
| 135 | + int ret; | |
| 136 | + | |
| 137 | + ttm_resource_manager_set_used(man, false); | |
| 138 | + | |
| 139 | + ret = ttm_resource_manager_force_list_clean(&adev->mman.bdev, man); | |
| 140 | + if (ret) | |
| 141 | + return; | |
| 142 | + | |
| 132 | 143 | spin_lock(&mgr->lock); |
| 133 | 144 | drm_mm_takedown(&mgr->mm); |
| 134 | 145 | spin_unlock(&mgr->lock); |
| 135 | − kfree(mgr); | |
| 136 | − man->priv = NULL; | |
| 137 | 146 | |
| 138 | 147 | device_remove_file(adev->dev, &dev_attr_mem_info_gtt_total); |
| 139 | 148 | device_remove_file(adev->dev, &dev_attr_mem_info_gtt_used); |
| 140 | 149 | |
| 141 | − return 0; | |
| 150 | + ttm_resource_manager_cleanup(man); | |
| 151 | + ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, NULL); | |
| 142 | 152 | } |
| 143 | 153 | |
| 144 | 154 | /** |
| @@ -148,7 +158,7 @@ static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man) · 3 unmodified lines | ||
| 148 | 158 | * |
| 149 | 159 | * Check if a mem object has already address space allocated. |
| 150 | 160 | */ |
| 151 | −bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg *mem) | |
| 161 | +bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem) | |
| 152 | 162 | { |
| 153 | 163 | return mem->mm_node != NULL; |
| 154 | 164 | } |
| @@ -163,12 +173,12 @@ bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg *mem) · 8 unmodified lines | ||
| 163 | 173 | * |
| 164 | 174 | * Dummy, allocate the node but no space for it yet. |
| 165 | 175 | */ |
| 166 | −static int amdgpu_gtt_mgr_new(struct ttm_mem_type_manager *man, | |
| 176 | +static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man, | |
| 167 | 177 | struct ttm_buffer_object *tbo, |
| 168 | 178 | const struct ttm_place *place, |
| 169 | − struct ttm_mem_reg *mem) | |
| 179 | + struct ttm_resource *mem) | |
| 170 | 180 | { |
| 171 | − struct amdgpu_gtt_mgr *mgr = man->priv; | |
| 181 | + struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); | |
| 172 | 182 | struct amdgpu_gtt_node *node; |
| 173 | 183 | int r; |
| 174 | 184 | |
| @@ -226,10 +236,10 @@ err_out: · 51 unmodified lines | ||
| 226 | 236 | * |
| 227 | 237 | * Free the allocated GTT again. |
| 228 | 238 | */ |
| 229 | −static void amdgpu_gtt_mgr_del(struct ttm_mem_type_manager *man, | |
| 230 | − struct ttm_mem_reg *mem) | |
| 239 | +static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man, | |
| 240 | + struct ttm_resource *mem) | |
| 231 | 241 | { |
| 232 | − struct amdgpu_gtt_mgr *mgr = man->priv; | |
| 242 | + struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); | |
| 233 | 243 | struct amdgpu_gtt_node *node = mem->mm_node; |
| 234 | 244 | |
| 235 | 245 | if (node) { |
| @@ -249,17 +259,17 @@ static void amdgpu_gtt_mgr_del(struct ttm_mem_type_manager *man, · 13 unmodified lines | ||
| 249 | 259 | * |
| 250 | 260 | * Return how many bytes are used in the GTT domain |
| 251 | 261 | */ |
| 252 | −uint64_t amdgpu_gtt_mgr_usage(struct ttm_mem_type_manager *man) | |
| 262 | +uint64_t amdgpu_gtt_mgr_usage(struct ttm_resource_manager *man) | |
| 253 | 263 | { |
| 254 | − struct amdgpu_gtt_mgr *mgr = man->priv; | |
| 264 | + struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); | |
| 255 | 265 | s64 result = man->size - atomic64_read(&mgr->available); |
| 256 | 266 | |
| 257 | 267 | return (result > 0 ? result : 0) * PAGE_SIZE; |
| 258 | 268 | } |
| 259 | 269 | |
| 260 | −int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man) | |
| 270 | +int amdgpu_gtt_mgr_recover(struct ttm_resource_manager *man) | |
| 261 | 271 | { |
| 262 | − struct amdgpu_gtt_mgr *mgr = man->priv; | |
| 272 | + struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); | |
| 263 | 273 | struct amdgpu_gtt_node *node; |
| 264 | 274 | struct drm_mm_node *mm_node; |
| 265 | 275 | int r = 0; |
| @@ -284,10 +294,10 @@ int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man) · 18 unmodified lines | ||
| 284 | 294 | * |
| 285 | 295 | * Dump the table content using printk. |
| 286 | 296 | */ |
| 287 | −static void amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager *man, | |
| 297 | +static void amdgpu_gtt_mgr_debug(struct ttm_resource_manager *man, | |
| 288 | 298 | struct drm_printer *printer) |
| 289 | 299 | { |
| 290 | − struct amdgpu_gtt_mgr *mgr = man->priv; | |
| 300 | + struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); | |
| 291 | 301 | |
| 292 | 302 | spin_lock(&mgr->lock); |
| 293 | 303 | drm_mm_print(&mgr->mm, printer); |
| @@ -298,10 +308,8 @@ static void amdgpu_gtt_mgr_debug(struct ttm_mem_type_manager *man, · 4 unmodified lines | ||
| 298 | 308 | amdgpu_gtt_mgr_usage(man) >> 20); |
| 299 | 309 | } |
| 300 | 310 | |
| 301 | −const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func = { | |
| 302 | − .init = amdgpu_gtt_mgr_init, | |
| 303 | − .takedown = amdgpu_gtt_mgr_fini, | |
| 304 | − .get_node = amdgpu_gtt_mgr_new, | |
| 305 | − .put_node = amdgpu_gtt_mgr_del, | |
| 311 | +static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func = { | |
| 312 | + .alloc = amdgpu_gtt_mgr_new, | |
| 313 | + .free = amdgpu_gtt_mgr_del, | |
| 306 | 314 | .debug = amdgpu_gtt_mgr_debug |
| 307 | 315 | }; |
| @@ -594,13 +594,13 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file · 593 unmodified lines | ||
| 594 | 594 | ui64 = atomic64_read(&adev->num_vram_cpu_page_faults); |
| 595 | 595 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; |
| 596 | 596 | case AMDGPU_INFO_VRAM_USAGE: |
| 597 | − ui64 = amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); | |
| 597 | + ui64 = amdgpu_vram_mgr_usage(ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM)); | |
| 598 | 598 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; |
| 599 | 599 | case AMDGPU_INFO_VIS_VRAM_USAGE: |
| 600 | − ui64 = amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); | |
| 600 | + ui64 = amdgpu_vram_mgr_vis_usage(ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM)); | |
| 601 | 601 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; |
| 602 | 602 | case AMDGPU_INFO_GTT_USAGE: |
| 603 | − ui64 = amdgpu_gtt_mgr_usage(&adev->mman.bdev.man[TTM_PL_TT]); | |
| 603 | + ui64 = amdgpu_gtt_mgr_usage(ttm_manager_type(&adev->mman.bdev, TTM_PL_TT)); | |
| 604 | 604 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; |
| 605 | 605 | case AMDGPU_INFO_GDS_CONFIG: { |
| 606 | 606 | struct drm_amdgpu_info_gds gds_info; |
| @@ -623,7 +623,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file · 16 unmodified lines | ||
| 623 | 623 | min(adev->gmc.visible_vram_size - |
| 624 | 624 | atomic64_read(&adev->visible_pin_size), |
| 625 | 625 | vram_gtt.vram_size); |
| 626 | − vram_gtt.gtt_size = adev->mman.bdev.man[TTM_PL_TT].size; | |
| 626 | + vram_gtt.gtt_size = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT)->size; | |
| 627 | 627 | vram_gtt.gtt_size *= PAGE_SIZE; |
| 628 | 628 | vram_gtt.gtt_size -= atomic64_read(&adev->gart_pin_size); |
| 629 | 629 | return copy_to_user(out, &vram_gtt, |
| @@ -631,14 +631,17 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file · 1 unmodified line | ||
| 631 | 631 | } |
| 632 | 632 | case AMDGPU_INFO_MEMORY: { |
| 633 | 633 | struct drm_amdgpu_memory_info mem; |
| 634 | − | |
| 634 | + struct ttm_resource_manager *vram_man = | |
| 635 | + ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); | |
| 636 | + struct ttm_resource_manager *gtt_man = | |
| 637 | + ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); | |
| 635 | 638 | memset(&mem, 0, sizeof(mem)); |
| 636 | 639 | mem.vram.total_heap_size = adev->gmc.real_vram_size; |
| 637 | 640 | mem.vram.usable_heap_size = adev->gmc.real_vram_size - |
| 638 | 641 | atomic64_read(&adev->vram_pin_size) - |
| 639 | 642 | AMDGPU_VM_RESERVED_VRAM; |
| 640 | 643 | mem.vram.heap_usage = |
| 641 | − amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); | |
| 644 | + amdgpu_vram_mgr_usage(vram_man); | |
| 642 | 645 | mem.vram.max_allocation = mem.vram.usable_heap_size * 3 / 4; |
| 643 | 646 | |
| 644 | 647 | mem.cpu_accessible_vram.total_heap_size = |
| @@ -648,16 +651,16 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file · 3 unmodified lines | ||
| 648 | 651 | atomic64_read(&adev->visible_pin_size), |
| 649 | 652 | mem.vram.usable_heap_size); |
| 650 | 653 | mem.cpu_accessible_vram.heap_usage = |
| 651 | − amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); | |
| 654 | + amdgpu_vram_mgr_vis_usage(vram_man); | |
| 652 | 655 | mem.cpu_accessible_vram.max_allocation = |
| 653 | 656 | mem.cpu_accessible_vram.usable_heap_size * 3 / 4; |
| 654 | 657 | |
| 655 | − mem.gtt.total_heap_size = adev->mman.bdev.man[TTM_PL_TT].size; | |
| 658 | + mem.gtt.total_heap_size = gtt_man->size; | |
| 656 | 659 | mem.gtt.total_heap_size *= PAGE_SIZE; |
| 657 | 660 | mem.gtt.usable_heap_size = mem.gtt.total_heap_size - |
| 658 | 661 | atomic64_read(&adev->gart_pin_size); |
| 659 | 662 | mem.gtt.heap_usage = |
| 660 | − amdgpu_gtt_mgr_usage(&adev->mman.bdev.man[TTM_PL_TT]); | |
| 663 | + amdgpu_gtt_mgr_usage(gtt_man); | |
| 661 | 664 | mem.gtt.max_allocation = mem.gtt.usable_heap_size * 3 / 4; |
| 662 | 665 | |
| 663 | 666 | return copy_to_user(out, &mem, |
| @@ -469,6 +469,7 @@ struct amdgpu_encoder { · 468 unmodified lines | ||
| 469 | 469 | struct amdgpu_connector_atom_dig { |
| 470 | 470 | /* displayport */ |
| 471 | 471 | u8 dpcd[DP_RECEIVER_CAP_SIZE]; |
| 472 | + u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; | |
| 472 | 473 | u8 dp_sink_type; |
| 473 | 474 | int dp_clock; |
| 474 | 475 | int dp_lane_count; |
| @@ -381,7 +381,7 @@ int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev, · 380 unmodified lines | ||
| 381 | 381 | if (cpu_addr) |
| 382 | 382 | amdgpu_bo_kunmap(*bo_ptr); |
| 383 | 383 | |
| 384 | − ttm_bo_mem_put(&(*bo_ptr)->tbo, &(*bo_ptr)->tbo.mem); | |
| 384 | + ttm_resource_free(&(*bo_ptr)->tbo, &(*bo_ptr)->tbo.mem); | |
| 385 | 385 | |
| 386 | 386 | for (i = 0; i < (*bo_ptr)->placement.num_placement; ++i) { |
| 387 | 387 | (*bo_ptr)->placements[i].fpfn = offset >> PAGE_SHIFT; |
| @@ -442,14 +442,14 @@ void amdgpu_bo_free_kernel(struct amdgpu_bo **bo, u64 *gpu_addr, · 54 unmodified lines | ||
| 442 | 442 | static bool amdgpu_bo_validate_size(struct amdgpu_device *adev, |
| 443 | 443 | unsigned long size, u32 domain) |
| 444 | 444 | { |
| 445 | − struct ttm_mem_type_manager *man = NULL; | |
| 445 | + struct ttm_resource_manager *man = NULL; | |
| 446 | 446 | |
| 447 | 447 | /* |
| 448 | 448 | * If GTT is part of requested domains the check must succeed to |
| 449 | 449 | * allow fall back to GTT |
| 450 | 450 | */ |
| 451 | 451 | if (domain & AMDGPU_GEM_DOMAIN_GTT) { |
| 452 | − man = &adev->mman.bdev.man[TTM_PL_TT]; | |
| 452 | + man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); | |
| 453 | 453 | |
| 454 | 454 | if (size < (man->size << PAGE_SHIFT)) |
| 455 | 455 | return true; |
| @@ -458,7 +458,7 @@ static bool amdgpu_bo_validate_size(struct amdgpu_device *adev, · 2 unmodified lines | ||
| 458 | 458 | } |
| 459 | 459 | |
| 460 | 460 | if (domain & AMDGPU_GEM_DOMAIN_VRAM) { |
| 461 | − man = &adev->mman.bdev.man[TTM_PL_VRAM]; | |
| 461 | + man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); | |
| 462 | 462 | |
| 463 | 463 | if (size < (man->size << PAGE_SHIFT)) |
| 464 | 464 | return true; |
| @@ -1268,11 +1268,11 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, · 803 unmodified lines | ||
| 1268 | 1268 | */ |
| 1269 | 1269 | void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, |
| 1270 | 1270 | bool evict, |
| 1271 | − struct ttm_mem_reg *new_mem) | |
| 1271 | + struct ttm_resource *new_mem) | |
| 1272 | 1272 | { |
| 1273 | 1273 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); |
| 1274 | 1274 | struct amdgpu_bo *abo; |
| 1275 | − struct ttm_mem_reg *old_mem = &bo->mem; | |
| 1275 | + struct ttm_resource *old_mem = &bo->mem; | |
| 1276 | 1276 | |
| 1277 | 1277 | if (!amdgpu_bo_is_amdgpu_bo(bo)) |
| 1278 | 1278 | return; |
| @@ -160,7 +160,7 @@ static inline int amdgpu_bo_reserve(struct amdgpu_bo *bo, bool no_intr) · 159 unmodified lines | ||
| 160 | 160 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); |
| 161 | 161 | int r; |
| 162 | 162 | |
| 163 | − r = __ttm_bo_reserve(&bo->tbo, !no_intr, false, NULL); | |
| 163 | + r = ttm_bo_reserve(&bo->tbo, !no_intr, false, NULL); | |
| 164 | 164 | if (unlikely(r != 0)) { |
| 165 | 165 | if (r != -ERESTARTSYS) |
| 166 | 166 | dev_err(adev->dev, "%p reserve failed\n", bo); |
| @@ -283,7 +283,7 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, · 116 unmodified lines | ||
| 283 | 283 | uint64_t *flags); |
| 284 | 284 | void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, |
| 285 | 285 | bool evict, |
| 286 | − struct ttm_mem_reg *new_mem); | |
| 286 | + struct ttm_resource *new_mem); | |
| 287 | 287 | void amdgpu_bo_release_notify(struct ttm_buffer_object *bo); |
| 288 | 288 | int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo); |
| 289 | 289 | void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence, |
| @@ -63,61 +63,13 @@ · 62 unmodified lines | ||
| 63 | 63 | |
| 64 | 64 | #define AMDGPU_TTM_VRAM_MAX_DW_READ (size_t)128 |
| 65 | 65 | |
| 66 | − | |
| 67 | −/** | |
| 68 | − * amdgpu_init_mem_type - Initialize a memory manager for a specific type of | |
| 69 | − * memory request. | |
| 70 | − * | |
| 71 | − * @bdev: The TTM BO device object (contains a reference to amdgpu_device) | |
| 72 | − * @type: The type of memory requested | |
| 73 | − * @man: The memory type manager for each domain | |
| 74 | − * | |
| 75 | − * This is called by ttm_bo_init_mm() when a buffer object is being | |
| 76 | − * initialized. | |
| 77 | − */ | |
| 78 | −static int amdgpu_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | |
| 79 | − struct ttm_mem_type_manager *man) | |
| 66 | +static int amdgpu_ttm_init_on_chip(struct amdgpu_device *adev, | |
| 67 | + unsigned int type, | |
| 68 | + uint64_t size) | |
| 80 | 69 | { |
| 81 | − struct amdgpu_device *adev; | |
| 82 | − | |
| 83 | − adev = amdgpu_ttm_adev(bdev); | |
| 84 | − | |
| 85 | − switch (type) { | |
| 86 | − case TTM_PL_SYSTEM: | |
| 87 | − /* System memory */ | |
| 88 | − man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | |
| 89 | − man->available_caching = TTM_PL_MASK_CACHING; | |
| 90 | − man->default_caching = TTM_PL_FLAG_CACHED; | |
| 91 | − break; | |
| 92 | − case TTM_PL_TT: | |
| 93 | − /* GTT memory */ | |
| 94 | − man->func = &amdgpu_gtt_mgr_func; | |
| 95 | − man->available_caching = TTM_PL_MASK_CACHING; | |
| 96 | − man->default_caching = TTM_PL_FLAG_CACHED; | |
| 97 | − man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | |
| 98 | − break; | |
| 99 | − case TTM_PL_VRAM: | |
| 100 | − /* "On-card" video ram */ | |
| 101 | − man->func = &amdgpu_vram_mgr_func; | |
| 102 | − man->flags = TTM_MEMTYPE_FLAG_FIXED | | |
| 103 | − TTM_MEMTYPE_FLAG_MAPPABLE; | |
| 104 | − man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; | |
| 105 | − man->default_caching = TTM_PL_FLAG_WC; | |
| 106 | − break; | |
| 107 | − case AMDGPU_PL_GDS: | |
| 108 | − case AMDGPU_PL_GWS: | |
| 109 | − case AMDGPU_PL_OA: | |
| 110 | − /* On-chip GDS memory*/ | |
| 111 | − man->func = &ttm_bo_manager_func; | |
| 112 | − man->flags = TTM_MEMTYPE_FLAG_FIXED; | |
| 113 | − man->available_caching = TTM_PL_FLAG_UNCACHED; | |
| 114 | − man->default_caching = TTM_PL_FLAG_UNCACHED; | |
| 115 | − break; | |
| 116 | − default: | |
| 117 | − DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); | |
| 118 | − return -EINVAL; | |
| 119 | − } | |
| 120 | − return 0; | |
| 70 | + return ttm_range_man_init(&adev->mman.bdev, type, | |
| 71 | + TTM_PL_FLAG_UNCACHED, TTM_PL_FLAG_UNCACHED, | |
| 72 | + false, size >> PAGE_SHIFT); | |
| 121 | 73 | } |
| 122 | 74 | |
| 123 | 75 | /** |
| @@ -231,9 +183,9 @@ static int amdgpu_verify_access(struct ttm_buffer_object *bo, struct file *filp) · 107 unmodified lines | ||
| 231 | 183 | * Assign the memory from new_mem to the memory of the buffer object bo. |
| 232 | 184 | */ |
| 233 | 185 | static void amdgpu_move_null(struct ttm_buffer_object *bo, |
| 234 | − struct ttm_mem_reg *new_mem) | |
| 186 | + struct ttm_resource *new_mem) | |
| 235 | 187 | { |
| 236 | − struct ttm_mem_reg *old_mem = &bo->mem; | |
| 188 | + struct ttm_resource *old_mem = &bo->mem; | |
| 237 | 189 | |
| 238 | 190 | BUG_ON(old_mem->mm_node != NULL); |
| 239 | 191 | *old_mem = *new_mem; |
| @@ -250,7 +202,7 @@ static void amdgpu_move_null(struct ttm_buffer_object *bo, · 10 unmodified lines | ||
| 250 | 202 | */ |
| 251 | 203 | static uint64_t amdgpu_mm_node_addr(struct ttm_buffer_object *bo, |
| 252 | 204 | struct drm_mm_node *mm_node, |
| 253 | − struct ttm_mem_reg *mem) | |
| 205 | + struct ttm_resource *mem) | |
| 254 | 206 | { |
| 255 | 207 | uint64_t addr = 0; |
| 256 | 208 | |
| @@ -270,7 +222,7 @@ static uint64_t amdgpu_mm_node_addr(struct ttm_buffer_object *bo, · 13 unmodified lines | ||
| 270 | 222 | * @offset: The offset that drm_mm_node is used for finding. |
| 271 | 223 | * |
| 272 | 224 | */ |
| 273 | −static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_mem_reg *mem, | |
| 225 | +static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_resource *mem, | |
| 274 | 226 | uint64_t *offset) |
| 275 | 227 | { |
| 276 | 228 | struct drm_mm_node *mm_node = mem->mm_node; |
| @@ -298,7 +250,7 @@ static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_mem_reg *mem, · 21 unmodified lines | ||
| 298 | 250 | * the physical address for local memory. |
| 299 | 251 | */ |
| 300 | 252 | static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo, |
| 301 | − struct ttm_mem_reg *mem, | |
| 253 | + struct ttm_resource *mem, | |
| 302 | 254 | struct drm_mm_node *mm_node, |
| 303 | 255 | unsigned num_pages, uint64_t offset, |
| 304 | 256 | unsigned window, struct amdgpu_ring *ring, |
| @@ -522,8 +474,8 @@ error: · 217 unmodified lines | ||
| 522 | 474 | */ |
| 523 | 475 | static int amdgpu_move_blit(struct ttm_buffer_object *bo, |
| 524 | 476 | bool evict, bool no_wait_gpu, |
| 525 | − struct ttm_mem_reg *new_mem, | |
| 526 | − struct ttm_mem_reg *old_mem) | |
| 477 | + struct ttm_resource *new_mem, | |
| 478 | + struct ttm_resource *old_mem) | |
| 527 | 479 | { |
| 528 | 480 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); |
| 529 | 481 | struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo); |
| @@ -582,10 +534,10 @@ error: · 52 unmodified lines | ||
| 582 | 534 | */ |
| 583 | 535 | static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict, |
| 584 | 536 | struct ttm_operation_ctx *ctx, |
| 585 | − struct ttm_mem_reg *new_mem) | |
| 537 | + struct ttm_resource *new_mem) | |
| 586 | 538 | { |
| 587 | − struct ttm_mem_reg *old_mem = &bo->mem; | |
| 588 | − struct ttm_mem_reg tmp_mem; | |
| 539 | + struct ttm_resource *old_mem = &bo->mem; | |
| 540 | + struct ttm_resource tmp_mem; | |
| 589 | 541 | struct ttm_place placements; |
| 590 | 542 | struct ttm_placement placement; |
| 591 | 543 | int r; |
| @@ -627,7 +579,7 @@ static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict, · 35 unmodified lines | ||
| 627 | 579 | /* move BO (in tmp_mem) to new_mem */ |
| 628 | 580 | r = ttm_bo_move_ttm(bo, ctx, new_mem); |
| 629 | 581 | out_cleanup: |
| 630 | − ttm_bo_mem_put(bo, &tmp_mem); | |
| 582 | + ttm_resource_free(bo, &tmp_mem); | |
| 631 | 583 | return r; |
| 632 | 584 | } |
| 633 | 585 | |
| @@ -638,10 +590,10 @@ out_cleanup: · 4 unmodified lines | ||
| 638 | 590 | */ |
| 639 | 591 | static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, bool evict, |
| 640 | 592 | struct ttm_operation_ctx *ctx, |
| 641 | − struct ttm_mem_reg *new_mem) | |
| 593 | + struct ttm_resource *new_mem) | |
| 642 | 594 | { |
| 643 | − struct ttm_mem_reg *old_mem = &bo->mem; | |
| 644 | − struct ttm_mem_reg tmp_mem; | |
| 595 | + struct ttm_resource *old_mem = &bo->mem; | |
| 596 | + struct ttm_resource tmp_mem; | |
| 645 | 597 | struct ttm_placement placement; |
| 646 | 598 | struct ttm_place placements; |
| 647 | 599 | int r; |
| @@ -674,7 +626,7 @@ static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, bool evict, · 26 unmodified lines | ||
| 674 | 626 | goto out_cleanup; |
| 675 | 627 | } |
| 676 | 628 | out_cleanup: |
| 677 | − ttm_bo_mem_put(bo, &tmp_mem); | |
| 629 | + ttm_resource_free(bo, &tmp_mem); | |
| 678 | 630 | return r; |
| 679 | 631 | } |
| 680 | 632 | |
| @@ -684,7 +636,7 @@ out_cleanup: · 3 unmodified lines | ||
| 684 | 636 | * Called by amdgpu_bo_move() |
| 685 | 637 | */ |
| 686 | 638 | static bool amdgpu_mem_visible(struct amdgpu_device *adev, |
| 687 | − struct ttm_mem_reg *mem) | |
| 639 | + struct ttm_resource *mem) | |
| 688 | 640 | { |
| 689 | 641 | struct drm_mm_node *nodes = mem->mm_node; |
| 690 | 642 | |
| @@ -694,7 +646,7 @@ static bool amdgpu_mem_visible(struct amdgpu_device *adev, · 3 unmodified lines | ||
| 694 | 646 | if (mem->mem_type != TTM_PL_VRAM) |
| 695 | 647 | return false; |
| 696 | 648 | |
| 697 | − /* ttm_mem_reg_ioremap only supports contiguous memory */ | |
| 649 | + /* ttm_resource_ioremap only supports contiguous memory */ | |
| 698 | 650 | if (nodes->size != mem->num_pages) |
| 699 | 651 | return false; |
| 700 | 652 | |
| @@ -709,11 +661,11 @@ static bool amdgpu_mem_visible(struct amdgpu_device *adev, · 8 unmodified lines | ||
| 709 | 661 | */ |
| 710 | 662 | static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict, |
| 711 | 663 | struct ttm_operation_ctx *ctx, |
| 712 | − struct ttm_mem_reg *new_mem) | |
| 664 | + struct ttm_resource *new_mem) | |
| 713 | 665 | { |
| 714 | 666 | struct amdgpu_device *adev; |
| 715 | 667 | struct amdgpu_bo *abo; |
| 716 | − struct ttm_mem_reg *old_mem = &bo->mem; | |
| 668 | + struct ttm_resource *old_mem = &bo->mem; | |
| 717 | 669 | int r; |
| 718 | 670 | |
| 719 | 671 | /* Can't move a pinned BO */ |
| @@ -795,19 +747,12 @@ memcpy: · 75 unmodified lines | ||
| 795 | 747 | * |
| 796 | 748 | * Called by ttm_mem_io_reserve() ultimately via ttm_bo_vm_fault() |
| 797 | 749 | */ |
| 798 | −static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) | |
| 750 | +static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *mem) | |
| 799 | 751 | { |
| 800 | − struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; | |
| 801 | 752 | struct amdgpu_device *adev = amdgpu_ttm_adev(bdev); |
| 802 | 753 | struct drm_mm_node *mm_node = mem->mm_node; |
| 754 | + size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT; | |
| 803 | 755 | |
| 804 | − mem->bus.addr = NULL; | |
| 805 | − mem->bus.offset = 0; | |
| 806 | − mem->bus.size = mem->num_pages << PAGE_SHIFT; | |
| 807 | − mem->bus.base = 0; | |
| 808 | − mem->bus.is_iomem = false; | |
| 809 | − if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) | |
| 810 | − return -EINVAL; | |
| 811 | 756 | switch (mem->mem_type) { |
| 812 | 757 | case TTM_PL_SYSTEM: |
| 813 | 758 | /* system memory */ |
| @@ -817,11 +762,11 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_ · 3 unmodified lines | ||
| 817 | 762 | case TTM_PL_VRAM: |
| 818 | 763 | mem->bus.offset = mem->start << PAGE_SHIFT; |
| 819 | 764 | /* check if it's visible */ |
| 820 | − if ((mem->bus.offset + mem->bus.size) > adev->gmc.visible_vram_size) | |
| 765 | + if ((mem->bus.offset + bus_size) > adev->gmc.visible_vram_size) | |
| 821 | 766 | return -EINVAL; |
| 822 | 767 | /* Only physically contiguous buffers apply. In a contiguous |
| 823 | 768 | * buffer, size of the first mm_node would match the number of |
| 824 | − * pages in ttm_mem_reg. | |
| 769 | + * pages in ttm_resource. | |
| 825 | 770 | */ |
| 826 | 771 | if (adev->mman.aper_base_kaddr && |
| 827 | 772 | (mm_node->size == mem->num_pages)) |
| @@ -1166,7 +1111,7 @@ gart_bind_fail: · 338 unmodified lines | ||
| 1166 | 1111 | * This handles binding GTT memory to the device address space. |
| 1167 | 1112 | */ |
| 1168 | 1113 | static int amdgpu_ttm_backend_bind(struct ttm_tt *ttm, |
| 1169 | − struct ttm_mem_reg *bo_mem) | |
| 1114 | + struct ttm_resource *bo_mem) | |
| 1170 | 1115 | { |
| 1171 | 1116 | struct amdgpu_device *adev = amdgpu_ttm_adev(ttm->bdev); |
| 1172 | 1117 | struct amdgpu_ttm_tt *gtt = (void*)ttm; |
| @@ -1217,7 +1162,7 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo) · 44 unmodified lines | ||
| 1217 | 1162 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); |
| 1218 | 1163 | struct ttm_operation_ctx ctx = { false, false }; |
| 1219 | 1164 | struct amdgpu_ttm_tt *gtt = (void*)bo->ttm; |
| 1220 | − struct ttm_mem_reg tmp; | |
| 1165 | + struct ttm_resource tmp; | |
| 1221 | 1166 | struct ttm_placement placement; |
| 1222 | 1167 | struct ttm_place placements; |
| 1223 | 1168 | uint64_t addr, flags; |
| @@ -1254,11 +1199,11 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo) · 30 unmodified lines | ||
| 1254 | 1199 | gtt->offset = (u64)tmp.start << PAGE_SHIFT; |
| 1255 | 1200 | r = amdgpu_ttm_gart_bind(adev, bo, flags); |
| 1256 | 1201 | if (unlikely(r)) { |
| 1257 | − ttm_bo_mem_put(bo, &tmp); | |
| 1202 | + ttm_resource_free(bo, &tmp); | |
| 1258 | 1203 | return r; |
| 1259 | 1204 | } |
| 1260 | 1205 | |
| 1261 | − ttm_bo_mem_put(bo, &bo->mem); | |
| 1206 | + ttm_resource_free(bo, &bo->mem); | |
| 1262 | 1207 | bo->mem = tmp; |
| 1263 | 1208 | } |
| 1264 | 1209 | |
| @@ -1457,21 +1402,26 @@ static void amdgpu_ttm_tt_unpopulate(struct ttm_tt *ttm) · 192 unmodified lines | ||
| 1457 | 1402 | * amdgpu_ttm_tt_set_userptr - Initialize userptr GTT ttm_tt for the current |
| 1458 | 1403 | * task |
| 1459 | 1404 | * |
| 1460 | − * @ttm: The ttm_tt object to bind this userptr object to | |
| 1405 | + * @bo: The ttm_buffer_object to bind this userptr to | |
| 1461 | 1406 | * @addr: The address in the current tasks VM space to use |
| 1462 | 1407 | * @flags: Requirements of userptr object. |
| 1463 | 1408 | * |
| 1464 | 1409 | * Called by amdgpu_gem_userptr_ioctl() to bind userptr pages |
| 1465 | 1410 | * to current task |
| 1466 | 1411 | */ |
| 1467 | −int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr, | |
| 1468 | − uint32_t flags) | |
| 1412 | +int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo, | |
| 1413 | + uint64_t addr, uint32_t flags) | |
| 1469 | 1414 | { |
| 1470 | − struct amdgpu_ttm_tt *gtt = (void *)ttm; | |
| 1415 | + struct amdgpu_ttm_tt *gtt; | |
| 1471 | 1416 | |
| 1472 | − if (gtt == NULL) | |
| 1473 | − return -EINVAL; | |
| 1417 | + if (!bo->ttm) { | |
| 1418 | + /* TODO: We want a separate TTM object type for userptrs */ | |
| 1419 | + bo->ttm = amdgpu_ttm_tt_create(bo, 0); | |
| 1420 | + if (bo->ttm == NULL) | |
| 1421 | + return -ENOMEM; | |
| 1422 | + } | |
| 1474 | 1423 | |
| 1424 | + gtt = (void*)bo->ttm; | |
| 1475 | 1425 | gtt->userptr = addr; |
| 1476 | 1426 | gtt->userflags = flags; |
| 1477 | 1427 | |
| @@ -1557,7 +1507,7 @@ bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm) · 79 unmodified lines | ||
| 1557 | 1507 | * |
| 1558 | 1508 | * Figure out the flags to use for a VM PDE (Page Directory Entry). |
| 1559 | 1509 | */ |
| 1560 | −uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_mem_reg *mem) | |
| 1510 | +uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_resource *mem) | |
| 1561 | 1511 | { |
| 1562 | 1512 | uint64_t flags = 0; |
| 1563 | 1513 | |
| @@ -1583,7 +1533,7 @@ uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_mem_reg *mem) · 19 unmodified lines | ||
| 1583 | 1533 | * Figure out the flags to use for a VM PTE (Page Table Entry). |
| 1584 | 1534 | */ |
| 1585 | 1535 | uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm, |
| 1586 | − struct ttm_mem_reg *mem) | |
| 1536 | + struct ttm_resource *mem) | |
| 1587 | 1537 | { |
| 1588 | 1538 | uint64_t flags = amdgpu_ttm_tt_pde_flags(ttm, mem); |
| 1589 | 1539 | |
| @@ -1741,7 +1691,6 @@ static struct ttm_bo_driver amdgpu_bo_driver = { · 151 unmodified lines | ||
| 1741 | 1691 | .ttm_tt_create = &amdgpu_ttm_tt_create, |
| 1742 | 1692 | .ttm_tt_populate = &amdgpu_ttm_tt_populate, |
| 1743 | 1693 | .ttm_tt_unpopulate = &amdgpu_ttm_tt_unpopulate, |
| 1744 | − .init_mem_type = &amdgpu_init_mem_type, | |
| 1745 | 1694 | .eviction_valuable = amdgpu_ttm_bo_eviction_valuable, |
| 1746 | 1695 | .evict_flags = &amdgpu_evict_flags, |
| 1747 | 1696 | .move = &amdgpu_bo_move, |
| @@ -1936,8 +1885,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) · 188 unmodified lines | ||
| 1936 | 1885 | adev->mman.bdev.no_retry = true; |
| 1937 | 1886 | |
| 1938 | 1887 | /* Initialize VRAM pool with all of VRAM divided into pages */ |
| 1939 | − r = ttm_bo_init_mm(&adev->mman.bdev, TTM_PL_VRAM, | |
| 1940 | − adev->gmc.real_vram_size >> PAGE_SHIFT); | |
| 1888 | + r = amdgpu_vram_mgr_init(adev); | |
| 1941 | 1889 | if (r) { |
| 1942 | 1890 | DRM_ERROR("Failed initializing VRAM heap.\n"); |
| 1943 | 1891 | return r; |
| @@ -2004,7 +1952,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) · 60 unmodified lines | ||
| 2004 | 1952 | gtt_size = (uint64_t)amdgpu_gtt_size << 20; |
| 2005 | 1953 | |
| 2006 | 1954 | /* Initialize GTT memory pool */ |
| 2007 | − r = ttm_bo_init_mm(&adev->mman.bdev, TTM_PL_TT, gtt_size >> PAGE_SHIFT); | |
| 1955 | + r = amdgpu_gtt_mgr_init(adev, gtt_size); | |
| 2008 | 1956 | if (r) { |
| 2009 | 1957 | DRM_ERROR("Failed initializing GTT heap.\n"); |
| 2010 | 1958 | return r; |
| @@ -2013,22 +1961,19 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) · 2 unmodified lines | ||
| 2013 | 1961 | (unsigned)(gtt_size / (1024 * 1024))); |
| 2014 | 1962 | |
| 2015 | 1963 | /* Initialize various on-chip memory pools */ |
| 2016 | − r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GDS, | |
| 2017 | − adev->gds.gds_size); | |
| 1964 | + r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GDS, adev->gds.gds_size); | |
| 2018 | 1965 | if (r) { |
| 2019 | 1966 | DRM_ERROR("Failed initializing GDS heap.\n"); |
| 2020 | 1967 | return r; |
| 2021 | 1968 | } |
| 2022 | 1969 | |
| 2023 | − r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GWS, | |
| 2024 | − adev->gds.gws_size); | |
| 1970 | + r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GWS, adev->gds.gws_size); | |
| 2025 | 1971 | if (r) { |
| 2026 | 1972 | DRM_ERROR("Failed initializing gws heap.\n"); |
| 2027 | 1973 | return r; |
| 2028 | 1974 | } |
| 2029 | 1975 | |
| 2030 | − r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_OA, | |
| 2031 | − adev->gds.oa_size); | |
| 1976 | + r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_OA, adev->gds.oa_size); | |
| 2032 | 1977 | if (r) { |
| 2033 | 1978 | DRM_ERROR("Failed initializing oa heap.\n"); |
| 2034 | 1979 | return r; |
| @@ -2064,11 +2009,11 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) · 29 unmodified lines | ||
| 2064 | 2009 | iounmap(adev->mman.aper_base_kaddr); |
| 2065 | 2010 | adev->mman.aper_base_kaddr = NULL; |
| 2066 | 2011 | |
| 2067 | − ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_VRAM); | |
| 2068 | − ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_TT); | |
| 2069 | − ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GDS); | |
| 2070 | − ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GWS); | |
| 2071 | − ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_OA); | |
| 2012 | + amdgpu_vram_mgr_fini(adev); | |
| 2013 | + amdgpu_gtt_mgr_fini(adev); | |
| 2014 | + ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GDS); | |
| 2015 | + ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GWS); | |
| 2016 | + ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_OA); | |
| 2072 | 2017 | ttm_bo_device_release(&adev->mman.bdev); |
| 2073 | 2018 | adev->mman.initialized = false; |
| 2074 | 2019 | DRM_INFO("amdgpu: ttm finalized\n"); |
| @@ -2085,7 +2030,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) · 10 unmodified lines | ||
| 2085 | 2030 | */ |
| 2086 | 2031 | void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable) |
| 2087 | 2032 | { |
| 2088 | − struct ttm_mem_type_manager *man = &adev->mman.bdev.man[TTM_PL_VRAM]; | |
| 2033 | + struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); | |
| 2089 | 2034 | uint64_t size; |
| 2090 | 2035 | int r; |
| 2091 | 2036 | |
| @@ -2307,7 +2252,7 @@ static int amdgpu_mm_dump_table(struct seq_file *m, void *data) · 215 unmodified lines | ||
| 2307 | 2252 | unsigned ttm_pl = (uintptr_t)node->info_ent->data; |
| 2308 | 2253 | struct drm_device *dev = node->minor->dev; |
| 2309 | 2254 | struct amdgpu_device *adev = dev->dev_private; |
| 2310 | − struct ttm_mem_type_manager *man = &adev->mman.bdev.man[ttm_pl]; | |
| 2255 | + struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, ttm_pl); | |
| 2311 | 2256 | struct drm_printer p = drm_seq_file_printer(m); |
| 2312 | 2257 | |
| 2313 | 2258 | man->func->debug(man, &p); |
| @@ -41,6 +41,21 @@ · 40 unmodified lines | ||
| 41 | 41 | |
| 42 | 42 | #define AMDGPU_POISON 0xd0bed0be |
| 43 | 43 | |
| 44 | +struct amdgpu_vram_mgr { | |
| 45 | + struct ttm_resource_manager manager; | |
| 46 | + struct drm_mm mm; | |
| 47 | + spinlock_t lock; | |
| 48 | + atomic64_t usage; | |
| 49 | + atomic64_t vis_usage; | |
| 50 | +}; | |
| 51 | + | |
| 52 | +struct amdgpu_gtt_mgr { | |
| 53 | + struct ttm_resource_manager manager; | |
| 54 | + struct drm_mm mm; | |
| 55 | + spinlock_t lock; | |
| 56 | + atomic64_t available; | |
| 57 | +}; | |
| 58 | + | |
| 44 | 59 | struct amdgpu_mman { |
| 45 | 60 | struct ttm_bo_device bdev; |
| 46 | 61 | bool mem_global_referenced; |
| @@ -59,24 +74,29 @@ struct amdgpu_mman { · 12 unmodified lines | ||
| 59 | 74 | struct mutex gtt_window_lock; |
| 60 | 75 | /* Scheduler entity for buffer moves */ |
| 61 | 76 | struct drm_sched_entity entity; |
| 77 | + | |
| 78 | + struct amdgpu_vram_mgr vram_mgr; | |
| 79 | + struct amdgpu_gtt_mgr gtt_mgr; | |
| 62 | 80 | }; |
| 63 | 81 | |
| 64 | 82 | struct amdgpu_copy_mem { |
| 65 | 83 | struct ttm_buffer_object *bo; |
| 66 | − struct ttm_mem_reg *mem; | |
| 84 | + struct ttm_resource *mem; | |
| 67 | 85 | unsigned long offset; |
| 68 | 86 | }; |
| 69 | 87 | |
| 70 | −extern const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func; | |
| 71 | −extern const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func; | |
| 88 | +int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size); | |
| 89 | +void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev); | |
| 90 | +int amdgpu_vram_mgr_init(struct amdgpu_device *adev); | |
| 91 | +void amdgpu_vram_mgr_fini(struct amdgpu_device *adev); | |
| 72 | 92 | |
| 73 | −bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg *mem); | |
| 74 | −uint64_t amdgpu_gtt_mgr_usage(struct ttm_mem_type_manager *man); | |
| 75 | −int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man); | |
| 93 | +bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem); | |
| 94 | +uint64_t amdgpu_gtt_mgr_usage(struct ttm_resource_manager *man); | |
| 95 | +int amdgpu_gtt_mgr_recover(struct ttm_resource_manager *man); | |
| 76 | 96 | |
| 77 | 97 | u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo); |
| 78 | 98 | int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev, |
| 79 | − struct ttm_mem_reg *mem, | |
| 99 | + struct ttm_resource *mem, | |
| 80 | 100 | struct device *dev, |
| 81 | 101 | enum dma_data_direction dir, |
| 82 | 102 | struct sg_table **sgt); |
| @@ -84,8 +104,8 @@ void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev, · 1 unmodified line | ||
| 84 | 104 | struct device *dev, |
| 85 | 105 | enum dma_data_direction dir, |
| 86 | 106 | struct sg_table *sgt); |
| 87 | −uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man); | |
| 88 | −uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man); | |
| 107 | +uint64_t amdgpu_vram_mgr_usage(struct ttm_resource_manager *man); | |
| 108 | +uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_resource_manager *man); | |
| 89 | 109 | |
| 90 | 110 | int amdgpu_ttm_init(struct amdgpu_device *adev); |
| 91 | 111 | void amdgpu_ttm_late_init(struct amdgpu_device *adev); |
| @@ -130,8 +150,8 @@ static inline bool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm) · 38 unmodified lines | ||
| 130 | 150 | #endif |
| 131 | 151 | |
| 132 | 152 | void amdgpu_ttm_tt_set_user_pages(struct ttm_tt *ttm, struct page **pages); |
| 133 | −int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr, | |
| 134 | − uint32_t flags); | |
| 153 | +int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo, | |
| 154 | + uint64_t addr, uint32_t flags); | |
| 135 | 155 | bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm); |
| 136 | 156 | struct mm_struct *amdgpu_ttm_tt_get_usermm(struct ttm_tt *ttm); |
| 137 | 157 | bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start, |
| @@ -140,9 +160,9 @@ bool amdgpu_ttm_tt_userptr_invalidated(struct ttm_tt *ttm, · 2 unmodified lines | ||
| 140 | 160 | int *last_invalidated); |
| 141 | 161 | bool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm); |
| 142 | 162 | bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm); |
| 143 | −uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_mem_reg *mem); | |
| 163 | +uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_resource *mem); | |
| 144 | 164 | uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm, |
| 145 | − struct ttm_mem_reg *mem); | |
| 165 | + struct ttm_resource *mem); | |
| 146 | 166 | |
| 147 | 167 | int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev); |
| 148 | 168 | |
| @@ -1765,7 +1765,7 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, · 1764 unmodified lines | ||
| 1765 | 1765 | struct amdgpu_vm *vm = bo_va->base.vm; |
| 1766 | 1766 | struct amdgpu_bo_va_mapping *mapping; |
| 1767 | 1767 | dma_addr_t *pages_addr = NULL; |
| 1768 | − struct ttm_mem_reg *mem; | |
| 1768 | + struct ttm_resource *mem; | |
| 1769 | 1769 | struct drm_mm_node *nodes; |
| 1770 | 1770 | struct dma_fence **last_update; |
| 1771 | 1771 | struct dma_resv *resv; |
| @@ -28,12 +28,15 @@ · 27 unmodified lines | ||
| 28 | 28 | #include "amdgpu_atomfirmware.h" |
| 29 | 29 | #include "atom.h" |
| 30 | 30 | |
| 31 | −struct amdgpu_vram_mgr { | |
| 32 | − struct drm_mm mm; | |
| 33 | − spinlock_t lock; | |
| 34 | − atomic64_t usage; | |
| 35 | − atomic64_t vis_usage; | |
| 36 | −}; | |
| 31 | +static inline struct amdgpu_vram_mgr *to_vram_mgr(struct ttm_resource_manager *man) | |
| 32 | +{ | |
| 33 | + return container_of(man, struct amdgpu_vram_mgr, manager); | |
| 34 | +} | |
| 35 | + | |
| 36 | +static inline struct amdgpu_device *to_amdgpu_device(struct amdgpu_vram_mgr *mgr) | |
| 37 | +{ | |
| 38 | + return container_of(mgr, struct amdgpu_device, mman.vram_mgr); | |
| 39 | +} | |
| 37 | 40 | |
| 38 | 41 | /** |
| 39 | 42 | * DOC: mem_info_vram_total |
| @@ -82,9 +85,9 @@ static ssize_t amdgpu_mem_info_vram_used_show(struct device *dev, · 42 unmodified lines | ||
| 82 | 85 | { |
| 83 | 86 | struct drm_device *ddev = dev_get_drvdata(dev); |
| 84 | 87 | struct amdgpu_device *adev = ddev->dev_private; |
| 85 | − | |
| 88 | + struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); | |
| 86 | 89 | return snprintf(buf, PAGE_SIZE, "%llu\n", |
| 87 | − amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM])); | |
| 90 | + amdgpu_vram_mgr_usage(man)); | |
| 88 | 91 | } |
| 89 | 92 | |
| 90 | 93 | /** |
| @@ -100,9 +103,9 @@ static ssize_t amdgpu_mem_info_vis_vram_used_show(struct device *dev, · 9 unmodified lines | ||
| 100 | 103 | { |
| 101 | 104 | struct drm_device *ddev = dev_get_drvdata(dev); |
| 102 | 105 | struct amdgpu_device *adev = ddev->dev_private; |
| 103 | − | |
| 106 | + struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); | |
| 104 | 107 | return snprintf(buf, PAGE_SIZE, "%llu\n", |
| 105 | − amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM])); | |
| 108 | + amdgpu_vram_mgr_vis_usage(man)); | |
| 106 | 109 | } |
| 107 | 110 | |
| 108 | 111 | static ssize_t amdgpu_mem_info_vram_vendor(struct device *dev, |
| @@ -158,6 +161,8 @@ static const struct attribute *amdgpu_vram_mgr_attributes[] = { · 49 unmodified lines | ||
| 158 | 161 | NULL |
| 159 | 162 | }; |
| 160 | 163 | |
| 164 | +static const struct ttm_resource_manager_func amdgpu_vram_mgr_func; | |
| 165 | + | |
| 161 | 166 | /** |
| 162 | 167 | * amdgpu_vram_mgr_init - init VRAM manager and DRM MM |
| 163 | 168 | * |
| @@ -166,26 +171,29 @@ static const struct attribute *amdgpu_vram_mgr_attributes[] = { · 2 unmodified lines | ||
| 166 | 171 | * |
| 167 | 172 | * Allocate and initialize the VRAM manager. |
| 168 | 173 | */ |
| 169 | −static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man, | |
| 170 | − unsigned long p_size) | |
| 174 | +int amdgpu_vram_mgr_init(struct amdgpu_device *adev) | |
| 171 | 175 | { |
| 172 | − struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); | |
| 173 | − struct amdgpu_vram_mgr *mgr; | |
| 176 | + struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr; | |
| 177 | + struct ttm_resource_manager *man = &mgr->manager; | |
| 174 | 178 | int ret; |
| 175 | 179 | |
| 176 | − mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); | |
| 177 | − if (!mgr) | |
| 178 | − return -ENOMEM; | |
| 180 | + man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; | |
| 181 | + man->default_caching = TTM_PL_FLAG_WC; | |
| 179 | 182 | |
| 180 | − drm_mm_init(&mgr->mm, 0, p_size); | |
| 183 | + ttm_resource_manager_init(man, adev->gmc.real_vram_size >> PAGE_SHIFT); | |
| 184 | + | |
| 185 | + man->func = &amdgpu_vram_mgr_func; | |
| 186 | + | |
| 187 | + drm_mm_init(&mgr->mm, 0, man->size); | |
| 181 | 188 | spin_lock_init(&mgr->lock); |
| 182 | − man->priv = mgr; | |
| 183 | 189 | |
| 184 | 190 | /* Add the two VRAM-related sysfs files */ |
| 185 | 191 | ret = sysfs_create_files(&adev->dev->kobj, amdgpu_vram_mgr_attributes); |
| 186 | 192 | if (ret) |
| 187 | 193 | DRM_ERROR("Failed to register sysfs\n"); |
| 188 | 194 | |
| 195 | + ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager); | |
| 196 | + ttm_resource_manager_set_used(man, true); | |
| 189 | 197 | return 0; |
| 190 | 198 | } |
| 191 | 199 | |
| @@ -197,18 +205,26 @@ static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man, · 5 unmodified lines | ||
| 197 | 205 | * Destroy and free the VRAM manager, returns -EBUSY if ranges are still |
| 198 | 206 | * allocated inside it. |
| 199 | 207 | */ |
| 200 | −static int amdgpu_vram_mgr_fini(struct ttm_mem_type_manager *man) | |
| 208 | +void amdgpu_vram_mgr_fini(struct amdgpu_device *adev) | |
| 201 | 209 | { |
| 202 | − struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); | |
| 203 | − struct amdgpu_vram_mgr *mgr = man->priv; | |
| 210 | + struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr; | |
| 211 | + struct ttm_resource_manager *man = &mgr->manager; | |
| 212 | + int ret; | |
| 213 | + | |
| 214 | + ttm_resource_manager_set_used(man, false); | |
| 215 | + | |
| 216 | + ret = ttm_resource_manager_force_list_clean(&adev->mman.bdev, man); | |
| 217 | + if (ret) | |
| 218 | + return; | |
| 204 | 219 | |
| 205 | 220 | spin_lock(&mgr->lock); |
| 206 | 221 | drm_mm_takedown(&mgr->mm); |
| 207 | 222 | spin_unlock(&mgr->lock); |
| 208 | − kfree(mgr); | |
| 209 | − man->priv = NULL; | |
| 223 | + | |
| 210 | 224 | sysfs_remove_files(&adev->dev->kobj, amdgpu_vram_mgr_attributes); |
| 211 | − return 0; | |
| 225 | + | |
| 226 | + ttm_resource_manager_cleanup(man); | |
| 227 | + ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, NULL); | |
| 212 | 228 | } |
| 213 | 229 | |
| 214 | 230 | /** |
| @@ -243,7 +259,7 @@ static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev, · 28 unmodified lines | ||
| 243 | 259 | u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo) |
| 244 | 260 | { |
| 245 | 261 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); |
| 246 | − struct ttm_mem_reg *mem = &bo->tbo.mem; | |
| 262 | + struct ttm_resource *mem = &bo->tbo.mem; | |
| 247 | 263 | struct drm_mm_node *nodes = mem->mm_node; |
| 248 | 264 | unsigned pages = mem->num_pages; |
| 249 | 265 | u64 usage; |
| @@ -263,13 +279,13 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo) · 13 unmodified lines | ||
| 263 | 279 | /** |
| 264 | 280 | * amdgpu_vram_mgr_virt_start - update virtual start address |
| 265 | 281 | * |
| 266 | − * @mem: ttm_mem_reg to update | |
| 282 | + * @mem: ttm_resource to update | |
| 267 | 283 | * @node: just allocated node |
| 268 | 284 | * |
| 269 | 285 | * Calculate a virtual BO start address to easily check if everything is CPU |
| 270 | 286 | * accessible. |
| 271 | 287 | */ |
| 272 | −static void amdgpu_vram_mgr_virt_start(struct ttm_mem_reg *mem, | |
| 288 | +static void amdgpu_vram_mgr_virt_start(struct ttm_resource *mem, | |
| 273 | 289 | struct drm_mm_node *node) |
| 274 | 290 | { |
| 275 | 291 | unsigned long start; |
| @@ -292,13 +308,13 @@ static void amdgpu_vram_mgr_virt_start(struct ttm_mem_reg *mem, · 16 unmodified lines | ||
| 292 | 308 | * |
| 293 | 309 | * Allocate VRAM for the given BO. |
| 294 | 310 | */ |
| 295 | −static int amdgpu_vram_mgr_new(struct ttm_mem_type_manager *man, | |
| 311 | +static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, | |
| 296 | 312 | struct ttm_buffer_object *tbo, |
| 297 | 313 | const struct ttm_place *place, |
| 298 | − struct ttm_mem_reg *mem) | |
| 314 | + struct ttm_resource *mem) | |
| 299 | 315 | { |
| 300 | − struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); | |
| 301 | − struct amdgpu_vram_mgr *mgr = man->priv; | |
| 316 | + struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); | |
| 317 | + struct amdgpu_device *adev = to_amdgpu_device(mgr); | |
| 302 | 318 | struct drm_mm *mm = &mgr->mm; |
| 303 | 319 | struct drm_mm_node *nodes; |
| 304 | 320 | enum drm_mm_insert_mode mode; |
| @@ -410,11 +426,11 @@ error: · 105 unmodified lines | ||
| 410 | 426 | * |
| 411 | 427 | * Free the allocated VRAM again. |
| 412 | 428 | */ |
| 413 | −static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man, | |
| 414 | − struct ttm_mem_reg *mem) | |
| 429 | +static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man, | |
| 430 | + struct ttm_resource *mem) | |
| 415 | 431 | { |
| 416 | − struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); | |
| 417 | − struct amdgpu_vram_mgr *mgr = man->priv; | |
| 432 | + struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); | |
| 433 | + struct amdgpu_device *adev = to_amdgpu_device(mgr); | |
| 418 | 434 | struct drm_mm_node *nodes = mem->mm_node; |
| 419 | 435 | uint64_t usage = 0, vis_usage = 0; |
| 420 | 436 | unsigned pages = mem->num_pages; |
| @@ -451,7 +467,7 @@ static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man, · 30 unmodified lines | ||
| 451 | 467 | * Allocate and fill a sg table from a VRAM allocation. |
| 452 | 468 | */ |
| 453 | 469 | int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev, |
| 454 | − struct ttm_mem_reg *mem, | |
| 470 | + struct ttm_resource *mem, | |
| 455 | 471 | struct device *dev, |
| 456 | 472 | enum dma_data_direction dir, |
| 457 | 473 | struct sg_table **sgt) |
| @@ -544,9 +560,9 @@ void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev, · 86 unmodified lines | ||
| 544 | 560 | * |
| 545 | 561 | * Returns how many bytes are used in this domain. |
| 546 | 562 | */ |
| 547 | −uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man) | |
| 563 | +uint64_t amdgpu_vram_mgr_usage(struct ttm_resource_manager *man) | |
| 548 | 564 | { |
| 549 | − struct amdgpu_vram_mgr *mgr = man->priv; | |
| 565 | + struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); | |
| 550 | 566 | |
| 551 | 567 | return atomic64_read(&mgr->usage); |
| 552 | 568 | } |
| @@ -558,9 +574,9 @@ uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man) · 5 unmodified lines | ||
| 558 | 574 | * |
| 559 | 575 | * Returns how many bytes are used in the visible part of VRAM |
| 560 | 576 | */ |
| 561 | −uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man) | |
| 577 | +uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_resource_manager *man) | |
| 562 | 578 | { |
| 563 | − struct amdgpu_vram_mgr *mgr = man->priv; | |
| 579 | + struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); | |
| 564 | 580 | |
| 565 | 581 | return atomic64_read(&mgr->vis_usage); |
| 566 | 582 | } |
| @@ -573,10 +589,10 @@ uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man) · 6 unmodified lines | ||
| 573 | 589 | * |
| 574 | 590 | * Dump the table content using printk. |
| 575 | 591 | */ |
| 576 | −static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man, | |
| 592 | +static void amdgpu_vram_mgr_debug(struct ttm_resource_manager *man, | |
| 577 | 593 | struct drm_printer *printer) |
| 578 | 594 | { |
| 579 | − struct amdgpu_vram_mgr *mgr = man->priv; | |
| 595 | + struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); | |
| 580 | 596 | |
| 581 | 597 | spin_lock(&mgr->lock); |
| 582 | 598 | drm_mm_print(&mgr->mm, printer); |
| @@ -587,10 +603,8 @@ static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man, · 4 unmodified lines | ||
| 587 | 603 | amdgpu_vram_mgr_vis_usage(man) >> 20); |
| 588 | 604 | } |
| 589 | 605 | |
| 590 | −const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func = { | |
| 591 | − .init = amdgpu_vram_mgr_init, | |
| 592 | − .takedown = amdgpu_vram_mgr_fini, | |
| 593 | − .get_node = amdgpu_vram_mgr_new, | |
| 594 | − .put_node = amdgpu_vram_mgr_del, | |
| 595 | − .debug = amdgpu_vram_mgr_debug | |
| 606 | +static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = { | |
| 607 | + .alloc = amdgpu_vram_mgr_new, | |
| 608 | + .free = amdgpu_vram_mgr_del, | |
| 609 | + .debug = amdgpu_vram_mgr_debug | |
| 596 | 610 | }; |
| @@ -328,6 +328,22 @@ static void amdgpu_atombios_dp_probe_oui(struct amdgpu_connector *amdgpu_connect · 327 unmodified lines | ||
| 328 | 328 | buf[0], buf[1], buf[2]); |
| 329 | 329 | } |
| 330 | 330 | |
| 331 | +static void amdgpu_atombios_dp_ds_ports(struct amdgpu_connector *amdgpu_connector) | |
| 332 | +{ | |
| 333 | + struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv; | |
| 334 | + int ret; | |
| 335 | + | |
| 336 | + if (dig_connector->dpcd[DP_DPCD_REV] > 0x10) { | |
| 337 | + ret = drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux, | |
| 338 | + DP_DOWNSTREAM_PORT_0, | |
| 339 | + dig_connector->downstream_ports, | |
| 340 | + DP_MAX_DOWNSTREAM_PORTS); | |
| 341 | + if (ret) | |
| 342 | + memset(dig_connector->downstream_ports, 0, | |
| 343 | + DP_MAX_DOWNSTREAM_PORTS); | |
| 344 | + } | |
| 345 | +} | |
| 346 | + | |
| 331 | 347 | int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector) |
| 332 | 348 | { |
| 333 | 349 | struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv; |
| @@ -343,7 +359,7 @@ int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector) · 9 unmodified lines | ||
| 343 | 359 | dig_connector->dpcd); |
| 344 | 360 | |
| 345 | 361 | amdgpu_atombios_dp_probe_oui(amdgpu_connector); |
| 346 | − | |
| 362 | + amdgpu_atombios_dp_ds_ports(amdgpu_connector); | |
| 347 | 363 | return 0; |
| 348 | 364 | } |
| 349 | 365 | |
| @@ -127,6 +127,42 @@ MODULE_FIRMWARE(FIRMWARE_NAVI12_DMCU); · 126 unmodified lines | ||
| 127 | 127 | static int amdgpu_dm_init(struct amdgpu_device *adev); |
| 128 | 128 | static void amdgpu_dm_fini(struct amdgpu_device *adev); |
| 129 | 129 | |
| 130 | +static enum drm_mode_subconnector get_subconnector_type(struct dc_link *link) | |
| 131 | +{ | |
| 132 | + switch (link->dpcd_caps.dongle_type) { | |
| 133 | + case DISPLAY_DONGLE_NONE: | |
| 134 | + return DRM_MODE_SUBCONNECTOR_Native; | |
| 135 | + case DISPLAY_DONGLE_DP_VGA_CONVERTER: | |
| 136 | + return DRM_MODE_SUBCONNECTOR_VGA; | |
| 137 | + case DISPLAY_DONGLE_DP_DVI_CONVERTER: | |
| 138 | + case DISPLAY_DONGLE_DP_DVI_DONGLE: | |
| 139 | + return DRM_MODE_SUBCONNECTOR_DVID; | |
| 140 | + case DISPLAY_DONGLE_DP_HDMI_CONVERTER: | |
| 141 | + case DISPLAY_DONGLE_DP_HDMI_DONGLE: | |
| 142 | + return DRM_MODE_SUBCONNECTOR_HDMIA; | |
| 143 | + case DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE: | |
| 144 | + default: | |
| 145 | + return DRM_MODE_SUBCONNECTOR_Unknown; | |
| 146 | + } | |
| 147 | +} | |
| 148 | + | |
| 149 | +static void update_subconnector_property(struct amdgpu_dm_connector *aconnector) | |
| 150 | +{ | |
| 151 | + struct dc_link *link = aconnector->dc_link; | |
| 152 | + struct drm_connector *connector = &aconnector->base; | |
| 153 | + enum drm_mode_subconnector subconnector = DRM_MODE_SUBCONNECTOR_Unknown; | |
| 154 | + | |
| 155 | + if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) | |
| 156 | + return; | |
| 157 | + | |
| 158 | + if (aconnector->dc_sink) | |
| 159 | + subconnector = get_subconnector_type(link); | |
| 160 | + | |
| 161 | + drm_object_property_set_value(&connector->base, | |
| 162 | + connector->dev->mode_config.dp_subconnector_property, | |
| 163 | + subconnector); | |
| 164 | +} | |
| 165 | + | |
| 130 | 166 | /* |
| 131 | 167 | * initializes drm_device display related structures, based on the information |
| 132 | 168 | * provided by DAL. The drm strcutures are: drm_crtc, drm_connector, |
| @@ -2095,7 +2131,6 @@ void amdgpu_dm_update_connector_after_detect( · 1962 unmodified lines | ||
| 2095 | 2131 | if (aconnector->mst_mgr.mst_state == true) |
| 2096 | 2132 | return; |
| 2097 | 2133 | |
| 2098 | − | |
| 2099 | 2134 | sink = aconnector->dc_link->local_sink; |
| 2100 | 2135 | if (sink) |
| 2101 | 2136 | dc_sink_retain(sink); |
| @@ -2222,6 +2257,8 @@ void amdgpu_dm_update_connector_after_detect( · 120 unmodified lines | ||
| 2222 | 2257 | |
| 2223 | 2258 | mutex_unlock(&dev->mode_config.mutex); |
| 2224 | 2259 | |
| 2260 | + update_subconnector_property(aconnector); | |
| 2261 | + | |
| 2225 | 2262 | if (sink) |
| 2226 | 2263 | dc_sink_release(sink); |
| 2227 | 2264 | } |
| @@ -4757,6 +4794,8 @@ amdgpu_dm_connector_detect(struct drm_connector *connector, bool force) · 2529 unmodified lines | ||
| 4757 | 4794 | else |
| 4758 | 4795 | connected = (aconnector->base.force == DRM_FORCE_ON); |
| 4759 | 4796 | |
| 4797 | + update_subconnector_property(aconnector); | |
| 4798 | + | |
| 4760 | 4799 | return (connected ? connector_status_connected : |
| 4761 | 4800 | connector_status_disconnected); |
| 4762 | 4801 | } |
| @@ -26,6 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | #include <linux/version.h> |
| 27 | 27 | #include <drm/drm_atomic_helper.h> |
| 28 | 28 | #include <drm/drm_dp_mst_helper.h> |
| 29 | +#include <drm/drm_dp_helper.h> | |
| 29 | 30 | #include "dm_services.h" |
| 30 | 31 | #include "amdgpu.h" |
| 31 | 32 | #include "amdgpu_dm.h" |
| @@ -431,6 +432,8 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, · 399 unmodified lines | ||
| 431 | 432 | 16, |
| 432 | 433 | 4, |
| 433 | 434 | aconnector->connector_id); |
| 435 | + | |
| 436 | + drm_connector_attach_dp_subconnector_property(&aconnector->base); | |
| 434 | 437 | } |
| 435 | 438 | |
| 436 | 439 | int dm_mst_get_pbn_divider(struct dc_link *link) |
| @@ -346,7 +346,7 @@ static bool malidp_check_pages_threshold(struct malidp_plane_state *ms, · 345 unmodified lines | ||
| 346 | 346 | if (cma_obj->sgt) |
| 347 | 347 | sgt = cma_obj->sgt; |
| 348 | 348 | else |
| 349 | − sgt = obj->dev->driver->gem_prime_get_sg_table(obj); | |
| 349 | + sgt = obj->funcs->get_sg_table(obj); | |
| 350 | 350 | |
| 351 | 351 | if (!sgt) |
| 352 | 352 | return false; |
| @@ -47,7 +47,7 @@ static void ast_cursor_fini(struct ast_private *ast) · 46 unmodified lines | ||
| 47 | 47 | |
| 48 | 48 | static void ast_cursor_release(struct drm_device *dev, void *ptr) |
| 49 | 49 | { |
| 50 | − struct ast_private *ast = dev->dev_private; | |
| 50 | + struct ast_private *ast = to_ast_private(dev); | |
| 51 | 51 | |
| 52 | 52 | ast_cursor_fini(ast); |
| 53 | 53 | } |
| @@ -57,7 +57,7 @@ static void ast_cursor_release(struct drm_device *dev, void *ptr) · 3 unmodified lines | ||
| 57 | 57 | */ |
| 58 | 58 | int ast_cursor_init(struct ast_private *ast) |
| 59 | 59 | { |
| 60 | − struct drm_device *dev = ast->dev; | |
| 60 | + struct drm_device *dev = &ast->base; | |
| 61 | 61 | size_t size, i; |
| 62 | 62 | struct drm_gem_vram_object *gbo; |
| 63 | 63 | void __iomem *vaddr; |
| @@ -168,7 +168,7 @@ static void update_cursor_image(u8 __iomem *dst, const u8 *src, int width, int h · 104 unmodified lines | ||
| 168 | 168 | |
| 169 | 169 | int ast_cursor_blit(struct ast_private *ast, struct drm_framebuffer *fb) |
| 170 | 170 | { |
| 171 | − struct drm_device *dev = ast->dev; | |
| 171 | + struct drm_device *dev = &ast->base; | |
| 172 | 172 | struct drm_gem_vram_object *gbo; |
| 173 | 173 | int ret; |
| 174 | 174 | void *src; |
| @@ -217,7 +217,7 @@ static void ast_cursor_set_base(struct ast_private *ast, u64 address) · 42 unmodified lines | ||
| 217 | 217 | |
| 218 | 218 | void ast_cursor_page_flip(struct ast_private *ast) |
| 219 | 219 | { |
| 220 | − struct drm_device *dev = ast->dev; | |
| 220 | + struct drm_device *dev = &ast->base; | |
| 221 | 221 | struct drm_gem_vram_object *gbo; |
| 222 | 222 | s64 off; |
| 223 | 223 | |
| @@ -253,7 +253,8 @@ void ast_cursor_show(struct ast_private *ast, int x, int y, · 29 unmodified lines | ||
| 253 | 253 | unsigned int offset_x, unsigned int offset_y) |
| 254 | 254 | { |
| 255 | 255 | u8 x_offset, y_offset; |
| 256 | − u8 __iomem *dst, __iomem *sig; | |
| 256 | + u8 __iomem *dst; | |
| 257 | + u8 __iomem *sig; | |
| 257 | 258 | u8 jreg; |
| 258 | 259 | |
| 259 | 260 | dst = ast->cursor.vaddr[ast->cursor.next_index]; |
| @@ -8,11 +8,24 @@ · 7 unmodified lines | ||
| 8 | 8 | |
| 9 | 9 | MODULE_FIRMWARE("ast_dp501_fw.bin"); |
| 10 | 10 | |
| 11 | +static void ast_release_firmware(void *data) | |
| 12 | +{ | |
| 13 | + struct ast_private *ast = data; | |
| 14 | + | |
| 15 | + release_firmware(ast->dp501_fw); | |
| 16 | + ast->dp501_fw = NULL; | |
| 17 | +} | |
| 18 | + | |
| 11 | 19 | static int ast_load_dp501_microcode(struct drm_device *dev) |
| 12 | 20 | { |
| 13 | 21 | struct ast_private *ast = to_ast_private(dev); |
| 22 | + int ret; | |
| 23 | + | |
| 24 | + ret = request_firmware(&ast->dp501_fw, "ast_dp501_fw.bin", dev->dev); | |
| 25 | + if (ret) | |
| 26 | + return ret; | |
| 14 | 27 | |
| 15 | − return request_firmware(&ast->dp501_fw, "ast_dp501_fw.bin", dev->dev); | |
| 28 | + return devm_add_action_or_reset(dev->dev, ast_release_firmware, ast); | |
| 16 | 29 | } |
| 17 | 30 | |
| 18 | 31 | static void send_ack(struct ast_private *ast) |
| @@ -435,11 +448,3 @@ void ast_init_3rdtx(struct drm_device *dev) · 416 unmodified lines | ||
| 435 | 448 | } |
| 436 | 449 | } |
| 437 | 450 | } |
| 438 | − | |
| 439 | −void ast_release_firmware(struct drm_device *dev) | |
| 440 | −{ | |
| 441 | − struct ast_private *ast = to_ast_private(dev); | |
| 442 | − | |
| 443 | − release_firmware(ast->dp501_fw); | |
| 444 | − ast->dp501_fw = NULL; | |
| 445 | −} | |
| @@ -43,9 +43,33 @@ int ast_modeset = -1; · 42 unmodified lines | ||
| 43 | 43 | MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); |
| 44 | 44 | module_param_named(modeset, ast_modeset, int, 0400); |
| 45 | 45 | |
| 46 | −#define PCI_VENDOR_ASPEED 0x1a03 | |
| 46 | +/* | |
| 47 | + * DRM driver | |
| 48 | + */ | |
| 49 | + | |
| 50 | +DEFINE_DRM_GEM_FOPS(ast_fops); | |
| 51 | + | |
| 52 | +static struct drm_driver ast_driver = { | |
| 53 | + .driver_features = DRIVER_ATOMIC | | |
| 54 | + DRIVER_GEM | | |
| 55 | + DRIVER_MODESET, | |
| 56 | + | |
| 57 | + .fops = &ast_fops, | |
| 58 | + .name = DRIVER_NAME, | |
| 59 | + .desc = DRIVER_DESC, | |
| 60 | + .date = DRIVER_DATE, | |
| 61 | + .major = DRIVER_MAJOR, | |
| 62 | + .minor = DRIVER_MINOR, | |
| 63 | + .patchlevel = DRIVER_PATCHLEVEL, | |
| 64 | + | |
| 65 | + DRM_GEM_VRAM_DRIVER | |
| 66 | +}; | |
| 67 | + | |
| 68 | +/* | |
| 69 | + * PCI driver | |
| 70 | + */ | |
| 47 | 71 | |
| 48 | −static struct drm_driver driver; | |
| 72 | +#define PCI_VENDOR_ASPEED 0x1a03 | |
| 49 | 73 | |
| 50 | 74 | #define AST_VGA_DEVICE(id, info) { \ |
| 51 | 75 | .class = PCI_BASE_CLASS_DISPLAY << 16, \ |
| @@ -56,13 +80,13 @@ static struct drm_driver driver; · 4 unmodified lines | ||
| 56 | 80 | .subdevice = PCI_ANY_ID, \ |
| 57 | 81 | .driver_data = (unsigned long) info } |
| 58 | 82 | |
| 59 | −static const struct pci_device_id pciidlist[] = { | |
| 83 | +static const struct pci_device_id ast_pciidlist[] = { | |
| 60 | 84 | AST_VGA_DEVICE(PCI_CHIP_AST2000, NULL), |
| 61 | 85 | AST_VGA_DEVICE(PCI_CHIP_AST2100, NULL), |
| 62 | 86 | {0, 0, 0}, |
| 63 | 87 | }; |
| 64 | 88 | |
| 65 | −MODULE_DEVICE_TABLE(pci, pciidlist); | |
| 89 | +MODULE_DEVICE_TABLE(pci, ast_pciidlist); | |
| 66 | 90 | |
| 67 | 91 | static void ast_kick_out_firmware_fb(struct pci_dev *pdev) |
| 68 | 92 | { |
| @@ -85,6 +109,7 @@ static void ast_kick_out_firmware_fb(struct pci_dev *pdev) · 16 unmodified lines | ||
| 85 | 109 | |
| 86 | 110 | static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
| 87 | 111 | { |
| 112 | + struct ast_private *ast; | |
| 88 | 113 | struct drm_device *dev; |
| 89 | 114 | int ret; |
| 90 | 115 | |
| @@ -94,41 +119,25 @@ static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) · 3 unmodified lines | ||
| 94 | 119 | if (ret) |
| 95 | 120 | return ret; |
| 96 | 121 | |
| 97 | − dev = drm_dev_alloc(&driver, &pdev->dev); | |
| 98 | − if (IS_ERR(dev)) | |
| 99 | − return PTR_ERR(dev); | |
| 100 | − | |
| 101 | − dev->pdev = pdev; | |
| 102 | − pci_set_drvdata(pdev, dev); | |
| 103 | − | |
| 104 | − ret = ast_driver_load(dev, ent->driver_data); | |
| 105 | − if (ret) | |
| 106 | − goto err_drm_dev_put; | |
| 122 | + ast = ast_device_create(&ast_driver, pdev, ent->driver_data); | |
| 123 | + if (IS_ERR(ast)) | |
| 124 | + return PTR_ERR(ast); | |
| 125 | + dev = &ast->base; | |
| 107 | 126 | |
| 108 | 127 | ret = drm_dev_register(dev, ent->driver_data); |
| 109 | 128 | if (ret) |
| 110 | − goto err_ast_driver_unload; | |
| 129 | + return ret; | |
| 111 | 130 | |
| 112 | 131 | drm_fbdev_generic_setup(dev, 32); |
| 113 | 132 | |
| 114 | 133 | return 0; |
| 115 | − | |
| 116 | −err_ast_driver_unload: | |
| 117 | − ast_driver_unload(dev); | |
| 118 | −err_drm_dev_put: | |
| 119 | − drm_dev_put(dev); | |
| 120 | − return ret; | |
| 121 | − | |
| 122 | 134 | } |
| 123 | 135 | |
| 124 | −static void | |
| 125 | −ast_pci_remove(struct pci_dev *pdev) | |
| 136 | +static void ast_pci_remove(struct pci_dev *pdev) | |
| 126 | 137 | { |
| 127 | 138 | struct drm_device *dev = pci_get_drvdata(pdev); |
| 128 | 139 | |
| 129 | 140 | drm_dev_unregister(dev); |
| 130 | − ast_driver_unload(dev); | |
| 131 | − drm_dev_put(dev); | |
| 132 | 141 | } |
| 133 | 142 | |
| 134 | 143 | static int ast_drm_freeze(struct drm_device *dev) |
| @@ -217,30 +226,12 @@ static const struct dev_pm_ops ast_pm_ops = { · 82 unmodified lines | ||
| 217 | 226 | |
| 218 | 227 | static struct pci_driver ast_pci_driver = { |
| 219 | 228 | .name = DRIVER_NAME, |
| 220 | − .id_table = pciidlist, | |
| 229 | + .id_table = ast_pciidlist, | |
| 221 | 230 | .probe = ast_pci_probe, |
| 222 | 231 | .remove = ast_pci_remove, |
| 223 | 232 | .driver.pm = &ast_pm_ops, |
| 224 | 233 | }; |
| 225 | 234 | |
| 226 | −DEFINE_DRM_GEM_FOPS(ast_fops); | |
| 227 | − | |
| 228 | −static struct drm_driver driver = { | |
| 229 | − .driver_features = DRIVER_ATOMIC | | |
| 230 | − DRIVER_GEM | | |
| 231 | − DRIVER_MODESET, | |
| 232 | − | |
| 233 | − .fops = &ast_fops, | |
| 234 | − .name = DRIVER_NAME, | |
| 235 | − .desc = DRIVER_DESC, | |
| 236 | − .date = DRIVER_DATE, | |
| 237 | − .major = DRIVER_MAJOR, | |
| 238 | − .minor = DRIVER_MINOR, | |
| 239 | − .patchlevel = DRIVER_PATCHLEVEL, | |
| 240 | − | |
| 241 | − DRM_GEM_VRAM_DRIVER | |
| 242 | −}; | |
| 243 | − | |
| 244 | 235 | static int __init ast_init(void) |
| 245 | 236 | { |
| 246 | 237 | if (vgacon_text_force() && ast_modeset == -1) |
| @@ -261,4 +252,3 @@ module_exit(ast_exit); · 14 unmodified lines | ||
| 261 | 252 | MODULE_AUTHOR(DRIVER_AUTHOR); |
| 262 | 253 | MODULE_DESCRIPTION(DRIVER_DESC); |
| 263 | 254 | MODULE_LICENSE("GPL and additional rights"); |
| 264 | − | |
| @@ -98,9 +98,25 @@ enum ast_tx_chip { · 97 unmodified lines | ||
| 98 | 98 | #define AST_HWC_SIGNATURE_HOTSPOTX 0x14 |
| 99 | 99 | #define AST_HWC_SIGNATURE_HOTSPOTY 0x18 |
| 100 | 100 | |
| 101 | +struct ast_i2c_chan { | |
| 102 | + struct i2c_adapter adapter; | |
| 103 | + struct drm_device *dev; | |
| 104 | + struct i2c_algo_bit_data bit; | |
| 105 | +}; | |
| 106 | + | |
| 107 | +struct ast_connector { | |
| 108 | + struct drm_connector base; | |
| 109 | + struct ast_i2c_chan *i2c; | |
| 110 | +}; | |
| 111 | + | |
| 112 | +static inline struct ast_connector * | |
| 113 | +to_ast_connector(struct drm_connector *connector) | |
| 114 | +{ | |
| 115 | + return container_of(connector, struct ast_connector, base); | |
| 116 | +} | |
| 101 | 117 | |
| 102 | 118 | struct ast_private { |
| 103 | − struct drm_device *dev; | |
| 119 | + struct drm_device base; | |
| 104 | 120 | |
| 105 | 121 | void __iomem *regs; |
| 106 | 122 | void __iomem *ioregs; |
| @@ -119,9 +135,11 @@ struct ast_private { · 12 unmodified lines | ||
| 119 | 135 | unsigned int next_index; |
| 120 | 136 | } cursor; |
| 121 | 137 | |
| 122 | − struct drm_encoder encoder; | |
| 123 | 138 | struct drm_plane primary_plane; |
| 124 | 139 | struct drm_plane cursor_plane; |
| 140 | + struct drm_crtc crtc; | |
| 141 | + struct drm_encoder encoder; | |
| 142 | + struct ast_connector connector; | |
| 125 | 143 | |
| 126 | 144 | bool support_wide_screen; |
| 127 | 145 | enum { |
| @@ -138,11 +156,12 @@ struct ast_private { · 10 unmodified lines | ||
| 138 | 156 | |
| 139 | 157 | static inline struct ast_private *to_ast_private(struct drm_device *dev) |
| 140 | 158 | { |
| 141 | − return dev->dev_private; | |
| 159 | + return container_of(dev, struct ast_private, base); | |
| 142 | 160 | } |
| 143 | 161 | |
| 144 | −int ast_driver_load(struct drm_device *dev, unsigned long flags); | |
| 145 | −void ast_driver_unload(struct drm_device *dev); | |
| 162 | +struct ast_private *ast_device_create(struct drm_driver *drv, | |
| 163 | + struct pci_dev *pdev, | |
| 164 | + unsigned long flags); | |
| 146 | 165 | |
| 147 | 166 | #define AST_IO_AR_PORT_WRITE (0x40) |
| 148 | 167 | #define AST_IO_MISC_PORT_WRITE (0x42) |
| @@ -226,19 +245,6 @@ static inline void ast_open_key(struct ast_private *ast) · 77 unmodified lines | ||
| 226 | 245 | |
| 227 | 246 | #define AST_VIDMEM_DEFAULT_SIZE AST_VIDMEM_SIZE_8M |
| 228 | 247 | |
| 229 | −struct ast_i2c_chan { | |
| 230 | − struct i2c_adapter adapter; | |
| 231 | − struct drm_device *dev; | |
| 232 | − struct i2c_algo_bit_data bit; | |
| 233 | −}; | |
| 234 | − | |
| 235 | −struct ast_connector { | |
| 236 | − struct drm_connector base; | |
| 237 | − struct ast_i2c_chan *i2c; | |
| 238 | −}; | |
| 239 | − | |
| 240 | −#define to_ast_connector(x) container_of(x, struct ast_connector, base) | |
| 241 | − | |
| 242 | 248 | struct ast_vbios_stdtable { |
| 243 | 249 | u8 misc; |
| 244 | 250 | u8 seq[4]; |
| @@ -305,7 +311,6 @@ bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size); · 60 unmodified lines | ||
| 305 | 311 | bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata); |
| 306 | 312 | u8 ast_get_dp501_max_clk(struct drm_device *dev); |
| 307 | 313 | void ast_init_3rdtx(struct drm_device *dev); |
| 308 | −void ast_release_firmware(struct drm_device *dev); | |
| 309 | 314 | |
| 310 | 315 | /* ast_cursor.c */ |
| 311 | 316 | int ast_cursor_init(struct ast_private *ast); |
| @@ -30,8 +30,10 @@ · 29 unmodified lines | ||
| 30 | 30 | |
| 31 | 31 | #include <drm/drm_atomic_helper.h> |
| 32 | 32 | #include <drm/drm_crtc_helper.h> |
| 33 | +#include <drm/drm_drv.h> | |
| 33 | 34 | #include <drm/drm_gem.h> |
| 34 | 35 | #include <drm/drm_gem_vram_helper.h> |
| 36 | +#include <drm/drm_managed.h> | |
| 35 | 37 | |
| 36 | 38 | #include "ast_drv.h" |
| 37 | 39 | |
| @@ -230,11 +232,11 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) · 192 unmodified lines | ||
| 230 | 232 | ast->tx_chip_type = AST_TX_SIL164; |
| 231 | 233 | break; |
| 232 | 234 | case 0x08: |
| 233 | − ast->dp501_fw_addr = kzalloc(32*1024, GFP_KERNEL); | |
| 235 | + ast->dp501_fw_addr = drmm_kzalloc(dev, 32*1024, GFP_KERNEL); | |
| 234 | 236 | if (ast->dp501_fw_addr) { |
| 235 | 237 | /* backup firmware */ |
| 236 | 238 | if (ast_backup_fw(dev, ast->dp501_fw_addr, 32*1024)) { |
| 237 | − kfree(ast->dp501_fw_addr); | |
| 239 | + drmm_kfree(dev, ast->dp501_fw_addr); | |
| 238 | 240 | ast->dp501_fw_addr = NULL; |
| 239 | 241 | } |
| 240 | 242 | } |
| @@ -378,24 +380,38 @@ static int ast_get_dram_info(struct drm_device *dev) · 137 unmodified lines | ||
| 378 | 380 | return 0; |
| 379 | 381 | } |
| 380 | 382 | |
| 381 | −int ast_driver_load(struct drm_device *dev, unsigned long flags) | |
| 383 | +/* | |
| 384 | + * Run this function as part of the HW device cleanup; not | |
| 385 | + * when the DRM device gets released. | |
| 386 | + */ | |
| 387 | +static void ast_device_release(void *data) | |
| 382 | 388 | { |
| 389 | + struct ast_private *ast = data; | |
| 390 | + | |
| 391 | + /* enable standard VGA decode */ | |
| 392 | + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x04); | |
| 393 | +} | |
| 394 | + | |
| 395 | +struct ast_private *ast_device_create(struct drm_driver *drv, | |
| 396 | + struct pci_dev *pdev, | |
| 397 | + unsigned long flags) | |
| 398 | +{ | |
| 399 | + struct drm_device *dev; | |
| 383 | 400 | struct ast_private *ast; |
| 384 | 401 | bool need_post; |
| 385 | 402 | int ret = 0; |
| 386 | 403 | |
| 387 | − ast = kzalloc(sizeof(struct ast_private), GFP_KERNEL); | |
| 388 | − if (!ast) | |
| 389 | − return -ENOMEM; | |
| 404 | + ast = devm_drm_dev_alloc(&pdev->dev, drv, struct ast_private, base); | |
| 405 | + if (IS_ERR(ast)) | |
| 406 | + return ast; | |
| 407 | + dev = &ast->base; | |
| 390 | 408 | |
| 391 | − dev->dev_private = ast; | |
| 392 | − ast->dev = dev; | |
| 409 | + dev->pdev = pdev; | |
| 410 | + pci_set_drvdata(pdev, dev); | |
| 393 | 411 | |
| 394 | 412 | ast->regs = pci_iomap(dev->pdev, 1, 0); |
| 395 | − if (!ast->regs) { | |
| 396 | − ret = -EIO; | |
| 397 | − goto out_free; | |
| 398 | − } | |
| 413 | + if (!ast->regs) | |
| 414 | + return ERR_PTR(-EIO); | |
| 399 | 415 | |
| 400 | 416 | /* |
| 401 | 417 | * If we don't have IO space at all, use MMIO now and |
| @@ -410,17 +426,16 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags) · 8 unmodified lines | ||
| 410 | 426 | /* "map" IO regs if the above hasn't done so already */ |
| 411 | 427 | if (!ast->ioregs) { |
| 412 | 428 | ast->ioregs = pci_iomap(dev->pdev, 2, 0); |
| 413 | − if (!ast->ioregs) { | |
| 414 | − ret = -EIO; | |
| 415 | − goto out_free; | |
| 416 | − } | |
| 429 | + if (!ast->ioregs) | |
| 430 | + return ERR_PTR(-EIO); | |
| 417 | 431 | } |
| 418 | 432 | |
| 419 | 433 | ast_detect_chip(dev, &need_post); |
| 420 | 434 | |
| 421 | 435 | ret = ast_get_dram_info(dev); |
| 422 | 436 | if (ret) |
| 423 | − goto out_free; | |
| 437 | + return ERR_PTR(ret); | |
| 438 | + | |
| 424 | 439 | drm_info(dev, "dram MCLK=%u Mhz type=%d bus_width=%d\n", |
| 425 | 440 | ast->mclk, ast->dram_type, ast->dram_bus_width); |
| 426 | 441 | |
| @@ -429,28 +444,15 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags) · 2 unmodified lines | ||
| 429 | 444 | |
| 430 | 445 | ret = ast_mm_init(ast); |
| 431 | 446 | if (ret) |
| 432 | − goto out_free; | |
| 447 | + return ERR_PTR(ret); | |
| 433 | 448 | |
| 434 | 449 | ret = ast_mode_config_init(ast); |
| 435 | 450 | if (ret) |
| 436 | − goto out_free; | |
| 451 | + return ERR_PTR(ret); | |
| 437 | 452 | |
| 438 | − return 0; | |
| 439 | −out_free: | |
| 440 | − kfree(ast); | |
| 441 | − dev->dev_private = NULL; | |
| 442 | − return ret; | |
| 443 | −} | |
| 444 | − | |
| 445 | −void ast_driver_unload(struct drm_device *dev) | |
| 446 | −{ | |
| 447 | − struct ast_private *ast = to_ast_private(dev); | |
| 448 | − | |
| 449 | − /* enable standard VGA decode */ | |
| 450 | − ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x04); | |
| 451 | − | |
| 452 | − ast_release_firmware(dev); | |
| 453 | − kfree(ast->dp501_fw_addr); | |
| 453 | + ret = devm_add_action_or_reset(dev->dev, ast_device_release, ast); | |
| 454 | + if (ret) | |
| 455 | + return ERR_PTR(ret); | |
| 454 | 456 | |
| 455 | − kfree(ast); | |
| 457 | + return ast; | |
| 456 | 458 | } |
| @@ -85,9 +85,9 @@ static void ast_mm_release(struct drm_device *dev, void *ptr) · 84 unmodified lines | ||
| 85 | 85 | |
| 86 | 86 | int ast_mm_init(struct ast_private *ast) |
| 87 | 87 | { |
| 88 | + struct drm_device *dev = &ast->base; | |
| 88 | 89 | u32 vram_size; |
| 89 | 90 | int ret; |
| 90 | − struct drm_device *dev = ast->dev; | |
| 91 | 91 | |
| 92 | 92 | vram_size = ast_get_vram_size(ast); |
| 93 | 93 | |
| @@ -663,7 +663,7 @@ ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, · 662 unmodified lines | ||
| 663 | 663 | { |
| 664 | 664 | struct drm_plane_state *state = plane->state; |
| 665 | 665 | struct drm_framebuffer *fb = state->fb; |
| 666 | − struct ast_private *ast = plane->dev->dev_private; | |
| 666 | + struct ast_private *ast = to_ast_private(plane->dev); | |
| 667 | 667 | unsigned int offset_x, offset_y; |
| 668 | 668 | |
| 669 | 669 | offset_x = AST_MAX_HWC_WIDTH - fb->width; |
| @@ -831,12 +831,6 @@ static void ast_crtc_reset(struct drm_crtc *crtc) · 161 unmodified lines | ||
| 831 | 831 | __drm_atomic_helper_crtc_reset(crtc, &ast_state->base); |
| 832 | 832 | } |
| 833 | 833 | |
| 834 | −static void ast_crtc_destroy(struct drm_crtc *crtc) | |
| 835 | −{ | |
| 836 | − drm_crtc_cleanup(crtc); | |
| 837 | − kfree(crtc); | |
| 838 | −} | |
| 839 | − | |
| 840 | 834 | static struct drm_crtc_state * |
| 841 | 835 | ast_crtc_atomic_duplicate_state(struct drm_crtc *crtc) |
| 842 | 836 | { |
| @@ -872,7 +866,7 @@ static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc, · 29 unmodified lines | ||
| 872 | 866 | static const struct drm_crtc_funcs ast_crtc_funcs = { |
| 873 | 867 | .reset = ast_crtc_reset, |
| 874 | 868 | .gamma_set = drm_atomic_helper_legacy_gamma_set, |
| 875 | − .destroy = ast_crtc_destroy, | |
| 869 | + .destroy = drm_crtc_cleanup, | |
| 876 | 870 | .set_config = drm_atomic_helper_set_config, |
| 877 | 871 | .page_flip = drm_atomic_helper_page_flip, |
| 878 | 872 | .atomic_duplicate_state = ast_crtc_atomic_duplicate_state, |
| @@ -882,27 +876,19 @@ static const struct drm_crtc_funcs ast_crtc_funcs = { · 3 unmodified lines | ||
| 882 | 876 | static int ast_crtc_init(struct drm_device *dev) |
| 883 | 877 | { |
| 884 | 878 | struct ast_private *ast = to_ast_private(dev); |
| 885 | − struct drm_crtc *crtc; | |
| 879 | + struct drm_crtc *crtc = &ast->crtc; | |
| 886 | 880 | int ret; |
| 887 | 881 | |
| 888 | − crtc = kzalloc(sizeof(*crtc), GFP_KERNEL); | |
| 889 | − if (!crtc) | |
| 890 | − return -ENOMEM; | |
| 891 | − | |
| 892 | 882 | ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane, |
| 893 | 883 | &ast->cursor_plane, &ast_crtc_funcs, |
| 894 | 884 | NULL); |
| 895 | 885 | if (ret) |
| 896 | − goto err_kfree; | |
| 886 | + return ret; | |
| 897 | 887 | |
| 898 | 888 | drm_mode_crtc_set_gamma_size(crtc, 256); |
| 899 | 889 | drm_crtc_helper_add(crtc, &ast_crtc_helper_funcs); |
| 900 | 890 | |
| 901 | 891 | return 0; |
| 902 | − | |
| 903 | −err_kfree: | |
| 904 | − kfree(crtc); | |
| 905 | − return ret; | |
| 906 | 892 | } |
| 907 | 893 | |
| 908 | 894 | /* |
| @@ -1021,7 +1007,6 @@ static void ast_connector_destroy(struct drm_connector *connector) · 112 unmodified lines | ||
| 1021 | 1007 | struct ast_connector *ast_connector = to_ast_connector(connector); |
| 1022 | 1008 | ast_i2c_destroy(ast_connector->i2c); |
| 1023 | 1009 | drm_connector_cleanup(connector); |
| 1024 | − kfree(connector); | |
| 1025 | 1010 | } |
| 1026 | 1011 | |
| 1027 | 1012 | static const struct drm_connector_helper_funcs ast_connector_helper_funcs = { |
| @@ -1039,15 +1024,11 @@ static const struct drm_connector_funcs ast_connector_funcs = { · 11 unmodified lines | ||
| 1039 | 1024 | |
| 1040 | 1025 | static int ast_connector_init(struct drm_device *dev) |
| 1041 | 1026 | { |
| 1042 | − struct ast_connector *ast_connector; | |
| 1043 | − struct drm_connector *connector; | |
| 1044 | − struct drm_encoder *encoder; | |
| 1045 | − | |
| 1046 | − ast_connector = kzalloc(sizeof(struct ast_connector), GFP_KERNEL); | |
| 1047 | − if (!ast_connector) | |
| 1048 | − return -ENOMEM; | |
| 1027 | + struct ast_private *ast = to_ast_private(dev); | |
| 1028 | + struct ast_connector *ast_connector = &ast->connector; | |
| 1029 | + struct drm_connector *connector = &ast_connector->base; | |
| 1030 | + struct drm_encoder *encoder = &ast->encoder; | |
| 1049 | 1031 | |
| 1050 | − connector = &ast_connector->base; | |
| 1051 | 1032 | ast_connector->i2c = ast_i2c_create(dev); |
| 1052 | 1033 | if (!ast_connector->i2c) |
| 1053 | 1034 | drm_err(dev, "failed to add ddc bus for connector\n"); |
| @@ -1064,7 +1045,6 @@ static int ast_connector_init(struct drm_device *dev) · 10 unmodified lines | ||
| 1064 | 1045 | |
| 1065 | 1046 | connector->polled = DRM_CONNECTOR_POLL_CONNECT; |
| 1066 | 1047 | |
| 1067 | − encoder = list_first_entry(&dev->mode_config.encoder_list, struct drm_encoder, head); | |
| 1068 | 1048 | drm_connector_attach_encoder(connector, encoder); |
| 1069 | 1049 | |
| 1070 | 1050 | return 0; |
| @@ -1083,7 +1063,7 @@ static const struct drm_mode_config_funcs ast_mode_config_funcs = { · 12 unmodified lines | ||
| 1083 | 1063 | |
| 1084 | 1064 | int ast_mode_config_init(struct ast_private *ast) |
| 1085 | 1065 | { |
| 1086 | − struct drm_device *dev = ast->dev; | |
| 1066 | + struct drm_device *dev = &ast->base; | |
| 1087 | 1067 | int ret; |
| 1088 | 1068 | |
| 1089 | 1069 | ret = ast_cursor_init(ast); |
| @@ -1099,7 +1079,7 @@ int ast_mode_config_init(struct ast_private *ast) · 9 unmodified lines | ||
| 1099 | 1079 | dev->mode_config.min_height = 0; |
| 1100 | 1080 | dev->mode_config.preferred_depth = 24; |
| 1101 | 1081 | dev->mode_config.prefer_shadow = 1; |
| 1102 | − dev->mode_config.fb_base = pci_resource_start(ast->dev->pdev, 0); | |
| 1082 | + dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0); | |
| 1103 | 1083 | |
| 1104 | 1084 | if (ast->chip == AST2100 || |
| 1105 | 1085 | ast->chip == AST2200 || |
| @@ -365,12 +365,12 @@ static void ast_init_dram_reg(struct drm_device *dev) · 364 unmodified lines | ||
| 365 | 365 | |
| 366 | 366 | void ast_post_gpu(struct drm_device *dev) |
| 367 | 367 | { |
| 368 | − u32 reg; | |
| 369 | 368 | struct ast_private *ast = to_ast_private(dev); |
| 369 | + u32 reg; | |
| 370 | 370 | |
| 371 | − pci_read_config_dword(ast->dev->pdev, 0x04, ®); | |
| 371 | + pci_read_config_dword(dev->pdev, 0x04, ®); | |
| 372 | 372 | reg |= 0x3; |
| 373 | − pci_write_config_dword(ast->dev->pdev, 0x04, reg); | |
| 373 | + pci_write_config_dword(dev->pdev, 0x04, reg); | |
| 374 | 374 | |
| 375 | 375 | ast_enable_vga(dev); |
| 376 | 376 | ast_open_key(ast); |
| @@ -48,6 +48,19 @@ config DRM_DISPLAY_CONNECTOR · 47 unmodified lines | ||
| 48 | 48 | on ARM-based platforms. Saying Y here when this driver is not needed |
| 49 | 49 | will not cause any issue. |
| 50 | 50 | |
| 51 | +config DRM_LONTIUM_LT9611 | |
| 52 | + tristate "Lontium LT9611 DSI/HDMI bridge" | |
| 53 | + select SND_SOC_HDMI_CODEC if SND_SOC | |
| 54 | + depends on OF | |
| 55 | + select DRM_PANEL_BRIDGE | |
| 56 | + select DRM_KMS_HELPER | |
| 57 | + select REGMAP_I2C | |
| 58 | + help | |
| 59 | + Driver for Lontium LT9611 DSI to HDMI bridge | |
| 60 | + chip driver that converts dual DSI and I2S to | |
| 61 | + HDMI signals | |
| 62 | + Please say Y if you have such hardware. | |
| 63 | + | |
| 51 | 64 | config DRM_LVDS_CODEC |
| 52 | 65 | tristate "Transparent LVDS encoders and decoders support" |
| 53 | 66 | depends on OF |
| @@ -153,6 +166,14 @@ config DRM_THINE_THC63LVD1024 · 99 unmodified lines | ||
| 153 | 166 | help |
| 154 | 167 | Thine THC63LVD1024 LVDS/parallel converter driver. |
| 155 | 168 | |
| 169 | +config DRM_TOSHIBA_TC358762 | |
| 170 | + tristate "TC358762 DSI/DPI bridge" | |
| 171 | + depends on OF | |
| 172 | + select DRM_MIPI_DSI | |
| 173 | + select DRM_PANEL_BRIDGE | |
| 174 | + help | |
| 175 | + Toshiba TC358762 DSI/DPI bridge driver. | |
| 176 | + | |
| 156 | 177 | config DRM_TOSHIBA_TC358764 |
| 157 | 178 | tristate "TC358764 DSI/LVDS bridge" |
| 158 | 179 | depends on OF |
| @@ -181,6 +202,16 @@ config DRM_TOSHIBA_TC358768 · 22 unmodified lines | ||
| 181 | 202 | help |
| 182 | 203 | Toshiba TC358768AXBG/TC358778XBG DSI bridge chip driver. |
| 183 | 204 | |
| 205 | +config DRM_TOSHIBA_TC358775 | |
| 206 | + tristate "Toshiba TC358775 DSI/LVDS bridge" | |
| 207 | + depends on OF | |
| 208 | + select DRM_KMS_HELPER | |
| 209 | + select REGMAP_I2C | |
| 210 | + select DRM_PANEL | |
| 211 | + select DRM_MIPI_DSI | |
| 212 | + help | |
| 213 | + Toshiba TC358775 DSI/LVDS bridge chip driver. | |
| 214 | + | |
| 184 | 215 | config DRM_TI_TFP410 |
| 185 | 216 | tristate "TI TFP410 DVI/HDMI bridge" |
| 186 | 217 | depends on OF |
| @@ -2,6 +2,7 @@ · 1 unmodified line | ||
| 2 | 2 | obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o |
| 3 | 3 | obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o |
| 4 | 4 | obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o |
| 5 | +obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o | |
| 5 | 6 | obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o |
| 6 | 7 | obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o |
| 7 | 8 | obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o |
| @@ -12,9 +13,11 @@ obj-$(CONFIG_DRM_SII902X) += sii902x.o · 4 unmodified lines | ||
| 12 | 13 | obj-$(CONFIG_DRM_SII9234) += sii9234.o |
| 13 | 14 | obj-$(CONFIG_DRM_SIMPLE_BRIDGE) += simple-bridge.o |
| 14 | 15 | obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o |
| 16 | +obj-$(CONFIG_DRM_TOSHIBA_TC358762) += tc358762.o | |
| 15 | 17 | obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o |
| 16 | 18 | obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o |
| 17 | 19 | obj-$(CONFIG_DRM_TOSHIBA_TC358768) += tc358768.o |
| 20 | +obj-$(CONFIG_DRM_TOSHIBA_TC358775) += tc358775.o | |
| 18 | 21 | obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/ |
| 19 | 22 | obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o |
| 20 | 23 | obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o |
| @@ -507,10 +507,6 @@ static const struct drm_connector_helper_funcs anx6345_connector_helper_funcs = · 506 unmodified lines | ||
| 507 | 507 | static void |
| 508 | 508 | anx6345_connector_destroy(struct drm_connector *connector) |
| 509 | 509 | { |
| 510 | − struct anx6345 *anx6345 = connector_to_anx6345(connector); | |
| 511 | − | |
| 512 | − if (anx6345->panel) | |
| 513 | − drm_panel_detach(anx6345->panel); | |
| 514 | 510 | drm_connector_cleanup(connector); |
| 515 | 511 | } |
| 516 | 512 | |
| @@ -575,14 +571,6 @@ static int anx6345_bridge_attach(struct drm_bridge *bridge, · 58 unmodified lines | ||
| 575 | 571 | return err; |
| 576 | 572 | } |
| 577 | 573 | |
| 578 | − if (anx6345->panel) { | |
| 579 | − err = drm_panel_attach(anx6345->panel, &anx6345->connector); | |
| 580 | − if (err) { | |
| 581 | − DRM_ERROR("Failed to attach panel: %d\n", err); | |
| 582 | − return err; | |
| 583 | − } | |
| 584 | − } | |
| 585 | − | |
| 586 | 574 | return 0; |
| 587 | 575 | } |
| 588 | 576 | |
| @@ -1265,14 +1265,6 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge, · 1264 unmodified lines | ||
| 1265 | 1265 | } |
| 1266 | 1266 | } |
| 1267 | 1267 | |
| 1268 | − if (dp->plat_data->panel) { | |
| 1269 | − ret = drm_panel_attach(dp->plat_data->panel, &dp->connector); | |
| 1270 | − if (ret) { | |
| 1271 | − DRM_ERROR("Failed to attach panel\n"); | |
| 1272 | − return ret; | |
| 1273 | − } | |
| 1274 | − } | |
| 1275 | − | |
| 1276 | 1268 | return 0; |
| 1277 | 1269 | } |
| 1278 | 1270 | |
| @@ -1803,7 +1795,6 @@ void analogix_dp_unbind(struct analogix_dp_device *dp) · 524 unmodified lines | ||
| 1803 | 1795 | if (dp->plat_data->panel) { |
| 1804 | 1796 | if (drm_panel_unprepare(dp->plat_data->panel)) |
| 1805 | 1797 | DRM_ERROR("failed to turnoff the panel\n"); |
| 1806 | − drm_panel_detach(dp->plat_data->panel); | |
| 1807 | 1798 | } |
| 1808 | 1799 | |
| 1809 | 1800 | drm_dp_aux_unregister(&dp->aux); |
| @@ -0,0 +1,1230 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Copyright (c) 2018, The Linux Foundation. All rights reserved. | |
| 4 | + * Copyright (c) 2019-2020. Linaro Limited. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +#include <linux/gpio/consumer.h> | |
| 8 | +#include <linux/interrupt.h> | |
| 9 | +#include <linux/module.h> | |
| 10 | +#include <linux/of_graph.h> | |
| 11 | +#include <linux/platform_device.h> | |
| 12 | +#include <linux/regmap.h> | |
| 13 | +#include <linux/regulator/consumer.h> | |
| 14 | + | |
| 15 | +#include <sound/hdmi-codec.h> | |
| 16 | + | |
| 17 | +#include <drm/drm_atomic_helper.h> | |
| 18 | +#include <drm/drm_bridge.h> | |
| 19 | +#include <drm/drm_mipi_dsi.h> | |
| 20 | +#include <drm/drm_print.h> | |
| 21 | +#include <drm/drm_probe_helper.h> | |
| 22 | + | |
| 23 | +#define EDID_SEG_SIZE 256 | |
| 24 | +#define EDID_LEN 32 | |
| 25 | +#define EDID_LOOP 8 | |
| 26 | +#define KEY_DDC_ACCS_DONE 0x02 | |
| 27 | +#define DDC_NO_ACK 0x50 | |
| 28 | + | |
| 29 | +#define LT9611_4LANES 0 | |
| 30 | + | |
| 31 | +struct lt9611 { | |
| 32 | + struct device *dev; | |
| 33 | + struct drm_bridge bridge; | |
| 34 | + struct drm_connector connector; | |
| 35 | + | |
| 36 | + struct regmap *regmap; | |
| 37 | + | |
| 38 | + struct device_node *dsi0_node; | |
| 39 | + struct device_node *dsi1_node; | |
| 40 | + struct mipi_dsi_device *dsi0; | |
| 41 | + struct mipi_dsi_device *dsi1; | |
| 42 | + struct platform_device *audio_pdev; | |
| 43 | + | |
| 44 | + bool ac_mode; | |
| 45 | + | |
| 46 | + struct gpio_desc *reset_gpio; | |
| 47 | + struct gpio_desc *enable_gpio; | |
| 48 | + | |
| 49 | + bool power_on; | |
| 50 | + bool sleep; | |
| 51 | + | |
| 52 | + struct regulator_bulk_data supplies[2]; | |
| 53 | + | |
| 54 | + struct i2c_client *client; | |
| 55 | + | |
| 56 | + enum drm_connector_status status; | |
| 57 | + | |
| 58 | + u8 edid_buf[EDID_SEG_SIZE]; | |
| 59 | + u32 vic; | |
| 60 | +}; | |
| 61 | + | |
| 62 | +#define LT9611_PAGE_CONTROL 0xff | |
| 63 | + | |
| 64 | +static const struct regmap_range_cfg lt9611_ranges[] = { | |
| 65 | + { | |
| 66 | + .name = "register_range", | |
| 67 | + .range_min = 0, | |
| 68 | + .range_max = 0x85ff, | |
| 69 | + .selector_reg = LT9611_PAGE_CONTROL, | |
| 70 | + .selector_mask = 0xff, | |
| 71 | + .selector_shift = 0, | |
| 72 | + .window_start = 0, | |
| 73 | + .window_len = 0x100, | |
| 74 | + }, | |
| 75 | +}; | |
| 76 | + | |
| 77 | +static const struct regmap_config lt9611_regmap_config = { | |
| 78 | + .reg_bits = 8, | |
| 79 | + .val_bits = 8, | |
| 80 | + .max_register = 0xffff, | |
| 81 | + .ranges = lt9611_ranges, | |
| 82 | + .num_ranges = ARRAY_SIZE(lt9611_ranges), | |
| 83 | +}; | |
| 84 | + | |
| 85 | +struct lt9611_mode { | |
| 86 | + u16 hdisplay; | |
| 87 | + u16 vdisplay; | |
| 88 | + u8 vrefresh; | |
| 89 | + u8 lanes; | |
| 90 | + u8 intfs; | |
| 91 | +}; | |
| 92 | + | |
| 93 | +static struct lt9611_mode lt9611_modes[] = { | |
| 94 | + { 3840, 2160, 30, 4, 2 }, /* 3840x2160 24bit 30Hz 4Lane 2ports */ | |
| 95 | + { 1920, 1080, 60, 4, 1 }, /* 1080P 24bit 60Hz 4lane 1port */ | |
| 96 | + { 1920, 1080, 30, 3, 1 }, /* 1080P 24bit 30Hz 3lane 1port */ | |
| 97 | + { 1920, 1080, 24, 3, 1 }, | |
| 98 | + { 720, 480, 60, 4, 1 }, | |
| 99 | + { 720, 576, 50, 2, 1 }, | |
| 100 | + { 640, 480, 60, 2, 1 }, | |
| 101 | +}; | |
| 102 | + | |
| 103 | +static struct lt9611 *bridge_to_lt9611(struct drm_bridge *bridge) | |
| 104 | +{ | |
| 105 | + return container_of(bridge, struct lt9611, bridge); | |
| 106 | +} | |
| 107 | + | |
| 108 | +static struct lt9611 *connector_to_lt9611(struct drm_connector *connector) | |
| 109 | +{ | |
| 110 | + return container_of(connector, struct lt9611, connector); | |
| 111 | +} | |
| 112 | + | |
| 113 | +static int lt9611_mipi_input_analog(struct lt9611 *lt9611) | |
| 114 | +{ | |
| 115 | + const struct reg_sequence reg_cfg[] = { | |
| 116 | + { 0x8106, 0x40 }, /* port A rx current */ | |
| 117 | + { 0x810a, 0xfe }, /* port A ldo voltage set */ | |
| 118 | + { 0x810b, 0xbf }, /* enable port A lprx */ | |
| 119 | + { 0x8111, 0x40 }, /* port B rx current */ | |
| 120 | + { 0x8115, 0xfe }, /* port B ldo voltage set */ | |
| 121 | + { 0x8116, 0xbf }, /* enable port B lprx */ | |
| 122 | + | |
| 123 | + { 0x811c, 0x03 }, /* PortA clk lane no-LP mode */ | |
| 124 | + { 0x8120, 0x03 }, /* PortB clk lane with-LP mode */ | |
| 125 | + }; | |
| 126 | + | |
| 127 | + return regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); | |
| 128 | +} | |
| 129 | + | |
| 130 | +static int lt9611_mipi_input_digital(struct lt9611 *lt9611, | |
| 131 | + const struct drm_display_mode *mode) | |
| 132 | +{ | |
| 133 | + struct reg_sequence reg_cfg[] = { | |
| 134 | + { 0x8300, LT9611_4LANES }, | |
| 135 | + { 0x830a, 0x00 }, | |
| 136 | + { 0x824f, 0x80 }, | |
| 137 | + { 0x8250, 0x10 }, | |
| 138 | + { 0x8302, 0x0a }, | |
| 139 | + { 0x8306, 0x0a }, | |
| 140 | + }; | |
| 141 | + | |
| 142 | + if (mode->hdisplay == 3840) | |
| 143 | + reg_cfg[1].def = 0x03; | |
| 144 | + | |
| 145 | + return regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); | |
| 146 | +} | |
| 147 | + | |
| 148 | +static void lt9611_mipi_video_setup(struct lt9611 *lt9611, | |
| 149 | + const struct drm_display_mode *mode) | |
| 150 | +{ | |
| 151 | + u32 h_total, hactive, hsync_len, hfront_porch, hsync_porch; | |
| 152 | + u32 v_total, vactive, vsync_len, vfront_porch, vsync_porch; | |
| 153 | + | |
| 154 | + h_total = mode->htotal; | |
| 155 | + v_total = mode->vtotal; | |
| 156 | + | |
| 157 | + hactive = mode->hdisplay; | |
| 158 | + hsync_len = mode->hsync_end - mode->hsync_start; | |
| 159 | + hfront_porch = mode->hsync_start - mode->hdisplay; | |
| 160 | + hsync_porch = hsync_len + mode->htotal - mode->hsync_end; | |
| 161 | + | |
| 162 | + vactive = mode->vdisplay; | |
| 163 | + vsync_len = mode->vsync_end - mode->vsync_start; | |
| 164 | + vfront_porch = mode->vsync_start - mode->vdisplay; | |
| 165 | + vsync_porch = vsync_len + mode->vtotal - mode->vsync_end; | |
| 166 | + | |
| 167 | + regmap_write(lt9611->regmap, 0x830d, (u8)(v_total / 256)); | |
| 168 | + regmap_write(lt9611->regmap, 0x830e, (u8)(v_total % 256)); | |
| 169 | + | |
| 170 | + regmap_write(lt9611->regmap, 0x830f, (u8)(vactive / 256)); | |
| 171 | + regmap_write(lt9611->regmap, 0x8310, (u8)(vactive % 256)); | |
| 172 | + | |
| 173 | + regmap_write(lt9611->regmap, 0x8311, (u8)(h_total / 256)); | |
| 174 | + regmap_write(lt9611->regmap, 0x8312, (u8)(h_total % 256)); | |
| 175 | + | |
| 176 | + regmap_write(lt9611->regmap, 0x8313, (u8)(hactive / 256)); | |
| 177 | + regmap_write(lt9611->regmap, 0x8314, (u8)(hactive % 256)); | |
| 178 | + | |
| 179 | + regmap_write(lt9611->regmap, 0x8315, (u8)(vsync_len % 256)); | |
| 180 | + regmap_write(lt9611->regmap, 0x8316, (u8)(hsync_len % 256)); | |
| 181 | + | |
| 182 | + regmap_write(lt9611->regmap, 0x8317, (u8)(vfront_porch % 256)); | |
| 183 | + | |
| 184 | + regmap_write(lt9611->regmap, 0x8318, (u8)(vsync_porch % 256)); | |
| 185 | + | |
| 186 | + regmap_write(lt9611->regmap, 0x8319, (u8)(hfront_porch % 256)); | |
| 187 | + | |
| 188 | + regmap_write(lt9611->regmap, 0x831a, (u8)(hsync_porch / 256)); | |
| 189 | + regmap_write(lt9611->regmap, 0x831b, (u8)(hsync_porch % 256)); | |
| 190 | +} | |
| 191 | + | |
| 192 | +static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode) | |
| 193 | +{ | |
| 194 | + const struct reg_sequence reg_cfg[] = { | |
| 195 | + { 0x830b, 0x01 }, | |
| 196 | + { 0x830c, 0x10 }, | |
| 197 | + { 0x8348, 0x00 }, | |
| 198 | + { 0x8349, 0x81 }, | |
| 199 | + | |
| 200 | + /* stage 1 */ | |
| 201 | + { 0x8321, 0x4a }, | |
| 202 | + { 0x8324, 0x71 }, | |
| 203 | + { 0x8325, 0x30 }, | |
| 204 | + { 0x832a, 0x01 }, | |
| 205 | + | |
| 206 | + /* stage 2 */ | |
| 207 | + { 0x834a, 0x40 }, | |
| 208 | + { 0x831d, 0x10 }, | |
| 209 | + | |
| 210 | + /* MK limit */ | |
| 211 | + { 0x832d, 0x38 }, | |
| 212 | + { 0x8331, 0x08 }, | |
| 213 | + }; | |
| 214 | + const struct reg_sequence reg_cfg2[] = { | |
| 215 | + { 0x830b, 0x03 }, | |
| 216 | + { 0x830c, 0xd0 }, | |
| 217 | + { 0x8348, 0x03 }, | |
| 218 | + { 0x8349, 0xe0 }, | |
| 219 | + { 0x8324, 0x72 }, | |
| 220 | + { 0x8325, 0x00 }, | |
| 221 | + { 0x832a, 0x01 }, | |
| 222 | + { 0x834a, 0x10 }, | |
| 223 | + { 0x831d, 0x10 }, | |
| 224 | + { 0x8326, 0x37 }, | |
| 225 | + }; | |
| 226 | + | |
| 227 | + regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); | |
| 228 | + | |
| 229 | + switch (mode->hdisplay) { | |
| 230 | + case 640: | |
| 231 | + regmap_write(lt9611->regmap, 0x8326, 0x14); | |
| 232 | + break; | |
| 233 | + case 1920: | |
| 234 | + regmap_write(lt9611->regmap, 0x8326, 0x37); | |
| 235 | + break; | |
| 236 | + case 3840: | |
| 237 | + regmap_multi_reg_write(lt9611->regmap, reg_cfg2, ARRAY_SIZE(reg_cfg2)); | |
| 238 | + break; | |
| 239 | + } | |
| 240 | + | |
| 241 | + /* pcr rst */ | |
| 242 | + regmap_write(lt9611->regmap, 0x8011, 0x5a); | |
| 243 | + regmap_write(lt9611->regmap, 0x8011, 0xfa); | |
| 244 | +} | |
| 245 | + | |
| 246 | +static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode) | |
| 247 | +{ | |
| 248 | + unsigned int pclk = mode->clock; | |
| 249 | + const struct reg_sequence reg_cfg[] = { | |
| 250 | + /* txpll init */ | |
| 251 | + { 0x8123, 0x40 }, | |
| 252 | + { 0x8124, 0x64 }, | |
| 253 | + { 0x8125, 0x80 }, | |
| 254 | + { 0x8126, 0x55 }, | |
| 255 | + { 0x812c, 0x37 }, | |
| 256 | + { 0x812f, 0x01 }, | |
| 257 | + { 0x8126, 0x55 }, | |
| 258 | + { 0x8127, 0x66 }, | |
| 259 | + { 0x8128, 0x88 }, | |
| 260 | + }; | |
| 261 | + | |
| 262 | + regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); | |
| 263 | + | |
| 264 | + if (pclk > 150000) | |
| 265 | + regmap_write(lt9611->regmap, 0x812d, 0x88); | |
| 266 | + else if (pclk > 70000) | |
| 267 | + regmap_write(lt9611->regmap, 0x812d, 0x99); | |
| 268 | + else | |
| 269 | + regmap_write(lt9611->regmap, 0x812d, 0xaa); | |
| 270 | + | |
| 271 | + /* | |
| 272 | + * first divide pclk by 2 first | |
| 273 | + * - write divide by 64k to 19:16 bits which means shift by 17 | |
| 274 | + * - write divide by 256 to 15:8 bits which means shift by 9 | |
| 275 | + * - write remainder to 7:0 bits, which means shift by 1 | |
| 276 | + */ | |
| 277 | + regmap_write(lt9611->regmap, 0x82e3, pclk >> 17); /* pclk[19:16] */ | |
| 278 | + regmap_write(lt9611->regmap, 0x82e4, pclk >> 9); /* pclk[15:8] */ | |
| 279 | + regmap_write(lt9611->regmap, 0x82e5, pclk >> 1); /* pclk[7:0] */ | |
| 280 | + | |
| 281 | + regmap_write(lt9611->regmap, 0x82de, 0x20); | |
| 282 | + regmap_write(lt9611->regmap, 0x82de, 0xe0); | |
| 283 | + | |
| 284 | + regmap_write(lt9611->regmap, 0x8016, 0xf1); | |
| 285 | + regmap_write(lt9611->regmap, 0x8016, 0xf3); | |
| 286 | + | |
| 287 | + return 0; | |
| 288 | +} | |
| 289 | + | |
| 290 | +static int lt9611_read_video_check(struct lt9611 *lt9611, unsigned int reg) | |
| 291 | +{ | |
| 292 | + unsigned int temp, temp2; | |
| 293 | + int ret; | |
| 294 | + | |
| 295 | + ret = regmap_read(lt9611->regmap, reg, &temp); | |
| 296 | + if (ret) | |
| 297 | + return ret; | |
| 298 | + temp <<= 8; | |
| 299 | + ret = regmap_read(lt9611->regmap, reg + 1, &temp2); | |
| 300 | + if (ret) | |
| 301 | + return ret; | |
| 302 | + | |
| 303 | + return (temp + temp2); | |
| 304 | +} | |
| 305 | + | |
| 306 | +static int lt9611_video_check(struct lt9611 *lt9611) | |
| 307 | +{ | |
| 308 | + u32 v_total, vactive, hactive_a, hactive_b, h_total_sysclk; | |
| 309 | + int temp; | |
| 310 | + | |
| 311 | + /* top module video check */ | |
| 312 | + | |
| 313 | + /* vactive */ | |
| 314 | + temp = lt9611_read_video_check(lt9611, 0x8282); | |
| 315 | + if (temp < 0) | |
| 316 | + goto end; | |
| 317 | + vactive = temp; | |
| 318 | + | |
| 319 | + /* v_total */ | |
| 320 | + temp = lt9611_read_video_check(lt9611, 0x826c); | |
| 321 | + if (temp < 0) | |
| 322 | + goto end; | |
| 323 | + v_total = temp; | |
| 324 | + | |
| 325 | + /* h_total_sysclk */ | |
| 326 | + temp = lt9611_read_video_check(lt9611, 0x8286); | |
| 327 | + if (temp < 0) | |
| 328 | + goto end; | |
| 329 | + h_total_sysclk = temp; | |
| 330 | + | |
| 331 | + /* hactive_a */ | |
| 332 | + temp = lt9611_read_video_check(lt9611, 0x8382); | |
| 333 | + if (temp < 0) | |
| 334 | + goto end; | |
| 335 | + hactive_a = temp / 3; | |
| 336 | + | |
| 337 | + /* hactive_b */ | |
| 338 | + temp = lt9611_read_video_check(lt9611, 0x8386); | |
| 339 | + if (temp < 0) | |
| 340 | + goto end; | |
| 341 | + hactive_b = temp / 3; | |
| 342 | + | |
| 343 | + dev_info(lt9611->dev, | |
| 344 | + "video check: hactive_a=%d, hactive_b=%d, vactive=%d, v_total=%d, h_total_sysclk=%d\n", | |
| 345 | + hactive_a, hactive_b, vactive, v_total, h_total_sysclk); | |
| 346 | + | |
| 347 | + return 0; | |
| 348 | + | |
| 349 | +end: | |
| 350 | + dev_err(lt9611->dev, "read video check error\n"); | |
| 351 | + return temp; | |
| 352 | +} | |
| 353 | + | |
| 354 | +static void lt9611_hdmi_tx_digital(struct lt9611 *lt9611) | |
| 355 | +{ | |
| 356 | + regmap_write(lt9611->regmap, 0x8443, 0x46 - lt9611->vic); | |
| 357 | + regmap_write(lt9611->regmap, 0x8447, lt9611->vic); | |
| 358 | + regmap_write(lt9611->regmap, 0x843d, 0x0a); /* UD1 infoframe */ | |
| 359 | + | |
| 360 | + regmap_write(lt9611->regmap, 0x82d6, 0x8c); | |
| 361 | + regmap_write(lt9611->regmap, 0x82d7, 0x04); | |
| 362 | +} | |
| 363 | + | |
| 364 | +static void lt9611_hdmi_tx_phy(struct lt9611 *lt9611) | |
| 365 | +{ | |
| 366 | + struct reg_sequence reg_cfg[] = { | |
| 367 | + { 0x8130, 0x6a }, | |
| 368 | + { 0x8131, 0x44 }, /* HDMI DC mode */ | |
| 369 | + { 0x8132, 0x4a }, | |
| 370 | + { 0x8133, 0x0b }, | |
| 371 | + { 0x8134, 0x00 }, | |
| 372 | + { 0x8135, 0x00 }, | |
| 373 | + { 0x8136, 0x00 }, | |
| 374 | + { 0x8137, 0x44 }, | |
| 375 | + { 0x813f, 0x0f }, | |
| 376 | + { 0x8140, 0xa0 }, | |
| 377 | + { 0x8141, 0xa0 }, | |
| 378 | + { 0x8142, 0xa0 }, | |
| 379 | + { 0x8143, 0xa0 }, | |
| 380 | + { 0x8144, 0x0a }, | |
| 381 | + }; | |
| 382 | + | |
| 383 | + /* HDMI AC mode */ | |
| 384 | + if (lt9611->ac_mode) | |
| 385 | + reg_cfg[2].def = 0x73; | |
| 386 | + | |
| 387 | + regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); | |
| 388 | +} | |
| 389 | + | |
| 390 | +static irqreturn_t lt9611_irq_thread_handler(int irq, void *dev_id) | |
| 391 | +{ | |
| 392 | + struct lt9611 *lt9611 = dev_id; | |
| 393 | + unsigned int irq_flag0 = 0; | |
| 394 | + unsigned int irq_flag3 = 0; | |
| 395 | + | |
| 396 | + regmap_read(lt9611->regmap, 0x820f, &irq_flag3); | |
| 397 | + regmap_read(lt9611->regmap, 0x820c, &irq_flag0); | |
| 398 | + | |
| 399 | + /* hpd changed low */ | |
| 400 | + if (irq_flag3 & 0x80) { | |
| 401 | + dev_info(lt9611->dev, "hdmi cable disconnected\n"); | |
| 402 | + | |
| 403 | + regmap_write(lt9611->regmap, 0x8207, 0xbf); | |
| 404 | + regmap_write(lt9611->regmap, 0x8207, 0x3f); | |
| 405 | + } | |
| 406 | + | |
| 407 | + /* hpd changed high */ | |
| 408 | + if (irq_flag3 & 0x40) { | |
| 409 | + dev_info(lt9611->dev, "hdmi cable connected\n"); | |
| 410 | + | |
| 411 | + regmap_write(lt9611->regmap, 0x8207, 0x7f); | |
| 412 | + regmap_write(lt9611->regmap, 0x8207, 0x3f); | |
| 413 | + } | |
| 414 | + | |
| 415 | + if (irq_flag3 & 0xc0 && lt9611->bridge.dev) | |
| 416 | + drm_kms_helper_hotplug_event(lt9611->bridge.dev); | |
| 417 | + | |
| 418 | + /* video input changed */ | |
| 419 | + if (irq_flag0 & 0x01) { | |
| 420 | + dev_info(lt9611->dev, "video input changed\n"); | |
| 421 | + regmap_write(lt9611->regmap, 0x829e, 0xff); | |
| 422 | + regmap_write(lt9611->regmap, 0x829e, 0xf7); | |
| 423 | + regmap_write(lt9611->regmap, 0x8204, 0xff); | |
| 424 | + regmap_write(lt9611->regmap, 0x8204, 0xfe); | |
| 425 | + } | |
| 426 | + | |
| 427 | + return IRQ_HANDLED; | |
| 428 | +} | |
| 429 | + | |
| 430 | +static void lt9611_enable_hpd_interrupts(struct lt9611 *lt9611) | |
| 431 | +{ | |
| 432 | + unsigned int val; | |
| 433 | + | |
| 434 | + regmap_read(lt9611->regmap, 0x8203, &val); | |
| 435 | + | |
| 436 | + val &= ~0xc0; | |
| 437 | + regmap_write(lt9611->regmap, 0x8203, val); | |
| 438 | + regmap_write(lt9611->regmap, 0x8207, 0xff); /* clear */ | |
| 439 | + regmap_write(lt9611->regmap, 0x8207, 0x3f); | |
| 440 | +} | |
| 441 | + | |
| 442 | +static void lt9611_sleep_setup(struct lt9611 *lt9611) | |
| 443 | +{ | |
| 444 | + const struct reg_sequence sleep_setup[] = { | |
| 445 | + { 0x8024, 0x76 }, | |
| 446 | + { 0x8023, 0x01 }, | |
| 447 | + { 0x8157, 0x03 }, /* set addr pin as output */ | |
| 448 | + { 0x8149, 0x0b }, | |
| 449 | + { 0x8151, 0x30 }, /* disable IRQ */ | |
| 450 | + { 0x8102, 0x48 }, /* MIPI Rx power down */ | |
| 451 | + { 0x8123, 0x80 }, | |
| 452 | + { 0x8130, 0x00 }, | |
| 453 | + { 0x8100, 0x01 }, /* bandgap power down */ | |
| 454 | + { 0x8101, 0x00 }, /* system clk power down */ | |
| 455 | + }; | |
| 456 | + | |
| 457 | + regmap_multi_reg_write(lt9611->regmap, | |
| 458 | + sleep_setup, ARRAY_SIZE(sleep_setup)); | |
| 459 | + lt9611->sleep = true; | |
| 460 | +} | |
| 461 | + | |
| 462 | +static int lt9611_power_on(struct lt9611 *lt9611) | |
| 463 | +{ | |
| 464 | + int ret; | |
| 465 | + const struct reg_sequence seq[] = { | |
| 466 | + /* LT9611_System_Init */ | |
| 467 | + { 0x8101, 0x18 }, /* sel xtal clock */ | |
| 468 | + | |
| 469 | + /* timer for frequency meter */ | |
| 470 | + { 0x821b, 0x69 }, /* timer 2 */ | |
| 471 | + { 0x821c, 0x78 }, | |
| 472 | + { 0x82cb, 0x69 }, /* timer 1 */ | |
| 473 | + { 0x82cc, 0x78 }, | |
| 474 | + | |
| 475 | + /* irq init */ | |
| 476 | + { 0x8251, 0x01 }, | |
| 477 | + { 0x8258, 0x0a }, /* hpd irq */ | |
| 478 | + { 0x8259, 0x80 }, /* hpd debounce width */ | |
| 479 | + { 0x829e, 0xf7 }, /* video check irq */ | |
| 480 | + | |
| 481 | + /* power consumption for work */ | |
| 482 | + { 0x8004, 0xf0 }, | |
| 483 | + { 0x8006, 0xf0 }, | |
| 484 | + { 0x800a, 0x80 }, | |
| 485 | + { 0x800b, 0x40 }, | |
| 486 | + { 0x800d, 0xef }, | |
| 487 | + { 0x8011, 0xfa }, | |
| 488 | + }; | |
| 489 | + | |
| 490 | + if (lt9611->power_on) | |
| 491 | + return 0; | |
| 492 | + | |
| 493 | + ret = regmap_multi_reg_write(lt9611->regmap, seq, ARRAY_SIZE(seq)); | |
| 494 | + if (!ret) | |
| 495 | + lt9611->power_on = true; | |
| 496 | + | |
| 497 | + return ret; | |
| 498 | +} | |
| 499 | + | |
| 500 | +static int lt9611_power_off(struct lt9611 *lt9611) | |
| 501 | +{ | |
| 502 | + int ret; | |
| 503 | + | |
| 504 | + ret = regmap_write(lt9611->regmap, 0x8130, 0x6a); | |
| 505 | + if (!ret) | |
| 506 | + lt9611->power_on = false; | |
| 507 | + | |
| 508 | + return ret; | |
| 509 | +} | |
| 510 | + | |
| 511 | +static void lt9611_reset(struct lt9611 *lt9611) | |
| 512 | +{ | |
| 513 | + gpiod_set_value_cansleep(lt9611->reset_gpio, 1); | |
| 514 | + msleep(20); | |
| 515 | + | |
| 516 | + gpiod_set_value_cansleep(lt9611->reset_gpio, 0); | |
| 517 | + msleep(20); | |
| 518 | + | |
| 519 | + gpiod_set_value_cansleep(lt9611->reset_gpio, 1); | |
| 520 | + msleep(100); | |
| 521 | +} | |
| 522 | + | |
| 523 | +static void lt9611_assert_5v(struct lt9611 *lt9611) | |
| 524 | +{ | |
| 525 | + if (!lt9611->enable_gpio) | |
| 526 | + return; | |
| 527 | + | |
| 528 | + gpiod_set_value_cansleep(lt9611->enable_gpio, 1); | |
| 529 | + msleep(20); | |
| 530 | +} | |
| 531 | + | |
| 532 | +static int lt9611_regulator_init(struct lt9611 *lt9611) | |
| 533 | +{ | |
| 534 | + int ret; | |
| 535 | + | |
| 536 | + lt9611->supplies[0].supply = "vdd"; | |
| 537 | + lt9611->supplies[1].supply = "vcc"; | |
| 538 | + | |
| 539 | + ret = devm_regulator_bulk_get(lt9611->dev, 2, lt9611->supplies); | |
| 540 | + if (ret < 0) | |
| 541 | + return ret; | |
| 542 | + | |
| 543 | + return regulator_set_load(lt9611->supplies[0].consumer, 300000); | |
| 544 | +} | |
| 545 | + | |
| 546 | +static int lt9611_regulator_enable(struct lt9611 *lt9611) | |
| 547 | +{ | |
| 548 | + int ret; | |
| 549 | + | |
| 550 | + ret = regulator_enable(lt9611->supplies[0].consumer); | |
| 551 | + if (ret < 0) | |
| 552 | + return ret; | |
| 553 | + | |
| 554 | + usleep_range(1000, 10000); | |
| 555 | + | |
| 556 | + ret = regulator_enable(lt9611->supplies[1].consumer); | |
| 557 | + if (ret < 0) { | |
| 558 | + regulator_disable(lt9611->supplies[0].consumer); | |
| 559 | + return ret; | |
| 560 | + } | |
| 561 | + | |
| 562 | + return 0; | |
| 563 | +} | |
| 564 | + | |
| 565 | +static struct lt9611_mode *lt9611_find_mode(const struct drm_display_mode *mode) | |
| 566 | +{ | |
| 567 | + int i; | |
| 568 | + | |
| 569 | + for (i = 0; i < ARRAY_SIZE(lt9611_modes); i++) { | |
| 570 | + if (lt9611_modes[i].hdisplay == mode->hdisplay && | |
| 571 | + lt9611_modes[i].vdisplay == mode->vdisplay && | |
| 572 | + lt9611_modes[i].vrefresh == drm_mode_vrefresh(mode)) { | |
| 573 | + return <9611_modes[i]; | |
| 574 | + } | |
| 575 | + } | |
| 576 | + | |
| 577 | + return NULL; | |
| 578 | +} | |
| 579 | + | |
| 580 | +/* connector funcs */ | |
| 581 | +static enum drm_connector_status | |
| 582 | +lt9611_connector_detect(struct drm_connector *connector, bool force) | |
| 583 | +{ | |
| 584 | + struct lt9611 *lt9611 = connector_to_lt9611(connector); | |
| 585 | + unsigned int reg_val = 0; | |
| 586 | + int connected = 0; | |
| 587 | + | |
| 588 | + regmap_read(lt9611->regmap, 0x825e, ®_val); | |
| 589 | + connected = (reg_val & BIT(2)); | |
| 590 | + | |
| 591 | + lt9611->status = connected ? connector_status_connected : | |
| 592 | + connector_status_disconnected; | |
| 593 | + | |
| 594 | + return lt9611->status; | |
| 595 | +} | |
| 596 | + | |
| 597 | +static int lt9611_read_edid(struct lt9611 *lt9611) | |
| 598 | +{ | |
| 599 | + unsigned int temp; | |
| 600 | + int ret = 0; | |
| 601 | + int i, j; | |
| 602 | + | |
| 603 | + /* memset to clear old buffer, if any */ | |
| 604 | + memset(lt9611->edid_buf, 0, sizeof(lt9611->edid_buf)); | |
| 605 | + | |
| 606 | + regmap_write(lt9611->regmap, 0x8503, 0xc9); | |
| 607 | + | |
| 608 | + /* 0xA0 is EDID device address */ | |
| 609 | + regmap_write(lt9611->regmap, 0x8504, 0xa0); | |
| 610 | + /* 0x00 is EDID offset address */ | |
| 611 | + regmap_write(lt9611->regmap, 0x8505, 0x00); | |
| 612 | + | |
| 613 | + /* length for read */ | |
| 614 | + regmap_write(lt9611->regmap, 0x8506, EDID_LEN); | |
| 615 | + regmap_write(lt9611->regmap, 0x8514, 0x7f); | |
| 616 | + | |
| 617 | + for (i = 0; i < EDID_LOOP; i++) { | |
| 618 | + /* offset address */ | |
| 619 | + regmap_write(lt9611->regmap, 0x8505, i * EDID_LEN); | |
| 620 | + regmap_write(lt9611->regmap, 0x8507, 0x36); | |
| 621 | + regmap_write(lt9611->regmap, 0x8507, 0x31); | |
| 622 | + regmap_write(lt9611->regmap, 0x8507, 0x37); | |
| 623 | + usleep_range(5000, 10000); | |
| 624 | + | |
| 625 | + regmap_read(lt9611->regmap, 0x8540, &temp); | |
| 626 | + | |
| 627 | + if (temp & KEY_DDC_ACCS_DONE) { | |
| 628 | + for (j = 0; j < EDID_LEN; j++) { | |
| 629 | + regmap_read(lt9611->regmap, 0x8583, &temp); | |
| 630 | + lt9611->edid_buf[i * EDID_LEN + j] = temp; | |
| 631 | + } | |
| 632 | + | |
| 633 | + } else if (temp & DDC_NO_ACK) { /* DDC No Ack or Abitration lost */ | |
| 634 | + dev_err(lt9611->dev, "read edid failed: no ack\n"); | |
| 635 | + ret = -EIO; | |
| 636 | + goto end; | |
| 637 | + | |
| 638 | + } else { | |
| 639 | + dev_err(lt9611->dev, "read edid failed: access not done\n"); | |
| 640 | + ret = -EIO; | |
| 641 | + goto end; | |
| 642 | + } | |
| 643 | + } | |
| 644 | + | |
| 645 | +end: | |
| 646 | + regmap_write(lt9611->regmap, 0x8507, 0x1f); | |
| 647 | + return ret; | |
| 648 | +} | |
| 649 | + | |
| 650 | +static int | |
| 651 | +lt9611_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) | |
| 652 | +{ | |
| 653 | + struct lt9611 *lt9611 = data; | |
| 654 | + int ret; | |
| 655 | + | |
| 656 | + if (len > 128) | |
| 657 | + return -EINVAL; | |
| 658 | + | |
| 659 | + /* supports up to 1 extension block */ | |
| 660 | + /* TODO: add support for more extension blocks */ | |
| 661 | + if (block > 1) | |
| 662 | + return -EINVAL; | |
| 663 | + | |
| 664 | + if (block == 0) { | |
| 665 | + ret = lt9611_read_edid(lt9611); | |
| 666 | + if (ret) { | |
| 667 | + dev_err(lt9611->dev, "edid read failed\n"); | |
| 668 | + return ret; | |
| 669 | + } | |
| 670 | + } | |
| 671 | + | |
| 672 | + block %= 2; | |
| 673 | + memcpy(buf, lt9611->edid_buf + (block * 128), len); | |
| 674 | + | |
| 675 | + return 0; | |
| 676 | +} | |
| 677 | + | |
| 678 | +static int lt9611_connector_get_modes(struct drm_connector *connector) | |
| 679 | +{ | |
| 680 | + struct lt9611 *lt9611 = connector_to_lt9611(connector); | |
| 681 | + unsigned int count; | |
| 682 | + struct edid *edid; | |
| 683 | + | |
| 684 | + lt9611_power_on(lt9611); | |
| 685 | + edid = drm_do_get_edid(connector, lt9611_get_edid_block, lt9611); | |
| 686 | + drm_connector_update_edid_property(connector, edid); | |
| 687 | + count = drm_add_edid_modes(connector, edid); | |
| 688 | + kfree(edid); | |
| 689 | + | |
| 690 | + return count; | |
| 691 | +} | |
| 692 | + | |
| 693 | +static enum drm_mode_status | |
| 694 | +lt9611_connector_mode_valid(struct drm_connector *connector, | |
| 695 | + struct drm_display_mode *mode) | |
| 696 | +{ | |
| 697 | + struct lt9611_mode *lt9611_mode = lt9611_find_mode(mode); | |
| 698 | + | |
| 699 | + return lt9611_mode ? MODE_OK : MODE_BAD; | |
| 700 | +} | |
| 701 | + | |
| 702 | +/* bridge funcs */ | |
| 703 | +static void lt9611_bridge_enable(struct drm_bridge *bridge) | |
| 704 | +{ | |
| 705 | + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); | |
| 706 | + | |
| 707 | + if (lt9611_power_on(lt9611)) { | |
| 708 | + dev_err(lt9611->dev, "power on failed\n"); | |
| 709 | + return; | |
| 710 | + } | |
| 711 | + | |
| 712 | + lt9611_mipi_input_analog(lt9611); | |
| 713 | + lt9611_hdmi_tx_digital(lt9611); | |
| 714 | + lt9611_hdmi_tx_phy(lt9611); | |
| 715 | + | |
| 716 | + msleep(500); | |
| 717 | + | |
| 718 | + lt9611_video_check(lt9611); | |
| 719 | + | |
| 720 | + /* Enable HDMI output */ | |
| 721 | + regmap_write(lt9611->regmap, 0x8130, 0xea); | |
| 722 | +} | |
| 723 | + | |
| 724 | +static void lt9611_bridge_disable(struct drm_bridge *bridge) | |
| 725 | +{ | |
| 726 | + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); | |
| 727 | + int ret; | |
| 728 | + | |
| 729 | + /* Disable HDMI output */ | |
| 730 | + ret = regmap_write(lt9611->regmap, 0x8130, 0x6a); | |
| 731 | + if (ret) { | |
| 732 | + dev_err(lt9611->dev, "video on failed\n"); | |
| 733 | + return; | |
| 734 | + } | |
| 735 | + | |
| 736 | + if (lt9611_power_off(lt9611)) { | |
| 737 | + dev_err(lt9611->dev, "power on failed\n"); | |
| 738 | + return; | |
| 739 | + } | |
| 740 | +} | |
| 741 | + | |
| 742 | +static struct | |
| 743 | +drm_connector_helper_funcs lt9611_bridge_connector_helper_funcs = { | |
| 744 | + .get_modes = lt9611_connector_get_modes, | |
| 745 | + .mode_valid = lt9611_connector_mode_valid, | |
| 746 | +}; | |
| 747 | + | |
| 748 | +static const struct drm_connector_funcs lt9611_bridge_connector_funcs = { | |
| 749 | + .fill_modes = drm_helper_probe_single_connector_modes, | |
| 750 | + .detect = lt9611_connector_detect, | |
| 751 | + .destroy = drm_connector_cleanup, | |
| 752 | + .reset = drm_atomic_helper_connector_reset, | |
| 753 | + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | |
| 754 | + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | |
| 755 | +}; | |
| 756 | + | |
| 757 | +static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611, | |
| 758 | + struct device_node *dsi_node) | |
| 759 | +{ | |
| 760 | + const struct mipi_dsi_device_info info = { "lt9611", 0, NULL }; | |
| 761 | + struct mipi_dsi_device *dsi; | |
| 762 | + struct mipi_dsi_host *host; | |
| 763 | + int ret; | |
| 764 | + | |
| 765 | + host = of_find_mipi_dsi_host_by_node(dsi_node); | |
| 766 | + if (!host) { | |
| 767 | + dev_err(lt9611->dev, "failed to find dsi host\n"); | |
| 768 | + return ERR_PTR(-EPROBE_DEFER); | |
| 769 | + } | |
| 770 | + | |
| 771 | + dsi = mipi_dsi_device_register_full(host, &info); | |
| 772 | + if (IS_ERR(dsi)) { | |
| 773 | + dev_err(lt9611->dev, "failed to create dsi device\n"); | |
| 774 | + return dsi; | |
| 775 | + } | |
| 776 | + | |
| 777 | + dsi->lanes = 4; | |
| 778 | + dsi->format = MIPI_DSI_FMT_RGB888; | |
| 779 | + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | | |
| 780 | + MIPI_DSI_MODE_VIDEO_HSE; | |
| 781 | + | |
| 782 | + ret = mipi_dsi_attach(dsi); | |
| 783 | + if (ret < 0) { | |
| 784 | + dev_err(lt9611->dev, "failed to attach dsi to host\n"); | |
| 785 | + mipi_dsi_device_unregister(dsi); | |
| 786 | + return ERR_PTR(ret); | |
| 787 | + } | |
| 788 | + | |
| 789 | + return dsi; | |
| 790 | +} | |
| 791 | + | |
| 792 | +static void lt9611_bridge_detach(struct drm_bridge *bridge) | |
| 793 | +{ | |
| 794 | + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); | |
| 795 | + | |
| 796 | + if (lt9611->dsi1) { | |
| 797 | + mipi_dsi_detach(lt9611->dsi1); | |
| 798 | + mipi_dsi_device_unregister(lt9611->dsi1); | |
| 799 | + } | |
| 800 | + | |
| 801 | + mipi_dsi_detach(lt9611->dsi0); | |
| 802 | + mipi_dsi_device_unregister(lt9611->dsi0); | |
| 803 | +} | |
| 804 | + | |
| 805 | +static int lt9611_connector_init(struct drm_bridge *bridge, struct lt9611 *lt9611) | |
| 806 | +{ | |
| 807 | + int ret; | |
| 808 | + | |
| 809 | + ret = drm_connector_init(bridge->dev, <9611->connector, | |
| 810 | + <9611_bridge_connector_funcs, | |
| 811 | + DRM_MODE_CONNECTOR_HDMIA); | |
| 812 | + if (ret) { | |
| 813 | + DRM_ERROR("Failed to initialize connector with drm\n"); | |
| 814 | + return ret; | |
| 815 | + } | |
| 816 | + | |
| 817 | + drm_connector_helper_add(<9611->connector, | |
| 818 | + <9611_bridge_connector_helper_funcs); | |
| 819 | + drm_connector_attach_encoder(<9611->connector, bridge->encoder); | |
| 820 | + | |
| 821 | + if (!bridge->encoder) { | |
| 822 | + DRM_ERROR("Parent encoder object not found"); | |
| 823 | + return -ENODEV; | |
| 824 | + } | |
| 825 | + | |
| 826 | + return 0; | |
| 827 | +} | |
| 828 | + | |
| 829 | +static int lt9611_bridge_attach(struct drm_bridge *bridge, | |
| 830 | + enum drm_bridge_attach_flags flags) | |
| 831 | +{ | |
| 832 | + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); | |
| 833 | + int ret; | |
| 834 | + | |
| 835 | + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { | |
| 836 | + ret = lt9611_connector_init(bridge, lt9611); | |
| 837 | + if (ret < 0) | |
| 838 | + return ret; | |
| 839 | + } | |
| 840 | + | |
| 841 | + /* Attach primary DSI */ | |
| 842 | + lt9611->dsi0 = lt9611_attach_dsi(lt9611, lt9611->dsi0_node); | |
| 843 | + if (IS_ERR(lt9611->dsi0)) | |
| 844 | + return PTR_ERR(lt9611->dsi0); | |
| 845 | + | |
| 846 | + /* Attach secondary DSI, if specified */ | |
| 847 | + if (lt9611->dsi1_node) { | |
| 848 | + lt9611->dsi1 = lt9611_attach_dsi(lt9611, lt9611->dsi1_node); | |
| 849 | + if (IS_ERR(lt9611->dsi1)) { | |
| 850 | + ret = PTR_ERR(lt9611->dsi1); | |
| 851 | + goto err_unregister_dsi0; | |
| 852 | + } | |
| 853 | + } | |
| 854 | + | |
| 855 | + return 0; | |
| 856 | + | |
| 857 | +err_unregister_dsi0: | |
| 858 | + lt9611_bridge_detach(bridge); | |
| 859 | + drm_connector_cleanup(<9611->connector); | |
| 860 | + mipi_dsi_device_unregister(lt9611->dsi0); | |
| 861 | + | |
| 862 | + return ret; | |
| 863 | +} | |
| 864 | + | |
| 865 | +static enum drm_mode_status lt9611_bridge_mode_valid(struct drm_bridge *bridge, | |
| 866 | + const struct drm_display_info *info, | |
| 867 | + const struct drm_display_mode *mode) | |
| 868 | +{ | |
| 869 | + struct lt9611_mode *lt9611_mode = lt9611_find_mode(mode); | |
| 870 | + | |
| 871 | + return lt9611_mode ? MODE_OK : MODE_BAD; | |
| 872 | +} | |
| 873 | + | |
| 874 | +static void lt9611_bridge_pre_enable(struct drm_bridge *bridge) | |
| 875 | +{ | |
| 876 | + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); | |
| 877 | + | |
| 878 | + if (!lt9611->sleep) | |
| 879 | + return; | |
| 880 | + | |
| 881 | + lt9611_reset(lt9611); | |
| 882 | + regmap_write(lt9611->regmap, 0x80ee, 0x01); | |
| 883 | + | |
| 884 | + lt9611->sleep = false; | |
| 885 | +} | |
| 886 | + | |
| 887 | +static void lt9611_bridge_post_disable(struct drm_bridge *bridge) | |
| 888 | +{ | |
| 889 | + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); | |
| 890 | + | |
| 891 | + lt9611_sleep_setup(lt9611); | |
| 892 | +} | |
| 893 | + | |
| 894 | +static void lt9611_bridge_mode_set(struct drm_bridge *bridge, | |
| 895 | + const struct drm_display_mode *mode, | |
| 896 | + const struct drm_display_mode *adj_mode) | |
| 897 | +{ | |
| 898 | + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); | |
| 899 | + struct hdmi_avi_infoframe avi_frame; | |
| 900 | + int ret; | |
| 901 | + | |
| 902 | + lt9611_bridge_pre_enable(bridge); | |
| 903 | + | |
| 904 | + lt9611_mipi_input_digital(lt9611, mode); | |
| 905 | + lt9611_pll_setup(lt9611, mode); | |
| 906 | + lt9611_mipi_video_setup(lt9611, mode); | |
| 907 | + lt9611_pcr_setup(lt9611, mode); | |
| 908 | + | |
| 909 | + ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame, | |
| 910 | + <9611->connector, | |
| 911 | + mode); | |
| 912 | + if (!ret) | |
| 913 | + lt9611->vic = avi_frame.video_code; | |
| 914 | +} | |
| 915 | + | |
| 916 | +static enum drm_connector_status lt9611_bridge_detect(struct drm_bridge *bridge) | |
| 917 | +{ | |
| 918 | + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); | |
| 919 | + unsigned int reg_val = 0; | |
| 920 | + int connected; | |
| 921 | + | |
| 922 | + regmap_read(lt9611->regmap, 0x825e, ®_val); | |
| 923 | + connected = reg_val & BIT(2); | |
| 924 | + | |
| 925 | + lt9611->status = connected ? connector_status_connected : | |
| 926 | + connector_status_disconnected; | |
| 927 | + | |
| 928 | + return lt9611->status; | |
| 929 | +} | |
| 930 | + | |
| 931 | +static struct edid *lt9611_bridge_get_edid(struct drm_bridge *bridge, | |
| 932 | + struct drm_connector *connector) | |
| 933 | +{ | |
| 934 | + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); | |
| 935 | + | |
| 936 | + lt9611_power_on(lt9611); | |
| 937 | + return drm_do_get_edid(connector, lt9611_get_edid_block, lt9611); | |
| 938 | +} | |
| 939 | + | |
| 940 | +static void lt9611_bridge_hpd_enable(struct drm_bridge *bridge) | |
| 941 | +{ | |
| 942 | + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); | |
| 943 | + | |
| 944 | + lt9611_enable_hpd_interrupts(lt9611); | |
| 945 | +} | |
| 946 | + | |
| 947 | +static const struct drm_bridge_funcs lt9611_bridge_funcs = { | |
| 948 | + .attach = lt9611_bridge_attach, | |
| 949 | + .detach = lt9611_bridge_detach, | |
| 950 | + .mode_valid = lt9611_bridge_mode_valid, | |
| 951 | + .enable = lt9611_bridge_enable, | |
| 952 | + .disable = lt9611_bridge_disable, | |
| 953 | + .post_disable = lt9611_bridge_post_disable, | |
| 954 | + .mode_set = lt9611_bridge_mode_set, | |
| 955 | + .detect = lt9611_bridge_detect, | |
| 956 | + .get_edid = lt9611_bridge_get_edid, | |
| 957 | + .hpd_enable = lt9611_bridge_hpd_enable, | |
| 958 | +}; | |
| 959 | + | |
| 960 | +static int lt9611_parse_dt(struct device *dev, | |
| 961 | + struct lt9611 *lt9611) | |
| 962 | +{ | |
| 963 | + lt9611->dsi0_node = of_graph_get_remote_node(dev->of_node, 1, -1); | |
| 964 | + if (!lt9611->dsi0_node) { | |
| 965 | + dev_err(lt9611->dev, "failed to get remote node for primary dsi\n"); | |
| 966 | + return -ENODEV; | |
| 967 | + } | |
| 968 | + | |
| 969 | + lt9611->dsi1_node = of_graph_get_remote_node(dev->of_node, 2, -1); | |
| 970 | + | |
| 971 | + lt9611->ac_mode = of_property_read_bool(dev->of_node, "lt,ac-mode"); | |
| 972 | + | |
| 973 | + return 0; | |
| 974 | +} | |
| 975 | + | |
| 976 | +static int lt9611_gpio_init(struct lt9611 *lt9611) | |
| 977 | +{ | |
| 978 | + struct device *dev = lt9611->dev; | |
| 979 | + | |
| 980 | + lt9611->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); | |
| 981 | + if (IS_ERR(lt9611->reset_gpio)) { | |
| 982 | + dev_err(dev, "failed to acquire reset gpio\n"); | |
| 983 | + return PTR_ERR(lt9611->reset_gpio); | |
| 984 | + } | |
| 985 | + | |
| 986 | + lt9611->enable_gpio = devm_gpiod_get_optional(dev, "enable", | |
| 987 | + GPIOD_OUT_LOW); | |
| 988 | + if (IS_ERR(lt9611->enable_gpio)) { | |
| 989 | + dev_err(dev, "failed to acquire enable gpio\n"); | |
| 990 | + return PTR_ERR(lt9611->enable_gpio); | |
| 991 | + } | |
| 992 | + | |
| 993 | + return 0; | |
| 994 | +} | |
| 995 | + | |
| 996 | +static int lt9611_read_device_rev(struct lt9611 *lt9611) | |
| 997 | +{ | |
| 998 | + unsigned int rev; | |
| 999 | + int ret; | |
| 1000 | + | |
| 1001 | + regmap_write(lt9611->regmap, 0x80ee, 0x01); | |
| 1002 | + ret = regmap_read(lt9611->regmap, 0x8002, &rev); | |
| 1003 | + if (ret) | |
| 1004 | + dev_err(lt9611->dev, "failed to read revision: %d\n", ret); | |
| 1005 | + else | |
| 1006 | + dev_info(lt9611->dev, "LT9611 revision: 0x%x\n", rev); | |
| 1007 | + | |
| 1008 | + return ret; | |
| 1009 | +} | |
| 1010 | + | |
| 1011 | +static int lt9611_hdmi_hw_params(struct device *dev, void *data, | |
| 1012 | + struct hdmi_codec_daifmt *fmt, | |
| 1013 | + struct hdmi_codec_params *hparms) | |
| 1014 | +{ | |
| 1015 | + struct lt9611 *lt9611 = data; | |
| 1016 | + | |
| 1017 | + if (hparms->sample_rate == 48000) | |
| 1018 | + regmap_write(lt9611->regmap, 0x840f, 0x2b); | |
| 1019 | + else if (hparms->sample_rate == 96000) | |
| 1020 | + regmap_write(lt9611->regmap, 0x840f, 0xab); | |
| 1021 | + else | |
| 1022 | + return -EINVAL; | |
| 1023 | + | |
| 1024 | + regmap_write(lt9611->regmap, 0x8435, 0x00); | |
| 1025 | + regmap_write(lt9611->regmap, 0x8436, 0x18); | |
| 1026 | + regmap_write(lt9611->regmap, 0x8437, 0x00); | |
| 1027 | + | |
| 1028 | + return 0; | |
| 1029 | +} | |
| 1030 | + | |
| 1031 | +static int lt9611_audio_startup(struct device *dev, void *data) | |
| 1032 | +{ | |
| 1033 | + struct lt9611 *lt9611 = data; | |
| 1034 | + | |
| 1035 | + regmap_write(lt9611->regmap, 0x82d6, 0x8c); | |
| 1036 | + regmap_write(lt9611->regmap, 0x82d7, 0x04); | |
| 1037 | + | |
| 1038 | + regmap_write(lt9611->regmap, 0x8406, 0x08); | |
| 1039 | + regmap_write(lt9611->regmap, 0x8407, 0x10); | |
| 1040 | + | |
| 1041 | + regmap_write(lt9611->regmap, 0x8434, 0xd5); | |
| 1042 | + | |
| 1043 | + return 0; | |
| 1044 | +} | |
| 1045 | + | |
| 1046 | +static void lt9611_audio_shutdown(struct device *dev, void *data) | |
| 1047 | +{ | |
| 1048 | + struct lt9611 *lt9611 = data; | |
| 1049 | + | |
| 1050 | + regmap_write(lt9611->regmap, 0x8406, 0x00); | |
| 1051 | + regmap_write(lt9611->regmap, 0x8407, 0x00); | |
| 1052 | +} | |
| 1053 | + | |
| 1054 | +static int lt9611_hdmi_i2s_get_dai_id(struct snd_soc_component *component, | |
| 1055 | + struct device_node *endpoint) | |
| 1056 | +{ | |
| 1057 | + struct of_endpoint of_ep; | |
| 1058 | + int ret; | |
| 1059 | + | |
| 1060 | + ret = of_graph_parse_endpoint(endpoint, &of_ep); | |
| 1061 | + if (ret < 0) | |
| 1062 | + return ret; | |
| 1063 | + | |
| 1064 | + /* | |
| 1065 | + * HDMI sound should be located as reg = <2> | |
| 1066 | + * Then, it is sound port 0 | |
| 1067 | + */ | |
| 1068 | + if (of_ep.port == 2) | |
| 1069 | + return 0; | |
| 1070 | + | |
| 1071 | + return -EINVAL; | |
| 1072 | +} | |
| 1073 | + | |
| 1074 | +static const struct hdmi_codec_ops lt9611_codec_ops = { | |
| 1075 | + .hw_params = lt9611_hdmi_hw_params, | |
| 1076 | + .audio_shutdown = lt9611_audio_shutdown, | |
| 1077 | + .audio_startup = lt9611_audio_startup, | |
| 1078 | + .get_dai_id = lt9611_hdmi_i2s_get_dai_id, | |
| 1079 | +}; | |
| 1080 | + | |
| 1081 | +static struct hdmi_codec_pdata codec_data = { | |
| 1082 | + .ops = <9611_codec_ops, | |
| 1083 | + .max_i2s_channels = 8, | |
| 1084 | + .i2s = 1, | |
| 1085 | +}; | |
| 1086 | + | |
| 1087 | +static int lt9611_audio_init(struct device *dev, struct lt9611 *lt9611) | |
| 1088 | +{ | |
| 1089 | + codec_data.data = lt9611; | |
| 1090 | + lt9611->audio_pdev = | |
| 1091 | + platform_device_register_data(dev, HDMI_CODEC_DRV_NAME, | |
| 1092 | + PLATFORM_DEVID_AUTO, | |
| 1093 | + &codec_data, sizeof(codec_data)); | |
| 1094 | + | |
| 1095 | + return PTR_ERR_OR_ZERO(lt9611->audio_pdev); | |
| 1096 | +} | |
| 1097 | + | |
| 1098 | +static void lt9611_audio_exit(struct lt9611 *lt9611) | |
| 1099 | +{ | |
| 1100 | + if (lt9611->audio_pdev) { | |
| 1101 | + platform_device_unregister(lt9611->audio_pdev); | |
| 1102 | + lt9611->audio_pdev = NULL; | |
| 1103 | + } | |
| 1104 | +} | |
| 1105 | + | |
| 1106 | +static int lt9611_probe(struct i2c_client *client, | |
| 1107 | + const struct i2c_device_id *id) | |
| 1108 | +{ | |
| 1109 | + struct lt9611 *lt9611; | |
| 1110 | + struct device *dev = &client->dev; | |
| 1111 | + int ret; | |
| 1112 | + | |
| 1113 | + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | |
| 1114 | + dev_err(dev, "device doesn't support I2C\n"); | |
| 1115 | + return -ENODEV; | |
| 1116 | + } | |
| 1117 | + | |
| 1118 | + lt9611 = devm_kzalloc(dev, sizeof(*lt9611), GFP_KERNEL); | |
| 1119 | + if (!lt9611) | |
| 1120 | + return -ENOMEM; | |
| 1121 | + | |
| 1122 | + lt9611->dev = &client->dev; | |
| 1123 | + lt9611->client = client; | |
| 1124 | + lt9611->sleep = false; | |
| 1125 | + | |
| 1126 | + lt9611->regmap = devm_regmap_init_i2c(client, <9611_regmap_config); | |
| 1127 | + if (IS_ERR(lt9611->regmap)) { | |
| 1128 | + dev_err(lt9611->dev, "regmap i2c init failed\n"); | |
| 1129 | + return PTR_ERR(lt9611->regmap); | |
| 1130 | + } | |
| 1131 | + | |
| 1132 | + ret = lt9611_parse_dt(&client->dev, lt9611); | |
| 1133 | + if (ret) { | |
| 1134 | + dev_err(dev, "failed to parse device tree\n"); | |
| 1135 | + return ret; | |
| 1136 | + } | |
| 1137 | + | |
| 1138 | + ret = lt9611_gpio_init(lt9611); | |
| 1139 | + if (ret < 0) | |
| 1140 | + goto err_of_put; | |
| 1141 | + | |
| 1142 | + ret = lt9611_regulator_init(lt9611); | |
| 1143 | + if (ret < 0) | |
| 1144 | + goto err_of_put; | |
| 1145 | + | |
| 1146 | + lt9611_assert_5v(lt9611); | |
| 1147 | + | |
| 1148 | + ret = lt9611_regulator_enable(lt9611); | |
| 1149 | + if (ret) | |
| 1150 | + goto err_of_put; | |
| 1151 | + | |
| 1152 | + lt9611_reset(lt9611); | |
| 1153 | + | |
| 1154 | + ret = lt9611_read_device_rev(lt9611); | |
| 1155 | + if (ret) { | |
| 1156 | + dev_err(dev, "failed to read chip rev\n"); | |
| 1157 | + goto err_disable_regulators; | |
| 1158 | + } | |
| 1159 | + | |
| 1160 | + ret = devm_request_threaded_irq(dev, client->irq, NULL, | |
| 1161 | + lt9611_irq_thread_handler, | |
| 1162 | + IRQF_ONESHOT, "lt9611", lt9611); | |
| 1163 | + if (ret) { | |
| 1164 | + dev_err(dev, "failed to request irq\n"); | |
| 1165 | + goto err_disable_regulators; | |
| 1166 | + } | |
| 1167 | + | |
| 1168 | + i2c_set_clientdata(client, lt9611); | |
| 1169 | + | |
| 1170 | + lt9611->bridge.funcs = <9611_bridge_funcs; | |
| 1171 | + lt9611->bridge.of_node = client->dev.of_node; | |
| 1172 | + lt9611->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | | |
| 1173 | + DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_MODES; | |
| 1174 | + lt9611->bridge.type = DRM_MODE_CONNECTOR_HDMIA; | |
| 1175 | + | |
| 1176 | + drm_bridge_add(<9611->bridge); | |
| 1177 | + | |
| 1178 | + lt9611_enable_hpd_interrupts(lt9611); | |
| 1179 | + | |
| 1180 | + return lt9611_audio_init(dev, lt9611); | |
| 1181 | + | |
| 1182 | +err_disable_regulators: | |
| 1183 | + regulator_bulk_disable(ARRAY_SIZE(lt9611->supplies), lt9611->supplies); | |
| 1184 | + | |
| 1185 | +err_of_put: | |
| 1186 | + of_node_put(lt9611->dsi1_node); | |
| 1187 | + of_node_put(lt9611->dsi0_node); | |
| 1188 | + | |
| 1189 | + return ret; | |
| 1190 | +} | |
| 1191 | + | |
| 1192 | +static int lt9611_remove(struct i2c_client *client) | |
| 1193 | +{ | |
| 1194 | + struct lt9611 *lt9611 = i2c_get_clientdata(client); | |
| 1195 | + | |
| 1196 | + disable_irq(client->irq); | |
| 1197 | + lt9611_audio_exit(lt9611); | |
| 1198 | + drm_bridge_remove(<9611->bridge); | |
| 1199 | + | |
| 1200 | + regulator_bulk_disable(ARRAY_SIZE(lt9611->supplies), lt9611->supplies); | |
| 1201 | + | |
| 1202 | + of_node_put(lt9611->dsi1_node); | |
| 1203 | + of_node_put(lt9611->dsi0_node); | |
| 1204 | + | |
| 1205 | + return 0; | |
| 1206 | +} | |
| 1207 | + | |
| 1208 | +static struct i2c_device_id lt9611_id[] = { | |
| 1209 | + { "lontium,lt9611", 0 }, | |
| 1210 | + {} | |
| 1211 | +}; | |
| 1212 | + | |
| 1213 | +static const struct of_device_id lt9611_match_table[] = { | |
| 1214 | + { .compatible = "lontium,lt9611" }, | |
| 1215 | + { } | |
| 1216 | +}; | |
| 1217 | +MODULE_DEVICE_TABLE(of, lt9611_match_table); | |
| 1218 | + | |
| 1219 | +static struct i2c_driver lt9611_driver = { | |
| 1220 | + .driver = { | |
| 1221 | + .name = "lt9611", | |
| 1222 | + .of_match_table = lt9611_match_table, | |
| 1223 | + }, | |
| 1224 | + .probe = lt9611_probe, | |
| 1225 | + .remove = lt9611_remove, | |
| 1226 | + .id_table = lt9611_id, | |
| 1227 | +}; | |
| 1228 | +module_i2c_driver(lt9611_driver); | |
| 1229 | + | |
| 1230 | +MODULE_LICENSE("GPL v2"); | |
| @@ -61,7 +61,6 @@ struct ge_b850v3_lvds { · 60 unmodified lines | ||
| 61 | 61 | struct drm_bridge bridge; |
| 62 | 62 | struct i2c_client *stdp4028_i2c; |
| 63 | 63 | struct i2c_client *stdp2690_i2c; |
| 64 | − struct edid *edid; | |
| 65 | 64 | }; |
| 66 | 65 | |
| 67 | 66 | static struct ge_b850v3_lvds *ge_b850v3_lvds_ptr; |
| @@ -131,22 +130,26 @@ err: · 63 unmodified lines | ||
| 131 | 130 | return NULL; |
| 132 | 131 | } |
| 133 | 132 | |
| 134 | −static int ge_b850v3_lvds_get_modes(struct drm_connector *connector) | |
| 133 | +static struct edid *ge_b850v3_lvds_get_edid(struct drm_bridge *bridge, | |
| 134 | + struct drm_connector *connector) | |
| 135 | 135 | { |
| 136 | 136 | struct i2c_client *client; |
| 137 | − int num_modes = 0; | |
| 138 | 137 | |
| 139 | 138 | client = ge_b850v3_lvds_ptr->stdp2690_i2c; |
| 140 | 139 | |
| 141 | − kfree(ge_b850v3_lvds_ptr->edid); | |
| 142 | − ge_b850v3_lvds_ptr->edid = (struct edid *)stdp2690_get_edid(client); | |
| 140 | + return (struct edid *)stdp2690_get_edid(client); | |
| 141 | +} | |
| 143 | 142 | |
| 144 | − if (ge_b850v3_lvds_ptr->edid) { | |
| 145 | − drm_connector_update_edid_property(connector, | |
| 146 | − ge_b850v3_lvds_ptr->edid); | |
| 147 | − num_modes = drm_add_edid_modes(connector, | |
| 148 | − ge_b850v3_lvds_ptr->edid); | |
| 149 | − } | |
| 143 | +static int ge_b850v3_lvds_get_modes(struct drm_connector *connector) | |
| 144 | +{ | |
| 145 | + struct edid *edid; | |
| 146 | + int num_modes; | |
| 147 | + | |
| 148 | + edid = ge_b850v3_lvds_get_edid(&ge_b850v3_lvds_ptr->bridge, connector); | |
| 149 | + | |
| 150 | + drm_connector_update_edid_property(connector, edid); | |
| 151 | + num_modes = drm_add_edid_modes(connector, edid); | |
| 152 | + kfree(edid); | |
| 150 | 153 | |
| 151 | 154 | return num_modes; |
| 152 | 155 | } |
| @@ -163,8 +166,7 @@ drm_connector_helper_funcs ge_b850v3_lvds_connector_helper_funcs = { · 10 unmodified lines | ||
| 163 | 166 | .mode_valid = ge_b850v3_lvds_mode_valid, |
| 164 | 167 | }; |
| 165 | 168 | |
| 166 | −static enum drm_connector_status ge_b850v3_lvds_detect( | |
| 167 | − struct drm_connector *connector, bool force) | |
| 169 | +static enum drm_connector_status ge_b850v3_lvds_bridge_detect(struct drm_bridge *bridge) | |
| 168 | 170 | { |
| 169 | 171 | struct i2c_client *stdp4028_i2c = |
| 170 | 172 | ge_b850v3_lvds_ptr->stdp4028_i2c; |
| @@ -182,6 +184,12 @@ static enum drm_connector_status ge_b850v3_lvds_detect( · 11 unmodified lines | ||
| 182 | 184 | return connector_status_unknown; |
| 183 | 185 | } |
| 184 | 186 | |
| 187 | +static enum drm_connector_status ge_b850v3_lvds_detect(struct drm_connector *connector, | |
| 188 | + bool force) | |
| 189 | +{ | |
| 190 | + return ge_b850v3_lvds_bridge_detect(&ge_b850v3_lvds_ptr->bridge); | |
| 191 | +} | |
| 192 | + | |
| 185 | 193 | static const struct drm_connector_funcs ge_b850v3_lvds_connector_funcs = { |
| 186 | 194 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 187 | 195 | .detect = ge_b850v3_lvds_detect, |
| @@ -191,34 +199,11 @@ static const struct drm_connector_funcs ge_b850v3_lvds_connector_funcs = { · 3 unmodified lines | ||
| 191 | 199 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
| 192 | 200 | }; |
| 193 | 201 | |
| 194 | −static irqreturn_t ge_b850v3_lvds_irq_handler(int irq, void *dev_id) | |
| 195 | −{ | |
| 196 | − struct i2c_client *stdp4028_i2c | |
| 197 | − = ge_b850v3_lvds_ptr->stdp4028_i2c; | |
| 198 | − | |
| 199 | − i2c_smbus_write_word_data(stdp4028_i2c, | |
| 200 | − STDP4028_DPTX_IRQ_STS_REG, | |
| 201 | − STDP4028_DPTX_IRQ_CLEAR); | |
| 202 | − | |
| 203 | − if (ge_b850v3_lvds_ptr->connector.dev) | |
| 204 | − drm_kms_helper_hotplug_event(ge_b850v3_lvds_ptr->connector.dev); | |
| 205 | − | |
| 206 | − return IRQ_HANDLED; | |
| 207 | −} | |
| 208 | − | |
| 209 | −static int ge_b850v3_lvds_attach(struct drm_bridge *bridge, | |
| 210 | − enum drm_bridge_attach_flags flags) | |
| 202 | +static int ge_b850v3_lvds_create_connector(struct drm_bridge *bridge) | |
| 211 | 203 | { |
| 212 | 204 | struct drm_connector *connector = &ge_b850v3_lvds_ptr->connector; |
| 213 | − struct i2c_client *stdp4028_i2c | |
| 214 | − = ge_b850v3_lvds_ptr->stdp4028_i2c; | |
| 215 | 205 | int ret; |
| 216 | 206 | |
| 217 | − if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { | |
| 218 | − DRM_ERROR("Fix bridge driver to make connector optional!"); | |
| 219 | − return -EINVAL; | |
| 220 | − } | |
| 221 | − | |
| 222 | 207 | if (!bridge->encoder) { |
| 223 | 208 | DRM_ERROR("Parent encoder object not found"); |
| 224 | 209 | return -ENODEV; |
| @@ -237,9 +222,29 @@ static int ge_b850v3_lvds_attach(struct drm_bridge *bridge, · 12 unmodified lines | ||
| 237 | 222 | return ret; |
| 238 | 223 | } |
| 239 | 224 | |
| 240 | − ret = drm_connector_attach_encoder(connector, bridge->encoder); | |
| 241 | − if (ret) | |
| 242 | − return ret; | |
| 225 | + return drm_connector_attach_encoder(connector, bridge->encoder); | |
| 226 | +} | |
| 227 | + | |
| 228 | +static irqreturn_t ge_b850v3_lvds_irq_handler(int irq, void *dev_id) | |
| 229 | +{ | |
| 230 | + struct i2c_client *stdp4028_i2c | |
| 231 | + = ge_b850v3_lvds_ptr->stdp4028_i2c; | |
| 232 | + | |
| 233 | + i2c_smbus_write_word_data(stdp4028_i2c, | |
| 234 | + STDP4028_DPTX_IRQ_STS_REG, | |
| 235 | + STDP4028_DPTX_IRQ_CLEAR); | |
| 236 | + | |
| 237 | + if (ge_b850v3_lvds_ptr->bridge.dev) | |
| 238 | + drm_kms_helper_hotplug_event(ge_b850v3_lvds_ptr->bridge.dev); | |
| 239 | + | |
| 240 | + return IRQ_HANDLED; | |
| 241 | +} | |
| 242 | + | |
| 243 | +static int ge_b850v3_lvds_attach(struct drm_bridge *bridge, | |
| 244 | + enum drm_bridge_attach_flags flags) | |
| 245 | +{ | |
| 246 | + struct i2c_client *stdp4028_i2c | |
| 247 | + = ge_b850v3_lvds_ptr->stdp4028_i2c; | |
| 243 | 248 | |
| 244 | 249 | /* Configures the bridge to re-enable interrupts after each ack. */ |
| 245 | 250 | i2c_smbus_write_word_data(stdp4028_i2c, |
| @@ -251,11 +256,16 @@ static int ge_b850v3_lvds_attach(struct drm_bridge *bridge, · 5 unmodified lines | ||
| 251 | 256 | STDP4028_DPTX_IRQ_EN_REG, |
| 252 | 257 | STDP4028_DPTX_IRQ_CONFIG); |
| 253 | 258 | |
| 254 | − return 0; | |
| 259 | + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) | |
| 260 | + return 0; | |
| 261 | + | |
| 262 | + return ge_b850v3_lvds_create_connector(bridge); | |
| 255 | 263 | } |
| 256 | 264 | |
| 257 | 265 | static const struct drm_bridge_funcs ge_b850v3_lvds_funcs = { |
| 258 | 266 | .attach = ge_b850v3_lvds_attach, |
| 267 | + .detect = ge_b850v3_lvds_bridge_detect, | |
| 268 | + .get_edid = ge_b850v3_lvds_get_edid, | |
| 259 | 269 | }; |
| 260 | 270 | |
| 261 | 271 | static int ge_b850v3_lvds_init(struct device *dev) |
| @@ -291,8 +301,6 @@ static void ge_b850v3_lvds_remove(void) · 29 unmodified lines | ||
| 291 | 301 | |
| 292 | 302 | drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge); |
| 293 | 303 | |
| 294 | − kfree(ge_b850v3_lvds_ptr->edid); | |
| 295 | − | |
| 296 | 304 | ge_b850v3_lvds_ptr = NULL; |
| 297 | 305 | out: |
| 298 | 306 | mutex_unlock(&ge_b850v3_lvds_dev_mutex); |
| @@ -302,14 +310,21 @@ static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c, · 3 unmodified lines | ||
| 302 | 310 | const struct i2c_device_id *id) |
| 303 | 311 | { |
| 304 | 312 | struct device *dev = &stdp4028_i2c->dev; |
| 313 | + int ret; | |
| 314 | + | |
| 315 | + ret = ge_b850v3_lvds_init(dev); | |
| 305 | 316 | |
| 306 | − ge_b850v3_lvds_init(dev); | |
| 317 | + if (ret) | |
| 318 | + return ret; | |
| 307 | 319 | |
| 308 | 320 | ge_b850v3_lvds_ptr->stdp4028_i2c = stdp4028_i2c; |
| 309 | 321 | i2c_set_clientdata(stdp4028_i2c, ge_b850v3_lvds_ptr); |
| 310 | 322 | |
| 311 | 323 | /* drm bridge initialization */ |
| 312 | 324 | ge_b850v3_lvds_ptr->bridge.funcs = &ge_b850v3_lvds_funcs; |
| 325 | + ge_b850v3_lvds_ptr->bridge.ops = DRM_BRIDGE_OP_DETECT | | |
| 326 | + DRM_BRIDGE_OP_EDID; | |
| 327 | + ge_b850v3_lvds_ptr->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; | |
| 313 | 328 | ge_b850v3_lvds_ptr->bridge.of_node = dev->of_node; |
| 314 | 329 | drm_bridge_add(&ge_b850v3_lvds_ptr->bridge); |
| 315 | 330 | |
| @@ -361,8 +376,12 @@ static int stdp2690_ge_b850v3_fw_probe(struct i2c_client *stdp2690_i2c, · 45 unmodified lines | ||
| 361 | 376 | const struct i2c_device_id *id) |
| 362 | 377 | { |
| 363 | 378 | struct device *dev = &stdp2690_i2c->dev; |
| 379 | + int ret; | |
| 380 | + | |
| 381 | + ret = ge_b850v3_lvds_init(dev); | |
| 364 | 382 | |
| 365 | − ge_b850v3_lvds_init(dev); | |
| 383 | + if (ret) | |
| 384 | + return ret; | |
| 366 | 385 | |
| 367 | 386 | ge_b850v3_lvds_ptr->stdp2690_i2c = stdp2690_i2c; |
| 368 | 387 | i2c_set_clientdata(stdp2690_i2c, ge_b850v3_lvds_ptr); |
| @@ -29,8 +29,7 @@ struct ptn3460_bridge { · 28 unmodified lines | ||
| 29 | 29 | struct drm_connector connector; |
| 30 | 30 | struct i2c_client *client; |
| 31 | 31 | struct drm_bridge bridge; |
| 32 | − struct edid *edid; | |
| 33 | − struct drm_panel *panel; | |
| 32 | + struct drm_bridge *panel_bridge; | |
| 34 | 33 | struct gpio_desc *gpio_pd_n; |
| 35 | 34 | struct gpio_desc *gpio_rst_n; |
| 36 | 35 | u32 edid_emulation; |
| @@ -127,11 +126,6 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge) · 90 unmodified lines | ||
| 127 | 126 | usleep_range(10, 20); |
| 128 | 127 | gpiod_set_value(ptn_bridge->gpio_rst_n, 1); |
| 129 | 128 | |
| 130 | − if (drm_panel_prepare(ptn_bridge->panel)) { | |
| 131 | − DRM_ERROR("failed to prepare panel\n"); | |
| 132 | − return; | |
| 133 | − } | |
| 134 | − | |
| 135 | 129 | /* |
| 136 | 130 | * There's a bug in the PTN chip where it falsely asserts hotplug before |
| 137 | 131 | * it is fully functional. We're forced to wait for the maximum start up |
| @@ -146,16 +140,6 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge) · 8 unmodified lines | ||
| 146 | 140 | ptn_bridge->enabled = true; |
| 147 | 141 | } |
| 148 | 142 | |
| 149 | −static void ptn3460_enable(struct drm_bridge *bridge) | |
| 150 | −{ | |
| 151 | − struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); | |
| 152 | − | |
| 153 | − if (drm_panel_enable(ptn_bridge->panel)) { | |
| 154 | − DRM_ERROR("failed to enable panel\n"); | |
| 155 | − return; | |
| 156 | − } | |
| 157 | −} | |
| 158 | − | |
| 159 | 143 | static void ptn3460_disable(struct drm_bridge *bridge) |
| 160 | 144 | { |
| 161 | 145 | struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); |
| @@ -165,36 +149,18 @@ static void ptn3460_disable(struct drm_bridge *bridge) · 3 unmodified lines | ||
| 165 | 149 | |
| 166 | 150 | ptn_bridge->enabled = false; |
| 167 | 151 | |
| 168 | − if (drm_panel_disable(ptn_bridge->panel)) { | |
| 169 | − DRM_ERROR("failed to disable panel\n"); | |
| 170 | − return; | |
| 171 | − } | |
| 172 | − | |
| 173 | 152 | gpiod_set_value(ptn_bridge->gpio_rst_n, 1); |
| 174 | 153 | gpiod_set_value(ptn_bridge->gpio_pd_n, 0); |
| 175 | 154 | } |
| 176 | 155 | |
| 177 | −static void ptn3460_post_disable(struct drm_bridge *bridge) | |
| 178 | −{ | |
| 179 | − struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); | |
| 180 | 156 | |
| 181 | − if (drm_panel_unprepare(ptn_bridge->panel)) { | |
| 182 | − DRM_ERROR("failed to unprepare panel\n"); | |
| 183 | − return; | |
| 184 | − } | |
| 185 | −} | |
| 186 | − | |
| 187 | −static int ptn3460_get_modes(struct drm_connector *connector) | |
| 157 | +static struct edid *ptn3460_get_edid(struct drm_bridge *bridge, | |
| 158 | + struct drm_connector *connector) | |
| 188 | 159 | { |
| 189 | − struct ptn3460_bridge *ptn_bridge; | |
| 190 | − u8 *edid; | |
| 191 | − int ret, num_modes = 0; | |
| 160 | + struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); | |
| 192 | 161 | bool power_off; |
| 193 | − | |
| 194 | − ptn_bridge = connector_to_ptn3460(connector); | |
| 195 | − | |
| 196 | − if (ptn_bridge->edid) | |
| 197 | − return drm_add_edid_modes(connector, ptn_bridge->edid); | |
| 162 | + u8 *edid; | |
| 163 | + int ret; | |
| 198 | 164 | |
| 199 | 165 | power_off = !ptn_bridge->enabled; |
| 200 | 166 | ptn3460_pre_enable(&ptn_bridge->bridge); |
| @@ -202,30 +168,40 @@ static int ptn3460_get_modes(struct drm_connector *connector) · 1 unmodified line | ||
| 202 | 168 | edid = kmalloc(EDID_LENGTH, GFP_KERNEL); |
| 203 | 169 | if (!edid) { |
| 204 | 170 | DRM_ERROR("Failed to allocate EDID\n"); |
| 205 | − return 0; | |
| 171 | + goto out; | |
| 206 | 172 | } |
| 207 | 173 | |
| 208 | 174 | ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid, |
| 209 | − EDID_LENGTH); | |
| 175 | + EDID_LENGTH); | |
| 210 | 176 | if (ret) { |
| 211 | 177 | kfree(edid); |
| 178 | + edid = NULL; | |
| 212 | 179 | goto out; |
| 213 | 180 | } |
| 214 | 181 | |
| 215 | − ptn_bridge->edid = (struct edid *)edid; | |
| 216 | − drm_connector_update_edid_property(connector, ptn_bridge->edid); | |
| 217 | − | |
| 218 | − num_modes = drm_add_edid_modes(connector, ptn_bridge->edid); | |
| 219 | − | |
| 220 | 182 | out: |
| 221 | 183 | if (power_off) |
| 222 | 184 | ptn3460_disable(&ptn_bridge->bridge); |
| 223 | 185 | |
| 186 | + return (struct edid *)edid; | |
| 187 | +} | |
| 188 | + | |
| 189 | +static int ptn3460_connector_get_modes(struct drm_connector *connector) | |
| 190 | +{ | |
| 191 | + struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector); | |
| 192 | + struct edid *edid; | |
| 193 | + int num_modes; | |
| 194 | + | |
| 195 | + edid = ptn3460_get_edid(&ptn_bridge->bridge, connector); | |
| 196 | + drm_connector_update_edid_property(connector, edid); | |
| 197 | + num_modes = drm_add_edid_modes(connector, edid); | |
| 198 | + kfree(edid); | |
| 199 | + | |
| 224 | 200 | return num_modes; |
| 225 | 201 | } |
| 226 | 202 | |
| 227 | 203 | static const struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { |
| 228 | − .get_modes = ptn3460_get_modes, | |
| 204 | + .get_modes = ptn3460_connector_get_modes, | |
| 229 | 205 | }; |
| 230 | 206 | |
| 231 | 207 | static const struct drm_connector_funcs ptn3460_connector_funcs = { |
| @@ -242,10 +218,14 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge, · 10 unmodified lines | ||
| 242 | 218 | struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); |
| 243 | 219 | int ret; |
| 244 | 220 | |
| 245 | − if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { | |
| 246 | − DRM_ERROR("Fix bridge driver to make connector optional!"); | |
| 247 | − return -EINVAL; | |
| 248 | − } | |
| 221 | + /* Let this driver create connector if requested */ | |
| 222 | + ret = drm_bridge_attach(bridge->encoder, ptn_bridge->panel_bridge, | |
| 223 | + bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR); | |
| 224 | + if (ret < 0) | |
| 225 | + return ret; | |
| 226 | + | |
| 227 | + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) | |
| 228 | + return 0; | |
| 249 | 229 | |
| 250 | 230 | if (!bridge->encoder) { |
| 251 | 231 | DRM_ERROR("Parent encoder object not found"); |
| @@ -265,9 +245,6 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge, · 13 unmodified lines | ||
| 265 | 245 | drm_connector_attach_encoder(&ptn_bridge->connector, |
| 266 | 246 | bridge->encoder); |
| 267 | 247 | |
| 268 | − if (ptn_bridge->panel) | |
| 269 | − drm_panel_attach(ptn_bridge->panel, &ptn_bridge->connector); | |
| 270 | − | |
| 271 | 248 | drm_helper_hpd_irq_event(ptn_bridge->connector.dev); |
| 272 | 249 | |
| 273 | 250 | return ret; |
| @@ -275,10 +252,9 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge, · 1 unmodified line | ||
| 275 | 252 | |
| 276 | 253 | static const struct drm_bridge_funcs ptn3460_bridge_funcs = { |
| 277 | 254 | .pre_enable = ptn3460_pre_enable, |
| 278 | − .enable = ptn3460_enable, | |
| 279 | 255 | .disable = ptn3460_disable, |
| 280 | − .post_disable = ptn3460_post_disable, | |
| 281 | 256 | .attach = ptn3460_bridge_attach, |
| 257 | + .get_edid = ptn3460_get_edid, | |
| 282 | 258 | }; |
| 283 | 259 | |
| 284 | 260 | static int ptn3460_probe(struct i2c_client *client, |
| @@ -286,6 +262,8 @@ static int ptn3460_probe(struct i2c_client *client, · 1 unmodified line | ||
| 286 | 262 | { |
| 287 | 263 | struct device *dev = &client->dev; |
| 288 | 264 | struct ptn3460_bridge *ptn_bridge; |
| 265 | + struct drm_bridge *panel_bridge; | |
| 266 | + struct drm_panel *panel; | |
| 289 | 267 | int ret; |
| 290 | 268 | |
| 291 | 269 | ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL); |
| @@ -293,10 +271,15 @@ static int ptn3460_probe(struct i2c_client *client, · 1 unmodified line | ||
| 293 | 271 | return -ENOMEM; |
| 294 | 272 | } |
| 295 | 273 | |
| 296 | − ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &ptn_bridge->panel, NULL); | |
| 274 | + ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, NULL); | |
| 297 | 275 | if (ret) |
| 298 | 276 | return ret; |
| 299 | 277 | |
| 278 | + panel_bridge = devm_drm_panel_bridge_add(dev, panel); | |
| 279 | + if (IS_ERR(panel_bridge)) | |
| 280 | + return PTR_ERR(panel_bridge); | |
| 281 | + | |
| 282 | + ptn_bridge->panel_bridge = panel_bridge; | |
| 300 | 283 | ptn_bridge->client = client; |
| 301 | 284 | |
| 302 | 285 | ptn_bridge->gpio_pd_n = devm_gpiod_get(&client->dev, "powerdown", |
| @@ -327,6 +310,8 @@ static int ptn3460_probe(struct i2c_client *client, · 24 unmodified lines | ||
| 327 | 310 | } |
| 328 | 311 | |
| 329 | 312 | ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs; |
| 313 | + ptn_bridge->bridge.ops = DRM_BRIDGE_OP_EDID; | |
| 314 | + ptn_bridge->bridge.type = DRM_MODE_CONNECTOR_LVDS; | |
| 330 | 315 | ptn_bridge->bridge.of_node = dev->of_node; |
| 331 | 316 | drm_bridge_add(&ptn_bridge->bridge); |
| 332 | 317 | |
| @@ -82,18 +82,11 @@ static int panel_bridge_attach(struct drm_bridge *bridge, · 81 unmodified lines | ||
| 82 | 82 | drm_connector_attach_encoder(&panel_bridge->connector, |
| 83 | 83 | bridge->encoder); |
| 84 | 84 | |
| 85 | − ret = drm_panel_attach(panel_bridge->panel, &panel_bridge->connector); | |
| 86 | − if (ret < 0) | |
| 87 | − return ret; | |
| 88 | − | |
| 89 | 85 | return 0; |
| 90 | 86 | } |
| 91 | 87 | |
| 92 | 88 | static void panel_bridge_detach(struct drm_bridge *bridge) |
| 93 | 89 | { |
| 94 | − struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); | |
| 95 | − | |
| 96 | − drm_panel_detach(panel_bridge->panel); | |
| 97 | 90 | } |
| 98 | 91 | |
| 99 | 92 | static void panel_bridge_pre_enable(struct drm_bridge *bridge) |
| @@ -42,10 +42,9 @@ · 41 unmodified lines | ||
| 42 | 42 | #endif |
| 43 | 43 | |
| 44 | 44 | struct ps8622_bridge { |
| 45 | − struct drm_connector connector; | |
| 46 | 45 | struct i2c_client *client; |
| 47 | 46 | struct drm_bridge bridge; |
| 48 | − struct drm_panel *panel; | |
| 47 | + struct drm_bridge *panel_bridge; | |
| 49 | 48 | struct regulator *v12; |
| 50 | 49 | struct backlight_device *bl; |
| 51 | 50 | |
| @@ -64,12 +63,6 @@ static inline struct ps8622_bridge * · 12 unmodified lines | ||
| 64 | 63 | return container_of(bridge, struct ps8622_bridge, bridge); |
| 65 | 64 | } |
| 66 | 65 | |
| 67 | −static inline struct ps8622_bridge * | |
| 68 | − connector_to_ps8622(struct drm_connector *connector) | |
| 69 | −{ | |
| 70 | − return container_of(connector, struct ps8622_bridge, connector); | |
| 71 | −} | |
| 72 | − | |
| 73 | 66 | static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val) |
| 74 | 67 | { |
| 75 | 68 | int ret; |
| @@ -365,11 +358,6 @@ static void ps8622_pre_enable(struct drm_bridge *bridge) · 289 unmodified lines | ||
| 365 | 358 | DRM_ERROR("fails to enable ps8622->v12"); |
| 366 | 359 | } |
| 367 | 360 | |
| 368 | − if (drm_panel_prepare(ps8622->panel)) { | |
| 369 | − DRM_ERROR("failed to prepare panel\n"); | |
| 370 | − return; | |
| 371 | − } | |
| 372 | − | |
| 373 | 361 | gpiod_set_value(ps8622->gpio_slp, 1); |
| 374 | 362 | |
| 375 | 363 | /* |
| @@ -399,24 +387,9 @@ static void ps8622_pre_enable(struct drm_bridge *bridge) · 23 unmodified lines | ||
| 399 | 387 | ps8622->enabled = true; |
| 400 | 388 | } |
| 401 | 389 | |
| 402 | −static void ps8622_enable(struct drm_bridge *bridge) | |
| 403 | −{ | |
| 404 | − struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); | |
| 405 | − | |
| 406 | − if (drm_panel_enable(ps8622->panel)) { | |
| 407 | − DRM_ERROR("failed to enable panel\n"); | |
| 408 | − return; | |
| 409 | − } | |
| 410 | −} | |
| 411 | − | |
| 412 | 390 | static void ps8622_disable(struct drm_bridge *bridge) |
| 413 | 391 | { |
| 414 | − struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); | |
| 415 | − | |
| 416 | − if (drm_panel_disable(ps8622->panel)) { | |
| 417 | − DRM_ERROR("failed to disable panel\n"); | |
| 418 | − return; | |
| 419 | − } | |
| 392 | + /* Delay after panel is disabled */ | |
| 420 | 393 | msleep(PS8622_PWMO_END_T12_MS); |
| 421 | 394 | } |
| 422 | 395 | |
| @@ -436,11 +409,6 @@ static void ps8622_post_disable(struct drm_bridge *bridge) · 13 unmodified lines | ||
| 436 | 409 | */ |
| 437 | 410 | gpiod_set_value(ps8622->gpio_slp, 0); |
| 438 | 411 | |
| 439 | − if (drm_panel_unprepare(ps8622->panel)) { | |
| 440 | − DRM_ERROR("failed to unprepare panel\n"); | |
| 441 | − return; | |
| 442 | − } | |
| 443 | − | |
| 444 | 412 | if (ps8622->v12) |
| 445 | 413 | regulator_disable(ps8622->v12); |
| 446 | 414 | |
| @@ -455,67 +423,17 @@ static void ps8622_post_disable(struct drm_bridge *bridge) · 8 unmodified lines | ||
| 455 | 423 | msleep(PS8622_POWER_OFF_T17_MS); |
| 456 | 424 | } |
| 457 | 425 | |
| 458 | −static int ps8622_get_modes(struct drm_connector *connector) | |
| 459 | −{ | |
| 460 | − struct ps8622_bridge *ps8622; | |
| 461 | − | |
| 462 | − ps8622 = connector_to_ps8622(connector); | |
| 463 | − | |
| 464 | − return drm_panel_get_modes(ps8622->panel, connector); | |
| 465 | −} | |
| 466 | − | |
| 467 | −static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = { | |
| 468 | − .get_modes = ps8622_get_modes, | |
| 469 | −}; | |
| 470 | − | |
| 471 | −static const struct drm_connector_funcs ps8622_connector_funcs = { | |
| 472 | − .fill_modes = drm_helper_probe_single_connector_modes, | |
| 473 | − .destroy = drm_connector_cleanup, | |
| 474 | − .reset = drm_atomic_helper_connector_reset, | |
| 475 | − .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | |
| 476 | − .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | |
| 477 | −}; | |
| 478 | − | |
| 479 | 426 | static int ps8622_attach(struct drm_bridge *bridge, |
| 480 | 427 | enum drm_bridge_attach_flags flags) |
| 481 | 428 | { |
| 482 | 429 | struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); |
| 483 | − int ret; | |
| 484 | − | |
| 485 | − if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { | |
| 486 | − DRM_ERROR("Fix bridge driver to make connector optional!"); | |
| 487 | − return -EINVAL; | |
| 488 | − } | |
| 489 | 430 | |
| 490 | − if (!bridge->encoder) { | |
| 491 | − DRM_ERROR("Parent encoder object not found"); | |
| 492 | − return -ENODEV; | |
| 493 | − } | |
| 494 | − | |
| 495 | − ps8622->connector.polled = DRM_CONNECTOR_POLL_HPD; | |
| 496 | − ret = drm_connector_init(bridge->dev, &ps8622->connector, | |
| 497 | − &ps8622_connector_funcs, DRM_MODE_CONNECTOR_LVDS); | |
| 498 | − if (ret) { | |
| 499 | − DRM_ERROR("Failed to initialize connector with drm\n"); | |
| 500 | − return ret; | |
| 501 | − } | |
| 502 | − drm_connector_helper_add(&ps8622->connector, | |
| 503 | − &ps8622_connector_helper_funcs); | |
| 504 | − drm_connector_register(&ps8622->connector); | |
| 505 | − drm_connector_attach_encoder(&ps8622->connector, | |
| 506 | − bridge->encoder); | |
| 507 | − | |
| 508 | − if (ps8622->panel) | |
| 509 | − drm_panel_attach(ps8622->panel, &ps8622->connector); | |
| 510 | − | |
| 511 | − drm_helper_hpd_irq_event(ps8622->connector.dev); | |
| 512 | − | |
| 513 | − return ret; | |
| 431 | + return drm_bridge_attach(ps8622->bridge.encoder, ps8622->panel_bridge, | |
| 432 | + &ps8622->bridge, flags); | |
| 514 | 433 | } |
| 515 | 434 | |
| 516 | 435 | static const struct drm_bridge_funcs ps8622_bridge_funcs = { |
| 517 | 436 | .pre_enable = ps8622_pre_enable, |
| 518 | − .enable = ps8622_enable, | |
| 519 | 437 | .disable = ps8622_disable, |
| 520 | 438 | .post_disable = ps8622_post_disable, |
| 521 | 439 | .attach = ps8622_attach, |
| @@ -533,16 +451,23 @@ static int ps8622_probe(struct i2c_client *client, · 11 unmodified lines | ||
| 533 | 451 | { |
| 534 | 452 | struct device *dev = &client->dev; |
| 535 | 453 | struct ps8622_bridge *ps8622; |
| 454 | + struct drm_bridge *panel_bridge; | |
| 455 | + struct drm_panel *panel; | |
| 536 | 456 | int ret; |
| 537 | 457 | |
| 538 | 458 | ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL); |
| 539 | 459 | if (!ps8622) |
| 540 | 460 | return -ENOMEM; |
| 541 | 461 | |
| 542 | − ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &ps8622->panel, NULL); | |
| 462 | + ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, NULL); | |
| 543 | 463 | if (ret) |
| 544 | 464 | return ret; |
| 545 | 465 | |
| 466 | + panel_bridge = devm_drm_panel_bridge_add(dev, panel); | |
| 467 | + if (IS_ERR(panel_bridge)) | |
| 468 | + return PTR_ERR(panel_bridge); | |
| 469 | + | |
| 470 | + ps8622->panel_bridge = panel_bridge; | |
| 546 | 471 | ps8622->client = client; |
| 547 | 472 | |
| 548 | 473 | ps8622->v12 = devm_regulator_get(dev, "vdd12"); |
| @@ -595,6 +520,7 @@ static int ps8622_probe(struct i2c_client *client, · 46 unmodified lines | ||
| 595 | 520 | } |
| 596 | 521 | |
| 597 | 522 | ps8622->bridge.funcs = &ps8622_bridge_funcs; |
| 523 | + ps8622->bridge.type = DRM_MODE_CONNECTOR_LVDS; | |
| 598 | 524 | ps8622->bridge.of_node = dev->of_node; |
| 599 | 525 | drm_bridge_add(&ps8622->bridge); |
| 600 | 526 | |
| @@ -82,8 +82,11 @@ static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge, · 81 unmodified lines | ||
| 82 | 82 | ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD, |
| 83 | 83 | sizeof(vdo_ctrl_buf), |
| 84 | 84 | vdo_ctrl_buf); |
| 85 | − if (ret < 0) | |
| 85 | + if (ret < 0) { | |
| 86 | + DRM_ERROR("failed to %sable VDO: %d\n", | |
| 87 | + ctrl == ENABLE ? "en" : "dis", ret); | |
| 86 | 88 | return ret; |
| 89 | + } | |
| 87 | 90 | |
| 88 | 91 | return 0; |
| 89 | 92 | } |
| @@ -150,10 +153,8 @@ static void ps8640_pre_enable(struct drm_bridge *bridge) · 60 unmodified lines | ||
| 150 | 153 | } |
| 151 | 154 | |
| 152 | 155 | ret = ps8640_bridge_vdo_control(ps_bridge, ENABLE); |
| 153 | − if (ret) { | |
| 154 | − DRM_ERROR("failed to enable VDO: %d\n", ret); | |
| 156 | + if (ret) | |
| 155 | 157 | goto err_regulators_disable; |
| 156 | − } | |
| 157 | 158 | |
| 158 | 159 | /* Switch access edp panel's edid through i2c */ |
| 159 | 160 | ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS, |
| @@ -175,9 +176,7 @@ static void ps8640_post_disable(struct drm_bridge *bridge) · 15 unmodified lines | ||
| 175 | 176 | struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); |
| 176 | 177 | int ret; |
| 177 | 178 | |
| 178 | − ret = ps8640_bridge_vdo_control(ps_bridge, DISABLE); | |
| 179 | − if (ret < 0) | |
| 180 | − DRM_ERROR("failed to disable VDO: %d\n", ret); | |
| 179 | + ps8640_bridge_vdo_control(ps_bridge, DISABLE); | |
| 181 | 180 | |
| 182 | 181 | gpiod_set_value(ps_bridge->gpio_reset, 1); |
| 183 | 182 | gpiod_set_value(ps_bridge->gpio_powerdown, 1); |
| @@ -200,6 +199,10 @@ static int ps8640_bridge_attach(struct drm_bridge *bridge, · 16 unmodified lines | ||
| 200 | 199 | .channel = 0, |
| 201 | 200 | .node = NULL, |
| 202 | 201 | }; |
| 202 | + | |
| 203 | + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) | |
| 204 | + return -EINVAL; | |
| 205 | + | |
| 203 | 206 | /* port@0 is ps8640 dsi input port */ |
| 204 | 207 | in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1); |
| 205 | 208 | if (!in_ep) |
| @@ -242,8 +245,18 @@ err_dsi_attach: · 36 unmodified lines | ||
| 242 | 245 | return ret; |
| 243 | 246 | } |
| 244 | 247 | |
| 248 | +static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge, | |
| 249 | + struct drm_connector *connector) | |
| 250 | +{ | |
| 251 | + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); | |
| 252 | + | |
| 253 | + return drm_get_edid(connector, | |
| 254 | + ps_bridge->page[PAGE0_DP_CNTL]->adapter); | |
| 255 | +} | |
| 256 | + | |
| 245 | 257 | static const struct drm_bridge_funcs ps8640_bridge_funcs = { |
| 246 | 258 | .attach = ps8640_bridge_attach, |
| 259 | + .get_edid = ps8640_bridge_get_edid, | |
| 247 | 260 | .post_disable = ps8640_post_disable, |
| 248 | 261 | .pre_enable = ps8640_pre_enable, |
| 249 | 262 | }; |
| @@ -294,6 +307,8 @@ static int ps8640_probe(struct i2c_client *client) · 44 unmodified lines | ||
| 294 | 307 | |
| 295 | 308 | ps_bridge->bridge.funcs = &ps8640_bridge_funcs; |
| 296 | 309 | ps_bridge->bridge.of_node = dev->of_node; |
| 310 | + ps_bridge->bridge.ops = DRM_BRIDGE_OP_EDID; | |
| 311 | + ps_bridge->bridge.type = DRM_MODE_CONNECTOR_eDP; | |
| 297 | 312 | |
| 298 | 313 | ps_bridge->page[PAGE0_DP_CNTL] = client; |
| 299 | 314 | |
| @@ -0,0 +1,280 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2020 Marek Vasut <marex@denx.de> | |
| 4 | + * | |
| 5 | + * Based on tc358764.c by | |
| 6 | + * Andrzej Hajda <a.hajda@samsung.com> | |
| 7 | + * Maciej Purski <m.purski@samsung.com> | |
| 8 | + * | |
| 9 | + * Based on rpi_touchscreen.c by | |
| 10 | + * Eric Anholt <eric@anholt.net> | |
| 11 | + */ | |
| 12 | + | |
| 13 | +#include <linux/delay.h> | |
| 14 | +#include <linux/module.h> | |
| 15 | +#include <linux/of_graph.h> | |
| 16 | +#include <linux/regulator/consumer.h> | |
| 17 | + | |
| 18 | +#include <video/mipi_display.h> | |
| 19 | + | |
| 20 | +#include <drm/drm_atomic_helper.h> | |
| 21 | +#include <drm/drm_crtc.h> | |
| 22 | +#include <drm/drm_fb_helper.h> | |
| 23 | +#include <drm/drm_mipi_dsi.h> | |
| 24 | +#include <drm/drm_of.h> | |
| 25 | +#include <drm/drm_panel.h> | |
| 26 | +#include <drm/drm_print.h> | |
| 27 | +#include <drm/drm_probe_helper.h> | |
| 28 | + | |
| 29 | +/* PPI layer registers */ | |
| 30 | +#define PPI_STARTPPI 0x0104 /* START control bit */ | |
| 31 | +#define PPI_LPTXTIMECNT 0x0114 /* LPTX timing signal */ | |
| 32 | +#define PPI_D0S_ATMR 0x0144 | |
| 33 | +#define PPI_D1S_ATMR 0x0148 | |
| 34 | +#define PPI_D0S_CLRSIPOCOUNT 0x0164 /* Assertion timer for Lane 0 */ | |
| 35 | +#define PPI_D1S_CLRSIPOCOUNT 0x0168 /* Assertion timer for Lane 1 */ | |
| 36 | +#define PPI_START_FUNCTION 1 | |
| 37 | + | |
| 38 | +/* DSI layer registers */ | |
| 39 | +#define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX */ | |
| 40 | +#define DSI_LANEENABLE 0x0210 /* Enables each lane */ | |
| 41 | +#define DSI_RX_START 1 | |
| 42 | + | |
| 43 | +/* LCDC/DPI Host Registers */ | |
| 44 | +#define LCDCTRL 0x0420 | |
| 45 | + | |
| 46 | +/* SPI Master Registers */ | |
| 47 | +#define SPICMR 0x0450 | |
| 48 | +#define SPITCR 0x0454 | |
| 49 | + | |
| 50 | +/* System Controller Registers */ | |
| 51 | +#define SYSCTRL 0x0464 | |
| 52 | + | |
| 53 | +/* System registers */ | |
| 54 | +#define LPX_PERIOD 3 | |
| 55 | + | |
| 56 | +/* Lane enable PPI and DSI register bits */ | |
| 57 | +#define LANEENABLE_CLEN BIT(0) | |
| 58 | +#define LANEENABLE_L0EN BIT(1) | |
| 59 | +#define LANEENABLE_L1EN BIT(2) | |
| 60 | + | |
| 61 | +struct tc358762 { | |
| 62 | + struct device *dev; | |
| 63 | + struct drm_bridge bridge; | |
| 64 | + struct drm_connector connector; | |
| 65 | + struct regulator *regulator; | |
| 66 | + struct drm_bridge *panel_bridge; | |
| 67 | + bool pre_enabled; | |
| 68 | + int error; | |
| 69 | +}; | |
| 70 | + | |
| 71 | +static int tc358762_clear_error(struct tc358762 *ctx) | |
| 72 | +{ | |
| 73 | + int ret = ctx->error; | |
| 74 | + | |
| 75 | + ctx->error = 0; | |
| 76 | + return ret; | |
| 77 | +} | |
| 78 | + | |
| 79 | +static void tc358762_write(struct tc358762 *ctx, u16 addr, u32 val) | |
| 80 | +{ | |
| 81 | + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | |
| 82 | + ssize_t ret; | |
| 83 | + u8 data[6]; | |
| 84 | + | |
| 85 | + if (ctx->error) | |
| 86 | + return; | |
| 87 | + | |
| 88 | + data[0] = addr; | |
| 89 | + data[1] = addr >> 8; | |
| 90 | + data[2] = val; | |
| 91 | + data[3] = val >> 8; | |
| 92 | + data[4] = val >> 16; | |
| 93 | + data[5] = val >> 24; | |
| 94 | + | |
| 95 | + ret = mipi_dsi_generic_write(dsi, data, sizeof(data)); | |
| 96 | + if (ret < 0) | |
| 97 | + ctx->error = ret; | |
| 98 | +} | |
| 99 | + | |
| 100 | +static inline struct tc358762 *bridge_to_tc358762(struct drm_bridge *bridge) | |
| 101 | +{ | |
| 102 | + return container_of(bridge, struct tc358762, bridge); | |
| 103 | +} | |
| 104 | + | |
| 105 | +static int tc358762_init(struct tc358762 *ctx) | |
| 106 | +{ | |
| 107 | + tc358762_write(ctx, DSI_LANEENABLE, | |
| 108 | + LANEENABLE_L0EN | LANEENABLE_CLEN); | |
| 109 | + tc358762_write(ctx, PPI_D0S_CLRSIPOCOUNT, 5); | |
| 110 | + tc358762_write(ctx, PPI_D1S_CLRSIPOCOUNT, 5); | |
| 111 | + tc358762_write(ctx, PPI_D0S_ATMR, 0); | |
| 112 | + tc358762_write(ctx, PPI_D1S_ATMR, 0); | |
| 113 | + tc358762_write(ctx, PPI_LPTXTIMECNT, LPX_PERIOD); | |
| 114 | + | |
| 115 | + tc358762_write(ctx, SPICMR, 0x00); | |
| 116 | + tc358762_write(ctx, LCDCTRL, 0x00100150); | |
| 117 | + tc358762_write(ctx, SYSCTRL, 0x040f); | |
| 118 | + msleep(100); | |
| 119 | + | |
| 120 | + tc358762_write(ctx, PPI_STARTPPI, PPI_START_FUNCTION); | |
| 121 | + tc358762_write(ctx, DSI_STARTDSI, DSI_RX_START); | |
| 122 | + | |
| 123 | + msleep(100); | |
| 124 | + | |
| 125 | + return tc358762_clear_error(ctx); | |
| 126 | +} | |
| 127 | + | |
| 128 | +static void tc358762_post_disable(struct drm_bridge *bridge) | |
| 129 | +{ | |
| 130 | + struct tc358762 *ctx = bridge_to_tc358762(bridge); | |
| 131 | + int ret; | |
| 132 | + | |
| 133 | + /* | |
| 134 | + * The post_disable hook might be called multiple times. | |
| 135 | + * We want to avoid regulator imbalance below. | |
| 136 | + */ | |
| 137 | + if (!ctx->pre_enabled) | |
| 138 | + return; | |
| 139 | + | |
| 140 | + ctx->pre_enabled = false; | |
| 141 | + | |
| 142 | + ret = regulator_disable(ctx->regulator); | |
| 143 | + if (ret < 0) | |
| 144 | + dev_err(ctx->dev, "error disabling regulators (%d)\n", ret); | |
| 145 | +} | |
| 146 | + | |
| 147 | +static void tc358762_pre_enable(struct drm_bridge *bridge) | |
| 148 | +{ | |
| 149 | + struct tc358762 *ctx = bridge_to_tc358762(bridge); | |
| 150 | + int ret; | |
| 151 | + | |
| 152 | + ret = regulator_enable(ctx->regulator); | |
| 153 | + if (ret < 0) | |
| 154 | + dev_err(ctx->dev, "error enabling regulators (%d)\n", ret); | |
| 155 | + | |
| 156 | + ret = tc358762_init(ctx); | |
| 157 | + if (ret < 0) | |
| 158 | + dev_err(ctx->dev, "error initializing bridge (%d)\n", ret); | |
| 159 | + | |
| 160 | + ctx->pre_enabled = true; | |
| 161 | +} | |
| 162 | + | |
| 163 | +static int tc358762_attach(struct drm_bridge *bridge, | |
| 164 | + enum drm_bridge_attach_flags flags) | |
| 165 | +{ | |
| 166 | + struct tc358762 *ctx = bridge_to_tc358762(bridge); | |
| 167 | + | |
| 168 | + return drm_bridge_attach(bridge->encoder, ctx->panel_bridge, | |
| 169 | + bridge, flags); | |
| 170 | +} | |
| 171 | + | |
| 172 | +static const struct drm_bridge_funcs tc358762_bridge_funcs = { | |
| 173 | + .post_disable = tc358762_post_disable, | |
| 174 | + .pre_enable = tc358762_pre_enable, | |
| 175 | + .attach = tc358762_attach, | |
| 176 | +}; | |
| 177 | + | |
| 178 | +static int tc358762_parse_dt(struct tc358762 *ctx) | |
| 179 | +{ | |
| 180 | + struct drm_bridge *panel_bridge; | |
| 181 | + struct device *dev = ctx->dev; | |
| 182 | + struct drm_panel *panel; | |
| 183 | + int ret; | |
| 184 | + | |
| 185 | + ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL); | |
| 186 | + if (ret) | |
| 187 | + return ret; | |
| 188 | + | |
| 189 | + panel_bridge = devm_drm_panel_bridge_add(dev, panel); | |
| 190 | + | |
| 191 | + if (IS_ERR(panel_bridge)) | |
| 192 | + return PTR_ERR(panel_bridge); | |
| 193 | + | |
| 194 | + ctx->panel_bridge = panel_bridge; | |
| 195 | + | |
| 196 | + return 0; | |
| 197 | +} | |
| 198 | + | |
| 199 | +static int tc358762_configure_regulators(struct tc358762 *ctx) | |
| 200 | +{ | |
| 201 | + ctx->regulator = devm_regulator_get(ctx->dev, "vddc"); | |
| 202 | + if (IS_ERR(ctx->regulator)) | |
| 203 | + return PTR_ERR(ctx->regulator); | |
| 204 | + | |
| 205 | + return 0; | |
| 206 | +} | |
| 207 | + | |
| 208 | +static int tc358762_probe(struct mipi_dsi_device *dsi) | |
| 209 | +{ | |
| 210 | + struct device *dev = &dsi->dev; | |
| 211 | + struct tc358762 *ctx; | |
| 212 | + int ret; | |
| 213 | + | |
| 214 | + ctx = devm_kzalloc(dev, sizeof(struct tc358762), GFP_KERNEL); | |
| 215 | + if (!ctx) | |
| 216 | + return -ENOMEM; | |
| 217 | + | |
| 218 | + mipi_dsi_set_drvdata(dsi, ctx); | |
| 219 | + | |
| 220 | + ctx->dev = dev; | |
| 221 | + ctx->pre_enabled = false; | |
| 222 | + | |
| 223 | + /* TODO: Find out how to get dual-lane mode working */ | |
| 224 | + dsi->lanes = 1; | |
| 225 | + dsi->format = MIPI_DSI_FMT_RGB888; | |
| 226 | + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | | |
| 227 | + MIPI_DSI_MODE_LPM; | |
| 228 | + | |
| 229 | + ret = tc358762_parse_dt(ctx); | |
| 230 | + if (ret < 0) | |
| 231 | + return ret; | |
| 232 | + | |
| 233 | + ret = tc358762_configure_regulators(ctx); | |
| 234 | + if (ret < 0) | |
| 235 | + return ret; | |
| 236 | + | |
| 237 | + ctx->bridge.funcs = &tc358762_bridge_funcs; | |
| 238 | + ctx->bridge.type = DRM_MODE_CONNECTOR_DPI; | |
| 239 | + ctx->bridge.of_node = dev->of_node; | |
| 240 | + | |
| 241 | + drm_bridge_add(&ctx->bridge); | |
| 242 | + | |
| 243 | + ret = mipi_dsi_attach(dsi); | |
| 244 | + if (ret < 0) { | |
| 245 | + drm_bridge_remove(&ctx->bridge); | |
| 246 | + dev_err(dev, "failed to attach dsi\n"); | |
| 247 | + } | |
| 248 | + | |
| 249 | + return ret; | |
| 250 | +} | |
| 251 | + | |
| 252 | +static int tc358762_remove(struct mipi_dsi_device *dsi) | |
| 253 | +{ | |
| 254 | + struct tc358762 *ctx = mipi_dsi_get_drvdata(dsi); | |
| 255 | + | |
| 256 | + mipi_dsi_detach(dsi); | |
| 257 | + drm_bridge_remove(&ctx->bridge); | |
| 258 | + | |
| 259 | + return 0; | |
| 260 | +} | |
| 261 | + | |
| 262 | +static const struct of_device_id tc358762_of_match[] = { | |
| 263 | + { .compatible = "toshiba,tc358762" }, | |
| 264 | + { } | |
| 265 | +}; | |
| 266 | +MODULE_DEVICE_TABLE(of, tc358762_of_match); | |
| 267 | + | |
| 268 | +static struct mipi_dsi_driver tc358762_driver = { | |
| 269 | + .probe = tc358762_probe, | |
| 270 | + .remove = tc358762_remove, | |
| 271 | + .driver = { | |
| 272 | + .name = "tc358762", | |
| 273 | + .of_match_table = tc358762_of_match, | |
| 274 | + }, | |
| 275 | +}; | |
| 276 | +module_mipi_dsi_driver(tc358762_driver); | |
| 277 | + | |
| 278 | +MODULE_AUTHOR("Marek Vasut <marex@denx.de>"); | |
| 279 | +MODULE_DESCRIPTION("MIPI-DSI based Driver for TC358762 DSI/DPI Bridge"); | |
| 280 | +MODULE_LICENSE("GPL v2"); | |
| @@ -153,10 +153,9 @@ static const char * const tc358764_supplies[] = { · 152 unmodified lines | ||
| 153 | 153 | struct tc358764 { |
| 154 | 154 | struct device *dev; |
| 155 | 155 | struct drm_bridge bridge; |
| 156 | − struct drm_connector connector; | |
| 157 | 156 | struct regulator_bulk_data supplies[ARRAY_SIZE(tc358764_supplies)]; |
| 158 | 157 | struct gpio_desc *gpio_reset; |
| 159 | − struct drm_panel *panel; | |
| 158 | + struct drm_bridge *panel_bridge; | |
| 160 | 159 | int error; |
| 161 | 160 | }; |
| 162 | 161 | |
| @@ -210,12 +209,6 @@ static inline struct tc358764 *bridge_to_tc358764(struct drm_bridge *bridge) · 47 unmodified lines | ||
| 210 | 209 | return container_of(bridge, struct tc358764, bridge); |
| 211 | 210 | } |
| 212 | 211 | |
| 213 | −static inline | |
| 214 | −struct tc358764 *connector_to_tc358764(struct drm_connector *connector) | |
| 215 | −{ | |
| 216 | − return container_of(connector, struct tc358764, connector); | |
| 217 | −} | |
| 218 | − | |
| 219 | 212 | static int tc358764_init(struct tc358764 *ctx) |
| 220 | 213 | { |
| 221 | 214 | u32 v = 0; |
| @@ -278,43 +271,11 @@ static void tc358764_reset(struct tc358764 *ctx) · 56 unmodified lines | ||
| 278 | 271 | usleep_range(1000, 2000); |
| 279 | 272 | } |
| 280 | 273 | |
| 281 | −static int tc358764_get_modes(struct drm_connector *connector) | |
| 282 | −{ | |
| 283 | − struct tc358764 *ctx = connector_to_tc358764(connector); | |
| 284 | − | |
| 285 | − return drm_panel_get_modes(ctx->panel, connector); | |
| 286 | −} | |
| 287 | − | |
| 288 | −static const | |
| 289 | −struct drm_connector_helper_funcs tc358764_connector_helper_funcs = { | |
| 290 | − .get_modes = tc358764_get_modes, | |
| 291 | −}; | |
| 292 | − | |
| 293 | −static const struct drm_connector_funcs tc358764_connector_funcs = { | |
| 294 | − .fill_modes = drm_helper_probe_single_connector_modes, | |
| 295 | − .destroy = drm_connector_cleanup, | |
| 296 | − .reset = drm_atomic_helper_connector_reset, | |
| 297 | − .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | |
| 298 | − .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | |
| 299 | −}; | |
| 300 | − | |
| 301 | −static void tc358764_disable(struct drm_bridge *bridge) | |
| 302 | −{ | |
| 303 | − struct tc358764 *ctx = bridge_to_tc358764(bridge); | |
| 304 | − int ret = drm_panel_disable(bridge_to_tc358764(bridge)->panel); | |
| 305 | − | |
| 306 | − if (ret < 0) | |
| 307 | − dev_err(ctx->dev, "error disabling panel (%d)\n", ret); | |
| 308 | −} | |
| 309 | − | |
| 310 | 274 | static void tc358764_post_disable(struct drm_bridge *bridge) |
| 311 | 275 | { |
| 312 | 276 | struct tc358764 *ctx = bridge_to_tc358764(bridge); |
| 313 | 277 | int ret; |
| 314 | 278 | |
| 315 | − ret = drm_panel_unprepare(ctx->panel); | |
| 316 | − if (ret < 0) | |
| 317 | − dev_err(ctx->dev, "error unpreparing panel (%d)\n", ret); | |
| 318 | 279 | tc358764_reset(ctx); |
| 319 | 280 | usleep_range(10000, 15000); |
| 320 | 281 | ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); |
| @@ -335,73 +296,28 @@ static void tc358764_pre_enable(struct drm_bridge *bridge) · 14 unmodified lines | ||
| 335 | 296 | ret = tc358764_init(ctx); |
| 336 | 297 | if (ret < 0) |
| 337 | 298 | dev_err(ctx->dev, "error initializing bridge (%d)\n", ret); |
| 338 | − ret = drm_panel_prepare(ctx->panel); | |
| 339 | − if (ret < 0) | |
| 340 | − dev_err(ctx->dev, "error preparing panel (%d)\n", ret); | |
| 341 | −} | |
| 342 | − | |
| 343 | −static void tc358764_enable(struct drm_bridge *bridge) | |
| 344 | −{ | |
| 345 | − struct tc358764 *ctx = bridge_to_tc358764(bridge); | |
| 346 | − int ret = drm_panel_enable(ctx->panel); | |
| 347 | − | |
| 348 | − if (ret < 0) | |
| 349 | − dev_err(ctx->dev, "error enabling panel (%d)\n", ret); | |
| 350 | 299 | } |
| 351 | 300 | |
| 352 | 301 | static int tc358764_attach(struct drm_bridge *bridge, |
| 353 | 302 | enum drm_bridge_attach_flags flags) |
| 354 | −{ | |
| 355 | − struct tc358764 *ctx = bridge_to_tc358764(bridge); | |
| 356 | − struct drm_device *drm = bridge->dev; | |
| 357 | − int ret; | |
| 358 | − | |
| 359 | − if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { | |
| 360 | − DRM_ERROR("Fix bridge driver to make connector optional!"); | |
| 361 | − return -EINVAL; | |
| 362 | − } | |
| 363 | − | |
| 364 | − ctx->connector.polled = DRM_CONNECTOR_POLL_HPD; | |
| 365 | − ret = drm_connector_init(drm, &ctx->connector, | |
| 366 | − &tc358764_connector_funcs, | |
| 367 | − DRM_MODE_CONNECTOR_LVDS); | |
| 368 | − if (ret) { | |
| 369 | − DRM_ERROR("Failed to initialize connector\n"); | |
| 370 | − return ret; | |
| 371 | − } | |
| 372 | − | |
| 373 | − drm_connector_helper_add(&ctx->connector, | |
| 374 | − &tc358764_connector_helper_funcs); | |
| 375 | − drm_connector_attach_encoder(&ctx->connector, bridge->encoder); | |
| 376 | − drm_panel_attach(ctx->panel, &ctx->connector); | |
| 377 | − ctx->connector.funcs->reset(&ctx->connector); | |
| 378 | − drm_connector_register(&ctx->connector); | |
| 379 | − | |
| 380 | − return 0; | |
| 381 | −} | |
| 382 | − | |
| 383 | −static void tc358764_detach(struct drm_bridge *bridge) | |
| 384 | 303 | { |
| 385 | 304 | struct tc358764 *ctx = bridge_to_tc358764(bridge); |
| 386 | 305 | |
| 387 | − drm_connector_unregister(&ctx->connector); | |
| 388 | − drm_panel_detach(ctx->panel); | |
| 389 | − ctx->panel = NULL; | |
| 390 | − drm_connector_put(&ctx->connector); | |
| 306 | + return drm_bridge_attach(bridge->encoder, ctx->panel_bridge, | |
| 307 | + bridge, flags); | |
| 391 | 308 | } |
| 392 | 309 | |
| 393 | 310 | static const struct drm_bridge_funcs tc358764_bridge_funcs = { |
| 394 | − .disable = tc358764_disable, | |
| 395 | 311 | .post_disable = tc358764_post_disable, |
| 396 | − .enable = tc358764_enable, | |
| 397 | 312 | .pre_enable = tc358764_pre_enable, |
| 398 | 313 | .attach = tc358764_attach, |
| 399 | − .detach = tc358764_detach, | |
| 400 | 314 | }; |
| 401 | 315 | |
| 402 | 316 | static int tc358764_parse_dt(struct tc358764 *ctx) |
| 403 | 317 | { |
| 318 | + struct drm_bridge *panel_bridge; | |
| 404 | 319 | struct device *dev = ctx->dev; |
| 320 | + struct drm_panel *panel; | |
| 405 | 321 | int ret; |
| 406 | 322 | |
| 407 | 323 | ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); |
| @@ -410,12 +326,16 @@ static int tc358764_parse_dt(struct tc358764 *ctx) · 2 unmodified lines | ||
| 410 | 326 | return PTR_ERR(ctx->gpio_reset); |
| 411 | 327 | } |
| 412 | 328 | |
| 413 | − ret = drm_of_find_panel_or_bridge(ctx->dev->of_node, 1, 0, &ctx->panel, | |
| 414 | − NULL); | |
| 415 | − if (ret && ret != -EPROBE_DEFER) | |
| 416 | − dev_err(dev, "cannot find panel (%d)\n", ret); | |
| 329 | + ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL); | |
| 330 | + if (ret) | |
| 331 | + return ret; | |
| 417 | 332 | |
| 418 | − return ret; | |
| 333 | + panel_bridge = devm_drm_panel_bridge_add(dev, panel); | |
| 334 | + if (IS_ERR(panel_bridge)) | |
| 335 | + return PTR_ERR(panel_bridge); | |
| 336 | + | |
| 337 | + ctx->panel_bridge = panel_bridge; | |
| 338 | + return 0; | |
| 419 | 339 | } |
| 420 | 340 | |
| 421 | 341 | static int tc358764_configure_regulators(struct tc358764 *ctx) |
| @@ -461,6 +381,7 @@ static int tc358764_probe(struct mipi_dsi_device *dsi) · 39 unmodified lines | ||
| 461 | 381 | return ret; |
| 462 | 382 | |
| 463 | 383 | ctx->bridge.funcs = &tc358764_bridge_funcs; |
| 384 | + ctx->bridge.type = DRM_MODE_CONNECTOR_LVDS; | |
| 464 | 385 | ctx->bridge.of_node = dev->of_node; |
| 465 | 386 | |
| 466 | 387 | drm_bridge_add(&ctx->bridge); |
| @@ -244,14 +244,12 @@ struct tc_data { · 243 unmodified lines | ||
| 244 | 244 | struct drm_dp_aux aux; |
| 245 | 245 | |
| 246 | 246 | struct drm_bridge bridge; |
| 247 | + struct drm_bridge *panel_bridge; | |
| 247 | 248 | struct drm_connector connector; |
| 248 | − struct drm_panel *panel; | |
| 249 | 249 | |
| 250 | 250 | /* link settings */ |
| 251 | 251 | struct tc_edp_link link; |
| 252 | 252 | |
| 253 | − /* display edid */ | |
| 254 | − struct edid *edid; | |
| 255 | 253 | /* current mode */ |
| 256 | 254 | struct drm_display_mode mode; |
| 257 | 255 | |
| @@ -1236,13 +1234,6 @@ static int tc_stream_disable(struct tc_data *tc) · 978 unmodified lines | ||
| 1236 | 1234 | return 0; |
| 1237 | 1235 | } |
| 1238 | 1236 | |
| 1239 | −static void tc_bridge_pre_enable(struct drm_bridge *bridge) | |
| 1240 | −{ | |
| 1241 | − struct tc_data *tc = bridge_to_tc(bridge); | |
| 1242 | − | |
| 1243 | − drm_panel_prepare(tc->panel); | |
| 1244 | −} | |
| 1245 | − | |
| 1246 | 1237 | static void tc_bridge_enable(struct drm_bridge *bridge) |
| 1247 | 1238 | { |
| 1248 | 1239 | struct tc_data *tc = bridge_to_tc(bridge); |
| @@ -1266,8 +1257,6 @@ static void tc_bridge_enable(struct drm_bridge *bridge) · 17 unmodified lines | ||
| 1266 | 1257 | tc_main_link_disable(tc); |
| 1267 | 1258 | return; |
| 1268 | 1259 | } |
| 1269 | − | |
| 1270 | − drm_panel_enable(tc->panel); | |
| 1271 | 1260 | } |
| 1272 | 1261 | |
| 1273 | 1262 | static void tc_bridge_disable(struct drm_bridge *bridge) |
| @@ -1275,8 +1264,6 @@ static void tc_bridge_disable(struct drm_bridge *bridge) · 1 unmodified line | ||
| 1275 | 1264 | struct tc_data *tc = bridge_to_tc(bridge); |
| 1276 | 1265 | int ret; |
| 1277 | 1266 | |
| 1278 | − drm_panel_disable(tc->panel); | |
| 1279 | − | |
| 1280 | 1267 | ret = tc_stream_disable(tc); |
| 1281 | 1268 | if (ret < 0) |
| 1282 | 1269 | dev_err(tc->dev, "main link stream stop error: %d\n", ret); |
| @@ -1286,13 +1273,6 @@ static void tc_bridge_disable(struct drm_bridge *bridge) · 3 unmodified lines | ||
| 1286 | 1273 | dev_err(tc->dev, "main link disable error: %d\n", ret); |
| 1287 | 1274 | } |
| 1288 | 1275 | |
| 1289 | −static void tc_bridge_post_disable(struct drm_bridge *bridge) | |
| 1290 | −{ | |
| 1291 | − struct tc_data *tc = bridge_to_tc(bridge); | |
| 1292 | − | |
| 1293 | − drm_panel_unprepare(tc->panel); | |
| 1294 | −} | |
| 1295 | − | |
| 1296 | 1276 | static bool tc_bridge_mode_fixup(struct drm_bridge *bridge, |
| 1297 | 1277 | const struct drm_display_mode *mode, |
| 1298 | 1278 | struct drm_display_mode *adj) |
| @@ -1335,11 +1315,19 @@ static void tc_bridge_mode_set(struct drm_bridge *bridge, · 36 unmodified lines | ||
| 1335 | 1315 | tc->mode = *mode; |
| 1336 | 1316 | } |
| 1337 | 1317 | |
| 1318 | +static struct edid *tc_get_edid(struct drm_bridge *bridge, | |
| 1319 | + struct drm_connector *connector) | |
| 1320 | +{ | |
| 1321 | + struct tc_data *tc = bridge_to_tc(bridge); | |
| 1322 | + | |
| 1323 | + return drm_get_edid(connector, &tc->aux.ddc); | |
| 1324 | +} | |
| 1325 | + | |
| 1338 | 1326 | static int tc_connector_get_modes(struct drm_connector *connector) |
| 1339 | 1327 | { |
| 1340 | 1328 | struct tc_data *tc = connector_to_tc(connector); |
| 1329 | + int num_modes; | |
| 1341 | 1330 | struct edid *edid; |
| 1342 | − int count; | |
| 1343 | 1331 | int ret; |
| 1344 | 1332 | |
| 1345 | 1333 | ret = tc_get_display_props(tc); |
| @@ -1348,42 +1336,30 @@ static int tc_connector_get_modes(struct drm_connector *connector) · 2 unmodified lines | ||
| 1348 | 1336 | return 0; |
| 1349 | 1337 | } |
| 1350 | 1338 | |
| 1351 | − count = drm_panel_get_modes(tc->panel, connector); | |
| 1352 | − if (count > 0) | |
| 1353 | − return count; | |
| 1354 | − | |
| 1355 | − edid = drm_get_edid(connector, &tc->aux.ddc); | |
| 1356 | − | |
| 1357 | − kfree(tc->edid); | |
| 1358 | − tc->edid = edid; | |
| 1359 | − if (!edid) | |
| 1360 | − return 0; | |
| 1339 | + if (tc->panel_bridge) { | |
| 1340 | + num_modes = drm_bridge_get_modes(tc->panel_bridge, connector); | |
| 1341 | + if (num_modes > 0) | |
| 1342 | + return num_modes; | |
| 1343 | + } | |
| 1361 | 1344 | |
| 1362 | − drm_connector_update_edid_property(connector, edid); | |
| 1363 | − count = drm_add_edid_modes(connector, edid); | |
| 1345 | + edid = tc_get_edid(&tc->bridge, connector); | |
| 1346 | + num_modes = drm_add_edid_modes(connector, edid); | |
| 1347 | + kfree(edid); | |
| 1364 | 1348 | |
| 1365 | − return count; | |
| 1349 | + return num_modes; | |
| 1366 | 1350 | } |
| 1367 | 1351 | |
| 1368 | 1352 | static const struct drm_connector_helper_funcs tc_connector_helper_funcs = { |
| 1369 | 1353 | .get_modes = tc_connector_get_modes, |
| 1370 | 1354 | }; |
| 1371 | 1355 | |
| 1372 | −static enum drm_connector_status tc_connector_detect(struct drm_connector *connector, | |
| 1373 | − bool force) | |
| 1356 | +static enum drm_connector_status tc_bridge_detect(struct drm_bridge *bridge) | |
| 1374 | 1357 | { |
| 1375 | − struct tc_data *tc = connector_to_tc(connector); | |
| 1358 | + struct tc_data *tc = bridge_to_tc(bridge); | |
| 1376 | 1359 | bool conn; |
| 1377 | 1360 | u32 val; |
| 1378 | 1361 | int ret; |
| 1379 | 1362 | |
| 1380 | − if (tc->hpd_pin < 0) { | |
| 1381 | − if (tc->panel) | |
| 1382 | − return connector_status_connected; | |
| 1383 | − else | |
| 1384 | − return connector_status_unknown; | |
| 1385 | − } | |
| 1386 | − | |
| 1387 | 1363 | ret = regmap_read(tc->regmap, GPIOI, &val); |
| 1388 | 1364 | if (ret) |
| 1389 | 1365 | return connector_status_unknown; |
| @@ -1396,6 +1372,20 @@ static enum drm_connector_status tc_connector_detect(struct drm_connector *conne · 6 unmodified lines | ||
| 1396 | 1372 | return connector_status_disconnected; |
| 1397 | 1373 | } |
| 1398 | 1374 | |
| 1375 | +static enum drm_connector_status | |
| 1376 | +tc_connector_detect(struct drm_connector *connector, bool force) | |
| 1377 | +{ | |
| 1378 | + struct tc_data *tc = connector_to_tc(connector); | |
| 1379 | + | |
| 1380 | + if (tc->hpd_pin >= 0) | |
| 1381 | + return tc_bridge_detect(&tc->bridge); | |
| 1382 | + | |
| 1383 | + if (tc->panel_bridge) | |
| 1384 | + return connector_status_connected; | |
| 1385 | + else | |
| 1386 | + return connector_status_unknown; | |
| 1387 | +} | |
| 1388 | + | |
| 1399 | 1389 | static const struct drm_connector_funcs tc_connector_funcs = { |
| 1400 | 1390 | .detect = tc_connector_detect, |
| 1401 | 1391 | .fill_modes = drm_helper_probe_single_connector_modes, |
| @@ -1413,16 +1403,20 @@ static int tc_bridge_attach(struct drm_bridge *bridge, · 11 unmodified lines | ||
| 1413 | 1403 | struct drm_device *drm = bridge->dev; |
| 1414 | 1404 | int ret; |
| 1415 | 1405 | |
| 1416 | − if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { | |
| 1417 | − DRM_ERROR("Fix bridge driver to make connector optional!"); | |
| 1418 | − return -EINVAL; | |
| 1406 | + if (tc->panel_bridge) { | |
| 1407 | + /* If a connector is required then this driver shall create it */ | |
| 1408 | + ret = drm_bridge_attach(tc->bridge.encoder, tc->panel_bridge, | |
| 1409 | + &tc->bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR); | |
| 1410 | + if (ret) | |
| 1411 | + return ret; | |
| 1419 | 1412 | } |
| 1420 | 1413 | |
| 1414 | + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) | |
| 1415 | + return 0; | |
| 1416 | + | |
| 1421 | 1417 | /* Create DP/eDP connector */ |
| 1422 | 1418 | drm_connector_helper_add(&tc->connector, &tc_connector_helper_funcs); |
| 1423 | − ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs, | |
| 1424 | − tc->panel ? DRM_MODE_CONNECTOR_eDP : | |
| 1425 | − DRM_MODE_CONNECTOR_DisplayPort); | |
| 1419 | + ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs, tc->bridge.type); | |
| 1426 | 1420 | if (ret) |
| 1427 | 1421 | return ret; |
| 1428 | 1422 | |
| @@ -1435,9 +1429,6 @@ static int tc_bridge_attach(struct drm_bridge *bridge, · 6 unmodified lines | ||
| 1435 | 1429 | DRM_CONNECTOR_POLL_DISCONNECT; |
| 1436 | 1430 | } |
| 1437 | 1431 | |
| 1438 | − if (tc->panel) | |
| 1439 | − drm_panel_attach(tc->panel, &tc->connector); | |
| 1440 | − | |
| 1441 | 1432 | drm_display_info_set_bus_formats(&tc->connector.display_info, |
| 1442 | 1433 | &bus_format, 1); |
| 1443 | 1434 | tc->connector.display_info.bus_flags = |
| @@ -1453,11 +1444,11 @@ static const struct drm_bridge_funcs tc_bridge_funcs = { · 9 unmodified lines | ||
| 1453 | 1444 | .attach = tc_bridge_attach, |
| 1454 | 1445 | .mode_valid = tc_mode_valid, |
| 1455 | 1446 | .mode_set = tc_bridge_mode_set, |
| 1456 | − .pre_enable = tc_bridge_pre_enable, | |
| 1457 | 1447 | .enable = tc_bridge_enable, |
| 1458 | 1448 | .disable = tc_bridge_disable, |
| 1459 | − .post_disable = tc_bridge_post_disable, | |
| 1460 | 1449 | .mode_fixup = tc_bridge_mode_fixup, |
| 1450 | + .detect = tc_bridge_detect, | |
| 1451 | + .get_edid = tc_get_edid, | |
| 1461 | 1452 | }; |
| 1462 | 1453 | |
| 1463 | 1454 | static bool tc_readable_reg(struct device *dev, unsigned int reg) |
| @@ -1547,6 +1538,7 @@ static irqreturn_t tc_irq_handler(int irq, void *arg) · 83 unmodified lines | ||
| 1547 | 1538 | static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) |
| 1548 | 1539 | { |
| 1549 | 1540 | struct device *dev = &client->dev; |
| 1541 | + struct drm_panel *panel; | |
| 1550 | 1542 | struct tc_data *tc; |
| 1551 | 1543 | int ret; |
| 1552 | 1544 | |
| @@ -1557,10 +1549,23 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) · 4 unmodified lines | ||
| 1557 | 1549 | tc->dev = dev; |
| 1558 | 1550 | |
| 1559 | 1551 | /* port@2 is the output port */ |
| 1560 | − ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &tc->panel, NULL); | |
| 1552 | + ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, NULL); | |
| 1561 | 1553 | if (ret && ret != -ENODEV) |
| 1562 | 1554 | return ret; |
| 1563 | 1555 | |
| 1556 | + if (panel) { | |
| 1557 | + struct drm_bridge *panel_bridge; | |
| 1558 | + | |
| 1559 | + panel_bridge = devm_drm_panel_bridge_add(dev, panel); | |
| 1560 | + if (IS_ERR(panel_bridge)) | |
| 1561 | + return PTR_ERR(panel_bridge); | |
| 1562 | + | |
| 1563 | + tc->panel_bridge = panel_bridge; | |
| 1564 | + tc->bridge.type = DRM_MODE_CONNECTOR_eDP; | |
| 1565 | + } else { | |
| 1566 | + tc->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; | |
| 1567 | + } | |
| 1568 | + | |
| 1564 | 1569 | /* Shut down GPIO is optional */ |
| 1565 | 1570 | tc->sd_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH); |
| 1566 | 1571 | if (IS_ERR(tc->sd_gpio)) |
| @@ -1680,6 +1685,10 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) · 113 unmodified lines | ||
| 1680 | 1685 | return ret; |
| 1681 | 1686 | |
| 1682 | 1687 | tc->bridge.funcs = &tc_bridge_funcs; |
| 1688 | + if (tc->hpd_pin >= 0) | |
| 1689 | + tc->bridge.ops |= DRM_BRIDGE_OP_DETECT; | |
| 1690 | + tc->bridge.ops |= DRM_BRIDGE_OP_EDID; | |
| 1691 | + | |
| 1683 | 1692 | tc->bridge.of_node = dev->of_node; |
| 1684 | 1693 | drm_bridge_add(&tc->bridge); |
| 1685 | 1694 | |
| @@ -0,0 +1,749 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * TC358775 DSI to LVDS bridge driver | |
| 4 | + * | |
| 5 | + * Copyright (C) 2020 SMART Wireless Computing | |
| 6 | + * Author: Vinay Simha BN <simhavcs@gmail.com> | |
| 7 | + * | |
| 8 | + */ | |
| 9 | +/* #define DEBUG */ | |
| 10 | +#include <linux/bitfield.h> | |
| 11 | +#include <linux/clk.h> | |
| 12 | +#include <linux/device.h> | |
| 13 | +#include <linux/gpio/consumer.h> | |
| 14 | +#include <linux/i2c.h> | |
| 15 | +#include <linux/kernel.h> | |
| 16 | +#include <linux/module.h> | |
| 17 | +#include <linux/regulator/consumer.h> | |
| 18 | +#include <linux/slab.h> | |
| 19 | + | |
| 20 | +#include <asm/unaligned.h> | |
| 21 | + | |
| 22 | +#include <drm/drm_atomic_helper.h> | |
| 23 | +#include <drm/drm_bridge.h> | |
| 24 | +#include <drm/drm_crtc_helper.h> | |
| 25 | +#include <drm/drm_dp_helper.h> | |
| 26 | +#include <drm/drm_mipi_dsi.h> | |
| 27 | +#include <drm/drm_of.h> | |
| 28 | +#include <drm/drm_panel.h> | |
| 29 | +#include <drm/drm_probe_helper.h> | |
| 30 | + | |
| 31 | +#define FLD_VAL(val, start, end) FIELD_PREP(GENMASK(start, end), val) | |
| 32 | + | |
| 33 | +/* Registers */ | |
| 34 | + | |
| 35 | +/* DSI D-PHY Layer Registers */ | |
| 36 | +#define D0W_DPHYCONTTX 0x0004 /* Data Lane 0 DPHY Tx Control */ | |
| 37 | +#define CLW_DPHYCONTRX 0x0020 /* Clock Lane DPHY Rx Control */ | |
| 38 | +#define D0W_DPHYCONTRX 0x0024 /* Data Lane 0 DPHY Rx Control */ | |
| 39 | +#define D1W_DPHYCONTRX 0x0028 /* Data Lane 1 DPHY Rx Control */ | |
| 40 | +#define D2W_DPHYCONTRX 0x002C /* Data Lane 2 DPHY Rx Control */ | |
| 41 | +#define D3W_DPHYCONTRX 0x0030 /* Data Lane 3 DPHY Rx Control */ | |
| 42 | +#define COM_DPHYCONTRX 0x0038 /* DPHY Rx Common Control */ | |
| 43 | +#define CLW_CNTRL 0x0040 /* Clock Lane Control */ | |
| 44 | +#define D0W_CNTRL 0x0044 /* Data Lane 0 Control */ | |
| 45 | +#define D1W_CNTRL 0x0048 /* Data Lane 1 Control */ | |
| 46 | +#define D2W_CNTRL 0x004C /* Data Lane 2 Control */ | |
| 47 | +#define D3W_CNTRL 0x0050 /* Data Lane 3 Control */ | |
| 48 | +#define DFTMODE_CNTRL 0x0054 /* DFT Mode Control */ | |
| 49 | + | |
| 50 | +/* DSI PPI Layer Registers */ | |
| 51 | +#define PPI_STARTPPI 0x0104 /* START control bit of PPI-TX function. */ | |
| 52 | +#define PPI_START_FUNCTION 1 | |
| 53 | + | |
| 54 | +#define PPI_BUSYPPI 0x0108 | |
| 55 | +#define PPI_LINEINITCNT 0x0110 /* Line Initialization Wait Counter */ | |
| 56 | +#define PPI_LPTXTIMECNT 0x0114 | |
| 57 | +#define PPI_LANEENABLE 0x0134 /* Enables each lane at the PPI layer. */ | |
| 58 | +#define PPI_TX_RX_TA 0x013C /* DSI Bus Turn Around timing parameters */ | |
| 59 | + | |
| 60 | +/* Analog timer function enable */ | |
| 61 | +#define PPI_CLS_ATMR 0x0140 /* Delay for Clock Lane in LPRX */ | |
| 62 | +#define PPI_D0S_ATMR 0x0144 /* Delay for Data Lane 0 in LPRX */ | |
| 63 | +#define PPI_D1S_ATMR 0x0148 /* Delay for Data Lane 1 in LPRX */ | |
| 64 | +#define PPI_D2S_ATMR 0x014C /* Delay for Data Lane 2 in LPRX */ | |
| 65 | +#define PPI_D3S_ATMR 0x0150 /* Delay for Data Lane 3 in LPRX */ | |
| 66 | + | |
| 67 | +#define PPI_D0S_CLRSIPOCOUNT 0x0164 /* For lane 0 */ | |
| 68 | +#define PPI_D1S_CLRSIPOCOUNT 0x0168 /* For lane 1 */ | |
| 69 | +#define PPI_D2S_CLRSIPOCOUNT 0x016C /* For lane 2 */ | |
| 70 | +#define PPI_D3S_CLRSIPOCOUNT 0x0170 /* For lane 3 */ | |
| 71 | + | |
| 72 | +#define CLS_PRE 0x0180 /* Digital Counter inside of PHY IO */ | |
| 73 | +#define D0S_PRE 0x0184 /* Digital Counter inside of PHY IO */ | |
| 74 | +#define D1S_PRE 0x0188 /* Digital Counter inside of PHY IO */ | |
| 75 | +#define D2S_PRE 0x018C /* Digital Counter inside of PHY IO */ | |
| 76 | +#define D3S_PRE 0x0190 /* Digital Counter inside of PHY IO */ | |
| 77 | +#define CLS_PREP 0x01A0 /* Digital Counter inside of PHY IO */ | |
| 78 | +#define D0S_PREP 0x01A4 /* Digital Counter inside of PHY IO */ | |
| 79 | +#define D1S_PREP 0x01A8 /* Digital Counter inside of PHY IO */ | |
| 80 | +#define D2S_PREP 0x01AC /* Digital Counter inside of PHY IO */ | |
| 81 | +#define D3S_PREP 0x01B0 /* Digital Counter inside of PHY IO */ | |
| 82 | +#define CLS_ZERO 0x01C0 /* Digital Counter inside of PHY IO */ | |
| 83 | +#define D0S_ZERO 0x01C4 /* Digital Counter inside of PHY IO */ | |
| 84 | +#define D1S_ZERO 0x01C8 /* Digital Counter inside of PHY IO */ | |
| 85 | +#define D2S_ZERO 0x01CC /* Digital Counter inside of PHY IO */ | |
| 86 | +#define D3S_ZERO 0x01D0 /* Digital Counter inside of PHY IO */ | |
| 87 | + | |
| 88 | +#define PPI_CLRFLG 0x01E0 /* PRE Counters has reached set values */ | |
| 89 | +#define PPI_CLRSIPO 0x01E4 /* Clear SIPO values, Slave mode use only. */ | |
| 90 | +#define HSTIMEOUT 0x01F0 /* HS Rx Time Out Counter */ | |
| 91 | +#define HSTIMEOUTENABLE 0x01F4 /* Enable HS Rx Time Out Counter */ | |
| 92 | +#define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX function */ | |
| 93 | +#define DSI_RX_START 1 | |
| 94 | + | |
| 95 | +#define DSI_BUSYDSI 0x0208 | |
| 96 | +#define DSI_LANEENABLE 0x0210 /* Enables each lane at the Protocol layer. */ | |
| 97 | +#define DSI_LANESTATUS0 0x0214 /* Displays lane is in HS RX mode. */ | |
| 98 | +#define DSI_LANESTATUS1 0x0218 /* Displays lane is in ULPS or STOP state */ | |
| 99 | + | |
| 100 | +#define DSI_INTSTATUS 0x0220 /* Interrupt Status */ | |
| 101 | +#define DSI_INTMASK 0x0224 /* Interrupt Mask */ | |
| 102 | +#define DSI_INTCLR 0x0228 /* Interrupt Clear */ | |
| 103 | +#define DSI_LPTXTO 0x0230 /* Low Power Tx Time Out Counter */ | |
| 104 | + | |
| 105 | +#define DSIERRCNT 0x0300 /* DSI Error Count */ | |
| 106 | +#define APLCTRL 0x0400 /* Application Layer Control */ | |
| 107 | +#define RDPKTLN 0x0404 /* Command Read Packet Length */ | |
| 108 | + | |
| 109 | +#define VPCTRL 0x0450 /* Video Path Control */ | |
| 110 | +#define HTIM1 0x0454 /* Horizontal Timing Control 1 */ | |
| 111 | +#define HTIM2 0x0458 /* Horizontal Timing Control 2 */ | |
| 112 | +#define VTIM1 0x045C /* Vertical Timing Control 1 */ | |
| 113 | +#define VTIM2 0x0460 /* Vertical Timing Control 2 */ | |
| 114 | +#define VFUEN 0x0464 /* Video Frame Timing Update Enable */ | |
| 115 | +#define VFUEN_EN BIT(0) /* Upload Enable */ | |
| 116 | + | |
| 117 | +/* Mux Input Select for LVDS LINK Input */ | |
| 118 | +#define LV_MX0003 0x0480 /* Bit 0 to 3 */ | |
| 119 | +#define LV_MX0407 0x0484 /* Bit 4 to 7 */ | |
| 120 | +#define LV_MX0811 0x0488 /* Bit 8 to 11 */ | |
| 121 | +#define LV_MX1215 0x048C /* Bit 12 to 15 */ | |
| 122 | +#define LV_MX1619 0x0490 /* Bit 16 to 19 */ | |
| 123 | +#define LV_MX2023 0x0494 /* Bit 20 to 23 */ | |
| 124 | +#define LV_MX2427 0x0498 /* Bit 24 to 27 */ | |
| 125 | +#define LV_MX(b0, b1, b2, b3) (FLD_VAL(b0, 4, 0) | FLD_VAL(b1, 12, 8) | \ | |
| 126 | + FLD_VAL(b2, 20, 16) | FLD_VAL(b3, 28, 24)) | |
| 127 | + | |
| 128 | +/* Input bit numbers used in mux registers */ | |
| 129 | +enum { | |
| 130 | + LVI_R0, | |
| 131 | + LVI_R1, | |
| 132 | + LVI_R2, | |
| 133 | + LVI_R3, | |
| 134 | + LVI_R4, | |
| 135 | + LVI_R5, | |
| 136 | + LVI_R6, | |
| 137 | + LVI_R7, | |
| 138 | + LVI_G0, | |
| 139 | + LVI_G1, | |
| 140 | + LVI_G2, | |
| 141 | + LVI_G3, | |
| 142 | + LVI_G4, | |
| 143 | + LVI_G5, | |
| 144 | + LVI_G6, | |
| 145 | + LVI_G7, | |
| 146 | + LVI_B0, | |
| 147 | + LVI_B1, | |
| 148 | + LVI_B2, | |
| 149 | + LVI_B3, | |
| 150 | + LVI_B4, | |
| 151 | + LVI_B5, | |
| 152 | + LVI_B6, | |
| 153 | + LVI_B7, | |
| 154 | + LVI_HS, | |
| 155 | + LVI_VS, | |
| 156 | + LVI_DE, | |
| 157 | + LVI_L0 | |
| 158 | +}; | |
| 159 | + | |
| 160 | +#define LVCFG 0x049C /* LVDS Configuration */ | |
| 161 | +#define LVPHY0 0x04A0 /* LVDS PHY 0 */ | |
| 162 | +#define LV_PHY0_RST(v) FLD_VAL(v, 22, 22) /* PHY reset */ | |
| 163 | +#define LV_PHY0_IS(v) FLD_VAL(v, 15, 14) | |
| 164 | +#define LV_PHY0_ND(v) FLD_VAL(v, 4, 0) /* Frequency range select */ | |
| 165 | +#define LV_PHY0_PRBS_ON(v) FLD_VAL(v, 20, 16) /* Clock/Data Flag pins */ | |
| 166 | + | |
| 167 | +#define LVPHY1 0x04A4 /* LVDS PHY 1 */ | |
| 168 | +#define SYSSTAT 0x0500 /* System Status */ | |
| 169 | +#define SYSRST 0x0504 /* System Reset */ | |
| 170 | + | |
| 171 | +#define SYS_RST_I2CS BIT(0) /* Reset I2C-Slave controller */ | |
| 172 | +#define SYS_RST_I2CM BIT(1) /* Reset I2C-Master controller */ | |
| 173 | +#define SYS_RST_LCD BIT(2) /* Reset LCD controller */ | |
| 174 | +#define SYS_RST_BM BIT(3) /* Reset Bus Management controller */ | |
| 175 | +#define SYS_RST_DSIRX BIT(4) /* Reset DSI-RX and App controller */ | |
| 176 | +#define SYS_RST_REG BIT(5) /* Reset Register module */ | |
| 177 | + | |
| 178 | +/* GPIO Registers */ | |
| 179 | +#define GPIOC 0x0520 /* GPIO Control */ | |
| 180 | +#define GPIOO 0x0524 /* GPIO Output */ | |
| 181 | +#define GPIOI 0x0528 /* GPIO Input */ | |
| 182 | + | |
| 183 | +/* I2C Registers */ | |
| 184 | +#define I2CTIMCTRL 0x0540 /* I2C IF Timing and Enable Control */ | |
| 185 | +#define I2CMADDR 0x0544 /* I2C Master Addressing */ | |
| 186 | +#define WDATAQ 0x0548 /* Write Data Queue */ | |
| 187 | +#define RDATAQ 0x054C /* Read Data Queue */ | |
| 188 | + | |
| 189 | +/* Chip ID and Revision ID Register */ | |
| 190 | +#define IDREG 0x0580 | |
| 191 | + | |
| 192 | +#define LPX_PERIOD 4 | |
| 193 | +#define TTA_GET 0x40000 | |
| 194 | +#define TTA_SURE 6 | |
| 195 | +#define SINGLE_LINK 1 | |
| 196 | +#define DUAL_LINK 2 | |
| 197 | + | |
| 198 | +#define TC358775XBG_ID 0x00007500 | |
| 199 | + | |
| 200 | +/* Debug Registers */ | |
| 201 | +#define DEBUG00 0x05A0 /* Debug */ | |
| 202 | +#define DEBUG01 0x05A4 /* LVDS Data */ | |
| 203 | + | |
| 204 | +#define DSI_CLEN_BIT BIT(0) | |
| 205 | +#define DIVIDE_BY_3 3 /* PCLK=DCLK/3 */ | |
| 206 | +#define DIVIDE_BY_6 6 /* PCLK=DCLK/6 */ | |
| 207 | +#define LVCFG_LVEN_BIT BIT(0) | |
| 208 | + | |
| 209 | +#define L0EN BIT(1) | |
| 210 | + | |
| 211 | +#define TC358775_VPCTRL_VSDELAY__MASK 0x3FF00000 | |
| 212 | +#define TC358775_VPCTRL_VSDELAY__SHIFT 20 | |
| 213 | +static inline u32 TC358775_VPCTRL_VSDELAY(uint32_t val) | |
| 214 | +{ | |
| 215 | + return ((val) << TC358775_VPCTRL_VSDELAY__SHIFT) & | |
| 216 | + TC358775_VPCTRL_VSDELAY__MASK; | |
| 217 | +} | |
| 218 | + | |
| 219 | +#define TC358775_VPCTRL_OPXLFMT__MASK 0x00000100 | |
| 220 | +#define TC358775_VPCTRL_OPXLFMT__SHIFT 8 | |
| 221 | +static inline u32 TC358775_VPCTRL_OPXLFMT(uint32_t val) | |
| 222 | +{ | |
| 223 | + return ((val) << TC358775_VPCTRL_OPXLFMT__SHIFT) & | |
| 224 | + TC358775_VPCTRL_OPXLFMT__MASK; | |
| 225 | +} | |
| 226 | + | |
| 227 | +#define TC358775_VPCTRL_MSF__MASK 0x00000001 | |
| 228 | +#define TC358775_VPCTRL_MSF__SHIFT 0 | |
| 229 | +static inline u32 TC358775_VPCTRL_MSF(uint32_t val) | |
| 230 | +{ | |
| 231 | + return ((val) << TC358775_VPCTRL_MSF__SHIFT) & | |
| 232 | + TC358775_VPCTRL_MSF__MASK; | |
| 233 | +} | |
| 234 | + | |
| 235 | +#define TC358775_LVCFG_PCLKDIV__MASK 0x000000f0 | |
| 236 | +#define TC358775_LVCFG_PCLKDIV__SHIFT 4 | |
| 237 | +static inline u32 TC358775_LVCFG_PCLKDIV(uint32_t val) | |
| 238 | +{ | |
| 239 | + return ((val) << TC358775_LVCFG_PCLKDIV__SHIFT) & | |
| 240 | + TC358775_LVCFG_PCLKDIV__MASK; | |
| 241 | +} | |
| 242 | + | |
| 243 | +#define TC358775_LVCFG_LVDLINK__MASK 0x00000002 | |
| 244 | +#define TC358775_LVCFG_LVDLINK__SHIFT 0 | |
| 245 | +static inline u32 TC358775_LVCFG_LVDLINK(uint32_t val) | |
| 246 | +{ | |
| 247 | + return ((val) << TC358775_LVCFG_LVDLINK__SHIFT) & | |
| 248 | + TC358775_LVCFG_LVDLINK__MASK; | |
| 249 | +} | |
| 250 | + | |
| 251 | +enum tc358775_ports { | |
| 252 | + TC358775_DSI_IN, | |
| 253 | + TC358775_LVDS_OUT0, | |
| 254 | + TC358775_LVDS_OUT1, | |
| 255 | +}; | |
| 256 | + | |
| 257 | +struct tc_data { | |
| 258 | + struct i2c_client *i2c; | |
| 259 | + struct device *dev; | |
| 260 | + | |
| 261 | + struct drm_bridge bridge; | |
| 262 | + struct drm_bridge *panel_bridge; | |
| 263 | + | |
| 264 | + struct device_node *host_node; | |
| 265 | + struct mipi_dsi_device *dsi; | |
| 266 | + u8 num_dsi_lanes; | |
| 267 | + | |
| 268 | + struct regulator *vdd; | |
| 269 | + struct regulator *vddio; | |
| 270 | + struct gpio_desc *reset_gpio; | |
| 271 | + struct gpio_desc *stby_gpio; | |
| 272 | + u8 lvds_link; /* single-link or dual-link */ | |
| 273 | + u8 bpc; | |
| 274 | +}; | |
| 275 | + | |
| 276 | +static inline struct tc_data *bridge_to_tc(struct drm_bridge *b) | |
| 277 | +{ | |
| 278 | + return container_of(b, struct tc_data, bridge); | |
| 279 | +} | |
| 280 | + | |
| 281 | +static void tc_bridge_pre_enable(struct drm_bridge *bridge) | |
| 282 | +{ | |
| 283 | + struct tc_data *tc = bridge_to_tc(bridge); | |
| 284 | + struct device *dev = &tc->dsi->dev; | |
| 285 | + int ret; | |
| 286 | + | |
| 287 | + ret = regulator_enable(tc->vddio); | |
| 288 | + if (ret < 0) | |
| 289 | + dev_err(dev, "regulator vddio enable failed, %d\n", ret); | |
| 290 | + usleep_range(10000, 11000); | |
| 291 | + | |
| 292 | + ret = regulator_enable(tc->vdd); | |
| 293 | + if (ret < 0) | |
| 294 | + dev_err(dev, "regulator vdd enable failed, %d\n", ret); | |
| 295 | + usleep_range(10000, 11000); | |
| 296 | + | |
| 297 | + gpiod_set_value(tc->stby_gpio, 0); | |
| 298 | + usleep_range(10000, 11000); | |
| 299 | + | |
| 300 | + gpiod_set_value(tc->reset_gpio, 0); | |
| 301 | + usleep_range(10, 20); | |
| 302 | +} | |
| 303 | + | |
| 304 | +static void tc_bridge_post_disable(struct drm_bridge *bridge) | |
| 305 | +{ | |
| 306 | + struct tc_data *tc = bridge_to_tc(bridge); | |
| 307 | + struct device *dev = &tc->dsi->dev; | |
| 308 | + int ret; | |
| 309 | + | |
| 310 | + gpiod_set_value(tc->reset_gpio, 1); | |
| 311 | + usleep_range(10, 20); | |
| 312 | + | |
| 313 | + gpiod_set_value(tc->stby_gpio, 1); | |
| 314 | + usleep_range(10000, 11000); | |
| 315 | + | |
| 316 | + ret = regulator_disable(tc->vdd); | |
| 317 | + if (ret < 0) | |
| 318 | + dev_err(dev, "regulator vdd disable failed, %d\n", ret); | |
| 319 | + usleep_range(10000, 11000); | |
| 320 | + | |
| 321 | + ret = regulator_disable(tc->vddio); | |
| 322 | + if (ret < 0) | |
| 323 | + dev_err(dev, "regulator vddio disable failed, %d\n", ret); | |
| 324 | + usleep_range(10000, 11000); | |
| 325 | +} | |
| 326 | + | |
| 327 | +static void d2l_read(struct i2c_client *i2c, u16 addr, u32 *val) | |
| 328 | +{ | |
| 329 | + int ret; | |
| 330 | + u8 buf_addr[2]; | |
| 331 | + | |
| 332 | + put_unaligned_be16(addr, buf_addr); | |
| 333 | + ret = i2c_master_send(i2c, buf_addr, sizeof(buf_addr)); | |
| 334 | + if (ret < 0) | |
| 335 | + goto fail; | |
| 336 | + | |
| 337 | + ret = i2c_master_recv(i2c, (u8 *)val, sizeof(*val)); | |
| 338 | + if (ret < 0) | |
| 339 | + goto fail; | |
| 340 | + | |
| 341 | + pr_debug("d2l: I2C : addr:%04x value:%08x\n", addr, *val); | |
| 342 | + | |
| 343 | +fail: | |
| 344 | + dev_err(&i2c->dev, "Error %d reading from subaddress 0x%x\n", | |
| 345 | + ret, addr); | |
| 346 | +} | |
| 347 | + | |
| 348 | +static void d2l_write(struct i2c_client *i2c, u16 addr, u32 val) | |
| 349 | +{ | |
| 350 | + u8 data[6]; | |
| 351 | + int ret; | |
| 352 | + | |
| 353 | + put_unaligned_be16(addr, data); | |
| 354 | + put_unaligned_le32(val, data + 2); | |
| 355 | + | |
| 356 | + ret = i2c_master_send(i2c, data, ARRAY_SIZE(data)); | |
| 357 | + if (ret < 0) | |
| 358 | + dev_err(&i2c->dev, "Error %d writing to subaddress 0x%x\n", | |
| 359 | + ret, addr); | |
| 360 | +} | |
| 361 | + | |
| 362 | +/* helper function to access bus_formats */ | |
| 363 | +static struct drm_connector *get_connector(struct drm_encoder *encoder) | |
| 364 | +{ | |
| 365 | + struct drm_device *dev = encoder->dev; | |
| 366 | + struct drm_connector *connector; | |
| 367 | + | |
| 368 | + list_for_each_entry(connector, &dev->mode_config.connector_list, head) | |
| 369 | + if (connector->encoder == encoder) | |
| 370 | + return connector; | |
| 371 | + | |
| 372 | + return NULL; | |
| 373 | +} | |
| 374 | + | |
| 375 | +static void tc_bridge_enable(struct drm_bridge *bridge) | |
| 376 | +{ | |
| 377 | + struct tc_data *tc = bridge_to_tc(bridge); | |
| 378 | + u32 hback_porch, hsync_len, hfront_porch, hactive, htime1, htime2; | |
| 379 | + u32 vback_porch, vsync_len, vfront_porch, vactive, vtime1, vtime2; | |
| 380 | + u32 val = 0; | |
| 381 | + u16 dsiclk, clkdiv, byteclk, t1, t2, t3, vsdelay; | |
| 382 | + struct drm_display_mode *mode; | |
| 383 | + struct drm_connector *connector = get_connector(bridge->encoder); | |
| 384 | + | |
| 385 | + mode = &bridge->encoder->crtc->state->adjusted_mode; | |
| 386 | + | |
| 387 | + hback_porch = mode->htotal - mode->hsync_end; | |
| 388 | + hsync_len = mode->hsync_end - mode->hsync_start; | |
| 389 | + vback_porch = mode->vtotal - mode->vsync_end; | |
| 390 | + vsync_len = mode->vsync_end - mode->vsync_start; | |
| 391 | + | |
| 392 | + htime1 = (hback_porch << 16) + hsync_len; | |
| 393 | + vtime1 = (vback_porch << 16) + vsync_len; | |
| 394 | + | |
| 395 | + hfront_porch = mode->hsync_start - mode->hdisplay; | |
| 396 | + hactive = mode->hdisplay; | |
| 397 | + vfront_porch = mode->vsync_start - mode->vdisplay; | |
| 398 | + vactive = mode->vdisplay; | |
| 399 | + | |
| 400 | + htime2 = (hfront_porch << 16) + hactive; | |
| 401 | + vtime2 = (vfront_porch << 16) + vactive; | |
| 402 | + | |
| 403 | + d2l_read(tc->i2c, IDREG, &val); | |
| 404 | + | |
| 405 | + dev_info(tc->dev, "DSI2LVDS Chip ID.%02x Revision ID. %02x **\n", | |
| 406 | + (val >> 8) & 0xFF, val & 0xFF); | |
| 407 | + | |
| 408 | + d2l_write(tc->i2c, SYSRST, SYS_RST_REG | SYS_RST_DSIRX | SYS_RST_BM | | |
| 409 | + SYS_RST_LCD | SYS_RST_I2CM | SYS_RST_I2CS); | |
| 410 | + usleep_range(30000, 40000); | |
| 411 | + | |
| 412 | + d2l_write(tc->i2c, PPI_TX_RX_TA, TTA_GET | TTA_SURE); | |
| 413 | + d2l_write(tc->i2c, PPI_LPTXTIMECNT, LPX_PERIOD); | |
| 414 | + d2l_write(tc->i2c, PPI_D0S_CLRSIPOCOUNT, 3); | |
| 415 | + d2l_write(tc->i2c, PPI_D1S_CLRSIPOCOUNT, 3); | |
| 416 | + d2l_write(tc->i2c, PPI_D2S_CLRSIPOCOUNT, 3); | |
| 417 | + d2l_write(tc->i2c, PPI_D3S_CLRSIPOCOUNT, 3); | |
| 418 | + | |
| 419 | + val = ((L0EN << tc->num_dsi_lanes) - L0EN) | DSI_CLEN_BIT; | |
| 420 | + d2l_write(tc->i2c, PPI_LANEENABLE, val); | |
| 421 | + d2l_write(tc->i2c, DSI_LANEENABLE, val); | |
| 422 | + | |
| 423 | + d2l_write(tc->i2c, PPI_STARTPPI, PPI_START_FUNCTION); | |
| 424 | + d2l_write(tc->i2c, DSI_STARTDSI, DSI_RX_START); | |
| 425 | + | |
| 426 | + if (tc->bpc == 8) | |
| 427 | + val = TC358775_VPCTRL_OPXLFMT(1); | |
| 428 | + else /* bpc = 6; */ | |
| 429 | + val = TC358775_VPCTRL_MSF(1); | |
| 430 | + | |
| 431 | + dsiclk = mode->crtc_clock * 3 * tc->bpc / tc->num_dsi_lanes / 1000; | |
| 432 | + clkdiv = dsiclk / DIVIDE_BY_3 * tc->lvds_link; | |
| 433 | + byteclk = dsiclk / 4; | |
| 434 | + t1 = hactive * (tc->bpc * 3 / 8) / tc->num_dsi_lanes; | |
| 435 | + t2 = ((100000 / clkdiv)) * (hactive + hback_porch + hsync_len + hfront_porch) / 1000; | |
| 436 | + t3 = ((t2 * byteclk) / 100) - (hactive * (tc->bpc * 3 / 8) / | |
| 437 | + tc->num_dsi_lanes); | |
| 438 | + | |
| 439 | + vsdelay = (clkdiv * (t1 + t3) / byteclk) - hback_porch - hsync_len - hactive; | |
| 440 | + | |
| 441 | + val |= TC358775_VPCTRL_VSDELAY(vsdelay); | |
| 442 | + d2l_write(tc->i2c, VPCTRL, val); | |
| 443 | + | |
| 444 | + d2l_write(tc->i2c, HTIM1, htime1); | |
| 445 | + d2l_write(tc->i2c, VTIM1, vtime1); | |
| 446 | + d2l_write(tc->i2c, HTIM2, htime2); | |
| 447 | + d2l_write(tc->i2c, VTIM2, vtime2); | |
| 448 | + | |
| 449 | + d2l_write(tc->i2c, VFUEN, VFUEN_EN); | |
| 450 | + d2l_write(tc->i2c, SYSRST, SYS_RST_LCD); | |
| 451 | + d2l_write(tc->i2c, LVPHY0, LV_PHY0_PRBS_ON(4) | LV_PHY0_ND(6)); | |
| 452 | + | |
| 453 | + dev_dbg(tc->dev, "bus_formats %04x bpc %d\n", | |
| 454 | + connector->display_info.bus_formats[0], | |
| 455 | + tc->bpc); | |
| 456 | + /* | |
| 457 | + * Default hardware register settings of tc358775 configured | |
| 458 | + * with MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA jeida-24 format | |
| 459 | + */ | |
| 460 | + if (connector->display_info.bus_formats[0] == | |
| 461 | + MEDIA_BUS_FMT_RGB888_1X7X4_SPWG) { | |
| 462 | + /* VESA-24 */ | |
| 463 | + d2l_write(tc->i2c, LV_MX0003, LV_MX(LVI_R0, LVI_R1, LVI_R2, LVI_R3)); | |
| 464 | + d2l_write(tc->i2c, LV_MX0407, LV_MX(LVI_R4, LVI_R7, LVI_R5, LVI_G0)); | |
| 465 | + d2l_write(tc->i2c, LV_MX0811, LV_MX(LVI_G1, LVI_G2, LVI_G6, LVI_G7)); | |
| 466 | + d2l_write(tc->i2c, LV_MX1215, LV_MX(LVI_G3, LVI_G4, LVI_G5, LVI_B0)); | |
| 467 | + d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_B6, LVI_B7, LVI_B1, LVI_B2)); | |
| 468 | + d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0)); | |
| 469 | + d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_R6)); | |
| 470 | + } else { /* MEDIA_BUS_FMT_RGB666_1X7X3_SPWG - JEIDA-18 */ | |
| 471 | + d2l_write(tc->i2c, LV_MX0003, LV_MX(LVI_R0, LVI_R1, LVI_R2, LVI_R3)); | |
| 472 | + d2l_write(tc->i2c, LV_MX0407, LV_MX(LVI_R4, LVI_L0, LVI_R5, LVI_G0)); | |
| 473 | + d2l_write(tc->i2c, LV_MX0811, LV_MX(LVI_G1, LVI_G2, LVI_L0, LVI_L0)); | |
| 474 | + d2l_write(tc->i2c, LV_MX1215, LV_MX(LVI_G3, LVI_G4, LVI_G5, LVI_B0)); | |
| 475 | + d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_L0, LVI_L0, LVI_B1, LVI_B2)); | |
| 476 | + d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0)); | |
| 477 | + d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_L0)); | |
| 478 | + } | |
| 479 | + | |
| 480 | + d2l_write(tc->i2c, VFUEN, VFUEN_EN); | |
| 481 | + | |
| 482 | + val = LVCFG_LVEN_BIT; | |
| 483 | + if (tc->lvds_link == DUAL_LINK) { | |
| 484 | + val |= TC358775_LVCFG_LVDLINK(1); | |
| 485 | + val |= TC358775_LVCFG_PCLKDIV(DIVIDE_BY_6); | |
| 486 | + } else { | |
| 487 | + val |= TC358775_LVCFG_PCLKDIV(DIVIDE_BY_3); | |
| 488 | + }; | |
| 489 | + d2l_write(tc->i2c, LVCFG, val); | |
| 490 | +} | |
| 491 | + | |
| 492 | +static enum drm_mode_status | |
| 493 | +tc_mode_valid(struct drm_bridge *bridge, | |
| 494 | + const struct drm_display_info *info, | |
| 495 | + const struct drm_display_mode *mode) | |
| 496 | +{ | |
| 497 | + struct tc_data *tc = bridge_to_tc(bridge); | |
| 498 | + | |
| 499 | + /* | |
| 500 | + * Maximum pixel clock speed 135MHz for single-link | |
| 501 | + * 270MHz for dual-link | |
| 502 | + */ | |
| 503 | + if ((mode->clock > 135000 && tc->lvds_link == SINGLE_LINK) || | |
| 504 | + (mode->clock > 270000 && tc->lvds_link == DUAL_LINK)) | |
| 505 | + return MODE_CLOCK_HIGH; | |
| 506 | + | |
| 507 | + switch (info->bus_formats[0]) { | |
| 508 | + case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: | |
| 509 | + case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: | |
| 510 | + /* RGB888 */ | |
| 511 | + tc->bpc = 8; | |
| 512 | + break; | |
| 513 | + case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: | |
| 514 | + /* RGB666 */ | |
| 515 | + tc->bpc = 6; | |
| 516 | + break; | |
| 517 | + default: | |
| 518 | + dev_warn(tc->dev, | |
| 519 | + "unsupported LVDS bus format 0x%04x\n", | |
| 520 | + info->bus_formats[0]); | |
| 521 | + return MODE_NOMODE; | |
| 522 | + } | |
| 523 | + | |
| 524 | + return MODE_OK; | |
| 525 | +} | |
| 526 | + | |
| 527 | +static int tc358775_parse_dt(struct device_node *np, struct tc_data *tc) | |
| 528 | +{ | |
| 529 | + struct device_node *endpoint; | |
| 530 | + struct device_node *parent; | |
| 531 | + struct device_node *remote; | |
| 532 | + struct property *prop; | |
| 533 | + int len = 0; | |
| 534 | + | |
| 535 | + /* | |
| 536 | + * To get the data-lanes of dsi, we need to access the dsi0_out of port1 | |
| 537 | + * of dsi0 endpoint from bridge port0 of d2l_in | |
| 538 | + */ | |
| 539 | + endpoint = of_graph_get_endpoint_by_regs(tc->dev->of_node, | |
| 540 | + TC358775_DSI_IN, -1); | |
| 541 | + if (endpoint) { | |
| 542 | + /* dsi0_out node */ | |
| 543 | + parent = of_graph_get_remote_port_parent(endpoint); | |
| 544 | + of_node_put(endpoint); | |
| 545 | + if (parent) { | |
| 546 | + /* dsi0 port 1 */ | |
| 547 | + endpoint = of_graph_get_endpoint_by_regs(parent, 1, -1); | |
| 548 | + of_node_put(parent); | |
| 549 | + if (endpoint) { | |
| 550 | + prop = of_find_property(endpoint, "data-lanes", | |
| 551 | + &len); | |
| 552 | + of_node_put(endpoint); | |
| 553 | + if (!prop) { | |
| 554 | + dev_err(tc->dev, | |
| 555 | + "failed to find data lane\n"); | |
| 556 | + return -EPROBE_DEFER; | |
| 557 | + } | |
| 558 | + } | |
| 559 | + } | |
| 560 | + } | |
| 561 | + | |
| 562 | + tc->num_dsi_lanes = len / sizeof(u32); | |
| 563 | + | |
| 564 | + if (tc->num_dsi_lanes < 1 || tc->num_dsi_lanes > 4) | |
| 565 | + return -EINVAL; | |
| 566 | + | |
| 567 | + tc->host_node = of_graph_get_remote_node(np, 0, 0); | |
| 568 | + if (!tc->host_node) | |
| 569 | + return -ENODEV; | |
| 570 | + | |
| 571 | + of_node_put(tc->host_node); | |
| 572 | + | |
| 573 | + tc->lvds_link = SINGLE_LINK; | |
| 574 | + endpoint = of_graph_get_endpoint_by_regs(tc->dev->of_node, | |
| 575 | + TC358775_LVDS_OUT1, -1); | |
| 576 | + if (endpoint) { | |
| 577 | + remote = of_graph_get_remote_port_parent(endpoint); | |
| 578 | + of_node_put(endpoint); | |
| 579 | + | |
| 580 | + if (remote) { | |
| 581 | + if (of_device_is_available(remote)) | |
| 582 | + tc->lvds_link = DUAL_LINK; | |
| 583 | + of_node_put(remote); | |
| 584 | + } | |
| 585 | + } | |
| 586 | + | |
| 587 | + dev_dbg(tc->dev, "no.of dsi lanes: %d\n", tc->num_dsi_lanes); | |
| 588 | + dev_dbg(tc->dev, "operating in %d-link mode\n", tc->lvds_link); | |
| 589 | + | |
| 590 | + return 0; | |
| 591 | +} | |
| 592 | + | |
| 593 | +static int tc_bridge_attach(struct drm_bridge *bridge, | |
| 594 | + enum drm_bridge_attach_flags flags) | |
| 595 | +{ | |
| 596 | + struct tc_data *tc = bridge_to_tc(bridge); | |
| 597 | + struct device *dev = &tc->i2c->dev; | |
| 598 | + struct mipi_dsi_host *host; | |
| 599 | + struct mipi_dsi_device *dsi; | |
| 600 | + int ret; | |
| 601 | + | |
| 602 | + const struct mipi_dsi_device_info info = { .type = "tc358775", | |
| 603 | + .channel = 0, | |
| 604 | + .node = NULL, | |
| 605 | + }; | |
| 606 | + | |
| 607 | + host = of_find_mipi_dsi_host_by_node(tc->host_node); | |
| 608 | + if (!host) { | |
| 609 | + dev_err(dev, "failed to find dsi host\n"); | |
| 610 | + return -EPROBE_DEFER; | |
| 611 | + } | |
| 612 | + | |
| 613 | + dsi = mipi_dsi_device_register_full(host, &info); | |
| 614 | + if (IS_ERR(dsi)) { | |
| 615 | + dev_err(dev, "failed to create dsi device\n"); | |
| 616 | + ret = PTR_ERR(dsi); | |
| 617 | + goto err_dsi_device; | |
| 618 | + } | |
| 619 | + | |
| 620 | + tc->dsi = dsi; | |
| 621 | + | |
| 622 | + dsi->lanes = tc->num_dsi_lanes; | |
| 623 | + dsi->format = MIPI_DSI_FMT_RGB888; | |
| 624 | + dsi->mode_flags = MIPI_DSI_MODE_VIDEO; | |
| 625 | + | |
| 626 | + ret = mipi_dsi_attach(dsi); | |
| 627 | + if (ret < 0) { | |
| 628 | + dev_err(dev, "failed to attach dsi to host\n"); | |
| 629 | + goto err_dsi_attach; | |
| 630 | + } | |
| 631 | + | |
| 632 | + /* Attach the panel-bridge to the dsi bridge */ | |
| 633 | + return drm_bridge_attach(bridge->encoder, tc->panel_bridge, | |
| 634 | + &tc->bridge, flags); | |
| 635 | +err_dsi_attach: | |
| 636 | + mipi_dsi_device_unregister(dsi); | |
| 637 | +err_dsi_device: | |
| 638 | + return ret; | |
| 639 | +} | |
| 640 | + | |
| 641 | +static const struct drm_bridge_funcs tc_bridge_funcs = { | |
| 642 | + .attach = tc_bridge_attach, | |
| 643 | + .pre_enable = tc_bridge_pre_enable, | |
| 644 | + .enable = tc_bridge_enable, | |
| 645 | + .mode_valid = tc_mode_valid, | |
| 646 | + .post_disable = tc_bridge_post_disable, | |
| 647 | +}; | |
| 648 | + | |
| 649 | +static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) | |
| 650 | +{ | |
| 651 | + struct device *dev = &client->dev; | |
| 652 | + struct drm_panel *panel; | |
| 653 | + struct tc_data *tc; | |
| 654 | + int ret; | |
| 655 | + | |
| 656 | + tc = devm_kzalloc(dev, sizeof(*tc), GFP_KERNEL); | |
| 657 | + if (!tc) | |
| 658 | + return -ENOMEM; | |
| 659 | + | |
| 660 | + tc->dev = dev; | |
| 661 | + tc->i2c = client; | |
| 662 | + | |
| 663 | + ret = drm_of_find_panel_or_bridge(dev->of_node, TC358775_LVDS_OUT0, | |
| 664 | + 0, &panel, NULL); | |
| 665 | + if (ret < 0) | |
| 666 | + return ret; | |
| 667 | + if (!panel) | |
| 668 | + return -ENODEV; | |
| 669 | + | |
| 670 | + tc->panel_bridge = devm_drm_panel_bridge_add(dev, panel); | |
| 671 | + if (IS_ERR(tc->panel_bridge)) | |
| 672 | + return PTR_ERR(tc->panel_bridge); | |
| 673 | + | |
| 674 | + ret = tc358775_parse_dt(dev->of_node, tc); | |
| 675 | + if (ret) | |
| 676 | + return ret; | |
| 677 | + | |
| 678 | + tc->vddio = devm_regulator_get(dev, "vddio-supply"); | |
| 679 | + if (IS_ERR(tc->vddio)) { | |
| 680 | + ret = PTR_ERR(tc->vddio); | |
| 681 | + dev_err(dev, "vddio-supply not found\n"); | |
| 682 | + return ret; | |
| 683 | + } | |
| 684 | + | |
| 685 | + tc->vdd = devm_regulator_get(dev, "vdd-supply"); | |
| 686 | + if (IS_ERR(tc->vdd)) { | |
| 687 | + ret = PTR_ERR(tc->vdd); | |
| 688 | + dev_err(dev, "vdd-supply not found\n"); | |
| 689 | + return ret; | |
| 690 | + } | |
| 691 | + | |
| 692 | + tc->stby_gpio = devm_gpiod_get(dev, "stby", GPIOD_OUT_HIGH); | |
| 693 | + if (IS_ERR(tc->stby_gpio)) { | |
| 694 | + ret = PTR_ERR(tc->stby_gpio); | |
| 695 | + dev_err(dev, "cannot get stby-gpio %d\n", ret); | |
| 696 | + return ret; | |
| 697 | + } | |
| 698 | + | |
| 699 | + tc->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); | |
| 700 | + if (IS_ERR(tc->reset_gpio)) { | |
| 701 | + ret = PTR_ERR(tc->reset_gpio); | |
| 702 | + dev_err(dev, "cannot get reset-gpios %d\n", ret); | |
| 703 | + return ret; | |
| 704 | + } | |
| 705 | + | |
| 706 | + tc->bridge.funcs = &tc_bridge_funcs; | |
| 707 | + tc->bridge.of_node = dev->of_node; | |
| 708 | + drm_bridge_add(&tc->bridge); | |
| 709 | + | |
| 710 | + i2c_set_clientdata(client, tc); | |
| 711 | + | |
| 712 | + return 0; | |
| 713 | +} | |
| 714 | + | |
| 715 | +static int tc_remove(struct i2c_client *client) | |
| 716 | +{ | |
| 717 | + struct tc_data *tc = i2c_get_clientdata(client); | |
| 718 | + | |
| 719 | + drm_bridge_remove(&tc->bridge); | |
| 720 | + | |
| 721 | + return 0; | |
| 722 | +} | |
| 723 | + | |
| 724 | +static const struct i2c_device_id tc358775_i2c_ids[] = { | |
| 725 | + { "tc358775", 0 }, | |
| 726 | + { } | |
| 727 | +}; | |
| 728 | +MODULE_DEVICE_TABLE(i2c, tc358775_i2c_ids); | |
| 729 | + | |
| 730 | +static const struct of_device_id tc358775_of_ids[] = { | |
| 731 | + { .compatible = "toshiba,tc358775", }, | |
| 732 | + { } | |
| 733 | +}; | |
| 734 | +MODULE_DEVICE_TABLE(of, tc358775_of_ids); | |
| 735 | + | |
| 736 | +static struct i2c_driver tc358775_driver = { | |
| 737 | + .driver = { | |
| 738 | + .name = "tc358775", | |
| 739 | + .of_match_table = tc358775_of_ids, | |
| 740 | + }, | |
| 741 | + .id_table = tc358775_i2c_ids, | |
| 742 | + .probe = tc_probe, | |
| 743 | + .remove = tc_remove, | |
| 744 | +}; | |
| 745 | +module_i2c_driver(tc358775_driver); | |
| 746 | + | |
| 747 | +MODULE_AUTHOR("Vinay Simha BN <simhavcs@gmail.com>"); | |
| 748 | +MODULE_DESCRIPTION("TC358775 DSI/LVDS bridge driver"); | |
| 749 | +MODULE_LICENSE("GPL v2"); | |
| @@ -394,9 +394,6 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge, · 393 unmodified lines | ||
| 394 | 394 | } |
| 395 | 395 | pdata->dsi = dsi; |
| 396 | 396 | |
| 397 | − /* attach panel to bridge */ | |
| 398 | − drm_panel_attach(pdata->panel, &pdata->connector); | |
| 399 | − | |
| 400 | 397 | return 0; |
| 401 | 398 | |
| 402 | 399 | err_dsi_attach: |
| @@ -187,6 +187,7 @@ drm_bridge_connector_detect(struct drm_connector *connector, bool force) · 186 unmodified lines | ||
| 187 | 187 | case DRM_MODE_CONNECTOR_DPI: |
| 188 | 188 | case DRM_MODE_CONNECTOR_LVDS: |
| 189 | 189 | case DRM_MODE_CONNECTOR_DSI: |
| 190 | + case DRM_MODE_CONNECTOR_eDP: | |
| 190 | 191 | status = connector_status_connected; |
| 191 | 192 | break; |
| 192 | 193 | default: |
| @@ -850,7 +850,7 @@ static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { · 849 unmodified lines | ||
| 850 | 850 | DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) |
| 851 | 851 | |
| 852 | 852 | static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { |
| 853 | − { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ | |
| 853 | + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ | |
| 854 | 854 | { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ |
| 855 | 855 | { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ |
| 856 | 856 | }; |
| @@ -867,7 +867,7 @@ static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { · 10 unmodified lines | ||
| 867 | 867 | DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) |
| 868 | 868 | |
| 869 | 869 | static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { |
| 870 | − { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ | |
| 870 | + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ | |
| 871 | 871 | { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ |
| 872 | 872 | { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ |
| 873 | 873 | { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ |
| @@ -876,6 +876,19 @@ static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { · 2 unmodified lines | ||
| 876 | 876 | DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, |
| 877 | 877 | drm_tv_subconnector_enum_list) |
| 878 | 878 | |
| 879 | +static const struct drm_prop_enum_list drm_dp_subconnector_enum_list[] = { | |
| 880 | + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ | |
| 881 | + { DRM_MODE_SUBCONNECTOR_VGA, "VGA" }, /* DP */ | |
| 882 | + { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DP */ | |
| 883 | + { DRM_MODE_SUBCONNECTOR_HDMIA, "HDMI" }, /* DP */ | |
| 884 | + { DRM_MODE_SUBCONNECTOR_DisplayPort, "DP" }, /* DP */ | |
| 885 | + { DRM_MODE_SUBCONNECTOR_Wireless, "Wireless" }, /* DP */ | |
| 886 | + { DRM_MODE_SUBCONNECTOR_Native, "Native" }, /* DP */ | |
| 887 | +}; | |
| 888 | + | |
| 889 | +DRM_ENUM_NAME_FN(drm_get_dp_subconnector_name, | |
| 890 | + drm_dp_subconnector_enum_list) | |
| 891 | + | |
| 879 | 892 | static const struct drm_prop_enum_list hdmi_colorspaces[] = { |
| 880 | 893 | /* For Default case, driver will set the colorspace */ |
| 881 | 894 | { DRM_MODE_COLORIMETRY_DEFAULT, "Default" }, |
| @@ -1217,6 +1230,14 @@ static const struct drm_prop_enum_list dp_colorspaces[] = { · 335 unmodified lines | ||
| 1217 | 1230 | * can also expose this property to external outputs, in which case they |
| 1218 | 1231 | * must support "None", which should be the default (since external screens |
| 1219 | 1232 | * have a built-in scaler). |
| 1233 | + * | |
| 1234 | + * subconnector: | |
| 1235 | + * This property is used by DVI-I, TVout and DisplayPort to indicate different | |
| 1236 | + * connector subtypes. Enum values more or less match with those from main | |
| 1237 | + * connector types. | |
| 1238 | + * For DVI-I and TVout there is also a matching property "select subconnector" | |
| 1239 | + * allowing to switch between signal types. | |
| 1240 | + * DP subconnector corresponds to a downstream port. | |
| 1220 | 1241 | */ |
| 1221 | 1242 | |
| 1222 | 1243 | int drm_connector_create_standard_properties(struct drm_device *dev) |
| @@ -1305,6 +1326,30 @@ int drm_mode_create_dvi_i_properties(struct drm_device *dev) · 82 unmodified lines | ||
| 1305 | 1326 | } |
| 1306 | 1327 | EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); |
| 1307 | 1328 | |
| 1329 | +/** | |
| 1330 | + * drm_connector_attach_dp_subconnector_property - create subconnector property for DP | |
| 1331 | + * @connector: drm_connector to attach property | |
| 1332 | + * | |
| 1333 | + * Called by a driver when DP connector is created. | |
| 1334 | + */ | |
| 1335 | +void drm_connector_attach_dp_subconnector_property(struct drm_connector *connector) | |
| 1336 | +{ | |
| 1337 | + struct drm_mode_config *mode_config = &connector->dev->mode_config; | |
| 1338 | + | |
| 1339 | + if (!mode_config->dp_subconnector_property) | |
| 1340 | + mode_config->dp_subconnector_property = | |
| 1341 | + drm_property_create_enum(connector->dev, | |
| 1342 | + DRM_MODE_PROP_IMMUTABLE, | |
| 1343 | + "subconnector", | |
| 1344 | + drm_dp_subconnector_enum_list, | |
| 1345 | + ARRAY_SIZE(drm_dp_subconnector_enum_list)); | |
| 1346 | + | |
| 1347 | + drm_object_attach_property(&connector->base, | |
| 1348 | + mode_config->dp_subconnector_property, | |
| 1349 | + DRM_MODE_SUBCONNECTOR_Unknown); | |
| 1350 | +} | |
| 1351 | +EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property); | |
| 1352 | + | |
| 1308 | 1353 | /** |
| 1309 | 1354 | * DOC: HDMI connector properties |
| 1310 | 1355 | * |
| @@ -597,6 +597,77 @@ void drm_dp_downstream_debug(struct seq_file *m, · 596 unmodified lines | ||
| 597 | 597 | } |
| 598 | 598 | EXPORT_SYMBOL(drm_dp_downstream_debug); |
| 599 | 599 | |
| 600 | +/** | |
| 601 | + * drm_dp_subconnector_type() - get DP branch device type | |
| 602 | + * | |
| 603 | + */ | |
| 604 | +enum drm_mode_subconnector | |
| 605 | +drm_dp_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE], | |
| 606 | + const u8 port_cap[4]) | |
| 607 | +{ | |
| 608 | + int type; | |
| 609 | + if (!drm_dp_is_branch(dpcd)) | |
| 610 | + return DRM_MODE_SUBCONNECTOR_Native; | |
| 611 | + /* DP 1.0 approach */ | |
| 612 | + if (dpcd[DP_DPCD_REV] == DP_DPCD_REV_10) { | |
| 613 | + type = dpcd[DP_DOWNSTREAMPORT_PRESENT] & | |
| 614 | + DP_DWN_STRM_PORT_TYPE_MASK; | |
| 615 | + | |
| 616 | + switch (type) { | |
| 617 | + case DP_DWN_STRM_PORT_TYPE_TMDS: | |
| 618 | + /* Can be HDMI or DVI-D, DVI-D is a safer option */ | |
| 619 | + return DRM_MODE_SUBCONNECTOR_DVID; | |
| 620 | + case DP_DWN_STRM_PORT_TYPE_ANALOG: | |
| 621 | + /* Can be VGA or DVI-A, VGA is more popular */ | |
| 622 | + return DRM_MODE_SUBCONNECTOR_VGA; | |
| 623 | + case DP_DWN_STRM_PORT_TYPE_DP: | |
| 624 | + return DRM_MODE_SUBCONNECTOR_DisplayPort; | |
| 625 | + case DP_DWN_STRM_PORT_TYPE_OTHER: | |
| 626 | + default: | |
| 627 | + return DRM_MODE_SUBCONNECTOR_Unknown; | |
| 628 | + } | |
| 629 | + } | |
| 630 | + type = port_cap[0] & DP_DS_PORT_TYPE_MASK; | |
| 631 | + | |
| 632 | + switch (type) { | |
| 633 | + case DP_DS_PORT_TYPE_DP: | |
| 634 | + case DP_DS_PORT_TYPE_DP_DUALMODE: | |
| 635 | + return DRM_MODE_SUBCONNECTOR_DisplayPort; | |
| 636 | + case DP_DS_PORT_TYPE_VGA: | |
| 637 | + return DRM_MODE_SUBCONNECTOR_VGA; | |
| 638 | + case DP_DS_PORT_TYPE_DVI: | |
| 639 | + return DRM_MODE_SUBCONNECTOR_DVID; | |
| 640 | + case DP_DS_PORT_TYPE_HDMI: | |
| 641 | + return DRM_MODE_SUBCONNECTOR_HDMIA; | |
| 642 | + case DP_DS_PORT_TYPE_WIRELESS: | |
| 643 | + return DRM_MODE_SUBCONNECTOR_Wireless; | |
| 644 | + case DP_DS_PORT_TYPE_NON_EDID: | |
| 645 | + default: | |
| 646 | + return DRM_MODE_SUBCONNECTOR_Unknown; | |
| 647 | + } | |
| 648 | +} | |
| 649 | +EXPORT_SYMBOL(drm_dp_subconnector_type); | |
| 650 | + | |
| 651 | +/** | |
| 652 | + * drm_mode_set_dp_subconnector_property - set subconnector for DP connector | |
| 653 | + * | |
| 654 | + * Called by a driver on every detect event. | |
| 655 | + */ | |
| 656 | +void drm_dp_set_subconnector_property(struct drm_connector *connector, | |
| 657 | + enum drm_connector_status status, | |
| 658 | + const u8 *dpcd, | |
| 659 | + const u8 port_cap[4]) | |
| 660 | +{ | |
| 661 | + enum drm_mode_subconnector subconnector = DRM_MODE_SUBCONNECTOR_Unknown; | |
| 662 | + | |
| 663 | + if (status == connector_status_connected) | |
| 664 | + subconnector = drm_dp_subconnector_type(dpcd, port_cap); | |
| 665 | + drm_object_property_set_value(&connector->base, | |
| 666 | + connector->dev->mode_config.dp_subconnector_property, | |
| 667 | + subconnector); | |
| 668 | +} | |
| 669 | +EXPORT_SYMBOL(drm_dp_set_subconnector_property); | |
| 670 | + | |
| 600 | 671 | /* |
| 601 | 672 | * I2C-over-AUX implementation |
| 602 | 673 | */ |
| @@ -653,7 +653,7 @@ static void drm_gem_vram_bo_driver_evict_flags(struct drm_gem_vram_object *gbo, · 652 unmodified lines | ||
| 653 | 653 | |
| 654 | 654 | static void drm_gem_vram_bo_driver_move_notify(struct drm_gem_vram_object *gbo, |
| 655 | 655 | bool evict, |
| 656 | − struct ttm_mem_reg *new_mem) | |
| 656 | + struct ttm_resource *new_mem) | |
| 657 | 657 | { |
| 658 | 658 | struct ttm_bo_kmap_obj *kmap = &gbo->kmap; |
| 659 | 659 | |
| @@ -1004,28 +1004,6 @@ err_ttm_tt_init: · 344 unmodified lines | ||
| 1004 | 1004 | return NULL; |
| 1005 | 1005 | } |
| 1006 | 1006 | |
| 1007 | −static int bo_driver_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | |
| 1008 | − struct ttm_mem_type_manager *man) | |
| 1009 | −{ | |
| 1010 | − switch (type) { | |
| 1011 | − case TTM_PL_SYSTEM: | |
| 1012 | − man->flags = 0; | |
| 1013 | − man->available_caching = TTM_PL_MASK_CACHING; | |
| 1014 | − man->default_caching = TTM_PL_FLAG_CACHED; | |
| 1015 | − break; | |
| 1016 | − case TTM_PL_VRAM: | |
| 1017 | − man->func = &ttm_bo_manager_func; | |
| 1018 | − man->flags = TTM_MEMTYPE_FLAG_FIXED; | |
| 1019 | − man->available_caching = TTM_PL_FLAG_UNCACHED | | |
| 1020 | − TTM_PL_FLAG_WC; | |
| 1021 | − man->default_caching = TTM_PL_FLAG_WC; | |
| 1022 | − break; | |
| 1023 | − default: | |
| 1024 | − return -EINVAL; | |
| 1025 | − } | |
| 1026 | − return 0; | |
| 1027 | −} | |
| 1028 | − | |
| 1029 | 1007 | static void bo_driver_evict_flags(struct ttm_buffer_object *bo, |
| 1030 | 1008 | struct ttm_placement *placement) |
| 1031 | 1009 | { |
| @@ -1042,7 +1020,7 @@ static void bo_driver_evict_flags(struct ttm_buffer_object *bo, · 10 unmodified lines | ||
| 1042 | 1020 | |
| 1043 | 1021 | static void bo_driver_move_notify(struct ttm_buffer_object *bo, |
| 1044 | 1022 | bool evict, |
| 1045 | − struct ttm_mem_reg *new_mem) | |
| 1023 | + struct ttm_resource *new_mem) | |
| 1046 | 1024 | { |
| 1047 | 1025 | struct drm_gem_vram_object *gbo; |
| 1048 | 1026 | |
| @@ -1056,18 +1034,12 @@ static void bo_driver_move_notify(struct ttm_buffer_object *bo, · 7 unmodified lines | ||
| 1056 | 1034 | } |
| 1057 | 1035 | |
| 1058 | 1036 | static int bo_driver_io_mem_reserve(struct ttm_bo_device *bdev, |
| 1059 | − struct ttm_mem_reg *mem) | |
| 1037 | + struct ttm_resource *mem) | |
| 1060 | 1038 | { |
| 1061 | 1039 | struct drm_vram_mm *vmm = drm_vram_mm_of_bdev(bdev); |
| 1062 | 1040 | |
| 1063 | − mem->bus.addr = NULL; | |
| 1064 | − mem->bus.size = mem->num_pages << PAGE_SHIFT; | |
| 1065 | − | |
| 1066 | 1041 | switch (mem->mem_type) { |
| 1067 | 1042 | case TTM_PL_SYSTEM: /* nothing to do */ |
| 1068 | − mem->bus.offset = 0; | |
| 1069 | − mem->bus.base = 0; | |
| 1070 | − mem->bus.is_iomem = false; | |
| 1071 | 1043 | break; |
| 1072 | 1044 | case TTM_PL_VRAM: |
| 1073 | 1045 | mem->bus.offset = mem->start << PAGE_SHIFT; |
| @@ -1083,9 +1055,6 @@ static int bo_driver_io_mem_reserve(struct ttm_bo_device *bdev, · 9 unmodified lines | ||
| 1083 | 1055 | |
| 1084 | 1056 | static struct ttm_bo_driver bo_driver = { |
| 1085 | 1057 | .ttm_tt_create = bo_driver_ttm_tt_create, |
| 1086 | − .ttm_tt_populate = ttm_pool_populate, | |
| 1087 | − .ttm_tt_unpopulate = ttm_pool_unpopulate, | |
| 1088 | − .init_mem_type = bo_driver_init_mem_type, | |
| 1089 | 1058 | .eviction_valuable = ttm_bo_eviction_valuable, |
| 1090 | 1059 | .evict_flags = bo_driver_evict_flags, |
| 1091 | 1060 | .move_notify = bo_driver_move_notify, |
| @@ -1100,12 +1069,10 @@ static int drm_vram_mm_debugfs(struct seq_file *m, void *data) · 8 unmodified lines | ||
| 1100 | 1069 | { |
| 1101 | 1070 | struct drm_info_node *node = (struct drm_info_node *) m->private; |
| 1102 | 1071 | struct drm_vram_mm *vmm = node->minor->dev->vram_mm; |
| 1103 | − struct drm_mm *mm = vmm->bdev.man[TTM_PL_VRAM].priv; | |
| 1072 | + struct ttm_resource_manager *man = ttm_manager_type(&vmm->bdev, TTM_PL_VRAM); | |
| 1104 | 1073 | struct drm_printer p = drm_seq_file_printer(m); |
| 1105 | 1074 | |
| 1106 | − spin_lock(&ttm_bo_glob.lru_lock); | |
| 1107 | − drm_mm_print(mm, &p); | |
| 1108 | − spin_unlock(&ttm_bo_glob.lru_lock); | |
| 1075 | + ttm_resource_manager_debug(man, &p); | |
| 1109 | 1076 | return 0; |
| 1110 | 1077 | } |
| 1111 | 1078 | |
| @@ -1142,7 +1109,10 @@ static int drm_vram_mm_init(struct drm_vram_mm *vmm, struct drm_device *dev, · 30 unmodified lines | ||
| 1142 | 1109 | if (ret) |
| 1143 | 1110 | return ret; |
| 1144 | 1111 | |
| 1145 | − ret = ttm_bo_init_mm(&vmm->bdev, TTM_PL_VRAM, vram_size >> PAGE_SHIFT); | |
| 1112 | + ret = ttm_range_man_init(&vmm->bdev, TTM_PL_VRAM, | |
| 1113 | + TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC, | |
| 1114 | + TTM_PL_FLAG_WC, false, | |
| 1115 | + vram_size >> PAGE_SHIFT); | |
| 1146 | 1116 | if (ret) |
| 1147 | 1117 | return ret; |
| 1148 | 1118 | |
| @@ -1151,6 +1121,7 @@ static int drm_vram_mm_init(struct drm_vram_mm *vmm, struct drm_device *dev, · 2 unmodified lines | ||
| 1151 | 1121 | |
| 1152 | 1122 | static void drm_vram_mm_cleanup(struct drm_vram_mm *vmm) |
| 1153 | 1123 | { |
| 1124 | + ttm_range_man_fini(&vmm->bdev, TTM_PL_VRAM); | |
| 1154 | 1125 | ttm_bo_device_release(&vmm->bdev); |
| 1155 | 1126 | } |
| 1156 | 1127 | |
| @@ -70,16 +70,12 @@ EXPORT_SYMBOL(drm_panel_init); · 69 unmodified lines | ||
| 70 | 70 | * |
| 71 | 71 | * Add a panel to the global registry so that it can be looked up by display |
| 72 | 72 | * drivers. |
| 73 | − * | |
| 74 | − * Return: 0 on success or a negative error code on failure. | |
| 75 | 73 | */ |
| 76 | −int drm_panel_add(struct drm_panel *panel) | |
| 74 | +void drm_panel_add(struct drm_panel *panel) | |
| 77 | 75 | { |
| 78 | 76 | mutex_lock(&panel_lock); |
| 79 | 77 | list_add_tail(&panel->list, &panel_list); |
| 80 | 78 | mutex_unlock(&panel_lock); |
| 81 | − | |
| 82 | − return 0; | |
| 83 | 79 | } |
| 84 | 80 | EXPORT_SYMBOL(drm_panel_add); |
| 85 | 81 | |
| @@ -97,42 +93,6 @@ void drm_panel_remove(struct drm_panel *panel) · 11 unmodified lines | ||
| 97 | 93 | } |
| 98 | 94 | EXPORT_SYMBOL(drm_panel_remove); |
| 99 | 95 | |
| 100 | −/** | |
| 101 | − * drm_panel_attach - attach a panel to a connector | |
| 102 | − * @panel: DRM panel | |
| 103 | − * @connector: DRM connector | |
| 104 | − * | |
| 105 | − * After obtaining a pointer to a DRM panel a display driver calls this | |
| 106 | − * function to attach a panel to a connector. | |
| 107 | − * | |
| 108 | − * An error is returned if the panel is already attached to another connector. | |
| 109 | − * | |
| 110 | − * When unloading, the driver should detach from the panel by calling | |
| 111 | − * drm_panel_detach(). | |
| 112 | − * | |
| 113 | − * Return: 0 on success or a negative error code on failure. | |
| 114 | − */ | |
| 115 | −int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector) | |
| 116 | −{ | |
| 117 | − return 0; | |
| 118 | −} | |
| 119 | −EXPORT_SYMBOL(drm_panel_attach); | |
| 120 | − | |
| 121 | −/** | |
| 122 | − * drm_panel_detach - detach a panel from a connector | |
| 123 | − * @panel: DRM panel | |
| 124 | − * | |
| 125 | − * Detaches a panel from the connector it is attached to. If a panel is not | |
| 126 | − * attached to any connector this is effectively a no-op. | |
| 127 | − * | |
| 128 | − * This function should not be called by the panel device itself. It | |
| 129 | − * is only for the drm device that called drm_panel_attach(). | |
| 130 | − */ | |
| 131 | −void drm_panel_detach(struct drm_panel *panel) | |
| 132 | −{ | |
| 133 | −} | |
| 134 | −EXPORT_SYMBOL(drm_panel_detach); | |
| 135 | − | |
| 136 | 96 | /** |
| 137 | 97 | * drm_panel_prepare - power on a panel |
| 138 | 98 | * @panel: DRM panel |
| @@ -300,6 +260,49 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np) · 161 unmodified lines | ||
| 300 | 260 | return ERR_PTR(-EPROBE_DEFER); |
| 301 | 261 | } |
| 302 | 262 | EXPORT_SYMBOL(of_drm_find_panel); |
| 263 | + | |
| 264 | +/** | |
| 265 | + * of_drm_get_panel_orientation - look up the orientation of the panel through | |
| 266 | + * the "rotation" binding from a device tree node | |
| 267 | + * @np: device tree node of the panel | |
| 268 | + * @orientation: orientation enum to be filled in | |
| 269 | + * | |
| 270 | + * Looks up the rotation of a panel in the device tree. The orientation of the | |
| 271 | + * panel is expressed as a property name "rotation" in the device tree. The | |
| 272 | + * rotation in the device tree is counter clockwise. | |
| 273 | + * | |
| 274 | + * Return: 0 when a valid rotation value (0, 90, 180, or 270) is read or the | |
| 275 | + * rotation property doesn't exist. Return a negative error code on failure. | |
| 276 | + */ | |
| 277 | +int of_drm_get_panel_orientation(const struct device_node *np, | |
| 278 | + enum drm_panel_orientation *orientation) | |
| 279 | +{ | |
| 280 | + int rotation, ret; | |
| 281 | + | |
| 282 | + ret = of_property_read_u32(np, "rotation", &rotation); | |
| 283 | + if (ret == -EINVAL) { | |
| 284 | + /* Don't return an error if there's no rotation property. */ | |
| 285 | + *orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; | |
| 286 | + return 0; | |
| 287 | + } | |
| 288 | + | |
| 289 | + if (ret < 0) | |
| 290 | + return ret; | |
| 291 | + | |
| 292 | + if (rotation == 0) | |
| 293 | + *orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL; | |
| 294 | + else if (rotation == 90) | |
| 295 | + *orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP; | |
| 296 | + else if (rotation == 180) | |
| 297 | + *orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP; | |
| 298 | + else if (rotation == 270) | |
| 299 | + *orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP; | |
| 300 | + else | |
| 301 | + return -EINVAL; | |
| 302 | + | |
| 303 | + return 0; | |
| 304 | +} | |
| 305 | +EXPORT_SYMBOL(of_drm_get_panel_orientation); | |
| 303 | 306 | #endif |
| 304 | 307 | |
| 305 | 308 | #if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE) |
| @@ -297,7 +297,7 @@ void drm_syncobj_add_point(struct drm_syncobj *syncobj, · 296 unmodified lines | ||
| 297 | 297 | prev = drm_syncobj_fence_get(syncobj); |
| 298 | 298 | /* You are adding an unorder point to timeline, which could cause payload returned from query_ioctl is 0! */ |
| 299 | 299 | if (prev && prev->seqno >= point) |
| 300 | − DRM_ERROR("You are adding an unorder point to timeline!\n"); | |
| 300 | + DRM_DEBUG("You are adding an unorder point to timeline!\n"); | |
| 301 | 301 | dma_fence_chain_init(chain, prev, fence, point); |
| 302 | 302 | rcu_assign_pointer(syncobj->fence, &chain->base); |
| 303 | 303 | |
| @@ -42,11 +42,6 @@ static inline struct exynos_dpi *encoder_to_dpi(struct drm_encoder *e) · 41 unmodified lines | ||
| 42 | 42 | static enum drm_connector_status |
| 43 | 43 | exynos_dpi_detect(struct drm_connector *connector, bool force) |
| 44 | 44 | { |
| 45 | − struct exynos_dpi *ctx = connector_to_dpi(connector); | |
| 46 | − | |
| 47 | − if (ctx->panel) | |
| 48 | − drm_panel_attach(ctx->panel, &ctx->connector); | |
| 49 | − | |
| 50 | 45 | return connector_status_connected; |
| 51 | 46 | } |
| 52 | 47 | |
| @@ -249,8 +244,5 @@ int exynos_dpi_remove(struct drm_encoder *encoder) · 196 unmodified lines | ||
| 249 | 244 | |
| 250 | 245 | exynos_dpi_disable(&ctx->encoder); |
| 251 | 246 | |
| 252 | − if (ctx->panel) | |
| 253 | − drm_panel_detach(ctx->panel); | |
| 254 | − | |
| 255 | 247 | return 0; |
| 256 | 248 | } |
| @@ -1551,12 +1551,10 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host, · 1550 unmodified lines | ||
| 1551 | 1551 | } |
| 1552 | 1552 | |
| 1553 | 1553 | dsi->panel = of_drm_find_panel(device->dev.of_node); |
| 1554 | − if (IS_ERR(dsi->panel)) { | |
| 1554 | + if (IS_ERR(dsi->panel)) | |
| 1555 | 1555 | dsi->panel = NULL; |
| 1556 | − } else { | |
| 1557 | − drm_panel_attach(dsi->panel, &dsi->connector); | |
| 1556 | + else | |
| 1558 | 1557 | dsi->connector.status = connector_status_connected; |
| 1559 | − } | |
| 1560 | 1558 | } |
| 1561 | 1559 | |
| 1562 | 1560 | /* |
| @@ -1596,7 +1594,6 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host, · 33 unmodified lines | ||
| 1596 | 1594 | if (dsi->panel) { |
| 1597 | 1595 | mutex_lock(&drm->mode_config.mutex); |
| 1598 | 1596 | exynos_dsi_disable(&dsi->encoder); |
| 1599 | − drm_panel_detach(dsi->panel); | |
| 1600 | 1597 | dsi->panel = NULL; |
| 1601 | 1598 | dsi->connector.status = connector_status_disconnected; |
| 1602 | 1599 | mutex_unlock(&drm->mode_config.mutex); |
| @@ -40,10 +40,7 @@ int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev, · 39 unmodified lines | ||
| 40 | 40 | |
| 41 | 41 | static void fsl_dcu_drm_connector_destroy(struct drm_connector *connector) |
| 42 | 42 | { |
| 43 | − struct fsl_dcu_drm_connector *fsl_con = to_fsl_dcu_connector(connector); | |
| 44 | − | |
| 45 | 43 | drm_connector_unregister(connector); |
| 46 | − drm_panel_detach(fsl_con->panel); | |
| 47 | 44 | drm_connector_cleanup(connector); |
| 48 | 45 | } |
| 49 | 46 | |
| @@ -101,12 +98,6 @@ static int fsl_dcu_attach_panel(struct fsl_dcu_drm_device *fsl_dev, · 51 unmodified lines | ||
| 101 | 98 | if (ret < 0) |
| 102 | 99 | goto err_sysfs; |
| 103 | 100 | |
| 104 | − ret = drm_panel_attach(panel, connector); | |
| 105 | − if (ret) { | |
| 106 | − dev_err(fsl_dev->dev, "failed to attach panel\n"); | |
| 107 | − goto err_sysfs; | |
| 108 | − } | |
| 109 | − | |
| 110 | 101 | return 0; |
| 111 | 102 | |
| 112 | 103 | err_sysfs: |
| @@ -2078,7 +2078,7 @@ cdv_intel_dp_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev · 2077 unmodified lines | ||
| 2078 | 2078 | intel_dp->dpcd, |
| 2079 | 2079 | sizeof(intel_dp->dpcd)); |
| 2080 | 2080 | cdv_intel_edp_panel_vdd_off(gma_encoder); |
| 2081 | − if (ret == 0) { | |
| 2081 | + if (ret <= 0) { | |
| 2082 | 2082 | /* if this fails, presume the device is a ghost */ |
| 2083 | 2083 | DRM_INFO("failed to retrieve link info, disabling eDP\n"); |
| 2084 | 2084 | drm_encoder_cleanup(encoder); |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | **************************************************************************/ |
| 7 | 7 | |
| 8 | 8 | #include <linux/delay.h> |
| 9 | +#include <linux/gpio/machine.h> | |
| 9 | 10 | |
| 10 | 11 | #include <asm/intel_scu_ipc.h> |
| 11 | 12 | |
| @@ -505,12 +506,31 @@ static const struct psb_offset mdfld_regmap[3] = { · 493 unmodified lines | ||
| 505 | 506 | }, |
| 506 | 507 | }; |
| 507 | 508 | |
| 509 | +/* | |
| 510 | + * The GPIO lines for resetting DSI pipe 0 and 2 are available in the | |
| 511 | + * PCI device 0000:00:0c.0 on the Medfield. | |
| 512 | + */ | |
| 513 | +static struct gpiod_lookup_table mdfld_dsi_pipe_gpio_table = { | |
| 514 | + .table = { | |
| 515 | + GPIO_LOOKUP("0000:00:0c.0", 128, "dsi-pipe0-reset", | |
| 516 | + GPIO_ACTIVE_HIGH), | |
| 517 | + GPIO_LOOKUP("0000:00:0c.0", 34, "dsi-pipe2-reset", | |
| 518 | + GPIO_ACTIVE_HIGH), | |
| 519 | + { }, | |
| 520 | + }, | |
| 521 | +}; | |
| 522 | + | |
| 508 | 523 | static int mdfld_chip_setup(struct drm_device *dev) |
| 509 | 524 | { |
| 510 | 525 | struct drm_psb_private *dev_priv = dev->dev_private; |
| 511 | 526 | if (pci_enable_msi(dev->pdev)) |
| 512 | 527 | dev_warn(dev->dev, "Enabling MSI failed!\n"); |
| 513 | 528 | dev_priv->regmap = mdfld_regmap; |
| 529 | + | |
| 530 | + /* Associate the GPIO lines with the DRM device */ | |
| 531 | + mdfld_dsi_pipe_gpio_table.dev_id = dev_name(dev->dev); | |
| 532 | + gpiod_add_lookup_table(&mdfld_dsi_pipe_gpio_table); | |
| 533 | + | |
| 514 | 534 | return mid_chip_setup(dev); |
| 515 | 535 | } |
| 516 | 536 | |
| @@ -955,7 +955,7 @@ struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev, · 954 unmodified lines | ||
| 955 | 955 | |
| 956 | 956 | /* panel hard-reset */ |
| 957 | 957 | if (p_funcs->reset) { |
| 958 | − ret = p_funcs->reset(pipe); | |
| 958 | + ret = p_funcs->reset(dev, pipe); | |
| 959 | 959 | if (ret) { |
| 960 | 960 | DRM_ERROR("Panel %d hard-reset failed\n", pipe); |
| 961 | 961 | return NULL; |
| @@ -28,6 +28,7 @@ · 27 unmodified lines | ||
| 28 | 28 | #include <linux/delay.h> |
| 29 | 29 | #include <linux/moduleparam.h> |
| 30 | 30 | #include <linux/pm_runtime.h> |
| 31 | +#include <linux/gpio/consumer.h> | |
| 31 | 32 | |
| 32 | 33 | #include <asm/intel_scu_ipc.h> |
| 33 | 34 | |
| @@ -366,7 +367,7 @@ static enum drm_mode_status mdfld_dsi_connector_mode_valid(struct drm_connector · 332 unmodified lines | ||
| 366 | 367 | /** |
| 367 | 368 | * FIXME: current DC has no fitting unit, reject any mode setting |
| 368 | 369 | * request |
| 369 | − * Will figure out a way to do up-scaling(pannel fitting) later. | |
| 370 | + * Will figure out a way to do up-scaling(panel fitting) later. | |
| 370 | 371 | **/ |
| 371 | 372 | if (fixed_mode) { |
| 372 | 373 | if (mode->hdisplay != fixed_mode->hdisplay) |
| @@ -432,42 +433,42 @@ static int mdfld_dsi_get_default_config(struct drm_device *dev, · 59 unmodified lines | ||
| 432 | 433 | return 0; |
| 433 | 434 | } |
| 434 | 435 | |
| 435 | −int mdfld_dsi_panel_reset(int pipe) | |
| 436 | +int mdfld_dsi_panel_reset(struct drm_device *ddev, int pipe) | |
| 436 | 437 | { |
| 437 | − unsigned gpio; | |
| 438 | − int ret = 0; | |
| 439 | − | |
| 438 | + struct device *dev = ddev->dev; | |
| 439 | + struct gpio_desc *gpiod; | |
| 440 | + | |
| 441 | + /* | |
| 442 | + * Raise the GPIO reset line for the corresponding pipe to HIGH, | |
| 443 | + * this is probably because it is active low so this takes the | |
| 444 | + * respective pipe out of reset. (We have no code to put it back | |
| 445 | + * into reset in this driver.) | |
| 446 | + */ | |
| 440 | 447 | switch (pipe) { |
| 441 | 448 | case 0: |
| 442 | − gpio = 128; | |
| 449 | + gpiod = gpiod_get(dev, "dsi-pipe0-reset", GPIOD_OUT_HIGH); | |
| 450 | + if (IS_ERR(gpiod)) | |
| 451 | + return PTR_ERR(gpiod); | |
| 443 | 452 | break; |
| 444 | 453 | case 2: |
| 445 | − gpio = 34; | |
| 454 | + gpiod = gpiod_get(dev, "dsi-pipe2-reset", GPIOD_OUT_HIGH); | |
| 455 | + if (IS_ERR(gpiod)) | |
| 456 | + return PTR_ERR(gpiod); | |
| 446 | 457 | break; |
| 447 | 458 | default: |
| 448 | − DRM_ERROR("Invalid output\n"); | |
| 459 | + DRM_DEV_ERROR(dev, "Invalid output pipe\n"); | |
| 449 | 460 | return -EINVAL; |
| 450 | 461 | } |
| 462 | + gpiod_put(gpiod); | |
| 451 | 463 | |
| 452 | − ret = gpio_request(gpio, "gfx"); | |
| 453 | − if (ret) { | |
| 454 | − DRM_ERROR("gpio_rqueset failed\n"); | |
| 455 | − return ret; | |
| 456 | − } | |
| 457 | − | |
| 458 | − ret = gpio_direction_output(gpio, 1); | |
| 459 | − if (ret) { | |
| 460 | − DRM_ERROR("gpio_direction_output failed\n"); | |
| 461 | − goto gpio_error; | |
| 462 | − } | |
| 464 | + /* Flush posted writes on the device */ | |
| 465 | + gpiod = gpiod_get(dev, "dsi-pipe0-reset", GPIOD_ASIS); | |
| 466 | + if (IS_ERR(gpiod)) | |
| 467 | + return PTR_ERR(gpiod); | |
| 468 | + gpiod_get_value(gpiod); | |
| 469 | + gpiod_put(gpiod); | |
| 463 | 470 | |
| 464 | − gpio_get_value(128); | |
| 465 | − | |
| 466 | −gpio_error: | |
| 467 | − if (gpio_is_valid(gpio)) | |
| 468 | − gpio_free(gpio); | |
| 469 | − | |
| 470 | − return ret; | |
| 471 | + return 0; | |
| 471 | 472 | } |
| 472 | 473 | |
| 473 | 474 | /* |
| @@ -531,7 +532,7 @@ void mdfld_dsi_output_init(struct drm_device *dev, · 57 unmodified lines | ||
| 531 | 532 | dsi_config->connector = dsi_connector; |
| 532 | 533 | |
| 533 | 534 | if (!dsi_config->fixed_mode) { |
| 534 | − DRM_ERROR("No pannel fixed mode was found\n"); | |
| 535 | + DRM_ERROR("No panel fixed mode was found\n"); | |
| 535 | 536 | goto dsi_init_err0; |
| 536 | 537 | } |
| 537 | 538 | |
| @@ -372,6 +372,6 @@ extern void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config, · 371 unmodified lines | ||
| 372 | 372 | |
| 373 | 373 | extern int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, |
| 374 | 374 | u32 *mode, bool hs); |
| 375 | −extern int mdfld_dsi_panel_reset(int pipe); | |
| 375 | +extern int mdfld_dsi_panel_reset(struct drm_device *dev, int pipe); | |
| 376 | 376 | |
| 377 | 377 | #endif /*__MDFLD_DSI_OUTPUT_H__*/ |
| @@ -54,7 +54,7 @@ struct panel_funcs { · 53 unmodified lines | ||
| 54 | 54 | const struct drm_encoder_helper_funcs *encoder_helper_funcs; |
| 55 | 55 | struct drm_display_mode * (*get_config_mode)(struct drm_device *); |
| 56 | 56 | int (*get_panel_info)(struct drm_device *, int, struct panel_info *); |
| 57 | − int (*reset)(int pipe); | |
| 57 | + int (*reset)(struct drm_device *, int); | |
| 58 | 58 | void (*drv_ic_init)(struct mdfld_dsi_config *dsi_config, int pipe); |
| 59 | 59 | }; |
| 60 | 60 | |
| @@ -13,7 +13,6 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <drm/drm_encoder.h> |
| 14 | 14 | #include <drm/drm_probe_helper.h> |
| 15 | 15 | #include <drm/drm_vblank.h> |
| 16 | −#include <linux/gpio.h> | |
| 17 | 16 | #include "gma_display.h" |
| 18 | 17 | |
| 19 | 18 | /* |
| @@ -125,7 +125,7 @@ struct psb_intel_sdvo { · 124 unmodified lines | ||
| 125 | 125 | bool is_lvds; |
| 126 | 126 | |
| 127 | 127 | /** |
| 128 | − * This is sdvo fixed pannel mode pointer | |
| 128 | + * This is sdvo fixed panel mode pointer | |
| 129 | 129 | */ |
| 130 | 130 | struct drm_display_mode *sdvo_lvds_fixed_mode; |
| 131 | 131 | |
| @@ -17,9 +17,6 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <drm/drm_atomic_helper.h> |
| 18 | 18 | #include <drm/drm_fourcc.h> |
| 19 | 19 | #include <drm/drm_gem_vram_helper.h> |
| 20 | −#include <drm/drm_plane_helper.h> | |
| 21 | −#include <drm/drm_print.h> | |
| 22 | −#include <drm/drm_probe_helper.h> | |
| 23 | 20 | #include <drm/drm_vblank.h> |
| 24 | 21 | |
| 25 | 22 | #include "hibmc_drm_drv.h" |
| @@ -74,12 +71,12 @@ static int hibmc_plane_atomic_check(struct drm_plane *plane, · 48 unmodified lines | ||
| 74 | 71 | return PTR_ERR(crtc_state); |
| 75 | 72 | |
| 76 | 73 | if (src_w != state->crtc_w || src_h != state->crtc_h) { |
| 77 | − DRM_DEBUG_ATOMIC("scale not support\n"); | |
| 74 | + drm_dbg_atomic(plane->dev, "scale not support\n"); | |
| 78 | 75 | return -EINVAL; |
| 79 | 76 | } |
| 80 | 77 | |
| 81 | 78 | if (state->crtc_x < 0 || state->crtc_y < 0) { |
| 82 | − DRM_DEBUG_ATOMIC("crtc_x/y of drm_plane state is invalid\n"); | |
| 79 | + drm_dbg_atomic(plane->dev, "crtc_x/y of drm_plane state is invalid\n"); | |
| 83 | 80 | return -EINVAL; |
| 84 | 81 | } |
| 85 | 82 | |
| @@ -90,12 +87,12 @@ static int hibmc_plane_atomic_check(struct drm_plane *plane, · 4 unmodified lines | ||
| 90 | 87 | crtc_state->adjusted_mode.hdisplay || |
| 91 | 88 | state->crtc_y + state->crtc_h > |
| 92 | 89 | crtc_state->adjusted_mode.vdisplay) { |
| 93 | − DRM_DEBUG_ATOMIC("visible portion of plane is invalid\n"); | |
| 90 | + drm_dbg_atomic(plane->dev, "visible portion of plane is invalid\n"); | |
| 94 | 91 | return -EINVAL; |
| 95 | 92 | } |
| 96 | 93 | |
| 97 | 94 | if (state->fb->pitches[0] % 128 != 0) { |
| 98 | − DRM_DEBUG_ATOMIC("wrong stride with 128-byte aligned\n"); | |
| 95 | + drm_dbg_atomic(plane->dev, "wrong stride with 128-byte aligned\n"); | |
| 99 | 96 | return -EINVAL; |
| 100 | 97 | } |
| 101 | 98 | return 0; |
| @@ -160,37 +157,6 @@ static const struct drm_plane_helper_funcs hibmc_plane_helper_funcs = { · 58 unmodified lines | ||
| 160 | 157 | .atomic_update = hibmc_plane_atomic_update, |
| 161 | 158 | }; |
| 162 | 159 | |
| 163 | −static struct drm_plane *hibmc_plane_init(struct hibmc_drm_private *priv) | |
| 164 | −{ | |
| 165 | − struct drm_device *dev = priv->dev; | |
| 166 | − struct drm_plane *plane; | |
| 167 | − int ret = 0; | |
| 168 | − | |
| 169 | − plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL); | |
| 170 | − if (!plane) { | |
| 171 | − DRM_ERROR("failed to alloc memory when init plane\n"); | |
| 172 | − return ERR_PTR(-ENOMEM); | |
| 173 | − } | |
| 174 | − /* | |
| 175 | − * plane init | |
| 176 | − * TODO: Now only support primary plane, overlay planes | |
| 177 | − * need to do. | |
| 178 | − */ | |
| 179 | − ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs, | |
| 180 | − channel_formats1, | |
| 181 | − ARRAY_SIZE(channel_formats1), | |
| 182 | − NULL, | |
| 183 | − DRM_PLANE_TYPE_PRIMARY, | |
| 184 | − NULL); | |
| 185 | − if (ret) { | |
| 186 | − DRM_ERROR("failed to init plane: %d\n", ret); | |
| 187 | − return ERR_PTR(ret); | |
| 188 | − } | |
| 189 | − | |
| 190 | − drm_plane_helper_add(plane, &hibmc_plane_helper_funcs); | |
| 191 | − return plane; | |
| 192 | −} | |
| 193 | − | |
| 194 | 160 | static void hibmc_crtc_dpms(struct drm_crtc *crtc, int dpms) |
| 195 | 161 | { |
| 196 | 162 | struct hibmc_drm_private *priv = crtc->dev->dev_private; |
| @@ -537,32 +503,34 @@ static const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = { · 340 unmodified lines | ||
| 537 | 503 | int hibmc_de_init(struct hibmc_drm_private *priv) |
| 538 | 504 | { |
| 539 | 505 | struct drm_device *dev = priv->dev; |
| 540 | − struct drm_crtc *crtc; | |
| 541 | − struct drm_plane *plane; | |
| 506 | + struct drm_crtc *crtc = &priv->crtc; | |
| 507 | + struct drm_plane *plane = &priv->primary_plane; | |
| 542 | 508 | int ret; |
| 543 | 509 | |
| 544 | − plane = hibmc_plane_init(priv); | |
| 545 | − if (IS_ERR(plane)) { | |
| 546 | − DRM_ERROR("failed to create plane: %ld\n", PTR_ERR(plane)); | |
| 547 | − return PTR_ERR(plane); | |
| 548 | − } | |
| 510 | + ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs, | |
| 511 | + channel_formats1, | |
| 512 | + ARRAY_SIZE(channel_formats1), | |
| 513 | + NULL, | |
| 514 | + DRM_PLANE_TYPE_PRIMARY, | |
| 515 | + NULL); | |
| 549 | 516 | |
| 550 | − crtc = devm_kzalloc(dev->dev, sizeof(*crtc), GFP_KERNEL); | |
| 551 | − if (!crtc) { | |
| 552 | − DRM_ERROR("failed to alloc memory when init crtc\n"); | |
| 553 | − return -ENOMEM; | |
| 517 | + if (ret) { | |
| 518 | + drm_err(dev, "failed to init plane: %d\n", ret); | |
| 519 | + return ret; | |
| 554 | 520 | } |
| 555 | 521 | |
| 522 | + drm_plane_helper_add(plane, &hibmc_plane_helper_funcs); | |
| 523 | + | |
| 556 | 524 | ret = drm_crtc_init_with_planes(dev, crtc, plane, |
| 557 | 525 | NULL, &hibmc_crtc_funcs, NULL); |
| 558 | 526 | if (ret) { |
| 559 | − DRM_ERROR("failed to init crtc: %d\n", ret); | |
| 527 | + drm_err(dev, "failed to init crtc: %d\n", ret); | |
| 560 | 528 | return ret; |
| 561 | 529 | } |
| 562 | 530 | |
| 563 | 531 | ret = drm_mode_crtc_set_gamma_size(crtc, 256); |
| 564 | 532 | if (ret) { |
| 565 | − DRM_ERROR("failed to set gamma size: %d\n", ret); | |
| 533 | + drm_err(dev, "failed to set gamma size: %d\n", ret); | |
| 566 | 534 | return ret; |
| 567 | 535 | } |
| 568 | 536 | drm_crtc_helper_add(crtc, &hibmc_crtc_helper_funcs); |
| @@ -11,18 +11,14 @@ · 10 unmodified lines | ||
| 11 | 11 | * Jianhua Li <lijianhua@huawei.com> |
| 12 | 12 | */ |
| 13 | 13 | |
| 14 | −#include <linux/console.h> | |
| 15 | 14 | #include <linux/module.h> |
| 16 | 15 | #include <linux/pci.h> |
| 17 | 16 | |
| 18 | 17 | #include <drm/drm_atomic_helper.h> |
| 19 | 18 | #include <drm/drm_drv.h> |
| 20 | −#include <drm/drm_fb_helper.h> | |
| 21 | 19 | #include <drm/drm_gem_vram_helper.h> |
| 22 | 20 | #include <drm/drm_irq.h> |
| 23 | 21 | #include <drm/drm_managed.h> |
| 24 | −#include <drm/drm_print.h> | |
| 25 | −#include <drm/drm_probe_helper.h> | |
| 26 | 22 | #include <drm/drm_vblank.h> |
| 27 | 23 | |
| 28 | 24 | #include "hibmc_drm_drv.h" |
| @@ -102,13 +98,13 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv) · 73 unmodified lines | ||
| 102 | 98 | |
| 103 | 99 | ret = hibmc_de_init(priv); |
| 104 | 100 | if (ret) { |
| 105 | − DRM_ERROR("failed to init de: %d\n", ret); | |
| 101 | + drm_err(priv->dev, "failed to init de: %d\n", ret); | |
| 106 | 102 | return ret; |
| 107 | 103 | } |
| 108 | 104 | |
| 109 | 105 | ret = hibmc_vdac_init(priv); |
| 110 | 106 | if (ret) { |
| 111 | − DRM_ERROR("failed to init vdac: %d\n", ret); | |
| 107 | + drm_err(priv->dev, "failed to init vdac: %d\n", ret); | |
| 112 | 108 | return ret; |
| 113 | 109 | } |
| 114 | 110 | |
| @@ -216,7 +212,7 @@ static int hibmc_hw_map(struct hibmc_drm_private *priv) · 101 unmodified lines | ||
| 216 | 212 | iosize = pci_resource_len(pdev, 1); |
| 217 | 213 | priv->mmio = devm_ioremap(dev->dev, ioaddr, iosize); |
| 218 | 214 | if (!priv->mmio) { |
| 219 | − DRM_ERROR("Cannot map mmio region\n"); | |
| 215 | + drm_err(dev, "Cannot map mmio region\n"); | |
| 220 | 216 | return -ENOMEM; |
| 221 | 217 | } |
| 222 | 218 | |
| @@ -224,7 +220,7 @@ static int hibmc_hw_map(struct hibmc_drm_private *priv) · 1 unmodified line | ||
| 224 | 220 | size = pci_resource_len(pdev, 0); |
| 225 | 221 | priv->fb_map = devm_ioremap(dev->dev, addr, size); |
| 226 | 222 | if (!priv->fb_map) { |
| 227 | − DRM_ERROR("Cannot map framebuffer\n"); | |
| 223 | + drm_err(dev, "Cannot map framebuffer\n"); | |
| 228 | 224 | return -ENOMEM; |
| 229 | 225 | } |
| 230 | 226 | priv->fb_base = addr; |
| @@ -254,9 +250,8 @@ static int hibmc_unload(struct drm_device *dev) · 23 unmodified lines | ||
| 254 | 250 | |
| 255 | 251 | if (dev->irq_enabled) |
| 256 | 252 | drm_irq_uninstall(dev); |
| 257 | − if (priv->msi_enabled) | |
| 258 | − pci_disable_msi(dev->pdev); | |
| 259 | 253 | |
| 254 | + pci_disable_msi(dev->pdev); | |
| 260 | 255 | hibmc_kms_fini(priv); |
| 261 | 256 | hibmc_mm_fini(priv); |
| 262 | 257 | dev->dev_private = NULL; |
| @@ -270,7 +265,7 @@ static int hibmc_load(struct drm_device *dev) · 7 unmodified lines | ||
| 270 | 265 | |
| 271 | 266 | priv = drmm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
| 272 | 267 | if (!priv) { |
| 273 | − DRM_ERROR("no memory to allocate for hibmc_drm_private\n"); | |
| 268 | + drm_err(dev, "no memory to allocate for hibmc_drm_private\n"); | |
| 274 | 269 | return -ENOMEM; |
| 275 | 270 | } |
| 276 | 271 | dev->dev_private = priv; |
| @@ -290,19 +285,17 @@ static int hibmc_load(struct drm_device *dev) · 13 unmodified lines | ||
| 290 | 285 | |
| 291 | 286 | ret = drm_vblank_init(dev, dev->mode_config.num_crtc); |
| 292 | 287 | if (ret) { |
| 293 | − DRM_ERROR("failed to initialize vblank: %d\n", ret); | |
| 288 | + drm_err(dev, "failed to initialize vblank: %d\n", ret); | |
| 294 | 289 | goto err; |
| 295 | 290 | } |
| 296 | 291 | |
| 297 | − priv->msi_enabled = 0; | |
| 298 | 292 | ret = pci_enable_msi(dev->pdev); |
| 299 | 293 | if (ret) { |
| 300 | − DRM_WARN("enabling MSI failed: %d\n", ret); | |
| 294 | + drm_warn(dev, "enabling MSI failed: %d\n", ret); | |
| 301 | 295 | } else { |
| 302 | − priv->msi_enabled = 1; | |
| 303 | 296 | ret = drm_irq_install(dev, dev->pdev->irq); |
| 304 | 297 | if (ret) |
| 305 | − DRM_WARN("install irq failed: %d\n", ret); | |
| 298 | + drm_warn(dev, "install irq failed: %d\n", ret); | |
| 306 | 299 | } |
| 307 | 300 | |
| 308 | 301 | /* reset all the states of crtc/plane/encoder/connector */ |
| @@ -312,7 +305,7 @@ static int hibmc_load(struct drm_device *dev) · 3 unmodified lines | ||
| 312 | 305 | |
| 313 | 306 | err: |
| 314 | 307 | hibmc_unload(dev); |
| 315 | − DRM_ERROR("failed to initialize drm driver: %d\n", ret); | |
| 308 | + drm_err(dev, "failed to initialize drm driver: %d\n", ret); | |
| 316 | 309 | return ret; |
| 317 | 310 | } |
| 318 | 311 | |
| @@ -338,19 +331,19 @@ static int hibmc_pci_probe(struct pci_dev *pdev, · 19 unmodified lines | ||
| 338 | 331 | |
| 339 | 332 | ret = pci_enable_device(pdev); |
| 340 | 333 | if (ret) { |
| 341 | − DRM_ERROR("failed to enable pci device: %d\n", ret); | |
| 334 | + drm_err(dev, "failed to enable pci device: %d\n", ret); | |
| 342 | 335 | goto err_free; |
| 343 | 336 | } |
| 344 | 337 | |
| 345 | 338 | ret = hibmc_load(dev); |
| 346 | 339 | if (ret) { |
| 347 | − DRM_ERROR("failed to load hibmc: %d\n", ret); | |
| 340 | + drm_err(dev, "failed to load hibmc: %d\n", ret); | |
| 348 | 341 | goto err_disable; |
| 349 | 342 | } |
| 350 | 343 | |
| 351 | 344 | ret = drm_dev_register(dev, 0); |
| 352 | 345 | if (ret) { |
| 353 | − DRM_ERROR("failed to register drv for userspace access: %d\n", | |
| 346 | + drm_err(dev, "failed to register drv for userspace access: %d\n", | |
| 354 | 347 | ret); |
| 355 | 348 | goto err_unload; |
| 356 | 349 | } |
| @@ -25,10 +25,11 @@ struct hibmc_drm_private { · 24 unmodified lines | ||
| 25 | 25 | void __iomem *fb_map; |
| 26 | 26 | unsigned long fb_base; |
| 27 | 27 | unsigned long fb_size; |
| 28 | − bool msi_enabled; | |
| 29 | 28 | |
| 30 | 29 | /* drm */ |
| 31 | 30 | struct drm_device *dev; |
| 31 | + struct drm_plane primary_plane; | |
| 32 | + struct drm_crtc crtc; | |
| 32 | 33 | struct drm_encoder encoder; |
| 33 | 34 | struct drm_connector connector; |
| 34 | 35 | bool mode_config_initialized; |
| @@ -11,10 +11,8 @@ · 10 unmodified lines | ||
| 11 | 11 | * Jianhua Li <lijianhua@huawei.com> |
| 12 | 12 | */ |
| 13 | 13 | |
| 14 | −#include <drm/drm_gem_vram_helper.h> | |
| 15 | 14 | #include <drm/drm_atomic_helper.h> |
| 16 | 15 | #include <drm/drm_probe_helper.h> |
| 17 | −#include <drm/drm_crtc_helper.h> | |
| 18 | 16 | #include <drm/drm_print.h> |
| 19 | 17 | |
| 20 | 18 | #include "hibmc_drm_drv.h" |
| @@ -87,7 +85,7 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv) · 66 unmodified lines | ||
| 87 | 85 | ret = drm_encoder_init(dev, encoder, &hibmc_encoder_funcs, |
| 88 | 86 | DRM_MODE_ENCODER_DAC, NULL); |
| 89 | 87 | if (ret) { |
| 90 | − DRM_ERROR("failed to init encoder: %d\n", ret); | |
| 88 | + drm_err(dev, "failed to init encoder: %d\n", ret); | |
| 91 | 89 | return ret; |
| 92 | 90 | } |
| 93 | 91 | |
| @@ -96,7 +94,7 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv) · 2 unmodified lines | ||
| 96 | 94 | ret = drm_connector_init(dev, connector, &hibmc_connector_funcs, |
| 97 | 95 | DRM_MODE_CONNECTOR_VGA); |
| 98 | 96 | if (ret) { |
| 99 | − DRM_ERROR("failed to init connector: %d\n", ret); | |
| 97 | + drm_err(dev, "failed to init connector: %d\n", ret); | |
| 100 | 98 | return ret; |
| 101 | 99 | } |
| 102 | 100 | drm_connector_helper_add(connector, &hibmc_connector_helper_funcs); |
| @@ -32,7 +32,7 @@ int hibmc_mm_init(struct hibmc_drm_private *hibmc) · 31 unmodified lines | ||
| 32 | 32 | hibmc->fb_size); |
| 33 | 33 | if (IS_ERR(vmm)) { |
| 34 | 34 | ret = PTR_ERR(vmm); |
| 35 | − DRM_ERROR("Error initializing VRAM MM; %d\n", ret); | |
| 35 | + drm_err(dev, "Error initializing VRAM MM; %d\n", ret); | |
| 36 | 36 | return ret; |
| 37 | 37 | } |
| 38 | 38 | |
| @@ -6243,6 +6243,11 @@ out: · 6242 unmodified lines | ||
| 6243 | 6243 | */ |
| 6244 | 6244 | intel_display_power_flush_work(dev_priv); |
| 6245 | 6245 | |
| 6246 | + if (!intel_dp_is_edp(intel_dp)) | |
| 6247 | + drm_dp_set_subconnector_property(connector, | |
| 6248 | + status, | |
| 6249 | + intel_dp->dpcd, | |
| 6250 | + intel_dp->downstream_ports); | |
| 6246 | 6251 | return status; |
| 6247 | 6252 | } |
| 6248 | 6253 | |
| @@ -7312,6 +7317,9 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect · 1063 unmodified lines | ||
| 7312 | 7317 | struct drm_i915_private *dev_priv = to_i915(connector->dev); |
| 7313 | 7318 | enum port port = dp_to_dig_port(intel_dp)->base.port; |
| 7314 | 7319 | |
| 7320 | + if (!intel_dp_is_edp(intel_dp)) | |
| 7321 | + drm_connector_attach_dp_subconnector_property(connector); | |
| 7322 | + | |
| 7315 | 7323 | if (!IS_G4X(dev_priv) && port != PORT_A) |
| 7316 | 7324 | intel_attach_force_audio_property(connector); |
| 7317 | 7325 | |
| @@ -455,13 +455,6 @@ static int imx_ldb_register(struct drm_device *drm, · 454 unmodified lines | ||
| 455 | 455 | drm_connector_attach_encoder(&imx_ldb_ch->connector, encoder); |
| 456 | 456 | } |
| 457 | 457 | |
| 458 | − if (imx_ldb_ch->panel) { | |
| 459 | − ret = drm_panel_attach(imx_ldb_ch->panel, | |
| 460 | − &imx_ldb_ch->connector); | |
| 461 | − if (ret) | |
| 462 | − return ret; | |
| 463 | − } | |
| 464 | − | |
| 465 | 458 | return 0; |
| 466 | 459 | } |
| 467 | 460 | |
| @@ -702,9 +695,6 @@ static void imx_ldb_unbind(struct device *dev, struct device *master, · 234 unmodified lines | ||
| 702 | 695 | for (i = 0; i < 2; i++) { |
| 703 | 696 | struct imx_ldb_channel *channel = &imx_ldb->channel[i]; |
| 704 | 697 | |
| 705 | − if (channel->panel) | |
| 706 | − drm_panel_detach(channel->panel); | |
| 707 | − | |
| 708 | 698 | kfree(channel->edid); |
| 709 | 699 | i2c_put_adapter(channel->ddc); |
| 710 | 700 | } |
| @@ -289,9 +289,6 @@ static int imx_pd_register(struct drm_device *drm, · 288 unmodified lines | ||
| 289 | 289 | DRM_MODE_CONNECTOR_DPI); |
| 290 | 290 | } |
| 291 | 291 | |
| 292 | − if (imxpd->panel) | |
| 293 | − drm_panel_attach(imxpd->panel, &imxpd->connector); | |
| 294 | − | |
| 295 | 292 | if (imxpd->next_bridge) { |
| 296 | 293 | ret = drm_bridge_attach(encoder, imxpd->next_bridge, |
| 297 | 294 | &imxpd->bridge, 0); |
| @@ -357,9 +354,6 @@ static void imx_pd_unbind(struct device *dev, struct device *master, · 59 unmodified lines | ||
| 357 | 354 | { |
| 358 | 355 | struct imx_parallel_display *imxpd = dev_get_drvdata(dev); |
| 359 | 356 | |
| 360 | − if (imxpd->panel) | |
| 361 | − drm_panel_detach(imxpd->panel); | |
| 362 | − | |
| 363 | 357 | kfree(imxpd->edid); |
| 364 | 358 | } |
| 365 | 359 | |
| @@ -199,26 +199,20 @@ static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc, · 198 unmodified lines | ||
| 199 | 199 | { |
| 200 | 200 | struct ingenic_drm *priv = drm_crtc_get_priv(crtc); |
| 201 | 201 | struct drm_plane_state *f1_state, *f0_state, *ipu_state = NULL; |
| 202 | − long rate; | |
| 203 | − | |
| 204 | − if (!drm_atomic_crtc_needs_modeset(state)) | |
| 205 | − return 0; | |
| 206 | − | |
| 207 | − if (state->mode.hdisplay > priv->soc_info->max_width || | |
| 208 | − state->mode.vdisplay > priv->soc_info->max_height) | |
| 209 | − return -EINVAL; | |
| 210 | 202 | |
| 211 | − rate = clk_round_rate(priv->pix_clk, | |
| 212 | − state->adjusted_mode.clock * 1000); | |
| 213 | − if (rate < 0) | |
| 214 | − return rate; | |
| 215 | − | |
| 216 | − if (priv->soc_info->has_osd) { | |
| 203 | + if (drm_atomic_crtc_needs_modeset(state) && priv->soc_info->has_osd) { | |
| 217 | 204 | f1_state = drm_atomic_get_plane_state(state->state, &priv->f1); |
| 205 | + if (IS_ERR(f1_state)) | |
| 206 | + return PTR_ERR(f1_state); | |
| 207 | + | |
| 218 | 208 | f0_state = drm_atomic_get_plane_state(state->state, &priv->f0); |
| 209 | + if (IS_ERR(f0_state)) | |
| 210 | + return PTR_ERR(f0_state); | |
| 219 | 211 | |
| 220 | 212 | if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU) && priv->ipu_plane) { |
| 221 | 213 | ipu_state = drm_atomic_get_plane_state(state->state, priv->ipu_plane); |
| 214 | + if (IS_ERR(ipu_state)) | |
| 215 | + return PTR_ERR(ipu_state); | |
| 222 | 216 | |
| 223 | 217 | /* IPU and F1 planes cannot be enabled at the same time. */ |
| 224 | 218 | if (f1_state->fb && ipu_state->fb) { |
| @@ -235,6 +229,24 @@ static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc, · 10 unmodified lines | ||
| 235 | 229 | return 0; |
| 236 | 230 | } |
| 237 | 231 | |
| 232 | +static enum drm_mode_status | |
| 233 | +ingenic_drm_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) | |
| 234 | +{ | |
| 235 | + struct ingenic_drm *priv = drm_crtc_get_priv(crtc); | |
| 236 | + long rate; | |
| 237 | + | |
| 238 | + if (mode->hdisplay > priv->soc_info->max_width) | |
| 239 | + return MODE_BAD_HVALUE; | |
| 240 | + if (mode->vdisplay > priv->soc_info->max_height) | |
| 241 | + return MODE_BAD_VVALUE; | |
| 242 | + | |
| 243 | + rate = clk_round_rate(priv->pix_clk, mode->clock * 1000); | |
| 244 | + if (rate < 0) | |
| 245 | + return MODE_CLOCK_RANGE; | |
| 246 | + | |
| 247 | + return MODE_OK; | |
| 248 | +} | |
| 249 | + | |
| 238 | 250 | static void ingenic_drm_crtc_atomic_begin(struct drm_crtc *crtc, |
| 239 | 251 | struct drm_crtc_state *oldstate) |
| 240 | 252 | { |
| @@ -648,6 +660,7 @@ static const struct drm_crtc_helper_funcs ingenic_drm_crtc_helper_funcs = { · 407 unmodified lines | ||
| 648 | 660 | .atomic_begin = ingenic_drm_crtc_atomic_begin, |
| 649 | 661 | .atomic_flush = ingenic_drm_crtc_atomic_flush, |
| 650 | 662 | .atomic_check = ingenic_drm_crtc_atomic_check, |
| 663 | + .mode_valid = ingenic_drm_crtc_mode_valid, | |
| 651 | 664 | }; |
| 652 | 665 | |
| 653 | 666 | static const struct drm_encoder_helper_funcs ingenic_drm_encoder_helper_funcs = { |
| @@ -35,6 +35,7 @@ struct soc_info { · 34 unmodified lines | ||
| 35 | 35 | const u32 *formats; |
| 36 | 36 | size_t num_formats; |
| 37 | 37 | bool has_bicubic; |
| 38 | + bool manual_restart; | |
| 38 | 39 | |
| 39 | 40 | void (*set_coefs)(struct ingenic_ipu *ipu, unsigned int reg, |
| 40 | 41 | unsigned int sharpness, bool downscale, |
| @@ -48,6 +49,7 @@ struct ingenic_ipu { · 7 unmodified lines | ||
| 48 | 49 | struct regmap *map; |
| 49 | 50 | struct clk *clk; |
| 50 | 51 | const struct soc_info *soc_info; |
| 52 | + bool clk_enabled; | |
| 51 | 53 | |
| 52 | 54 | unsigned int num_w, num_h, denom_w, denom_h; |
| 53 | 55 | |
| @@ -287,12 +289,23 @@ static void ingenic_ipu_plane_atomic_update(struct drm_plane *plane, · 233 unmodified lines | ||
| 287 | 289 | const struct drm_format_info *finfo; |
| 288 | 290 | u32 ctrl, stride = 0, coef_index = 0, format = 0; |
| 289 | 291 | bool needs_modeset, upscaling_w, upscaling_h; |
| 292 | + int err; | |
| 290 | 293 | |
| 291 | 294 | if (!state || !state->fb) |
| 292 | 295 | return; |
| 293 | 296 | |
| 294 | 297 | finfo = drm_format_info(state->fb->format->format); |
| 295 | 298 | |
| 299 | + if (!ipu->clk_enabled) { | |
| 300 | + err = clk_enable(ipu->clk); | |
| 301 | + if (err) { | |
| 302 | + dev_err(ipu->dev, "Unable to enable clock: %d\n", err); | |
| 303 | + return; | |
| 304 | + } | |
| 305 | + | |
| 306 | + ipu->clk_enabled = true; | |
| 307 | + } | |
| 308 | + | |
| 296 | 309 | /* Reset all the registers if needed */ |
| 297 | 310 | needs_modeset = drm_atomic_crtc_needs_modeset(state->crtc->state); |
| 298 | 311 | if (needs_modeset) { |
| @@ -577,6 +590,11 @@ static void ingenic_ipu_plane_atomic_disable(struct drm_plane *plane, · 278 unmodified lines | ||
| 577 | 590 | regmap_clear_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_CHIP_EN); |
| 578 | 591 | |
| 579 | 592 | ingenic_drm_plane_disable(ipu->master, plane); |
| 593 | + | |
| 594 | + if (ipu->clk_enabled) { | |
| 595 | + clk_disable(ipu->clk); | |
| 596 | + ipu->clk_enabled = false; | |
| 597 | + } | |
| 580 | 598 | } |
| 581 | 599 | |
| 582 | 600 | static const struct drm_plane_helper_funcs ingenic_ipu_plane_helper_funcs = { |
| @@ -645,7 +663,8 @@ static irqreturn_t ingenic_ipu_irq_handler(int irq, void *arg) · 62 unmodified lines | ||
| 645 | 663 | unsigned int dummy; |
| 646 | 664 | |
| 647 | 665 | /* dummy read allows CPU to reconfigure IPU */ |
| 648 | − regmap_read(ipu->map, JZ_REG_IPU_STATUS, &dummy); | |
| 666 | + if (ipu->soc_info->manual_restart) | |
| 667 | + regmap_read(ipu->map, JZ_REG_IPU_STATUS, &dummy); | |
| 649 | 668 | |
| 650 | 669 | /* ACK interrupt */ |
| 651 | 670 | regmap_write(ipu->map, JZ_REG_IPU_STATUS, 0); |
| @@ -656,7 +675,8 @@ static irqreturn_t ingenic_ipu_irq_handler(int irq, void *arg) · 4 unmodified lines | ||
| 656 | 675 | regmap_write(ipu->map, JZ_REG_IPU_V_ADDR, ipu->addr_v); |
| 657 | 676 | |
| 658 | 677 | /* Run IPU for the new frame */ |
| 659 | − regmap_set_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_RUN); | |
| 678 | + if (ipu->soc_info->manual_restart) | |
| 679 | + regmap_set_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_RUN); | |
| 660 | 680 | |
| 661 | 681 | drm_crtc_handle_vblank(crtc); |
| 662 | 682 | |
| @@ -758,9 +778,9 @@ static int ingenic_ipu_bind(struct device *dev, struct device *master, void *d) · 95 unmodified lines | ||
| 758 | 778 | drm_object_attach_property(&plane->base, ipu->sharpness_prop, |
| 759 | 779 | ipu->sharpness); |
| 760 | 780 | |
| 761 | − err = clk_prepare_enable(ipu->clk); | |
| 781 | + err = clk_prepare(ipu->clk); | |
| 762 | 782 | if (err) { |
| 763 | − dev_err(dev, "Unable to enable clock\n"); | |
| 783 | + dev_err(dev, "Unable to prepare clock\n"); | |
| 764 | 784 | return err; |
| 765 | 785 | } |
| 766 | 786 | |
| @@ -772,7 +792,7 @@ static void ingenic_ipu_unbind(struct device *dev, · 5 unmodified lines | ||
| 772 | 792 | { |
| 773 | 793 | struct ingenic_ipu *ipu = dev_get_drvdata(dev); |
| 774 | 794 | |
| 775 | − clk_disable_unprepare(ipu->clk); | |
| 795 | + clk_unprepare(ipu->clk); | |
| 776 | 796 | } |
| 777 | 797 | |
| 778 | 798 | static const struct component_ops ingenic_ipu_ops = { |
| @@ -792,10 +812,16 @@ static int ingenic_ipu_remove(struct platform_device *pdev) · 13 unmodified lines | ||
| 792 | 812 | } |
| 793 | 813 | |
| 794 | 814 | static const u32 jz4725b_ipu_formats[] = { |
| 815 | + /* | |
| 816 | + * While officially supported, packed YUV 4:2:2 formats can cause | |
| 817 | + * random hardware crashes on JZ4725B under certain circumstances. | |
| 818 | + * It seems to happen with some specific resize ratios. | |
| 819 | + * Until a proper workaround or fix is found, disable these formats. | |
| 795 | 820 | DRM_FORMAT_YUYV, |
| 796 | 821 | DRM_FORMAT_YVYU, |
| 797 | 822 | DRM_FORMAT_UYVY, |
| 798 | 823 | DRM_FORMAT_VYUY, |
| 824 | + */ | |
| 799 | 825 | DRM_FORMAT_YUV411, |
| 800 | 826 | DRM_FORMAT_YUV420, |
| 801 | 827 | DRM_FORMAT_YUV422, |
| @@ -806,6 +832,7 @@ static const struct soc_info jz4725b_soc_info = { · 4 unmodified lines | ||
| 806 | 832 | .formats = jz4725b_ipu_formats, |
| 807 | 833 | .num_formats = ARRAY_SIZE(jz4725b_ipu_formats), |
| 808 | 834 | .has_bicubic = false, |
| 835 | + .manual_restart = true, | |
| 809 | 836 | .set_coefs = jz4725b_set_coefs, |
| 810 | 837 | }; |
| 811 | 838 | |
| @@ -831,6 +858,7 @@ static const struct soc_info jz4760_soc_info = { · 19 unmodified lines | ||
| 831 | 858 | .formats = jz4760_ipu_formats, |
| 832 | 859 | .num_formats = ARRAY_SIZE(jz4760_ipu_formats), |
| 833 | 860 | .has_bicubic = true, |
| 861 | + .manual_restart = false, | |
| 834 | 862 | .set_coefs = jz4760_set_coefs, |
| 835 | 863 | }; |
| 836 | 864 | |
| @@ -7,6 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | #include <linux/clk.h> |
| 8 | 8 | #include <linux/delay.h> |
| 9 | 9 | #include <linux/dma-buf.h> |
| 10 | +#include <linux/regulator/consumer.h> | |
| 10 | 11 | |
| 11 | 12 | #include <drm/drm_device.h> |
| 12 | 13 | #include <drm/drm_fb_cma_helper.h> |
| @@ -89,7 +90,7 @@ void mcde_display_irq(struct mcde *mcde) · 76 unmodified lines | ||
| 89 | 90 | * the update function is called, then we disable the |
| 90 | 91 | * flow on the channel once we get the TE IRQ. |
| 91 | 92 | */ |
| 92 | − if (mcde->oneshot_mode) { | |
| 93 | + if (mcde->flow_mode == MCDE_COMMAND_ONESHOT_FLOW) { | |
| 93 | 94 | spin_lock(&mcde->flow_lock); |
| 94 | 95 | if (--mcde->flow_active == 0) { |
| 95 | 96 | dev_dbg(mcde->dev, "TE0 IRQ\n"); |
| @@ -333,7 +334,7 @@ static void mcde_configure_overlay(struct mcde *mcde, enum mcde_overlay ovl, · 237 unmodified lines | ||
| 333 | 334 | enum mcde_extsrc src, |
| 334 | 335 | enum mcde_channel ch, |
| 335 | 336 | const struct drm_display_mode *mode, |
| 336 | − u32 format) | |
| 337 | + u32 format, int cpp) | |
| 337 | 338 | { |
| 338 | 339 | u32 val; |
| 339 | 340 | u32 conf1; |
| @@ -342,6 +343,7 @@ static void mcde_configure_overlay(struct mcde *mcde, enum mcde_overlay ovl, · 2 unmodified lines | ||
| 342 | 343 | u32 ljinc; |
| 343 | 344 | u32 cr; |
| 344 | 345 | u32 comp; |
| 346 | + u32 pixel_fetcher_watermark; | |
| 345 | 347 | |
| 346 | 348 | switch (ovl) { |
| 347 | 349 | case MCDE_OVERLAY_0: |
| @@ -426,8 +428,33 @@ static void mcde_configure_overlay(struct mcde *mcde, enum mcde_overlay ovl, · 78 unmodified lines | ||
| 426 | 428 | format); |
| 427 | 429 | break; |
| 428 | 430 | } |
| 429 | − /* The default watermark level for overlay 0 is 48 */ | |
| 430 | − val |= 48 << MCDE_OVLXCONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT; | |
| 431 | + | |
| 432 | + /* | |
| 433 | + * Pixel fetch watermark level is max 0x1FFF pixels. | |
| 434 | + * Two basic rules should be followed: | |
| 435 | + * 1. The value should be at least 256 bits. | |
| 436 | + * 2. The sum of all active overlays pixelfetch watermark level | |
| 437 | + * multiplied with bits per pixel, should be lower than the | |
| 438 | + * size of input_fifo_size in bits. | |
| 439 | + * 3. The value should be a multiple of a line (256 bits). | |
| 440 | + */ | |
| 441 | + switch (cpp) { | |
| 442 | + case 2: | |
| 443 | + pixel_fetcher_watermark = 128; | |
| 444 | + break; | |
| 445 | + case 3: | |
| 446 | + pixel_fetcher_watermark = 96; | |
| 447 | + break; | |
| 448 | + case 4: | |
| 449 | + pixel_fetcher_watermark = 48; | |
| 450 | + break; | |
| 451 | + default: | |
| 452 | + pixel_fetcher_watermark = 48; | |
| 453 | + break; | |
| 454 | + } | |
| 455 | + dev_dbg(mcde->dev, "pixel fetcher watermark level %d pixels\n", | |
| 456 | + pixel_fetcher_watermark); | |
| 457 | + val |= pixel_fetcher_watermark << MCDE_OVLXCONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT; | |
| 431 | 458 | writel(val, mcde->regs + conf2); |
| 432 | 459 | |
| 433 | 460 | /* Number of bytes to fetch per line */ |
| @@ -498,19 +525,47 @@ static void mcde_configure_channel(struct mcde *mcde, enum mcde_channel ch, · 64 unmodified lines | ||
| 498 | 525 | } |
| 499 | 526 | |
| 500 | 527 | /* Set up channel 0 sync (based on chnl_update_registers()) */ |
| 501 | − if (mcde->video_mode || mcde->te_sync) | |
| 528 | + switch (mcde->flow_mode) { | |
| 529 | + case MCDE_COMMAND_ONESHOT_FLOW: | |
| 530 | + /* Oneshot is achieved with software sync */ | |
| 531 | + val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SOFTWARE | |
| 532 | + << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; | |
| 533 | + break; | |
| 534 | + case MCDE_COMMAND_TE_FLOW: | |
| 502 | 535 | val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE |
| 503 | 536 | << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; |
| 504 | − else | |
| 505 | − val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SOFTWARE | |
| 537 | + val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0 | |
| 538 | + << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; | |
| 539 | + break; | |
| 540 | + case MCDE_COMMAND_BTA_TE_FLOW: | |
| 541 | + val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE | |
| 542 | + << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; | |
| 543 | + /* | |
| 544 | + * TODO: | |
| 545 | + * The vendor driver uses the formatter as sync source | |
| 546 | + * for BTA TE mode. Test to use TE if you have a panel | |
| 547 | + * that uses this mode. | |
| 548 | + */ | |
| 549 | + val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_FORMATTER | |
| 550 | + << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; | |
| 551 | + break; | |
| 552 | + case MCDE_VIDEO_TE_FLOW: | |
| 553 | + val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE | |
| 506 | 554 | << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; |
| 507 | − | |
| 508 | − if (mcde->te_sync) | |
| 509 | 555 | val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0 |
| 510 | 556 | << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; |
| 511 | − else | |
| 557 | + break; | |
| 558 | + case MCDE_VIDEO_FORMATTER_FLOW: | |
| 559 | + val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE | |
| 560 | + << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; | |
| 512 | 561 | val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_FORMATTER |
| 513 | 562 | << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; |
| 563 | + break; | |
| 564 | + default: | |
| 565 | + dev_err(mcde->dev, "unknown flow mode %d\n", | |
| 566 | + mcde->flow_mode); | |
| 567 | + break; | |
| 568 | + } | |
| 514 | 569 | |
| 515 | 570 | writel(val, mcde->regs + sync); |
| 516 | 571 | |
| @@ -825,6 +880,14 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, · 308 unmodified lines | ||
| 825 | 880 | u32 formatter_frame; |
| 826 | 881 | u32 pkt_div; |
| 827 | 882 | u32 val; |
| 883 | + int ret; | |
| 884 | + | |
| 885 | + /* This powers up the entire MCDE block and the DSI hardware */ | |
| 886 | + ret = regulator_enable(mcde->epod); | |
| 887 | + if (ret) { | |
| 888 | + dev_err(drm->dev, "can't re-enable EPOD regulator\n"); | |
| 889 | + return; | |
| 890 | + } | |
| 828 | 891 | |
| 829 | 892 | dev_info(drm->dev, "enable MCDE, %d x %d format %s\n", |
| 830 | 893 | mode->hdisplay, mode->vdisplay, |
| @@ -835,6 +898,26 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, · 4 unmodified lines | ||
| 835 | 898 | return; |
| 836 | 899 | } |
| 837 | 900 | |
| 901 | + /* Set up the main control, watermark level at 7 */ | |
| 902 | + val = 7 << MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT; | |
| 903 | + /* 24 bits DPI: connect LSB Ch B to D[0:7] */ | |
| 904 | + val |= 3 << MCDE_CONF0_OUTMUX0_SHIFT; | |
| 905 | + /* TV out: connect LSB Ch B to D[8:15] */ | |
| 906 | + val |= 3 << MCDE_CONF0_OUTMUX1_SHIFT; | |
| 907 | + /* Don't care about this muxing */ | |
| 908 | + val |= 0 << MCDE_CONF0_OUTMUX2_SHIFT; | |
| 909 | + /* 24 bits DPI: connect MID Ch B to D[24:31] */ | |
| 910 | + val |= 4 << MCDE_CONF0_OUTMUX3_SHIFT; | |
| 911 | + /* 5: 24 bits DPI: connect MSB Ch B to D[32:39] */ | |
| 912 | + val |= 5 << MCDE_CONF0_OUTMUX4_SHIFT; | |
| 913 | + /* Syncmux bits zero: DPI channel A and B on output pins A and B resp */ | |
| 914 | + writel(val, mcde->regs + MCDE_CONF0); | |
| 915 | + | |
| 916 | + /* Clear any pending interrupts */ | |
| 917 | + mcde_display_disable_irqs(mcde); | |
| 918 | + writel(0, mcde->regs + MCDE_IMSCERR); | |
| 919 | + writel(0xFFFFFFFF, mcde->regs + MCDE_RISERR); | |
| 920 | + | |
| 838 | 921 | dev_info(drm->dev, "output in %s mode, format %dbpp\n", |
| 839 | 922 | (mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? |
| 840 | 923 | "VIDEO" : "CMD", |
| @@ -904,7 +987,7 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, · 63 unmodified lines | ||
| 904 | 987 | * channel 0 |
| 905 | 988 | */ |
| 906 | 989 | mcde_configure_overlay(mcde, MCDE_OVERLAY_0, MCDE_EXTSRC_0, |
| 907 | − MCDE_CHANNEL_0, mode, format); | |
| 990 | + MCDE_CHANNEL_0, mode, format, cpp); | |
| 908 | 991 | |
| 909 | 992 | /* |
| 910 | 993 | * Configure pixel-per-line and line-per-frame for channel 0 and then |
| @@ -916,11 +999,25 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, · 5 unmodified lines | ||
| 916 | 999 | mcde_configure_fifo(mcde, MCDE_FIFO_A, MCDE_DSI_FORMATTER_0, |
| 917 | 1000 | fifo_wtrmrk); |
| 918 | 1001 | |
| 1002 | + /* | |
| 1003 | + * This brings up the DSI bridge which is tightly connected | |
| 1004 | + * to the MCDE DSI formatter. | |
| 1005 | + * | |
| 1006 | + * FIXME: if we want to use another formatter, such as DPI, | |
| 1007 | + * we need to be more elaborate here and select the appropriate | |
| 1008 | + * bridge. | |
| 1009 | + */ | |
| 1010 | + mcde_dsi_enable(mcde->bridge); | |
| 1011 | + | |
| 919 | 1012 | /* Configure the DSI formatter 0 for the DSI panel output */ |
| 920 | 1013 | mcde_configure_dsi_formatter(mcde, MCDE_DSI_FORMATTER_0, |
| 921 | 1014 | formatter_frame, pkt_size); |
| 922 | 1015 | |
| 923 | − if (mcde->te_sync) { | |
| 1016 | + switch (mcde->flow_mode) { | |
| 1017 | + case MCDE_COMMAND_TE_FLOW: | |
| 1018 | + case MCDE_COMMAND_BTA_TE_FLOW: | |
| 1019 | + case MCDE_VIDEO_TE_FLOW: | |
| 1020 | + /* We are using TE in some comination */ | |
| 924 | 1021 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) |
| 925 | 1022 | val = MCDE_VSCRC_VSPOL; |
| 926 | 1023 | else |
| @@ -930,16 +1027,31 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, · 3 unmodified lines | ||
| 930 | 1027 | val = readl(mcde->regs + MCDE_CRC); |
| 931 | 1028 | val |= MCDE_CRC_SYCEN0; |
| 932 | 1029 | writel(val, mcde->regs + MCDE_CRC); |
| 1030 | + break; | |
| 1031 | + default: | |
| 1032 | + /* No TE capture */ | |
| 1033 | + break; | |
| 933 | 1034 | } |
| 934 | 1035 | |
| 935 | 1036 | drm_crtc_vblank_on(crtc); |
| 936 | 1037 | |
| 937 | − if (mcde->video_mode) | |
| 938 | − /* | |
| 939 | − * Keep FIFO permanently enabled in video mode, | |
| 940 | − * otherwise MCDE will stop feeding data to the panel. | |
| 941 | − */ | |
| 1038 | + /* | |
| 1039 | + * If we're using oneshot mode we don't start the flow | |
| 1040 | + * until each time the display is given an update, and | |
| 1041 | + * then we disable it immediately after. For all other | |
| 1042 | + * modes (command or video) we start the FIFO flow | |
| 1043 | + * right here. This is necessary for the hardware to | |
| 1044 | + * behave right. | |
| 1045 | + */ | |
| 1046 | + if (mcde->flow_mode != MCDE_COMMAND_ONESHOT_FLOW) { | |
| 942 | 1047 | mcde_enable_fifo(mcde, MCDE_FIFO_A); |
| 1048 | + dev_dbg(mcde->dev, "started MCDE video FIFO flow\n"); | |
| 1049 | + } | |
| 1050 | + | |
| 1051 | + /* Enable MCDE with automatic clock gating */ | |
| 1052 | + val = readl(mcde->regs + MCDE_CR); | |
| 1053 | + val |= MCDE_CR_MCDEEN | MCDE_CR_AUTOCLKG_EN; | |
| 1054 | + writel(val, mcde->regs + MCDE_CR); | |
| 943 | 1055 | |
| 944 | 1056 | dev_info(drm->dev, "MCDE display is enabled\n"); |
| 945 | 1057 | } |
| @@ -950,12 +1062,16 @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe) · 4 unmodified lines | ||
| 950 | 1062 | struct drm_device *drm = crtc->dev; |
| 951 | 1063 | struct mcde *mcde = to_mcde(drm); |
| 952 | 1064 | struct drm_pending_vblank_event *event; |
| 1065 | + int ret; | |
| 953 | 1066 | |
| 954 | 1067 | drm_crtc_vblank_off(crtc); |
| 955 | 1068 | |
| 956 | 1069 | /* Disable FIFO A flow */ |
| 957 | 1070 | mcde_disable_fifo(mcde, MCDE_FIFO_A, true); |
| 958 | 1071 | |
| 1072 | + /* This disables the DSI bridge */ | |
| 1073 | + mcde_dsi_disable(mcde->bridge); | |
| 1074 | + | |
| 959 | 1075 | event = crtc->state->event; |
| 960 | 1076 | if (event) { |
| 961 | 1077 | crtc->state->event = NULL; |
| @@ -965,43 +1081,47 @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe) · 3 unmodified lines | ||
| 965 | 1081 | spin_unlock_irq(&crtc->dev->event_lock); |
| 966 | 1082 | } |
| 967 | 1083 | |
| 1084 | + ret = regulator_disable(mcde->epod); | |
| 1085 | + if (ret) | |
| 1086 | + dev_err(drm->dev, "can't disable EPOD regulator\n"); | |
| 1087 | + /* Make sure we are powered down (before we may power up again) */ | |
| 1088 | + usleep_range(50000, 70000); | |
| 1089 | + | |
| 968 | 1090 | dev_info(drm->dev, "MCDE display is disabled\n"); |
| 969 | 1091 | } |
| 970 | 1092 | |
| 971 | −static void mcde_display_send_one_frame(struct mcde *mcde) | |
| 1093 | +static void mcde_start_flow(struct mcde *mcde) | |
| 972 | 1094 | { |
| 973 | − /* Request a TE ACK */ | |
| 974 | − if (mcde->te_sync) | |
| 1095 | + /* Request a TE ACK only in TE+BTA mode */ | |
| 1096 | + if (mcde->flow_mode == MCDE_COMMAND_BTA_TE_FLOW) | |
| 975 | 1097 | mcde_dsi_te_request(mcde->mdsi); |
| 976 | 1098 | |
| 977 | 1099 | /* Enable FIFO A flow */ |
| 978 | 1100 | mcde_enable_fifo(mcde, MCDE_FIFO_A); |
| 979 | 1101 | |
| 980 | − if (mcde->te_sync) { | |
| 1102 | + /* | |
| 1103 | + * If oneshot mode is enabled, the flow will be disabled | |
| 1104 | + * when the TE0 IRQ arrives in the interrupt handler. Otherwise | |
| 1105 | + * updates are continuously streamed to the display after this | |
| 1106 | + * point. | |
| 1107 | + */ | |
| 1108 | + | |
| 1109 | + if (mcde->flow_mode == MCDE_COMMAND_ONESHOT_FLOW) { | |
| 1110 | + /* Trigger a software sync out on channel 0 */ | |
| 1111 | + writel(MCDE_CHNLXSYNCHSW_SW_TRIG, | |
| 1112 | + mcde->regs + MCDE_CHNL0SYNCHSW); | |
| 1113 | + | |
| 981 | 1114 | /* |
| 982 | − * If oneshot mode is enabled, the flow will be disabled | |
| 983 | − * when the TE0 IRQ arrives in the interrupt handler. Otherwise | |
| 984 | − * updates are continuously streamed to the display after this | |
| 985 | − * point. | |
| 1115 | + * Disable FIFO A flow again: since we are using TE sync we | |
| 1116 | + * need to wait for the FIFO to drain before we continue | |
| 1117 | + * so repeated calls to this function will not cause a mess | |
| 1118 | + * in the hardware by pushing updates will updates are going | |
| 1119 | + * on already. | |
| 986 | 1120 | */ |
| 987 | − dev_dbg(mcde->dev, "sent TE0 framebuffer update\n"); | |
| 988 | − return; | |
| 1121 | + mcde_disable_fifo(mcde, MCDE_FIFO_A, true); | |
| 989 | 1122 | } |
| 990 | 1123 | |
| 991 | − /* Trigger a software sync out on channel 0 */ | |
| 992 | − writel(MCDE_CHNLXSYNCHSW_SW_TRIG, | |
| 993 | − mcde->regs + MCDE_CHNL0SYNCHSW); | |
| 994 | − | |
| 995 | − /* | |
| 996 | − * Disable FIFO A flow again: since we are using TE sync we | |
| 997 | − * need to wait for the FIFO to drain before we continue | |
| 998 | − * so repeated calls to this function will not cause a mess | |
| 999 | − * in the hardware by pushing updates will updates are going | |
| 1000 | − * on already. | |
| 1001 | − */ | |
| 1002 | − mcde_disable_fifo(mcde, MCDE_FIFO_A, true); | |
| 1003 | − | |
| 1004 | − dev_dbg(mcde->dev, "sent SW framebuffer update\n"); | |
| 1124 | + dev_dbg(mcde->dev, "started MCDE FIFO flow\n"); | |
| 1005 | 1125 | } |
| 1006 | 1126 | |
| 1007 | 1127 | static void mcde_set_extsrc(struct mcde *mcde, u32 buffer_address) |
| @@ -1060,15 +1180,13 @@ static void mcde_display_update(struct drm_simple_display_pipe *pipe, · 52 unmodified lines | ||
| 1060 | 1180 | */ |
| 1061 | 1181 | if (fb) { |
| 1062 | 1182 | mcde_set_extsrc(mcde, drm_fb_cma_get_gem_addr(fb, pstate, 0)); |
| 1063 | − if (!mcde->video_mode) { | |
| 1064 | − /* | |
| 1065 | − * Send a single frame using software sync if the flow | |
| 1066 | − * is not active yet. | |
| 1067 | − */ | |
| 1068 | − if (mcde->flow_active == 0) | |
| 1069 | − mcde_display_send_one_frame(mcde); | |
| 1070 | − } | |
| 1071 | − dev_info_once(mcde->dev, "sent first display update\n"); | |
| 1183 | + dev_info_once(mcde->dev, "first update of display contents\n"); | |
| 1184 | + /* | |
| 1185 | + * Usually the flow is already active, unless we are in | |
| 1186 | + * oneshot mode, then we need to kick the flow right here. | |
| 1187 | + */ | |
| 1188 | + if (mcde->flow_active == 0) | |
| 1189 | + mcde_start_flow(mcde); | |
| 1072 | 1190 | } else { |
| 1073 | 1191 | /* |
| 1074 | 1192 | * If an update is receieved before the MCDE is enabled |
| @@ -9,6 +9,61 @@ · 8 unmodified lines | ||
| 9 | 9 | #ifndef _MCDE_DRM_H_ |
| 10 | 10 | #define _MCDE_DRM_H_ |
| 11 | 11 | |
| 12 | +/* Shared basic registers */ | |
| 13 | +#define MCDE_CR 0x00000000 | |
| 14 | +#define MCDE_CR_IFIFOEMPTYLINECOUNT_V422_SHIFT 0 | |
| 15 | +#define MCDE_CR_IFIFOEMPTYLINECOUNT_V422_MASK 0x0000003F | |
| 16 | +#define MCDE_CR_IFIFOCTRLEN BIT(15) | |
| 17 | +#define MCDE_CR_UFRECOVERY_MODE_V422 BIT(16) | |
| 18 | +#define MCDE_CR_WRAP_MODE_V422_SHIFT BIT(17) | |
| 19 | +#define MCDE_CR_AUTOCLKG_EN BIT(30) | |
| 20 | +#define MCDE_CR_MCDEEN BIT(31) | |
| 21 | + | |
| 22 | +#define MCDE_CONF0 0x00000004 | |
| 23 | +#define MCDE_CONF0_SYNCMUX0 BIT(0) | |
| 24 | +#define MCDE_CONF0_SYNCMUX1 BIT(1) | |
| 25 | +#define MCDE_CONF0_SYNCMUX2 BIT(2) | |
| 26 | +#define MCDE_CONF0_SYNCMUX3 BIT(3) | |
| 27 | +#define MCDE_CONF0_SYNCMUX4 BIT(4) | |
| 28 | +#define MCDE_CONF0_SYNCMUX5 BIT(5) | |
| 29 | +#define MCDE_CONF0_SYNCMUX6 BIT(6) | |
| 30 | +#define MCDE_CONF0_SYNCMUX7 BIT(7) | |
| 31 | +#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT 12 | |
| 32 | +#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_MASK 0x00007000 | |
| 33 | +#define MCDE_CONF0_OUTMUX0_SHIFT 16 | |
| 34 | +#define MCDE_CONF0_OUTMUX0_MASK 0x00070000 | |
| 35 | +#define MCDE_CONF0_OUTMUX1_SHIFT 19 | |
| 36 | +#define MCDE_CONF0_OUTMUX1_MASK 0x00380000 | |
| 37 | +#define MCDE_CONF0_OUTMUX2_SHIFT 22 | |
| 38 | +#define MCDE_CONF0_OUTMUX2_MASK 0x01C00000 | |
| 39 | +#define MCDE_CONF0_OUTMUX3_SHIFT 25 | |
| 40 | +#define MCDE_CONF0_OUTMUX3_MASK 0x0E000000 | |
| 41 | +#define MCDE_CONF0_OUTMUX4_SHIFT 28 | |
| 42 | +#define MCDE_CONF0_OUTMUX4_MASK 0x70000000 | |
| 43 | + | |
| 44 | +#define MCDE_SSP 0x00000008 | |
| 45 | +#define MCDE_AIS 0x00000100 | |
| 46 | +#define MCDE_IMSCERR 0x00000110 | |
| 47 | +#define MCDE_RISERR 0x00000120 | |
| 48 | +#define MCDE_MISERR 0x00000130 | |
| 49 | +#define MCDE_SISERR 0x00000140 | |
| 50 | + | |
| 51 | +enum mcde_flow_mode { | |
| 52 | + /* One-shot mode: flow stops after one frame */ | |
| 53 | + MCDE_COMMAND_ONESHOT_FLOW, | |
| 54 | + /* Command mode with tearing effect (TE) IRQ sync */ | |
| 55 | + MCDE_COMMAND_TE_FLOW, | |
| 56 | + /* | |
| 57 | + * Command mode with bus turn-around (BTA) and tearing effect | |
| 58 | + * (TE) IRQ sync. | |
| 59 | + */ | |
| 60 | + MCDE_COMMAND_BTA_TE_FLOW, | |
| 61 | + /* Video mode with tearing effect (TE) sync IRQ */ | |
| 62 | + MCDE_VIDEO_TE_FLOW, | |
| 63 | + /* Video mode with the formatter itself as sync source */ | |
| 64 | + MCDE_VIDEO_FORMATTER_FLOW, | |
| 65 | +}; | |
| 66 | + | |
| 12 | 67 | struct mcde { |
| 13 | 68 | struct drm_device drm; |
| 14 | 69 | struct device *dev; |
| @@ -18,9 +73,7 @@ struct mcde { · 3 unmodified lines | ||
| 18 | 73 | struct drm_simple_display_pipe pipe; |
| 19 | 74 | struct mipi_dsi_device *mdsi; |
| 20 | 75 | s16 stride; |
| 21 | − bool te_sync; | |
| 22 | − bool video_mode; | |
| 23 | − bool oneshot_mode; | |
| 76 | + enum mcde_flow_mode flow_mode; | |
| 24 | 77 | unsigned int flow_active; |
| 25 | 78 | spinlock_t flow_lock; /* Locks the channel flow control */ |
| 26 | 79 | |
| @@ -36,8 +89,16 @@ struct mcde { · 9 unmodified lines | ||
| 36 | 89 | |
| 37 | 90 | #define to_mcde(dev) container_of(dev, struct mcde, drm) |
| 38 | 91 | |
| 92 | +static inline bool mcde_flow_is_video(struct mcde *mcde) | |
| 93 | +{ | |
| 94 | + return (mcde->flow_mode == MCDE_VIDEO_TE_FLOW || | |
| 95 | + mcde->flow_mode == MCDE_VIDEO_FORMATTER_FLOW); | |
| 96 | +} | |
| 97 | + | |
| 39 | 98 | bool mcde_dsi_irq(struct mipi_dsi_device *mdsi); |
| 40 | 99 | void mcde_dsi_te_request(struct mipi_dsi_device *mdsi); |
| 100 | +void mcde_dsi_enable(struct drm_bridge *bridge); | |
| 101 | +void mcde_dsi_disable(struct drm_bridge *bridge); | |
| 41 | 102 | extern struct platform_driver mcde_dsi_driver; |
| 42 | 103 | |
| 43 | 104 | void mcde_display_irq(struct mcde *mcde); |
| @@ -63,6 +63,7 @@ · 62 unmodified lines | ||
| 63 | 63 | #include <linux/platform_device.h> |
| 64 | 64 | #include <linux/regulator/consumer.h> |
| 65 | 65 | #include <linux/slab.h> |
| 66 | +#include <linux/delay.h> | |
| 66 | 67 | |
| 67 | 68 | #include <drm/drm_atomic_helper.h> |
| 68 | 69 | #include <drm/drm_bridge.h> |
| @@ -82,44 +83,6 @@ · 13 unmodified lines | ||
| 82 | 83 | |
| 83 | 84 | #define DRIVER_DESC "DRM module for MCDE" |
| 84 | 85 | |
| 85 | −#define MCDE_CR 0x00000000 | |
| 86 | −#define MCDE_CR_IFIFOEMPTYLINECOUNT_V422_SHIFT 0 | |
| 87 | −#define MCDE_CR_IFIFOEMPTYLINECOUNT_V422_MASK 0x0000003F | |
| 88 | −#define MCDE_CR_IFIFOCTRLEN BIT(15) | |
| 89 | −#define MCDE_CR_UFRECOVERY_MODE_V422 BIT(16) | |
| 90 | −#define MCDE_CR_WRAP_MODE_V422_SHIFT BIT(17) | |
| 91 | −#define MCDE_CR_AUTOCLKG_EN BIT(30) | |
| 92 | −#define MCDE_CR_MCDEEN BIT(31) | |
| 93 | − | |
| 94 | −#define MCDE_CONF0 0x00000004 | |
| 95 | −#define MCDE_CONF0_SYNCMUX0 BIT(0) | |
| 96 | −#define MCDE_CONF0_SYNCMUX1 BIT(1) | |
| 97 | −#define MCDE_CONF0_SYNCMUX2 BIT(2) | |
| 98 | −#define MCDE_CONF0_SYNCMUX3 BIT(3) | |
| 99 | −#define MCDE_CONF0_SYNCMUX4 BIT(4) | |
| 100 | −#define MCDE_CONF0_SYNCMUX5 BIT(5) | |
| 101 | −#define MCDE_CONF0_SYNCMUX6 BIT(6) | |
| 102 | −#define MCDE_CONF0_SYNCMUX7 BIT(7) | |
| 103 | −#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT 12 | |
| 104 | −#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_MASK 0x00007000 | |
| 105 | −#define MCDE_CONF0_OUTMUX0_SHIFT 16 | |
| 106 | −#define MCDE_CONF0_OUTMUX0_MASK 0x00070000 | |
| 107 | −#define MCDE_CONF0_OUTMUX1_SHIFT 19 | |
| 108 | −#define MCDE_CONF0_OUTMUX1_MASK 0x00380000 | |
| 109 | −#define MCDE_CONF0_OUTMUX2_SHIFT 22 | |
| 110 | −#define MCDE_CONF0_OUTMUX2_MASK 0x01C00000 | |
| 111 | −#define MCDE_CONF0_OUTMUX3_SHIFT 25 | |
| 112 | −#define MCDE_CONF0_OUTMUX3_MASK 0x0E000000 | |
| 113 | −#define MCDE_CONF0_OUTMUX4_SHIFT 28 | |
| 114 | −#define MCDE_CONF0_OUTMUX4_MASK 0x70000000 | |
| 115 | − | |
| 116 | −#define MCDE_SSP 0x00000008 | |
| 117 | −#define MCDE_AIS 0x00000100 | |
| 118 | −#define MCDE_IMSCERR 0x00000110 | |
| 119 | −#define MCDE_RISERR 0x00000120 | |
| 120 | −#define MCDE_MISERR 0x00000130 | |
| 121 | −#define MCDE_SISERR 0x00000140 | |
| 122 | − | |
| 123 | 86 | #define MCDE_PID 0x000001FC |
| 124 | 87 | #define MCDE_PID_METALFIX_VERSION_SHIFT 0 |
| 125 | 88 | #define MCDE_PID_METALFIX_VERSION_MASK 0x000000FF |
| @@ -293,7 +256,6 @@ static int mcde_probe(struct platform_device *pdev) · 167 unmodified lines | ||
| 293 | 256 | struct component_match *match = NULL; |
| 294 | 257 | struct resource *res; |
| 295 | 258 | u32 pid; |
| 296 | − u32 val; | |
| 297 | 259 | int irq; |
| 298 | 260 | int ret; |
| 299 | 261 | int i; |
| @@ -305,9 +267,6 @@ static int mcde_probe(struct platform_device *pdev) · 5 unmodified lines | ||
| 305 | 267 | mcde->dev = dev; |
| 306 | 268 | platform_set_drvdata(pdev, drm); |
| 307 | 269 | |
| 308 | − /* Enable continuous updates: this is what Linux' framebuffer expects */ | |
| 309 | − mcde->oneshot_mode = false; | |
| 310 | − | |
| 311 | 270 | /* First obtain and turn on the main power */ |
| 312 | 271 | mcde->epod = devm_regulator_get(dev, "epod"); |
| 313 | 272 | if (IS_ERR(mcde->epod)) { |
| @@ -405,27 +364,7 @@ static int mcde_probe(struct platform_device *pdev) · 91 unmodified lines | ||
| 405 | 364 | goto clk_disable; |
| 406 | 365 | } |
| 407 | 366 | |
| 408 | − /* Set up the main control, watermark level at 7 */ | |
| 409 | − val = 7 << MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT; | |
| 410 | − /* 24 bits DPI: connect LSB Ch B to D[0:7] */ | |
| 411 | − val |= 3 << MCDE_CONF0_OUTMUX0_SHIFT; | |
| 412 | − /* TV out: connect LSB Ch B to D[8:15] */ | |
| 413 | − val |= 3 << MCDE_CONF0_OUTMUX1_SHIFT; | |
| 414 | − /* Don't care about this muxing */ | |
| 415 | − val |= 0 << MCDE_CONF0_OUTMUX2_SHIFT; | |
| 416 | − /* 24 bits DPI: connect MID Ch B to D[24:31] */ | |
| 417 | − val |= 4 << MCDE_CONF0_OUTMUX3_SHIFT; | |
| 418 | − /* 5: 24 bits DPI: connect MSB Ch B to D[32:39] */ | |
| 419 | − val |= 5 << MCDE_CONF0_OUTMUX4_SHIFT; | |
| 420 | − /* Syncmux bits zero: DPI channel A and B on output pins A and B resp */ | |
| 421 | − writel(val, mcde->regs + MCDE_CONF0); | |
| 422 | − | |
| 423 | − /* Enable automatic clock gating */ | |
| 424 | − val = readl(mcde->regs + MCDE_CR); | |
| 425 | − val |= MCDE_CR_MCDEEN | MCDE_CR_AUTOCLKG_EN; | |
| 426 | − writel(val, mcde->regs + MCDE_CR); | |
| 427 | − | |
| 428 | − /* Clear any pending interrupts */ | |
| 367 | + /* Disable and clear any pending interrupts */ | |
| 429 | 368 | mcde_display_disable_irqs(mcde); |
| 430 | 369 | writel(0, mcde->regs + MCDE_IMSCERR); |
| 431 | 370 | writel(0xFFFFFFFF, mcde->regs + MCDE_RISERR); |
| @@ -455,12 +394,28 @@ static int mcde_probe(struct platform_device *pdev) · 23 unmodified lines | ||
| 455 | 394 | ret = PTR_ERR(match); |
| 456 | 395 | goto clk_disable; |
| 457 | 396 | } |
| 397 | + | |
| 398 | + /* | |
| 399 | + * Perform an invasive reset of the MCDE and all blocks by | |
| 400 | + * cutting the power to the subsystem, then bring it back up | |
| 401 | + * later when we enable the display as a result of | |
| 402 | + * component_master_add_with_match(). | |
| 403 | + */ | |
| 404 | + ret = regulator_disable(mcde->epod); | |
| 405 | + if (ret) { | |
| 406 | + dev_err(dev, "can't disable EPOD regulator\n"); | |
| 407 | + return ret; | |
| 408 | + } | |
| 409 | + /* Wait 50 ms so we are sure we cut the power */ | |
| 410 | + usleep_range(50000, 70000); | |
| 411 | + | |
| 458 | 412 | ret = component_master_add_with_match(&pdev->dev, &mcde_drm_comp_ops, |
| 459 | 413 | match); |
| 460 | 414 | if (ret) { |
| 461 | 415 | dev_err(dev, "failed to add component master\n"); |
| 462 | 416 | goto clk_disable; |
| 463 | 417 | } |
| 418 | + | |
| 464 | 419 | return 0; |
| 465 | 420 | |
| 466 | 421 | clk_disable: |
| @@ -43,6 +43,7 @@ struct mcde_dsi { · 42 unmodified lines | ||
| 43 | 43 | struct drm_bridge *bridge_out; |
| 44 | 44 | struct mipi_dsi_host dsi_host; |
| 45 | 45 | struct mipi_dsi_device *mdsi; |
| 46 | + const struct drm_display_mode *mode; | |
| 46 | 47 | struct clk *hs_clk; |
| 47 | 48 | struct clk *lp_clk; |
| 48 | 49 | unsigned long hs_freq; |
| @@ -148,9 +149,22 @@ static void mcde_dsi_attach_to_mcde(struct mcde_dsi *d) · 99 unmodified lines | ||
| 148 | 149 | { |
| 149 | 150 | d->mcde->mdsi = d->mdsi; |
| 150 | 151 | |
| 151 | − d->mcde->video_mode = !!(d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO); | |
| 152 | − /* Enable use of the TE signal for all command mode panels */ | |
| 153 | − d->mcde->te_sync = !d->mcde->video_mode; | |
| 152 | + /* | |
| 153 | + * Select the way the DSI data flow is pushing to the display: | |
| 154 | + * currently we just support video or command mode depending | |
| 155 | + * on the type of display. Video mode defaults to using the | |
| 156 | + * formatter itself for synchronization (stateless video panel). | |
| 157 | + * | |
| 158 | + * FIXME: add flags to struct mipi_dsi_device .flags to indicate | |
| 159 | + * displays that require BTA (bus turn around) so we can handle | |
| 160 | + * such displays as well. Figure out how to properly handle | |
| 161 | + * single frame on-demand updates with DRM for command mode | |
| 162 | + * displays (MCDE_COMMAND_ONESHOT_FLOW). | |
| 163 | + */ | |
| 164 | + if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) | |
| 165 | + d->mcde->flow_mode = MCDE_VIDEO_FORMATTER_FLOW; | |
| 166 | + else | |
| 167 | + d->mcde->flow_mode = MCDE_COMMAND_TE_FLOW; | |
| 154 | 168 | } |
| 155 | 169 | |
| 156 | 170 | static int mcde_dsi_host_attach(struct mipi_dsi_host *host, |
| @@ -194,79 +208,16 @@ static int mcde_dsi_host_detach(struct mipi_dsi_host *host, · 37 unmodified lines | ||
| 194 | 208 | (type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM) || \ |
| 195 | 209 | (type == MIPI_DSI_DCS_READ)) |
| 196 | 210 | |
| 197 | −static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host, | |
| 198 | − const struct mipi_dsi_msg *msg) | |
| 211 | +static int mcde_dsi_execute_transfer(struct mcde_dsi *d, | |
| 212 | + const struct mipi_dsi_msg *msg) | |
| 199 | 213 | { |
| 200 | − struct mcde_dsi *d = host_to_mcde_dsi(host); | |
| 201 | 214 | const u32 loop_delay_us = 10; /* us */ |
| 202 | − const u8 *tx = msg->tx_buf; | |
| 203 | 215 | u32 loop_counter; |
| 204 | 216 | size_t txlen = msg->tx_len; |
| 205 | 217 | size_t rxlen = msg->rx_len; |
| 218 | + int i; | |
| 206 | 219 | u32 val; |
| 207 | 220 | int ret; |
| 208 | − int i; | |
| 209 | − | |
| 210 | − if (txlen > 16) { | |
| 211 | − dev_err(d->dev, | |
| 212 | − "dunno how to write more than 16 bytes yet\n"); | |
| 213 | − return -EIO; | |
| 214 | − } | |
| 215 | − if (rxlen > 4) { | |
| 216 | − dev_err(d->dev, | |
| 217 | − "dunno how to read more than 4 bytes yet\n"); | |
| 218 | − return -EIO; | |
| 219 | − } | |
| 220 | − | |
| 221 | − dev_dbg(d->dev, | |
| 222 | − "message to channel %d, write %zd bytes read %zd bytes\n", | |
| 223 | − msg->channel, txlen, rxlen); | |
| 224 | − | |
| 225 | − /* Command "nature" */ | |
| 226 | − if (MCDE_DSI_HOST_IS_READ(msg->type)) | |
| 227 | − /* MCTL_MAIN_DATA_CTL already set up */ | |
| 228 | − val = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_READ; | |
| 229 | − else | |
| 230 | − val = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_WRITE; | |
| 231 | − /* | |
| 232 | − * More than 2 bytes will not fit in a single packet, so it's | |
| 233 | − * time to set the "long not short" bit. One byte is used by | |
| 234 | − * the MIPI DCS command leaving just one byte for the payload | |
| 235 | − * in a short package. | |
| 236 | − */ | |
| 237 | − if (mipi_dsi_packet_format_is_long(msg->type)) | |
| 238 | − val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT; | |
| 239 | − val |= 0 << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID_SHIFT; | |
| 240 | − val |= txlen << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE_SHIFT; | |
| 241 | − val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN; | |
| 242 | − val |= msg->type << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SHIFT; | |
| 243 | − writel(val, d->regs + DSI_DIRECT_CMD_MAIN_SETTINGS); | |
| 244 | − | |
| 245 | − /* MIPI DCS command is part of the data */ | |
| 246 | − if (txlen > 0) { | |
| 247 | − val = 0; | |
| 248 | − for (i = 0; i < 4 && i < txlen; i++) | |
| 249 | − val |= tx[i] << (i * 8); | |
| 250 | − } | |
| 251 | − writel(val, d->regs + DSI_DIRECT_CMD_WRDAT0); | |
| 252 | − if (txlen > 4) { | |
| 253 | − val = 0; | |
| 254 | − for (i = 0; i < 4 && (i + 4) < txlen; i++) | |
| 255 | − val |= tx[i + 4] << (i * 8); | |
| 256 | − writel(val, d->regs + DSI_DIRECT_CMD_WRDAT1); | |
| 257 | − } | |
| 258 | − if (txlen > 8) { | |
| 259 | − val = 0; | |
| 260 | − for (i = 0; i < 4 && (i + 8) < txlen; i++) | |
| 261 | − val |= tx[i + 8] << (i * 8); | |
| 262 | − writel(val, d->regs + DSI_DIRECT_CMD_WRDAT2); | |
| 263 | − } | |
| 264 | − if (txlen > 12) { | |
| 265 | − val = 0; | |
| 266 | − for (i = 0; i < 4 && (i + 12) < txlen; i++) | |
| 267 | − val |= tx[i + 12] << (i * 8); | |
| 268 | − writel(val, d->regs + DSI_DIRECT_CMD_WRDAT3); | |
| 269 | − } | |
| 270 | 221 | |
| 271 | 222 | writel(~0, d->regs + DSI_DIRECT_CMD_STS_CLR); |
| 272 | 223 | writel(~0, d->regs + DSI_CMD_MODE_STS_CLR); |
| @@ -283,6 +234,7 @@ static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host, · 10 unmodified lines | ||
| 283 | 234 | usleep_range(loop_delay_us, (loop_delay_us * 3) / 2); |
| 284 | 235 | if (!loop_counter) { |
| 285 | 236 | dev_err(d->dev, "DSI read timeout!\n"); |
| 237 | + /* Set exit code and retry */ | |
| 286 | 238 | return -ETIME; |
| 287 | 239 | } |
| 288 | 240 | } else { |
| @@ -293,6 +245,7 @@ static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host, · 4 unmodified lines | ||
| 293 | 245 | usleep_range(loop_delay_us, (loop_delay_us * 3) / 2); |
| 294 | 246 | |
| 295 | 247 | if (!loop_counter) { |
| 248 | + /* Set exit code and retry */ | |
| 296 | 249 | dev_err(d->dev, "DSI write timeout!\n"); |
| 297 | 250 | return -ETIME; |
| 298 | 251 | } |
| @@ -334,6 +287,93 @@ static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host, · 35 unmodified lines | ||
| 334 | 287 | ret = rdsz; |
| 335 | 288 | } |
| 336 | 289 | |
| 290 | + /* Successful transmission */ | |
| 291 | + return ret; | |
| 292 | +} | |
| 293 | + | |
| 294 | +static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host, | |
| 295 | + const struct mipi_dsi_msg *msg) | |
| 296 | +{ | |
| 297 | + struct mcde_dsi *d = host_to_mcde_dsi(host); | |
| 298 | + const u8 *tx = msg->tx_buf; | |
| 299 | + size_t txlen = msg->tx_len; | |
| 300 | + size_t rxlen = msg->rx_len; | |
| 301 | + unsigned int retries = 0; | |
| 302 | + u32 val; | |
| 303 | + int ret; | |
| 304 | + int i; | |
| 305 | + | |
| 306 | + if (txlen > 16) { | |
| 307 | + dev_err(d->dev, | |
| 308 | + "dunno how to write more than 16 bytes yet\n"); | |
| 309 | + return -EIO; | |
| 310 | + } | |
| 311 | + if (rxlen > 4) { | |
| 312 | + dev_err(d->dev, | |
| 313 | + "dunno how to read more than 4 bytes yet\n"); | |
| 314 | + return -EIO; | |
| 315 | + } | |
| 316 | + | |
| 317 | + dev_dbg(d->dev, | |
| 318 | + "message to channel %d, write %zd bytes read %zd bytes\n", | |
| 319 | + msg->channel, txlen, rxlen); | |
| 320 | + | |
| 321 | + /* Command "nature" */ | |
| 322 | + if (MCDE_DSI_HOST_IS_READ(msg->type)) | |
| 323 | + /* MCTL_MAIN_DATA_CTL already set up */ | |
| 324 | + val = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_READ; | |
| 325 | + else | |
| 326 | + val = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_WRITE; | |
| 327 | + /* | |
| 328 | + * More than 2 bytes will not fit in a single packet, so it's | |
| 329 | + * time to set the "long not short" bit. One byte is used by | |
| 330 | + * the MIPI DCS command leaving just one byte for the payload | |
| 331 | + * in a short package. | |
| 332 | + */ | |
| 333 | + if (mipi_dsi_packet_format_is_long(msg->type)) | |
| 334 | + val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT; | |
| 335 | + val |= 0 << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID_SHIFT; | |
| 336 | + val |= txlen << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE_SHIFT; | |
| 337 | + val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN; | |
| 338 | + val |= msg->type << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SHIFT; | |
| 339 | + writel(val, d->regs + DSI_DIRECT_CMD_MAIN_SETTINGS); | |
| 340 | + | |
| 341 | + /* MIPI DCS command is part of the data */ | |
| 342 | + if (txlen > 0) { | |
| 343 | + val = 0; | |
| 344 | + for (i = 0; i < 4 && i < txlen; i++) | |
| 345 | + val |= tx[i] << (i * 8); | |
| 346 | + } | |
| 347 | + writel(val, d->regs + DSI_DIRECT_CMD_WRDAT0); | |
| 348 | + if (txlen > 4) { | |
| 349 | + val = 0; | |
| 350 | + for (i = 0; i < 4 && (i + 4) < txlen; i++) | |
| 351 | + val |= tx[i + 4] << (i * 8); | |
| 352 | + writel(val, d->regs + DSI_DIRECT_CMD_WRDAT1); | |
| 353 | + } | |
| 354 | + if (txlen > 8) { | |
| 355 | + val = 0; | |
| 356 | + for (i = 0; i < 4 && (i + 8) < txlen; i++) | |
| 357 | + val |= tx[i + 8] << (i * 8); | |
| 358 | + writel(val, d->regs + DSI_DIRECT_CMD_WRDAT2); | |
| 359 | + } | |
| 360 | + if (txlen > 12) { | |
| 361 | + val = 0; | |
| 362 | + for (i = 0; i < 4 && (i + 12) < txlen; i++) | |
| 363 | + val |= tx[i + 12] << (i * 8); | |
| 364 | + writel(val, d->regs + DSI_DIRECT_CMD_WRDAT3); | |
| 365 | + } | |
| 366 | + | |
| 367 | + while (retries < 3) { | |
| 368 | + ret = mcde_dsi_execute_transfer(d, msg); | |
| 369 | + if (ret >= 0) | |
| 370 | + break; | |
| 371 | + retries++; | |
| 372 | + } | |
| 373 | + if (ret < 0 && retries) | |
| 374 | + dev_err(d->dev, "gave up after %d retries\n", retries); | |
| 375 | + | |
| 376 | + /* Clear any errors */ | |
| 337 | 377 | writel(~0, d->regs + DSI_DIRECT_CMD_STS_CLR); |
| 338 | 378 | writel(~0, d->regs + DSI_CMD_MODE_STS_CLR); |
| 339 | 379 | |
| @@ -799,10 +839,11 @@ static void mcde_dsi_start(struct mcde_dsi *d) · 459 unmodified lines | ||
| 799 | 839 | /* Command mode, clear IF1 ID */ |
| 800 | 840 | val = readl(d->regs + DSI_CMD_MODE_CTL); |
| 801 | 841 | /* |
| 802 | − * If we enable low-power mode here, with | |
| 803 | − * val |= DSI_CMD_MODE_CTL_IF1_LP_EN | |
| 842 | + * If we enable low-power mode here, | |
| 804 | 843 | * then display updates become really slow. |
| 805 | 844 | */ |
| 845 | + if (d->mdsi->mode_flags & MIPI_DSI_MODE_LPM) | |
| 846 | + val |= DSI_CMD_MODE_CTL_IF1_LP_EN; | |
| 806 | 847 | val &= ~DSI_CMD_MODE_CTL_IF1_ID_MASK; |
| 807 | 848 | writel(val, d->regs + DSI_CMD_MODE_CTL); |
| 808 | 849 | |
| @@ -811,23 +852,11 @@ static void mcde_dsi_start(struct mcde_dsi *d) · 2 unmodified lines | ||
| 811 | 852 | dev_info(d->dev, "DSI link enabled\n"); |
| 812 | 853 | } |
| 813 | 854 | |
| 814 | − | |
| 815 | −static void mcde_dsi_bridge_enable(struct drm_bridge *bridge) | |
| 816 | −{ | |
| 817 | − struct mcde_dsi *d = bridge_to_mcde_dsi(bridge); | |
| 818 | − u32 val; | |
| 819 | − | |
| 820 | − if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) { | |
| 821 | − /* Enable video mode */ | |
| 822 | − val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL); | |
| 823 | − val |= DSI_MCTL_MAIN_DATA_CTL_VID_EN; | |
| 824 | − writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL); | |
| 825 | − } | |
| 826 | − | |
| 827 | − dev_info(d->dev, "enable DSI master\n"); | |
| 828 | −}; | |
| 829 | − | |
| 830 | −static void mcde_dsi_bridge_pre_enable(struct drm_bridge *bridge) | |
| 855 | +/* | |
| 856 | + * Notice that this is called from inside the display controller | |
| 857 | + * and not from the bridge callbacks. | |
| 858 | + */ | |
| 859 | +void mcde_dsi_enable(struct drm_bridge *bridge) | |
| 831 | 860 | { |
| 832 | 861 | struct mcde_dsi *d = bridge_to_mcde_dsi(bridge); |
| 833 | 862 | unsigned long hs_freq, lp_freq; |
| @@ -871,7 +900,25 @@ static void mcde_dsi_bridge_pre_enable(struct drm_bridge *bridge) · 37 unmodified lines | ||
| 871 | 900 | dev_info(d->dev, "DSI HS clock rate %lu Hz\n", |
| 872 | 901 | d->hs_freq); |
| 873 | 902 | |
| 903 | + /* Assert RESET through the PRCMU, active low */ | |
| 904 | + /* FIXME: which DSI block? */ | |
| 905 | + regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET, | |
| 906 | + PRCM_DSI_SW_RESET_DSI0_SW_RESETN, 0); | |
| 907 | + | |
| 908 | + usleep_range(100, 200); | |
| 909 | + | |
| 910 | + /* De-assert RESET again */ | |
| 911 | + regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET, | |
| 912 | + PRCM_DSI_SW_RESET_DSI0_SW_RESETN, | |
| 913 | + PRCM_DSI_SW_RESET_DSI0_SW_RESETN); | |
| 914 | + | |
| 915 | + /* Start up the hardware */ | |
| 916 | + mcde_dsi_start(d); | |
| 917 | + | |
| 874 | 918 | if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) { |
| 919 | + /* Set up the video mode from the DRM mode */ | |
| 920 | + mcde_dsi_setup_video_mode(d, d->mode); | |
| 921 | + | |
| 875 | 922 | /* Put IF1 into video mode */ |
| 876 | 923 | val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL); |
| 877 | 924 | val |= DSI_MCTL_MAIN_DATA_CTL_IF1_MODE; |
| @@ -887,17 +934,25 @@ static void mcde_dsi_bridge_pre_enable(struct drm_bridge *bridge) · 9 unmodified lines | ||
| 887 | 934 | val |= DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC; |
| 888 | 935 | val |= DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA; |
| 889 | 936 | writel(val, d->regs + DSI_VID_MODE_STS_CTL); |
| 937 | + | |
| 938 | + /* Enable video mode */ | |
| 939 | + val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL); | |
| 940 | + val |= DSI_MCTL_MAIN_DATA_CTL_VID_EN; | |
| 941 | + writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL); | |
| 890 | 942 | } else { |
| 891 | 943 | /* Command mode, clear IF1 ID */ |
| 892 | 944 | val = readl(d->regs + DSI_CMD_MODE_CTL); |
| 893 | 945 | /* |
| 894 | − * If we enable low-power mode here with | |
| 895 | − * val |= DSI_CMD_MODE_CTL_IF1_LP_EN | |
| 946 | + * If we enable low-power mode here | |
| 896 | 947 | * the display updates become really slow. |
| 897 | 948 | */ |
| 949 | + if (d->mdsi->mode_flags & MIPI_DSI_MODE_LPM) | |
| 950 | + val |= DSI_CMD_MODE_CTL_IF1_LP_EN; | |
| 898 | 951 | val &= ~DSI_CMD_MODE_CTL_IF1_ID_MASK; |
| 899 | 952 | writel(val, d->regs + DSI_CMD_MODE_CTL); |
| 900 | 953 | } |
| 954 | + | |
| 955 | + dev_info(d->dev, "enabled MCDE DSI master\n"); | |
| 901 | 956 | } |
| 902 | 957 | |
| 903 | 958 | static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge, |
| @@ -911,13 +966,12 @@ static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge, · 7 unmodified lines | ||
| 911 | 966 | return; |
| 912 | 967 | } |
| 913 | 968 | |
| 969 | + d->mode = mode; | |
| 970 | + | |
| 914 | 971 | dev_info(d->dev, "set DSI master to %dx%d %u Hz %s mode\n", |
| 915 | 972 | mode->hdisplay, mode->vdisplay, mode->clock * 1000, |
| 916 | 973 | (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? "VIDEO" : "CMD" |
| 917 | 974 | ); |
| 918 | − | |
| 919 | − if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) | |
| 920 | − mcde_dsi_setup_video_mode(d, mode); | |
| 921 | 975 | } |
| 922 | 976 | |
| 923 | 977 | static void mcde_dsi_wait_for_command_mode_stop(struct mcde_dsi *d) |
| @@ -961,14 +1015,15 @@ static void mcde_dsi_wait_for_video_mode_stop(struct mcde_dsi *d) · 37 unmodified lines | ||
| 961 | 1015 | } |
| 962 | 1016 | } |
| 963 | 1017 | |
| 964 | −static void mcde_dsi_bridge_disable(struct drm_bridge *bridge) | |
| 1018 | +/* | |
| 1019 | + * Notice that this is called from inside the display controller | |
| 1020 | + * and not from the bridge callbacks. | |
| 1021 | + */ | |
| 1022 | +void mcde_dsi_disable(struct drm_bridge *bridge) | |
| 965 | 1023 | { |
| 966 | 1024 | struct mcde_dsi *d = bridge_to_mcde_dsi(bridge); |
| 967 | 1025 | u32 val; |
| 968 | 1026 | |
| 969 | − /* Disable all error interrupts */ | |
| 970 | − writel(0, d->regs + DSI_VID_MODE_STS_CTL); | |
| 971 | − | |
| 972 | 1027 | if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) { |
| 973 | 1028 | /* Stop video mode */ |
| 974 | 1029 | val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL); |
| @@ -980,7 +1035,14 @@ static void mcde_dsi_bridge_disable(struct drm_bridge *bridge) · 5 unmodified lines | ||
| 980 | 1035 | mcde_dsi_wait_for_command_mode_stop(d); |
| 981 | 1036 | } |
| 982 | 1037 | |
| 983 | − /* Stop clocks */ | |
| 1038 | + /* | |
| 1039 | + * Stop clocks and terminate any DSI traffic here so the panel can | |
| 1040 | + * send commands to shut down the display using DSI direct write until | |
| 1041 | + * this point. | |
| 1042 | + */ | |
| 1043 | + | |
| 1044 | + /* Disable all error interrupts */ | |
| 1045 | + writel(0, d->regs + DSI_VID_MODE_STS_CTL); | |
| 984 | 1046 | clk_disable_unprepare(d->hs_clk); |
| 985 | 1047 | clk_disable_unprepare(d->lp_clk); |
| 986 | 1048 | } |
| @@ -1010,9 +1072,6 @@ static int mcde_dsi_bridge_attach(struct drm_bridge *bridge, · 23 unmodified lines | ||
| 1010 | 1072 | static const struct drm_bridge_funcs mcde_dsi_bridge_funcs = { |
| 1011 | 1073 | .attach = mcde_dsi_bridge_attach, |
| 1012 | 1074 | .mode_set = mcde_dsi_bridge_mode_set, |
| 1013 | − .disable = mcde_dsi_bridge_disable, | |
| 1014 | − .enable = mcde_dsi_bridge_enable, | |
| 1015 | − .pre_enable = mcde_dsi_bridge_pre_enable, | |
| 1016 | 1075 | }; |
| 1017 | 1076 | |
| 1018 | 1077 | static int mcde_dsi_bind(struct device *dev, struct device *master, |
| @@ -1048,21 +1107,6 @@ static int mcde_dsi_bind(struct device *dev, struct device *master, · 29 unmodified lines | ||
| 1048 | 1107 | return PTR_ERR(d->lp_clk); |
| 1049 | 1108 | } |
| 1050 | 1109 | |
| 1051 | − /* Assert RESET through the PRCMU, active low */ | |
| 1052 | − /* FIXME: which DSI block? */ | |
| 1053 | − regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET, | |
| 1054 | − PRCM_DSI_SW_RESET_DSI0_SW_RESETN, 0); | |
| 1055 | − | |
| 1056 | − usleep_range(100, 200); | |
| 1057 | − | |
| 1058 | − /* De-assert RESET again */ | |
| 1059 | − regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET, | |
| 1060 | − PRCM_DSI_SW_RESET_DSI0_SW_RESETN, | |
| 1061 | − PRCM_DSI_SW_RESET_DSI0_SW_RESETN); | |
| 1062 | − | |
| 1063 | − /* Start up the hardware */ | |
| 1064 | − mcde_dsi_start(d); | |
| 1065 | − | |
| 1066 | 1110 | /* Look for a panel as a child to this node */ |
| 1067 | 1111 | for_each_available_child_of_node(dev->of_node, child) { |
| 1068 | 1112 | panel = of_drm_find_panel(child); |
| @@ -1,13 +1,11 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | 2 | config DRM_MGAG200 |
| 3 | − tristate "Kernel modesetting driver for MGA G200 server engines" | |
| 3 | + tristate "Matrox G200" | |
| 4 | 4 | depends on DRM && PCI && MMU |
| 5 | 5 | select DRM_GEM_SHMEM_HELPER |
| 6 | 6 | select DRM_KMS_HELPER |
| 7 | 7 | help |
| 8 | − This is a KMS driver for the MGA G200 server chips, it | |
| 9 | − does not support the original MGA G200 or any of the desktop | |
| 10 | − chips. It requires 0.3.0 of the modesetting userspace driver, | |
| 11 | − and a version of mga driver that will fail on KMS enabled | |
| 12 | − devices. | |
| 13 | − | |
| 8 | + This is a KMS driver for Matrox G200 chips. It supports the original | |
| 9 | + MGA G200 desktop chips and the server variants. It requires 0.3.0 | |
| 10 | + of the modesetting userspace driver, and a version of mga driver | |
| 11 | + that will fail on KMS enabled devices. | |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/console.h> |
| 10 | 10 | #include <linux/module.h> |
| 11 | 11 | #include <linux/pci.h> |
| 12 | +#include <linux/vmalloc.h> | |
| 12 | 13 | |
| 13 | 14 | #include <drm/drm_drv.h> |
| 14 | 15 | #include <drm/drm_file.h> |
| @@ -36,6 +37,7 @@ static struct drm_driver mgag200_driver = { · 21 unmodified lines | ||
| 36 | 37 | .major = DRIVER_MAJOR, |
| 37 | 38 | .minor = DRIVER_MINOR, |
| 38 | 39 | .patchlevel = DRIVER_PATCHLEVEL, |
| 40 | + .gem_create_object = drm_gem_shmem_create_object_cached, | |
| 39 | 41 | DRM_GEM_SHMEM_DRIVER_OPS, |
| 40 | 42 | }; |
| 41 | 43 | |
| @@ -43,18 +45,66 @@ static struct drm_driver mgag200_driver = { · 1 unmodified line | ||
| 43 | 45 | * DRM device |
| 44 | 46 | */ |
| 45 | 47 | |
| 46 | −static int mgag200_device_init(struct mga_device *mdev, unsigned long flags) | |
| 48 | +static bool mgag200_has_sgram(struct mga_device *mdev) | |
| 47 | 49 | { |
| 48 | 50 | struct drm_device *dev = &mdev->base; |
| 49 | − int ret, option; | |
| 51 | + u32 option; | |
| 52 | + int ret; | |
| 50 | 53 | |
| 51 | − mdev->flags = mgag200_flags_from_driver_data(flags); | |
| 52 | − mdev->type = mgag200_type_from_driver_data(flags); | |
| 54 | + ret = pci_read_config_dword(dev->pdev, PCI_MGA_OPTION, &option); | |
| 55 | + if (drm_WARN(dev, ret, "failed to read PCI config dword: %d\n", ret)) | |
| 56 | + return false; | |
| 53 | 57 | |
| 54 | − pci_read_config_dword(dev->pdev, PCI_MGA_OPTION, &option); | |
| 55 | − mdev->has_sdram = !(option & (1 << 14)); | |
| 58 | + return !!(option & PCI_MGA_OPTION_HARDPWMSK); | |
| 59 | +} | |
| 56 | 60 | |
| 57 | − /* BAR 0 is the framebuffer, BAR 1 contains registers */ | |
| 61 | +static int mgag200_regs_init(struct mga_device *mdev) | |
| 62 | +{ | |
| 63 | + struct drm_device *dev = &mdev->base; | |
| 64 | + u32 option, option2; | |
| 65 | + u8 crtcext3; | |
| 66 | + | |
| 67 | + switch (mdev->type) { | |
| 68 | + case G200_PCI: | |
| 69 | + case G200_AGP: | |
| 70 | + if (mgag200_has_sgram(mdev)) | |
| 71 | + option = 0x4049cd21; | |
| 72 | + else | |
| 73 | + option = 0x40499121; | |
| 74 | + option2 = 0x00008000; | |
| 75 | + break; | |
| 76 | + case G200_SE_A: | |
| 77 | + case G200_SE_B: | |
| 78 | + option = 0x40049120; | |
| 79 | + if (mgag200_has_sgram(mdev)) | |
| 80 | + option |= PCI_MGA_OPTION_HARDPWMSK; | |
| 81 | + option2 = 0x00008000; | |
| 82 | + break; | |
| 83 | + case G200_WB: | |
| 84 | + case G200_EW3: | |
| 85 | + option = 0x41049120; | |
| 86 | + option2 = 0x0000b000; | |
| 87 | + break; | |
| 88 | + case G200_EV: | |
| 89 | + option = 0x00000120; | |
| 90 | + option2 = 0x0000b000; | |
| 91 | + break; | |
| 92 | + case G200_EH: | |
| 93 | + case G200_EH3: | |
| 94 | + option = 0x00000120; | |
| 95 | + option2 = 0x0000b000; | |
| 96 | + break; | |
| 97 | + default: | |
| 98 | + option = 0; | |
| 99 | + option2 = 0; | |
| 100 | + } | |
| 101 | + | |
| 102 | + if (option) | |
| 103 | + pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option); | |
| 104 | + if (option2) | |
| 105 | + pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2); | |
| 106 | + | |
| 107 | + /* BAR 1 contains registers */ | |
| 58 | 108 | mdev->rmmio_base = pci_resource_start(dev->pdev, 1); |
| 59 | 109 | mdev->rmmio_size = pci_resource_len(dev->pdev, 1); |
| 60 | 110 | |
| @@ -68,12 +118,163 @@ static int mgag200_device_init(struct mga_device *mdev, unsigned long flags) · 7 unmodified lines | ||
| 68 | 118 | if (mdev->rmmio == NULL) |
| 69 | 119 | return -ENOMEM; |
| 70 | 120 | |
| 71 | − /* stash G200 SE model number for later use */ | |
| 72 | − if (IS_G200_SE(mdev)) { | |
| 73 | − mdev->unique_rev_id = RREG32(0x1e24); | |
| 74 | − drm_dbg(dev, "G200 SE unique revision id is 0x%x\n", | |
| 75 | − mdev->unique_rev_id); | |
| 121 | + RREG_ECRT(0x03, crtcext3); | |
| 122 | + crtcext3 |= MGAREG_CRTCEXT3_MGAMODE; | |
| 123 | + WREG_ECRT(0x03, crtcext3); | |
| 124 | + | |
| 125 | + return 0; | |
| 126 | +} | |
| 127 | + | |
| 128 | +static void mgag200_g200_interpret_bios(struct mga_device *mdev, | |
| 129 | + const unsigned char *bios, | |
| 130 | + size_t size) | |
| 131 | +{ | |
| 132 | + static const char matrox[] = {'M', 'A', 'T', 'R', 'O', 'X'}; | |
| 133 | + static const unsigned int expected_length[6] = { | |
| 134 | + 0, 64, 64, 64, 128, 128 | |
| 135 | + }; | |
| 136 | + struct drm_device *dev = &mdev->base; | |
| 137 | + const unsigned char *pins; | |
| 138 | + unsigned int pins_len, version; | |
| 139 | + int offset; | |
| 140 | + int tmp; | |
| 141 | + | |
| 142 | + /* Test for MATROX string. */ | |
| 143 | + if (size < 45 + sizeof(matrox)) | |
| 144 | + return; | |
| 145 | + if (memcmp(&bios[45], matrox, sizeof(matrox)) != 0) | |
| 146 | + return; | |
| 147 | + | |
| 148 | + /* Get the PInS offset. */ | |
| 149 | + if (size < MGA_BIOS_OFFSET + 2) | |
| 150 | + return; | |
| 151 | + offset = (bios[MGA_BIOS_OFFSET + 1] << 8) | bios[MGA_BIOS_OFFSET]; | |
| 152 | + | |
| 153 | + /* Get PInS data structure. */ | |
| 154 | + | |
| 155 | + if (size < offset + 6) | |
| 156 | + return; | |
| 157 | + pins = bios + offset; | |
| 158 | + if (pins[0] == 0x2e && pins[1] == 0x41) { | |
| 159 | + version = pins[5]; | |
| 160 | + pins_len = pins[2]; | |
| 161 | + } else { | |
| 162 | + version = 1; | |
| 163 | + pins_len = pins[0] + (pins[1] << 8); | |
| 164 | + } | |
| 165 | + | |
| 166 | + if (version < 1 || version > 5) { | |
| 167 | + drm_warn(dev, "Unknown BIOS PInS version: %d\n", version); | |
| 168 | + return; | |
| 169 | + } | |
| 170 | + if (pins_len != expected_length[version]) { | |
| 171 | + drm_warn(dev, "Unexpected BIOS PInS size: %d expected: %d\n", | |
| 172 | + pins_len, expected_length[version]); | |
| 173 | + return; | |
| 76 | 174 | } |
| 175 | + if (size < offset + pins_len) | |
| 176 | + return; | |
| 177 | + | |
| 178 | + drm_dbg_kms(dev, "MATROX BIOS PInS version %d size: %d found\n", | |
| 179 | + version, pins_len); | |
| 180 | + | |
| 181 | + /* Extract the clock values */ | |
| 182 | + | |
| 183 | + switch (version) { | |
| 184 | + case 1: | |
| 185 | + tmp = pins[24] + (pins[25] << 8); | |
| 186 | + if (tmp) | |
| 187 | + mdev->model.g200.pclk_max = tmp * 10; | |
| 188 | + break; | |
| 189 | + case 2: | |
| 190 | + if (pins[41] != 0xff) | |
| 191 | + mdev->model.g200.pclk_max = (pins[41] + 100) * 1000; | |
| 192 | + break; | |
| 193 | + case 3: | |
| 194 | + if (pins[36] != 0xff) | |
| 195 | + mdev->model.g200.pclk_max = (pins[36] + 100) * 1000; | |
| 196 | + if (pins[52] & 0x20) | |
| 197 | + mdev->model.g200.ref_clk = 14318; | |
| 198 | + break; | |
| 199 | + case 4: | |
| 200 | + if (pins[39] != 0xff) | |
| 201 | + mdev->model.g200.pclk_max = pins[39] * 4 * 1000; | |
| 202 | + if (pins[92] & 0x01) | |
| 203 | + mdev->model.g200.ref_clk = 14318; | |
| 204 | + break; | |
| 205 | + case 5: | |
| 206 | + tmp = pins[4] ? 8000 : 6000; | |
| 207 | + if (pins[123] != 0xff) | |
| 208 | + mdev->model.g200.pclk_min = pins[123] * tmp; | |
| 209 | + if (pins[38] != 0xff) | |
| 210 | + mdev->model.g200.pclk_max = pins[38] * tmp; | |
| 211 | + if (pins[110] & 0x01) | |
| 212 | + mdev->model.g200.ref_clk = 14318; | |
| 213 | + break; | |
| 214 | + default: | |
| 215 | + break; | |
| 216 | + } | |
| 217 | +} | |
| 218 | + | |
| 219 | +static void mgag200_g200_init_refclk(struct mga_device *mdev) | |
| 220 | +{ | |
| 221 | + struct drm_device *dev = &mdev->base; | |
| 222 | + unsigned char __iomem *rom; | |
| 223 | + unsigned char *bios; | |
| 224 | + size_t size; | |
| 225 | + | |
| 226 | + mdev->model.g200.pclk_min = 50000; | |
| 227 | + mdev->model.g200.pclk_max = 230000; | |
| 228 | + mdev->model.g200.ref_clk = 27050; | |
| 229 | + | |
| 230 | + rom = pci_map_rom(dev->pdev, &size); | |
| 231 | + if (!rom) | |
| 232 | + return; | |
| 233 | + | |
| 234 | + bios = vmalloc(size); | |
| 235 | + if (!bios) | |
| 236 | + goto out; | |
| 237 | + memcpy_fromio(bios, rom, size); | |
| 238 | + | |
| 239 | + if (size != 0 && bios[0] == 0x55 && bios[1] == 0xaa) | |
| 240 | + mgag200_g200_interpret_bios(mdev, bios, size); | |
| 241 | + | |
| 242 | + drm_dbg_kms(dev, "pclk_min: %ld pclk_max: %ld ref_clk: %ld\n", | |
| 243 | + mdev->model.g200.pclk_min, mdev->model.g200.pclk_max, | |
| 244 | + mdev->model.g200.ref_clk); | |
| 245 | + | |
| 246 | + vfree(bios); | |
| 247 | +out: | |
| 248 | + pci_unmap_rom(dev->pdev, rom); | |
| 249 | +} | |
| 250 | + | |
| 251 | +static void mgag200_g200se_init_unique_id(struct mga_device *mdev) | |
| 252 | +{ | |
| 253 | + struct drm_device *dev = &mdev->base; | |
| 254 | + | |
| 255 | + /* stash G200 SE model number for later use */ | |
| 256 | + mdev->model.g200se.unique_rev_id = RREG32(0x1e24); | |
| 257 | + | |
| 258 | + drm_dbg(dev, "G200 SE unique revision id is 0x%x\n", | |
| 259 | + mdev->model.g200se.unique_rev_id); | |
| 260 | +} | |
| 261 | + | |
| 262 | +static int mgag200_device_init(struct mga_device *mdev, unsigned long flags) | |
| 263 | +{ | |
| 264 | + struct drm_device *dev = &mdev->base; | |
| 265 | + int ret; | |
| 266 | + | |
| 267 | + mdev->flags = mgag200_flags_from_driver_data(flags); | |
| 268 | + mdev->type = mgag200_type_from_driver_data(flags); | |
| 269 | + | |
| 270 | + ret = mgag200_regs_init(mdev); | |
| 271 | + if (ret) | |
| 272 | + return ret; | |
| 273 | + | |
| 274 | + if (mdev->type == G200_PCI || mdev->type == G200_AGP) | |
| 275 | + mgag200_g200_init_refclk(mdev); | |
| 276 | + else if (IS_G200_SE(mdev)) | |
| 277 | + mgag200_g200se_init_unique_id(mdev); | |
| 77 | 278 | |
| 78 | 279 | ret = mgag200_mm_init(mdev); |
| 79 | 280 | if (ret) |
| @@ -116,6 +317,8 @@ mgag200_device_create(struct pci_dev *pdev, unsigned long flags) · 36 unmodified lines | ||
| 116 | 317 | */ |
| 117 | 318 | |
| 118 | 319 | static const struct pci_device_id mgag200_pciidlist[] = { |
| 320 | + { PCI_VENDOR_ID_MATROX, 0x520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_PCI }, | |
| 321 | + { PCI_VENDOR_ID_MATROX, 0x521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_AGP }, | |
| 119 | 322 | { PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
| 120 | 323 | G200_SE_A | MGAG200_FLAG_HW_BUG_NO_STARTADD}, |
| 121 | 324 | { PCI_VENDOR_ID_MATROX, 0x524, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_B }, |
| @@ -38,6 +38,8 @@ · 37 unmodified lines | ||
| 38 | 38 | #define RREG32(reg) ioread32(((void __iomem *)mdev->rmmio) + (reg)) |
| 39 | 39 | #define WREG32(reg, v) iowrite32(v, ((void __iomem *)mdev->rmmio) + (reg)) |
| 40 | 40 | |
| 41 | +#define MGA_BIOS_OFFSET 0x7ffc | |
| 42 | + | |
| 41 | 43 | #define ATTR_INDEX 0x1fc0 |
| 42 | 44 | #define ATTR_DATA 0x1fc1 |
| 43 | 45 | |
| @@ -129,6 +131,8 @@ struct mga_mc { · 85 unmodified lines | ||
| 129 | 131 | }; |
| 130 | 132 | |
| 131 | 133 | enum mga_type { |
| 134 | + G200_PCI, | |
| 135 | + G200_AGP, | |
| 132 | 136 | G200_SE_A, |
| 133 | 137 | G200_SE_B, |
| 134 | 138 | G200_WB, |
| @@ -161,14 +165,23 @@ struct mga_device { · 26 unmodified lines | ||
| 161 | 165 | size_t vram_fb_available; |
| 162 | 166 | |
| 163 | 167 | enum mga_type type; |
| 164 | − int has_sdram; | |
| 165 | 168 | |
| 166 | 169 | int bpp_shifts[4]; |
| 167 | 170 | |
| 168 | 171 | int fb_mtrr; |
| 169 | 172 | |
| 170 | − /* SE model number stored in reg 0x1e24 */ | |
| 171 | − u32 unique_rev_id; | |
| 173 | + union { | |
| 174 | + struct { | |
| 175 | + long ref_clk; | |
| 176 | + long pclk_min; | |
| 177 | + long pclk_max; | |
| 178 | + } g200; | |
| 179 | + struct { | |
| 180 | + /* SE model number stored in reg 0x1e24 */ | |
| 181 | + u32 unique_rev_id; | |
| 182 | + } g200se; | |
| 183 | + } model; | |
| 184 | + | |
| 172 | 185 | |
| 173 | 186 | struct mga_connector connector; |
| 174 | 187 | struct drm_simple_display_pipe display_pipe; |
| @@ -90,9 +90,17 @@ static void mgag200_mm_release(struct drm_device *dev, void *ptr) · 89 unmodified lines | ||
| 90 | 90 | int mgag200_mm_init(struct mga_device *mdev) |
| 91 | 91 | { |
| 92 | 92 | struct drm_device *dev = &mdev->base; |
| 93 | + u8 misc; | |
| 93 | 94 | resource_size_t start, len; |
| 94 | 95 | int ret; |
| 95 | 96 | |
| 97 | + WREG_ECRT(0x04, 0x00); | |
| 98 | + | |
| 99 | + misc = RREG8(MGA_MISC_IN); | |
| 100 | + misc |= MGAREG_MISC_RAMMAPEN | | |
| 101 | + MGAREG_MISC_HIGH_PG_SEL; | |
| 102 | + WREG8(MGA_MISC_OUT, misc); | |
| 103 | + | |
| 96 | 104 | /* BAR 0 is VRAM */ |
| 97 | 105 | start = pci_resource_start(dev->pdev, 0); |
| 98 | 106 | len = pci_resource_len(dev->pdev, 0); |
| @@ -9,7 +9,6 @@ · 8 unmodified lines | ||
| 9 | 9 | */ |
| 10 | 10 | |
| 11 | 11 | #include <linux/delay.h> |
| 12 | −#include <linux/pci.h> | |
| 13 | 12 | |
| 14 | 13 | #include <drm/drm_atomic_helper.h> |
| 15 | 14 | #include <drm/drm_atomic_state_helper.h> |
| @@ -109,10 +108,82 @@ static inline void mga_wait_busy(struct mga_device *mdev) · 93 unmodified lines | ||
| 109 | 108 | } while ((status & 0x01) && time_before(jiffies, timeout)); |
| 110 | 109 | } |
| 111 | 110 | |
| 111 | +/* | |
| 112 | + * PLL setup | |
| 113 | + */ | |
| 114 | + | |
| 115 | +static int mgag200_g200_set_plls(struct mga_device *mdev, long clock) | |
| 116 | +{ | |
| 117 | + struct drm_device *dev = &mdev->base; | |
| 118 | + const int post_div_max = 7; | |
| 119 | + const int in_div_min = 1; | |
| 120 | + const int in_div_max = 6; | |
| 121 | + const int feed_div_min = 7; | |
| 122 | + const int feed_div_max = 127; | |
| 123 | + u8 testm, testn; | |
| 124 | + u8 n = 0, m = 0, p, s; | |
| 125 | + long f_vco; | |
| 126 | + long computed; | |
| 127 | + long delta, tmp_delta; | |
| 128 | + long ref_clk = mdev->model.g200.ref_clk; | |
| 129 | + long p_clk_min = mdev->model.g200.pclk_min; | |
| 130 | + long p_clk_max = mdev->model.g200.pclk_max; | |
| 131 | + | |
| 132 | + if (clock > p_clk_max) { | |
| 133 | + drm_err(dev, "Pixel Clock %ld too high\n", clock); | |
| 134 | + return 1; | |
| 135 | + } | |
| 136 | + | |
| 137 | + if (clock < p_clk_min >> 3) | |
| 138 | + clock = p_clk_min >> 3; | |
| 139 | + | |
| 140 | + f_vco = clock; | |
| 141 | + for (p = 0; | |
| 142 | + p <= post_div_max && f_vco < p_clk_min; | |
| 143 | + p = (p << 1) + 1, f_vco <<= 1) | |
| 144 | + ; | |
| 145 | + | |
| 146 | + delta = clock; | |
| 147 | + | |
| 148 | + for (testm = in_div_min; testm <= in_div_max; testm++) { | |
| 149 | + for (testn = feed_div_min; testn <= feed_div_max; testn++) { | |
| 150 | + computed = ref_clk * (testn + 1) / (testm + 1); | |
| 151 | + if (computed < f_vco) | |
| 152 | + tmp_delta = f_vco - computed; | |
| 153 | + else | |
| 154 | + tmp_delta = computed - f_vco; | |
| 155 | + if (tmp_delta < delta) { | |
| 156 | + delta = tmp_delta; | |
| 157 | + m = testm; | |
| 158 | + n = testn; | |
| 159 | + } | |
| 160 | + } | |
| 161 | + } | |
| 162 | + f_vco = ref_clk * (n + 1) / (m + 1); | |
| 163 | + if (f_vco < 100000) | |
| 164 | + s = 0; | |
| 165 | + else if (f_vco < 140000) | |
| 166 | + s = 1; | |
| 167 | + else if (f_vco < 180000) | |
| 168 | + s = 2; | |
| 169 | + else | |
| 170 | + s = 3; | |
| 171 | + | |
| 172 | + drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n", | |
| 173 | + clock, f_vco, m, n, p, s); | |
| 174 | + | |
| 175 | + WREG_DAC(MGA1064_PIX_PLLC_M, m); | |
| 176 | + WREG_DAC(MGA1064_PIX_PLLC_N, n); | |
| 177 | + WREG_DAC(MGA1064_PIX_PLLC_P, (p | (s << 3))); | |
| 178 | + | |
| 179 | + return 0; | |
| 180 | +} | |
| 181 | + | |
| 112 | 182 | #define P_ARRAY_SIZE 9 |
| 113 | 183 | |
| 114 | 184 | static int mga_g200se_set_plls(struct mga_device *mdev, long clock) |
| 115 | 185 | { |
| 186 | + u32 unique_rev_id = mdev->model.g200se.unique_rev_id; | |
| 116 | 187 | unsigned int vcomax, vcomin, pllreffreq; |
| 117 | 188 | unsigned int delta, tmpdelta, permitteddelta; |
| 118 | 189 | unsigned int testp, testm, testn; |
| @@ -122,7 +193,7 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock) · 3 unmodified lines | ||
| 122 | 193 | unsigned int fvv; |
| 123 | 194 | unsigned int i; |
| 124 | 195 | |
| 125 | − if (mdev->unique_rev_id <= 0x03) { | |
| 196 | + if (unique_rev_id <= 0x03) { | |
| 126 | 197 | |
| 127 | 198 | m = n = p = 0; |
| 128 | 199 | vcomax = 320000; |
| @@ -220,7 +291,7 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock) · 91 unmodified lines | ||
| 220 | 291 | WREG_DAC(MGA1064_PIX_PLLC_N, n); |
| 221 | 292 | WREG_DAC(MGA1064_PIX_PLLC_P, p); |
| 222 | 293 | |
| 223 | − if (mdev->unique_rev_id >= 0x04) { | |
| 294 | + if (unique_rev_id >= 0x04) { | |
| 224 | 295 | WREG_DAC(0x1a, 0x09); |
| 225 | 296 | msleep(20); |
| 226 | 297 | WREG_DAC(0x1a, 0x01); |
| @@ -717,6 +788,9 @@ static int mgag200_crtc_set_plls(struct mga_device *mdev, long clock) · 490 unmodified lines | ||
| 717 | 788 | u8 misc; |
| 718 | 789 | |
| 719 | 790 | switch(mdev->type) { |
| 791 | + case G200_PCI: | |
| 792 | + case G200_AGP: | |
| 793 | + return mgag200_g200_set_plls(mdev, clock); | |
| 720 | 794 | case G200_SE_A: |
| 721 | 795 | case G200_SE_B: |
| 722 | 796 | return mga_g200se_set_plls(mdev, clock); |
| @@ -877,45 +951,6 @@ static void mgag200_set_startadd(struct mga_device *mdev, · 154 unmodified lines | ||
| 877 | 951 | WREG_ECRT(0x00, crtcext0); |
| 878 | 952 | } |
| 879 | 953 | |
| 880 | −static void mgag200_set_pci_regs(struct mga_device *mdev) | |
| 881 | −{ | |
| 882 | − uint32_t option = 0, option2 = 0; | |
| 883 | − struct drm_device *dev = &mdev->base; | |
| 884 | − | |
| 885 | − switch (mdev->type) { | |
| 886 | − case G200_SE_A: | |
| 887 | − case G200_SE_B: | |
| 888 | − if (mdev->has_sdram) | |
| 889 | − option = 0x40049120; | |
| 890 | − else | |
| 891 | − option = 0x4004d120; | |
| 892 | − option2 = 0x00008000; | |
| 893 | − break; | |
| 894 | − case G200_WB: | |
| 895 | − case G200_EW3: | |
| 896 | − option = 0x41049120; | |
| 897 | − option2 = 0x0000b000; | |
| 898 | − break; | |
| 899 | − case G200_EV: | |
| 900 | − option = 0x00000120; | |
| 901 | − option2 = 0x0000b000; | |
| 902 | − break; | |
| 903 | − case G200_EH: | |
| 904 | − case G200_EH3: | |
| 905 | − option = 0x00000120; | |
| 906 | − option2 = 0x0000b000; | |
| 907 | − break; | |
| 908 | − case G200_ER: | |
| 909 | − break; | |
| 910 | − } | |
| 911 | − | |
| 912 | − if (option) | |
| 913 | − pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option); | |
| 914 | − | |
| 915 | − if (option2) | |
| 916 | − pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2); | |
| 917 | −} | |
| 918 | − | |
| 919 | 954 | static void mgag200_set_dac_regs(struct mga_device *mdev) |
| 920 | 955 | { |
| 921 | 956 | size_t i; |
| @@ -933,6 +968,12 @@ static void mgag200_set_dac_regs(struct mga_device *mdev) · 11 unmodified lines | ||
| 933 | 968 | }; |
| 934 | 969 | |
| 935 | 970 | switch (mdev->type) { |
| 971 | + case G200_PCI: | |
| 972 | + case G200_AGP: | |
| 973 | + dacvalue[MGA1064_SYS_PLL_M] = 0x04; | |
| 974 | + dacvalue[MGA1064_SYS_PLL_N] = 0x2D; | |
| 975 | + dacvalue[MGA1064_SYS_PLL_P] = 0x19; | |
| 976 | + break; | |
| 936 | 977 | case G200_SE_A: |
| 937 | 978 | case G200_SE_B: |
| 938 | 979 | dacvalue[MGA1064_VREF_CTL] = 0x03; |
| @@ -986,9 +1027,8 @@ static void mgag200_set_dac_regs(struct mga_device *mdev) · 47 unmodified lines | ||
| 986 | 1027 | |
| 987 | 1028 | static void mgag200_init_regs(struct mga_device *mdev) |
| 988 | 1029 | { |
| 989 | − u8 crtc11, crtcext3, crtcext4, misc; | |
| 1030 | + u8 crtc11, misc; | |
| 990 | 1031 | |
| 991 | − mgag200_set_pci_regs(mdev); | |
| 992 | 1032 | mgag200_set_dac_regs(mdev); |
| 993 | 1033 | |
| 994 | 1034 | WREG_SEQ(2, 0x0f); |
| @@ -1002,14 +1042,6 @@ static void mgag200_init_regs(struct mga_device *mdev) · 7 unmodified lines | ||
| 1002 | 1042 | WREG_CRT(14, 0); |
| 1003 | 1043 | WREG_CRT(15, 0); |
| 1004 | 1044 | |
| 1005 | − RREG_ECRT(0x03, crtcext3); | |
| 1006 | − | |
| 1007 | − crtcext3 |= BIT(7); /* enable MGA mode */ | |
| 1008 | − crtcext4 = 0x00; | |
| 1009 | − | |
| 1010 | − WREG_ECRT(0x03, crtcext3); | |
| 1011 | − WREG_ECRT(0x04, crtcext4); | |
| 1012 | − | |
| 1013 | 1045 | RREG_CRT(0x11, crtc11); |
| 1014 | 1046 | crtc11 &= ~(MGAREG_CRTC11_CRTCPROTECT | |
| 1015 | 1047 | MGAREG_CRTC11_VINTEN | |
| @@ -1023,9 +1055,7 @@ static void mgag200_init_regs(struct mga_device *mdev) · 7 unmodified lines | ||
| 1023 | 1055 | WREG_ECRT(0x34, 0x5); |
| 1024 | 1056 | |
| 1025 | 1057 | misc = RREG8(MGA_MISC_IN); |
| 1026 | − misc |= MGAREG_MISC_IOADSEL | | |
| 1027 | − MGAREG_MISC_RAMMAPEN | | |
| 1028 | − MGAREG_MISC_HIGH_PG_SEL; | |
| 1058 | + misc |= MGAREG_MISC_IOADSEL; | |
| 1029 | 1059 | WREG8(MGA_MISC_OUT, misc); |
| 1030 | 1060 | } |
| 1031 | 1061 | |
| @@ -1234,12 +1264,13 @@ static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev, · 202 unmodified lines | ||
| 1234 | 1264 | const struct drm_display_mode *mode, |
| 1235 | 1265 | const struct drm_framebuffer *fb) |
| 1236 | 1266 | { |
| 1267 | + u32 unique_rev_id = mdev->model.g200se.unique_rev_id; | |
| 1237 | 1268 | unsigned int hiprilvl; |
| 1238 | 1269 | u8 crtcext6; |
| 1239 | 1270 | |
| 1240 | − if (mdev->unique_rev_id >= 0x04) { | |
| 1271 | + if (unique_rev_id >= 0x04) { | |
| 1241 | 1272 | hiprilvl = 0; |
| 1242 | − } else if (mdev->unique_rev_id >= 0x02) { | |
| 1273 | + } else if (unique_rev_id >= 0x02) { | |
| 1243 | 1274 | unsigned int bpp; |
| 1244 | 1275 | unsigned long mb; |
| 1245 | 1276 | |
| @@ -1264,7 +1295,7 @@ static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev, · 18 unmodified lines | ||
| 1264 | 1295 | else |
| 1265 | 1296 | hiprilvl = 5; |
| 1266 | 1297 | |
| 1267 | − } else if (mdev->unique_rev_id >= 0x01) { | |
| 1298 | + } else if (unique_rev_id >= 0x01) { | |
| 1268 | 1299 | hiprilvl = 3; |
| 1269 | 1300 | } else { |
| 1270 | 1301 | hiprilvl = 4; |
| @@ -1388,7 +1419,9 @@ static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector, · 117 unmodified lines | ||
| 1388 | 1419 | int bpp = 32; |
| 1389 | 1420 | |
| 1390 | 1421 | if (IS_G200_SE(mdev)) { |
| 1391 | − if (mdev->unique_rev_id == 0x01) { | |
| 1422 | + u32 unique_rev_id = mdev->model.g200se.unique_rev_id; | |
| 1423 | + | |
| 1424 | + if (unique_rev_id == 0x01) { | |
| 1392 | 1425 | if (mode->hdisplay > 1600) |
| 1393 | 1426 | return MODE_VIRTUAL_X; |
| 1394 | 1427 | if (mode->vdisplay > 1200) |
| @@ -1396,7 +1429,7 @@ static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector, · 1 unmodified line | ||
| 1396 | 1429 | if (mga_vga_calculate_mode_bandwidth(mode, bpp) |
| 1397 | 1430 | > (24400 * 1024)) |
| 1398 | 1431 | return MODE_BANDWIDTH; |
| 1399 | − } else if (mdev->unique_rev_id == 0x02) { | |
| 1432 | + } else if (unique_rev_id == 0x02) { | |
| 1400 | 1433 | if (mode->hdisplay > 1920) |
| 1401 | 1434 | return MODE_VIRTUAL_X; |
| 1402 | 1435 | if (mode->vdisplay > 1200) |
| @@ -256,6 +256,8 @@ · 255 unmodified lines | ||
| 256 | 256 | #define MGAREG_CRTCEXT1_VSYNCOFF BIT(5) |
| 257 | 257 | #define MGAREG_CRTCEXT1_HSYNCOFF BIT(4) |
| 258 | 258 | |
| 259 | +#define MGAREG_CRTCEXT3_MGAMODE BIT(7) | |
| 260 | + | |
| 259 | 261 | /* Cursor X and Y position */ |
| 260 | 262 | #define MGA_CURPOSXL 0x3c0c |
| 261 | 263 | #define MGA_CURPOSXH 0x3c0d |
| @@ -282,6 +284,8 @@ · 20 unmodified lines | ||
| 282 | 284 | #define PCI_MGA_OPTION2 0x50 |
| 283 | 285 | #define PCI_MGA_OPTION3 0x54 |
| 284 | 286 | |
| 287 | +#define PCI_MGA_OPTION_HARDPWMSK BIT(14) | |
| 288 | + | |
| 285 | 289 | #define RAMDAC_OFFSET 0x3c00 |
| 286 | 290 | |
| 287 | 291 | /* TVP3026 direct registers */ |
| @@ -50,14 +50,9 @@ static int mdp4_lvds_connector_get_modes(struct drm_connector *connector) · 49 unmodified lines | ||
| 50 | 50 | struct drm_panel *panel = mdp4_lvds_connector->panel; |
| 51 | 51 | int ret = 0; |
| 52 | 52 | |
| 53 | − if (panel) { | |
| 54 | − drm_panel_attach(panel, connector); | |
| 55 | − | |
| 53 | + if (panel) | |
| 56 | 54 | ret = drm_panel_get_modes(panel, connector); |
| 57 | 55 | |
| 58 | − drm_panel_detach(panel); | |
| 59 | − } | |
| 60 | − | |
| 61 | 56 | return ret; |
| 62 | 57 | } |
| 63 | 58 | |
| @@ -328,7 +328,6 @@ static int dsi_mgr_connector_get_modes(struct drm_connector *connector) · 327 unmodified lines | ||
| 328 | 328 | * In dual DSI mode, we have one connector that can be |
| 329 | 329 | * attached to the drm_panel. |
| 330 | 330 | */ |
| 331 | − drm_panel_attach(panel, connector); | |
| 332 | 331 | num = drm_panel_get_modes(panel, connector); |
| 333 | 332 | if (!num) |
| 334 | 333 | return 0; |
| @@ -5,7 +5,7 @@ config DRM_MXS · 4 unmodified lines | ||
| 5 | 5 | Choose this option to select drivers for MXS FB devices |
| 6 | 6 | |
| 7 | 7 | config DRM_MXSFB |
| 8 | − tristate "i.MX23/i.MX28/i.MX6SX MXSFB LCD controller" | |
| 8 | + tristate "i.MX (e)LCDIF LCD controller" | |
| 9 | 9 | depends on DRM && OF |
| 10 | 10 | depends on COMMON_CLK |
| 11 | 11 | select DRM_MXS |
| @@ -13,8 +13,10 @@ config DRM_MXSFB · 1 unmodified line | ||
| 13 | 13 | select DRM_KMS_FB_HELPER |
| 14 | 14 | select DRM_KMS_CMA_HELPER |
| 15 | 15 | select DRM_PANEL |
| 16 | + select DRM_PANEL_BRIDGE | |
| 16 | 17 | help |
| 17 | − Choose this option if you have an i.MX23/i.MX28/i.MX6SX MXSFB | |
| 18 | − LCD controller. | |
| 18 | + Choose this option if you have an LCDIF or eLCDIF LCD controller. | |
| 19 | + Those devices are found in various i.MX SoC (including i.MX23, | |
| 20 | + i.MX28, i.MX6SX, i.MX7 and i.MX8M). | |
| 19 | 21 | |
| 20 | 22 | If M is selected the module will be called mxsfb. |
| @@ -1,3 +1,3 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | −mxsfb-y := mxsfb_drv.o mxsfb_crtc.o mxsfb_out.o | |
| 2 | +mxsfb-y := mxsfb_drv.o mxsfb_kms.o | |
| 3 | 3 | obj-$(CONFIG_DRM_MXSFB) += mxsfb.o |
| @@ -1,343 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | −/* | |
| 3 | − * Copyright (C) 2016 Marek Vasut <marex@denx.de> | |
| 4 | − * | |
| 5 | − * This code is based on drivers/video/fbdev/mxsfb.c : | |
| 6 | − * Copyright (C) 2010 Juergen Beisert, Pengutronix | |
| 7 | − * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. | |
| 8 | − * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved. | |
| 9 | − */ | |
| 10 | − | |
| 11 | −#include <linux/clk.h> | |
| 12 | −#include <linux/iopoll.h> | |
| 13 | −#include <linux/of_graph.h> | |
| 14 | −#include <linux/platform_data/simplefb.h> | |
| 15 | − | |
| 16 | −#include <video/videomode.h> | |
| 17 | − | |
| 18 | −#include <drm/drm_atomic_helper.h> | |
| 19 | −#include <drm/drm_crtc.h> | |
| 20 | −#include <drm/drm_fb_cma_helper.h> | |
| 21 | −#include <drm/drm_fb_helper.h> | |
| 22 | −#include <drm/drm_gem_cma_helper.h> | |
| 23 | −#include <drm/drm_of.h> | |
| 24 | −#include <drm/drm_plane_helper.h> | |
| 25 | −#include <drm/drm_probe_helper.h> | |
| 26 | −#include <drm/drm_simple_kms_helper.h> | |
| 27 | −#include <drm/drm_vblank.h> | |
| 28 | − | |
| 29 | −#include "mxsfb_drv.h" | |
| 30 | −#include "mxsfb_regs.h" | |
| 31 | − | |
| 32 | −#define MXS_SET_ADDR 0x4 | |
| 33 | −#define MXS_CLR_ADDR 0x8 | |
| 34 | −#define MODULE_CLKGATE BIT(30) | |
| 35 | −#define MODULE_SFTRST BIT(31) | |
| 36 | −/* 1 second delay should be plenty of time for block reset */ | |
| 37 | −#define RESET_TIMEOUT 1000000 | |
| 38 | − | |
| 39 | −static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val) | |
| 40 | −{ | |
| 41 | − return (val & mxsfb->devdata->hs_wdth_mask) << | |
| 42 | − mxsfb->devdata->hs_wdth_shift; | |
| 43 | −} | |
| 44 | − | |
| 45 | −/* Setup the MXSFB registers for decoding the pixels out of the framebuffer */ | |
| 46 | −static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb) | |
| 47 | −{ | |
| 48 | − struct drm_crtc *crtc = &mxsfb->pipe.crtc; | |
| 49 | − struct drm_device *drm = crtc->dev; | |
| 50 | − const u32 format = crtc->primary->state->fb->format->format; | |
| 51 | − u32 ctrl, ctrl1; | |
| 52 | − | |
| 53 | − ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER; | |
| 54 | − | |
| 55 | − /* | |
| 56 | − * WARNING: The bus width, CTRL_SET_BUS_WIDTH(), is configured to | |
| 57 | − * match the selected mode here. This differs from the original | |
| 58 | − * MXSFB driver, which had the option to configure the bus width | |
| 59 | − * to arbitrary value. This limitation should not pose an issue. | |
| 60 | − */ | |
| 61 | − | |
| 62 | − /* CTRL1 contains IRQ config and status bits, preserve those. */ | |
| 63 | − ctrl1 = readl(mxsfb->base + LCDC_CTRL1); | |
| 64 | − ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ; | |
| 65 | − | |
| 66 | − switch (format) { | |
| 67 | − case DRM_FORMAT_RGB565: | |
| 68 | − dev_dbg(drm->dev, "Setting up RGB565 mode\n"); | |
| 69 | − ctrl |= CTRL_SET_WORD_LENGTH(0); | |
| 70 | − ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf); | |
| 71 | − break; | |
| 72 | − case DRM_FORMAT_XRGB8888: | |
| 73 | − dev_dbg(drm->dev, "Setting up XRGB8888 mode\n"); | |
| 74 | − ctrl |= CTRL_SET_WORD_LENGTH(3); | |
| 75 | − /* Do not use packed pixels = one pixel per word instead. */ | |
| 76 | − ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7); | |
| 77 | − break; | |
| 78 | − default: | |
| 79 | − dev_err(drm->dev, "Unhandled pixel format %08x\n", format); | |
| 80 | − return -EINVAL; | |
| 81 | − } | |
| 82 | − | |
| 83 | − writel(ctrl1, mxsfb->base + LCDC_CTRL1); | |
| 84 | − writel(ctrl, mxsfb->base + LCDC_CTRL); | |
| 85 | − | |
| 86 | − return 0; | |
| 87 | −} | |
| 88 | − | |
| 89 | −static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb) | |
| 90 | −{ | |
| 91 | − struct drm_crtc *crtc = &mxsfb->pipe.crtc; | |
| 92 | − struct drm_device *drm = crtc->dev; | |
| 93 | − u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; | |
| 94 | − u32 reg; | |
| 95 | − | |
| 96 | − reg = readl(mxsfb->base + LCDC_CTRL); | |
| 97 | − | |
| 98 | − if (mxsfb->connector->display_info.num_bus_formats) | |
| 99 | − bus_format = mxsfb->connector->display_info.bus_formats[0]; | |
| 100 | − | |
| 101 | − DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n", | |
| 102 | − bus_format); | |
| 103 | − | |
| 104 | − reg &= ~CTRL_BUS_WIDTH_MASK; | |
| 105 | − switch (bus_format) { | |
| 106 | − case MEDIA_BUS_FMT_RGB565_1X16: | |
| 107 | − reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT); | |
| 108 | − break; | |
| 109 | − case MEDIA_BUS_FMT_RGB666_1X18: | |
| 110 | − reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT); | |
| 111 | − break; | |
| 112 | − case MEDIA_BUS_FMT_RGB888_1X24: | |
| 113 | − reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT); | |
| 114 | − break; | |
| 115 | − default: | |
| 116 | − dev_err(drm->dev, "Unknown media bus format %d\n", bus_format); | |
| 117 | − break; | |
| 118 | − } | |
| 119 | − writel(reg, mxsfb->base + LCDC_CTRL); | |
| 120 | −} | |
| 121 | − | |
| 122 | −static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb) | |
| 123 | −{ | |
| 124 | − u32 reg; | |
| 125 | − | |
| 126 | − if (mxsfb->clk_disp_axi) | |
| 127 | − clk_prepare_enable(mxsfb->clk_disp_axi); | |
| 128 | − clk_prepare_enable(mxsfb->clk); | |
| 129 | − | |
| 130 | − /* If it was disabled, re-enable the mode again */ | |
| 131 | − writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET); | |
| 132 | − | |
| 133 | − /* Enable the SYNC signals first, then the DMA engine */ | |
| 134 | − reg = readl(mxsfb->base + LCDC_VDCTRL4); | |
| 135 | − reg |= VDCTRL4_SYNC_SIGNALS_ON; | |
| 136 | − writel(reg, mxsfb->base + LCDC_VDCTRL4); | |
| 137 | − | |
| 138 | − writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET); | |
| 139 | −} | |
| 140 | − | |
| 141 | −static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb) | |
| 142 | −{ | |
| 143 | − u32 reg; | |
| 144 | − | |
| 145 | − /* | |
| 146 | − * Even if we disable the controller here, it will still continue | |
| 147 | − * until its FIFOs are running out of data | |
| 148 | − */ | |
| 149 | − writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR); | |
| 150 | − | |
| 151 | − readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN), | |
| 152 | − 0, 1000); | |
| 153 | − | |
| 154 | − reg = readl(mxsfb->base + LCDC_VDCTRL4); | |
| 155 | − reg &= ~VDCTRL4_SYNC_SIGNALS_ON; | |
| 156 | − writel(reg, mxsfb->base + LCDC_VDCTRL4); | |
| 157 | − | |
| 158 | − clk_disable_unprepare(mxsfb->clk); | |
| 159 | − if (mxsfb->clk_disp_axi) | |
| 160 | − clk_disable_unprepare(mxsfb->clk_disp_axi); | |
| 161 | −} | |
| 162 | − | |
| 163 | −/* | |
| 164 | − * Clear the bit and poll it cleared. This is usually called with | |
| 165 | − * a reset address and mask being either SFTRST(bit 31) or CLKGATE | |
| 166 | − * (bit 30). | |
| 167 | − */ | |
| 168 | −static int clear_poll_bit(void __iomem *addr, u32 mask) | |
| 169 | −{ | |
| 170 | − u32 reg; | |
| 171 | − | |
| 172 | − writel(mask, addr + MXS_CLR_ADDR); | |
| 173 | − return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT); | |
| 174 | −} | |
| 175 | − | |
| 176 | −static int mxsfb_reset_block(void __iomem *reset_addr) | |
| 177 | −{ | |
| 178 | − int ret; | |
| 179 | − | |
| 180 | − ret = clear_poll_bit(reset_addr, MODULE_SFTRST); | |
| 181 | − if (ret) | |
| 182 | − return ret; | |
| 183 | − | |
| 184 | − writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR); | |
| 185 | − | |
| 186 | − ret = clear_poll_bit(reset_addr, MODULE_SFTRST); | |
| 187 | − if (ret) | |
| 188 | − return ret; | |
| 189 | − | |
| 190 | − return clear_poll_bit(reset_addr, MODULE_CLKGATE); | |
| 191 | −} | |
| 192 | − | |
| 193 | −static dma_addr_t mxsfb_get_fb_paddr(struct mxsfb_drm_private *mxsfb) | |
| 194 | −{ | |
| 195 | − struct drm_framebuffer *fb = mxsfb->pipe.plane.state->fb; | |
| 196 | − struct drm_gem_cma_object *gem; | |
| 197 | − | |
| 198 | − if (!fb) | |
| 199 | − return 0; | |
| 200 | − | |
| 201 | − gem = drm_fb_cma_get_gem_obj(fb, 0); | |
| 202 | − if (!gem) | |
| 203 | − return 0; | |
| 204 | − | |
| 205 | − return gem->paddr; | |
| 206 | −} | |
| 207 | − | |
| 208 | −static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) | |
| 209 | −{ | |
| 210 | − struct drm_device *drm = mxsfb->pipe.crtc.dev; | |
| 211 | − struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode; | |
| 212 | − u32 bus_flags = mxsfb->connector->display_info.bus_flags; | |
| 213 | − u32 vdctrl0, vsync_pulse_len, hsync_pulse_len; | |
| 214 | − int err; | |
| 215 | − | |
| 216 | − /* | |
| 217 | − * It seems, you can't re-program the controller if it is still | |
| 218 | − * running. This may lead to shifted pictures (FIFO issue?), so | |
| 219 | − * first stop the controller and drain its FIFOs. | |
| 220 | − */ | |
| 221 | − | |
| 222 | − /* Mandatory eLCDIF reset as per the Reference Manual */ | |
| 223 | − err = mxsfb_reset_block(mxsfb->base); | |
| 224 | − if (err) | |
| 225 | − return; | |
| 226 | − | |
| 227 | − /* Clear the FIFOs */ | |
| 228 | − writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET); | |
| 229 | − | |
| 230 | − err = mxsfb_set_pixel_fmt(mxsfb); | |
| 231 | − if (err) | |
| 232 | − return; | |
| 233 | − | |
| 234 | − clk_set_rate(mxsfb->clk, m->crtc_clock * 1000); | |
| 235 | − | |
| 236 | − if (mxsfb->bridge && mxsfb->bridge->timings) | |
| 237 | − bus_flags = mxsfb->bridge->timings->input_bus_flags; | |
| 238 | − | |
| 239 | − DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n", | |
| 240 | − m->crtc_clock, | |
| 241 | − (int)(clk_get_rate(mxsfb->clk) / 1000)); | |
| 242 | − DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n", | |
| 243 | − bus_flags); | |
| 244 | − DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags); | |
| 245 | − | |
| 246 | − writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) | | |
| 247 | − TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay), | |
| 248 | − mxsfb->base + mxsfb->devdata->transfer_count); | |
| 249 | − | |
| 250 | − vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start; | |
| 251 | − | |
| 252 | − vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* Always in DOTCLOCK mode */ | |
| 253 | − VDCTRL0_VSYNC_PERIOD_UNIT | | |
| 254 | − VDCTRL0_VSYNC_PULSE_WIDTH_UNIT | | |
| 255 | − VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len); | |
| 256 | − if (m->flags & DRM_MODE_FLAG_PHSYNC) | |
| 257 | − vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH; | |
| 258 | − if (m->flags & DRM_MODE_FLAG_PVSYNC) | |
| 259 | − vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH; | |
| 260 | − /* Make sure Data Enable is high active by default */ | |
| 261 | − if (!(bus_flags & DRM_BUS_FLAG_DE_LOW)) | |
| 262 | − vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH; | |
| 263 | − /* | |
| 264 | − * DRM_BUS_FLAG_PIXDATA_DRIVE_ defines are controller centric, | |
| 265 | − * controllers VDCTRL0_DOTCLK is display centric. | |
| 266 | − * Drive on positive edge -> display samples on falling edge | |
| 267 | − * DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING | |
| 268 | − */ | |
| 269 | − if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE) | |
| 270 | − vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING; | |
| 271 | − | |
| 272 | − writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0); | |
| 273 | − | |
| 274 | − mxsfb_set_bus_fmt(mxsfb); | |
| 275 | − | |
| 276 | − /* Frame length in lines. */ | |
| 277 | − writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1); | |
| 278 | − | |
| 279 | − /* Line length in units of clocks or pixels. */ | |
| 280 | − hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start; | |
| 281 | − writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) | | |
| 282 | − VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal), | |
| 283 | − mxsfb->base + LCDC_VDCTRL2); | |
| 284 | − | |
| 285 | − writel(SET_HOR_WAIT_CNT(m->crtc_htotal - m->crtc_hsync_start) | | |
| 286 | − SET_VERT_WAIT_CNT(m->crtc_vtotal - m->crtc_vsync_start), | |
| 287 | − mxsfb->base + LCDC_VDCTRL3); | |
| 288 | − | |
| 289 | − writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay), | |
| 290 | − mxsfb->base + LCDC_VDCTRL4); | |
| 291 | −} | |
| 292 | − | |
| 293 | −void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb) | |
| 294 | −{ | |
| 295 | − dma_addr_t paddr; | |
| 296 | − | |
| 297 | − mxsfb_enable_axi_clk(mxsfb); | |
| 298 | − mxsfb_crtc_mode_set_nofb(mxsfb); | |
| 299 | − | |
| 300 | − /* Write cur_buf as well to avoid an initial corrupt frame */ | |
| 301 | − paddr = mxsfb_get_fb_paddr(mxsfb); | |
| 302 | − if (paddr) { | |
| 303 | − writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf); | |
| 304 | − writel(paddr, mxsfb->base + mxsfb->devdata->next_buf); | |
| 305 | − } | |
| 306 | − | |
| 307 | − mxsfb_enable_controller(mxsfb); | |
| 308 | −} | |
| 309 | − | |
| 310 | −void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb) | |
| 311 | −{ | |
| 312 | − mxsfb_disable_controller(mxsfb); | |
| 313 | − mxsfb_disable_axi_clk(mxsfb); | |
| 314 | −} | |
| 315 | − | |
| 316 | −void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb, | |
| 317 | − struct drm_plane_state *state) | |
| 318 | −{ | |
| 319 | − struct drm_simple_display_pipe *pipe = &mxsfb->pipe; | |
| 320 | − struct drm_crtc *crtc = &pipe->crtc; | |
| 321 | − struct drm_pending_vblank_event *event; | |
| 322 | − dma_addr_t paddr; | |
| 323 | − | |
| 324 | − spin_lock_irq(&crtc->dev->event_lock); | |
| 325 | − event = crtc->state->event; | |
| 326 | − if (event) { | |
| 327 | − crtc->state->event = NULL; | |
| 328 | − | |
| 329 | − if (drm_crtc_vblank_get(crtc) == 0) { | |
| 330 | − drm_crtc_arm_vblank_event(crtc, event); | |
| 331 | − } else { | |
| 332 | − drm_crtc_send_vblank_event(crtc, event); | |
| 333 | − } | |
| 334 | − } | |
| 335 | − spin_unlock_irq(&crtc->dev->event_lock); | |
| 336 | − | |
| 337 | − paddr = mxsfb_get_fb_paddr(mxsfb); | |
| 338 | − if (paddr) { | |
| 339 | − mxsfb_enable_axi_clk(mxsfb); | |
| 340 | − writel(paddr, mxsfb->base + mxsfb->devdata->next_buf); | |
| 341 | − mxsfb_disable_axi_clk(mxsfb); | |
| 342 | − } | |
| 343 | −} | |
| @@ -9,30 +9,24 @@ · 8 unmodified lines | ||
| 9 | 9 | */ |
| 10 | 10 | |
| 11 | 11 | #include <linux/clk.h> |
| 12 | −#include <linux/component.h> | |
| 13 | 12 | #include <linux/dma-mapping.h> |
| 14 | −#include <linux/list.h> | |
| 13 | +#include <linux/io.h> | |
| 15 | 14 | #include <linux/module.h> |
| 16 | 15 | #include <linux/of_device.h> |
| 17 | −#include <linux/of_graph.h> | |
| 18 | −#include <linux/of_reserved_mem.h> | |
| 16 | +#include <linux/platform_device.h> | |
| 19 | 17 | #include <linux/pm_runtime.h> |
| 20 | −#include <linux/dma-resv.h> | |
| 21 | −#include <linux/spinlock.h> | |
| 22 | 18 | |
| 23 | −#include <drm/drm_atomic.h> | |
| 24 | 19 | #include <drm/drm_atomic_helper.h> |
| 25 | −#include <drm/drm_crtc.h> | |
| 20 | +#include <drm/drm_bridge.h> | |
| 21 | +#include <drm/drm_connector.h> | |
| 26 | 22 | #include <drm/drm_drv.h> |
| 27 | −#include <drm/drm_fb_cma_helper.h> | |
| 28 | 23 | #include <drm/drm_fb_helper.h> |
| 29 | 24 | #include <drm/drm_gem_cma_helper.h> |
| 30 | 25 | #include <drm/drm_gem_framebuffer_helper.h> |
| 31 | 26 | #include <drm/drm_irq.h> |
| 27 | +#include <drm/drm_mode_config.h> | |
| 32 | 28 | #include <drm/drm_of.h> |
| 33 | −#include <drm/drm_panel.h> | |
| 34 | 29 | #include <drm/drm_probe_helper.h> |
| 35 | −#include <drm/drm_simple_kms_helper.h> | |
| 36 | 30 | #include <drm/drm_vblank.h> |
| 37 | 31 | |
| 38 | 32 | #include "mxsfb_drv.h" |
| @@ -41,6 +35,11 @@ · 2 unmodified lines | ||
| 41 | 35 | enum mxsfb_devtype { |
| 42 | 36 | MXSFB_V3, |
| 43 | 37 | MXSFB_V4, |
| 38 | + /* | |
| 39 | + * Starting at i.MX6 the hardware version register is gone, use the | |
| 40 | + * i.MX family number as the version. | |
| 41 | + */ | |
| 42 | + MXSFB_V6, | |
| 44 | 43 | }; |
| 45 | 44 | |
| 46 | 45 | static const struct mxsfb_devdata mxsfb_devdata[] = { |
| @@ -48,38 +47,28 @@ static const struct mxsfb_devdata mxsfb_devdata[] = { · 1 unmodified line | ||
| 48 | 47 | .transfer_count = LCDC_V3_TRANSFER_COUNT, |
| 49 | 48 | .cur_buf = LCDC_V3_CUR_BUF, |
| 50 | 49 | .next_buf = LCDC_V3_NEXT_BUF, |
| 51 | − .debug0 = LCDC_V3_DEBUG0, | |
| 52 | 50 | .hs_wdth_mask = 0xff, |
| 53 | 51 | .hs_wdth_shift = 24, |
| 54 | − .ipversion = 3, | |
| 52 | + .has_overlay = false, | |
| 55 | 53 | }, |
| 56 | 54 | [MXSFB_V4] = { |
| 57 | 55 | .transfer_count = LCDC_V4_TRANSFER_COUNT, |
| 58 | 56 | .cur_buf = LCDC_V4_CUR_BUF, |
| 59 | 57 | .next_buf = LCDC_V4_NEXT_BUF, |
| 60 | − .debug0 = LCDC_V4_DEBUG0, | |
| 61 | 58 | .hs_wdth_mask = 0x3fff, |
| 62 | 59 | .hs_wdth_shift = 18, |
| 63 | − .ipversion = 4, | |
| 60 | + .has_overlay = false, | |
| 61 | + }, | |
| 62 | + [MXSFB_V6] = { | |
| 63 | + .transfer_count = LCDC_V4_TRANSFER_COUNT, | |
| 64 | + .cur_buf = LCDC_V4_CUR_BUF, | |
| 65 | + .next_buf = LCDC_V4_NEXT_BUF, | |
| 66 | + .hs_wdth_mask = 0x3fff, | |
| 67 | + .hs_wdth_shift = 18, | |
| 68 | + .has_overlay = true, | |
| 64 | 69 | }, |
| 65 | 70 | }; |
| 66 | 71 | |
| 67 | −static const uint32_t mxsfb_formats[] = { | |
| 68 | − DRM_FORMAT_XRGB8888, | |
| 69 | − DRM_FORMAT_RGB565 | |
| 70 | −}; | |
| 71 | − | |
| 72 | −static const uint64_t mxsfb_modifiers[] = { | |
| 73 | − DRM_FORMAT_MOD_LINEAR, | |
| 74 | − DRM_FORMAT_MOD_INVALID | |
| 75 | −}; | |
| 76 | − | |
| 77 | −static struct mxsfb_drm_private * | |
| 78 | −drm_pipe_to_mxsfb_drm_private(struct drm_simple_display_pipe *pipe) | |
| 79 | −{ | |
| 80 | − return container_of(pipe, struct mxsfb_drm_private, pipe); | |
| 81 | −} | |
| 82 | − | |
| 83 | 72 | void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb) |
| 84 | 73 | { |
| 85 | 74 | if (mxsfb->clk_axi) |
| @@ -102,101 +91,51 @@ static const struct drm_mode_config_helper_funcs mxsfb_mode_config_helpers = { · 16 unmodified lines | ||
| 102 | 91 | .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, |
| 103 | 92 | }; |
| 104 | 93 | |
| 105 | −static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe, | |
| 106 | − struct drm_crtc_state *crtc_state, | |
| 107 | − struct drm_plane_state *plane_state) | |
| 94 | +static int mxsfb_attach_bridge(struct mxsfb_drm_private *mxsfb) | |
| 108 | 95 | { |
| 109 | − struct drm_connector *connector; | |
| 110 | − struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); | |
| 111 | − struct drm_device *drm = pipe->plane.dev; | |
| 112 | − | |
| 113 | − if (!mxsfb->connector) { | |
| 114 | − list_for_each_entry(connector, | |
| 115 | − &drm->mode_config.connector_list, | |
| 116 | − head) | |
| 117 | − if (connector->encoder == &mxsfb->pipe.encoder) { | |
| 118 | − mxsfb->connector = connector; | |
| 119 | − break; | |
| 120 | − } | |
| 121 | − } | |
| 122 | − | |
| 123 | − if (!mxsfb->connector) { | |
| 124 | − dev_warn(drm->dev, "No connector attached, using default\n"); | |
| 125 | − mxsfb->connector = &mxsfb->panel_connector; | |
| 126 | − } | |
| 127 | − | |
| 128 | − pm_runtime_get_sync(drm->dev); | |
| 129 | − drm_panel_prepare(mxsfb->panel); | |
| 130 | − mxsfb_crtc_enable(mxsfb); | |
| 131 | − drm_panel_enable(mxsfb->panel); | |
| 132 | −} | |
| 96 | + struct drm_device *drm = mxsfb->drm; | |
| 97 | + struct drm_connector_list_iter iter; | |
| 98 | + struct drm_panel *panel; | |
| 99 | + struct drm_bridge *bridge; | |
| 100 | + int ret; | |
| 133 | 101 | |
| 134 | −static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe) | |
| 135 | −{ | |
| 136 | − struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); | |
| 137 | − struct drm_device *drm = pipe->plane.dev; | |
| 138 | − struct drm_crtc *crtc = &pipe->crtc; | |
| 139 | − struct drm_pending_vblank_event *event; | |
| 140 | − | |
| 141 | − drm_panel_disable(mxsfb->panel); | |
| 142 | − mxsfb_crtc_disable(mxsfb); | |
| 143 | − drm_panel_unprepare(mxsfb->panel); | |
| 144 | − pm_runtime_put_sync(drm->dev); | |
| 102 | + ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, &panel, | |
| 103 | + &bridge); | |
| 104 | + if (ret) | |
| 105 | + return ret; | |
| 145 | 106 | |
| 146 | − spin_lock_irq(&drm->event_lock); | |
| 147 | − event = crtc->state->event; | |
| 148 | − if (event) { | |
| 149 | − crtc->state->event = NULL; | |
| 150 | − drm_crtc_send_vblank_event(crtc, event); | |
| 107 | + if (panel) { | |
| 108 | + bridge = devm_drm_panel_bridge_add_typed(drm->dev, panel, | |
| 109 | + DRM_MODE_CONNECTOR_DPI); | |
| 110 | + if (IS_ERR(bridge)) | |
| 111 | + return PTR_ERR(bridge); | |
| 151 | 112 | } |
| 152 | − spin_unlock_irq(&drm->event_lock); | |
| 153 | 113 | |
| 154 | − if (mxsfb->connector != &mxsfb->panel_connector) | |
| 155 | − mxsfb->connector = NULL; | |
| 156 | −} | |
| 157 | − | |
| 158 | −static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe, | |
| 159 | − struct drm_plane_state *plane_state) | |
| 160 | −{ | |
| 161 | − struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); | |
| 114 | + if (!bridge) | |
| 115 | + return -ENODEV; | |
| 162 | 116 | |
| 163 | − mxsfb_plane_atomic_update(mxsfb, plane_state); | |
| 164 | −} | |
| 117 | + ret = drm_bridge_attach(&mxsfb->encoder, bridge, NULL, 0); | |
| 118 | + if (ret) { | |
| 119 | + DRM_DEV_ERROR(drm->dev, | |
| 120 | + "failed to attach bridge: %d\n", ret); | |
| 121 | + return ret; | |
| 122 | + } | |
| 165 | 123 | |
| 166 | −static int mxsfb_pipe_enable_vblank(struct drm_simple_display_pipe *pipe) | |
| 167 | −{ | |
| 168 | − struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); | |
| 124 | + mxsfb->bridge = bridge; | |
| 169 | 125 | |
| 170 | − /* Clear and enable VBLANK IRQ */ | |
| 171 | − mxsfb_enable_axi_clk(mxsfb); | |
| 172 | − writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); | |
| 173 | − writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET); | |
| 174 | − mxsfb_disable_axi_clk(mxsfb); | |
| 126 | + /* | |
| 127 | + * Get hold of the connector. This is a bit of a hack, until the bridge | |
| 128 | + * API gives us bus flags and formats. | |
| 129 | + */ | |
| 130 | + drm_connector_list_iter_begin(drm, &iter); | |
| 131 | + mxsfb->connector = drm_connector_list_iter_next(&iter); | |
| 132 | + drm_connector_list_iter_end(&iter); | |
| 175 | 133 | |
| 176 | 134 | return 0; |
| 177 | 135 | } |
| 178 | 136 | |
| 179 | −static void mxsfb_pipe_disable_vblank(struct drm_simple_display_pipe *pipe) | |
| 180 | −{ | |
| 181 | − struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); | |
| 182 | − | |
| 183 | − /* Disable and clear VBLANK IRQ */ | |
| 184 | − mxsfb_enable_axi_clk(mxsfb); | |
| 185 | − writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR); | |
| 186 | − writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); | |
| 187 | − mxsfb_disable_axi_clk(mxsfb); | |
| 188 | −} | |
| 189 | − | |
| 190 | −static struct drm_simple_display_pipe_funcs mxsfb_funcs = { | |
| 191 | − .enable = mxsfb_pipe_enable, | |
| 192 | − .disable = mxsfb_pipe_disable, | |
| 193 | − .update = mxsfb_pipe_update, | |
| 194 | − .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, | |
| 195 | − .enable_vblank = mxsfb_pipe_enable_vblank, | |
| 196 | − .disable_vblank = mxsfb_pipe_disable_vblank, | |
| 197 | −}; | |
| 198 | − | |
| 199 | −static int mxsfb_load(struct drm_device *drm) | |
| 137 | +static int mxsfb_load(struct drm_device *drm, | |
| 138 | + const struct mxsfb_devdata *devdata) | |
| 200 | 139 | { |
| 201 | 140 | struct platform_device *pdev = to_platform_device(drm->dev); |
| 202 | 141 | struct mxsfb_drm_private *mxsfb; |
| @@ -207,8 +146,9 @@ static int mxsfb_load(struct drm_device *drm) · 4 unmodified lines | ||
| 207 | 146 | if (!mxsfb) |
| 208 | 147 | return -ENOMEM; |
| 209 | 148 | |
| 149 | + mxsfb->drm = drm; | |
| 210 | 150 | drm->dev_private = mxsfb; |
| 211 | − mxsfb->devdata = &mxsfb_devdata[pdev->id_entry->driver_data]; | |
| 151 | + mxsfb->devdata = devdata; | |
| 212 | 152 | |
| 213 | 153 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 214 | 154 | mxsfb->base = devm_ioremap_resource(drm->dev, res); |
| @@ -233,50 +173,28 @@ static int mxsfb_load(struct drm_device *drm) · 18 unmodified lines | ||
| 233 | 173 | |
| 234 | 174 | pm_runtime_enable(drm->dev); |
| 235 | 175 | |
| 236 | − ret = drm_vblank_init(drm, drm->mode_config.num_crtc); | |
| 237 | − if (ret < 0) { | |
| 238 | − dev_err(drm->dev, "Failed to initialise vblank\n"); | |
| 239 | − goto err_vblank; | |
| 240 | − } | |
| 241 | − | |
| 242 | 176 | /* Modeset init */ |
| 243 | 177 | drm_mode_config_init(drm); |
| 244 | 178 | |
| 245 | − ret = mxsfb_create_output(drm); | |
| 179 | + ret = mxsfb_kms_init(mxsfb); | |
| 246 | 180 | if (ret < 0) { |
| 247 | − dev_err(drm->dev, "Failed to create outputs\n"); | |
| 181 | + dev_err(drm->dev, "Failed to initialize KMS pipeline\n"); | |
| 248 | 182 | goto err_vblank; |
| 249 | 183 | } |
| 250 | 184 | |
| 251 | − ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs, | |
| 252 | − mxsfb_formats, ARRAY_SIZE(mxsfb_formats), | |
| 253 | − mxsfb_modifiers, mxsfb->connector); | |
| 185 | + ret = drm_vblank_init(drm, drm->mode_config.num_crtc); | |
| 254 | 186 | if (ret < 0) { |
| 255 | − dev_err(drm->dev, "Cannot setup simple display pipe\n"); | |
| 187 | + dev_err(drm->dev, "Failed to initialise vblank\n"); | |
| 256 | 188 | goto err_vblank; |
| 257 | 189 | } |
| 258 | 190 | |
| 259 | − /* | |
| 260 | − * Attach panel only if there is one. | |
| 261 | − * If there is no panel attach, it must be a bridge. In this case, we | |
| 262 | − * need a reference to its connector for a proper initialization. | |
| 263 | − * We will do this check in pipe->enable(), since the connector won't | |
| 264 | − * be attached to an encoder until then. | |
| 265 | − */ | |
| 191 | + /* Start with vertical blanking interrupt reporting disabled. */ | |
| 192 | + drm_crtc_vblank_off(&mxsfb->crtc); | |
| 266 | 193 | |
| 267 | − if (mxsfb->panel) { | |
| 268 | − ret = drm_panel_attach(mxsfb->panel, mxsfb->connector); | |
| 269 | − if (ret) { | |
| 270 | − dev_err(drm->dev, "Cannot connect panel: %d\n", ret); | |
| 271 | − goto err_vblank; | |
| 272 | − } | |
| 273 | − } else if (mxsfb->bridge) { | |
| 274 | − ret = drm_simple_display_pipe_attach_bridge(&mxsfb->pipe, | |
| 275 | − mxsfb->bridge); | |
| 276 | − if (ret) { | |
| 277 | − dev_err(drm->dev, "Cannot connect bridge: %d\n", ret); | |
| 278 | − goto err_vblank; | |
| 279 | − } | |
| 194 | + ret = mxsfb_attach_bridge(mxsfb); | |
| 195 | + if (ret) { | |
| 196 | + dev_err(drm->dev, "Cannot connect bridge: %d\n", ret); | |
| 197 | + goto err_vblank; | |
| 280 | 198 | } |
| 281 | 199 | |
| 282 | 200 | drm->mode_config.min_width = MXSFB_MIN_XRES; |
| @@ -294,7 +212,7 @@ static int mxsfb_load(struct drm_device *drm) · 11 unmodified lines | ||
| 294 | 212 | |
| 295 | 213 | if (ret < 0) { |
| 296 | 214 | dev_err(drm->dev, "Failed to install IRQ handler\n"); |
| 297 | − goto err_irq; | |
| 215 | + goto err_vblank; | |
| 298 | 216 | } |
| 299 | 217 | |
| 300 | 218 | drm_kms_helper_poll_init(drm); |
| @@ -305,8 +223,6 @@ static int mxsfb_load(struct drm_device *drm) · 4 unmodified lines | ||
| 305 | 223 | |
| 306 | 224 | return 0; |
| 307 | 225 | |
| 308 | −err_irq: | |
| 309 | − drm_panel_detach(mxsfb->panel); | |
| 310 | 226 | err_vblank: |
| 311 | 227 | pm_runtime_disable(drm->dev); |
| 312 | 228 | |
| @@ -327,11 +243,13 @@ static void mxsfb_unload(struct drm_device *drm) · 14 unmodified lines | ||
| 327 | 243 | pm_runtime_disable(drm->dev); |
| 328 | 244 | } |
| 329 | 245 | |
| 330 | −static void mxsfb_irq_preinstall(struct drm_device *drm) | |
| 246 | +static void mxsfb_irq_disable(struct drm_device *drm) | |
| 331 | 247 | { |
| 332 | 248 | struct mxsfb_drm_private *mxsfb = drm->dev_private; |
| 333 | 249 | |
| 334 | − mxsfb_pipe_disable_vblank(&mxsfb->pipe); | |
| 250 | + mxsfb_enable_axi_clk(mxsfb); | |
| 251 | + mxsfb->crtc.funcs->disable_vblank(&mxsfb->crtc); | |
| 252 | + mxsfb_disable_axi_clk(mxsfb); | |
| 335 | 253 | } |
| 336 | 254 | |
| 337 | 255 | static irqreturn_t mxsfb_irq_handler(int irq, void *data) |
| @@ -340,17 +258,13 @@ static irqreturn_t mxsfb_irq_handler(int irq, void *data) · 2 unmodified lines | ||
| 340 | 258 | struct mxsfb_drm_private *mxsfb = drm->dev_private; |
| 341 | 259 | u32 reg; |
| 342 | 260 | |
| 343 | − mxsfb_enable_axi_clk(mxsfb); | |
| 344 | − | |
| 345 | 261 | reg = readl(mxsfb->base + LCDC_CTRL1); |
| 346 | 262 | |
| 347 | 263 | if (reg & CTRL1_CUR_FRAME_DONE_IRQ) |
| 348 | − drm_crtc_handle_vblank(&mxsfb->pipe.crtc); | |
| 264 | + drm_crtc_handle_vblank(&mxsfb->crtc); | |
| 349 | 265 | |
| 350 | 266 | writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); |
| 351 | 267 | |
| 352 | − mxsfb_disable_axi_clk(mxsfb); | |
| 353 | − | |
| 354 | 268 | return IRQ_HANDLED; |
| 355 | 269 | } |
| 356 | 270 | |
| @@ -359,8 +273,8 @@ DEFINE_DRM_GEM_CMA_FOPS(fops); · 2 unmodified lines | ||
| 359 | 273 | static struct drm_driver mxsfb_driver = { |
| 360 | 274 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, |
| 361 | 275 | .irq_handler = mxsfb_irq_handler, |
| 362 | − .irq_preinstall = mxsfb_irq_preinstall, | |
| 363 | − .irq_uninstall = mxsfb_irq_preinstall, | |
| 276 | + .irq_preinstall = mxsfb_irq_disable, | |
| 277 | + .irq_uninstall = mxsfb_irq_disable, | |
| 364 | 278 | DRM_GEM_CMA_DRIVER_OPS, |
| 365 | 279 | .fops = &fops, |
| 366 | 280 | .name = "mxsfb-drm", |
| @@ -370,18 +284,10 @@ static struct drm_driver mxsfb_driver = { · 3 unmodified lines | ||
| 370 | 284 | .minor = 0, |
| 371 | 285 | }; |
| 372 | 286 | |
| 373 | −static const struct platform_device_id mxsfb_devtype[] = { | |
| 374 | − { .name = "imx23-fb", .driver_data = MXSFB_V3, }, | |
| 375 | − { .name = "imx28-fb", .driver_data = MXSFB_V4, }, | |
| 376 | − { .name = "imx6sx-fb", .driver_data = MXSFB_V4, }, | |
| 377 | − { /* sentinel */ } | |
| 378 | −}; | |
| 379 | −MODULE_DEVICE_TABLE(platform, mxsfb_devtype); | |
| 380 | − | |
| 381 | 287 | static const struct of_device_id mxsfb_dt_ids[] = { |
| 382 | − { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devtype[0], }, | |
| 383 | − { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devtype[1], }, | |
| 384 | − { .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devtype[2], }, | |
| 288 | + { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devdata[MXSFB_V3], }, | |
| 289 | + { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devdata[MXSFB_V4], }, | |
| 290 | + { .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devdata[MXSFB_V6], }, | |
| 385 | 291 | { /* sentinel */ } |
| 386 | 292 | }; |
| 387 | 293 | MODULE_DEVICE_TABLE(of, mxsfb_dt_ids); |
| @@ -396,14 +302,11 @@ static int mxsfb_probe(struct platform_device *pdev) · 8 unmodified lines | ||
| 396 | 302 | if (!pdev->dev.of_node) |
| 397 | 303 | return -ENODEV; |
| 398 | 304 | |
| 399 | − if (of_id) | |
| 400 | − pdev->id_entry = of_id->data; | |
| 401 | − | |
| 402 | 305 | drm = drm_dev_alloc(&mxsfb_driver, &pdev->dev); |
| 403 | 306 | if (IS_ERR(drm)) |
| 404 | 307 | return PTR_ERR(drm); |
| 405 | 308 | |
| 406 | − ret = mxsfb_load(drm); | |
| 309 | + ret = mxsfb_load(drm, of_id->data); | |
| 407 | 310 | if (ret) |
| 408 | 311 | goto err_free; |
| 409 | 312 | |
| @@ -457,7 +360,6 @@ static const struct dev_pm_ops mxsfb_pm_ops = { · 47 unmodified lines | ||
| 457 | 360 | static struct platform_driver mxsfb_platform_driver = { |
| 458 | 361 | .probe = mxsfb_probe, |
| 459 | 362 | .remove = mxsfb_remove, |
| 460 | − .id_table = mxsfb_devtype, | |
| 461 | 363 | .driver = { |
| 462 | 364 | .name = "mxsfb", |
| 463 | 365 | .of_match_table = mxsfb_dt_ids, |
| @@ -8,14 +8,20 @@ · 7 unmodified lines | ||
| 8 | 8 | #ifndef __MXSFB_DRV_H__ |
| 9 | 9 | #define __MXSFB_DRV_H__ |
| 10 | 10 | |
| 11 | +#include <drm/drm_crtc.h> | |
| 12 | +#include <drm/drm_device.h> | |
| 13 | +#include <drm/drm_encoder.h> | |
| 14 | +#include <drm/drm_plane.h> | |
| 15 | + | |
| 16 | +struct clk; | |
| 17 | + | |
| 11 | 18 | struct mxsfb_devdata { |
| 12 | − unsigned int transfer_count; | |
| 13 | − unsigned int cur_buf; | |
| 14 | − unsigned int next_buf; | |
| 15 | − unsigned int debug0; | |
| 16 | − unsigned int hs_wdth_mask; | |
| 17 | − unsigned int hs_wdth_shift; | |
| 18 | − unsigned int ipversion; | |
| 19 | + unsigned int transfer_count; | |
| 20 | + unsigned int cur_buf; | |
| 21 | + unsigned int next_buf; | |
| 22 | + unsigned int hs_wdth_mask; | |
| 23 | + unsigned int hs_wdth_shift; | |
| 24 | + bool has_overlay; | |
| 19 | 25 | }; |
| 20 | 26 | |
| 21 | 27 | struct mxsfb_drm_private { |
| @@ -26,22 +32,26 @@ struct mxsfb_drm_private { · 4 unmodified lines | ||
| 26 | 32 | struct clk *clk_axi; |
| 27 | 33 | struct clk *clk_disp_axi; |
| 28 | 34 | |
| 29 | − struct drm_simple_display_pipe pipe; | |
| 30 | − struct drm_connector panel_connector; | |
| 35 | + struct drm_device *drm; | |
| 36 | + struct { | |
| 37 | + struct drm_plane primary; | |
| 38 | + struct drm_plane overlay; | |
| 39 | + } planes; | |
| 40 | + struct drm_crtc crtc; | |
| 41 | + struct drm_encoder encoder; | |
| 31 | 42 | struct drm_connector *connector; |
| 32 | − struct drm_panel *panel; | |
| 33 | 43 | struct drm_bridge *bridge; |
| 34 | 44 | }; |
| 35 | 45 | |
| 36 | −int mxsfb_setup_crtc(struct drm_device *dev); | |
| 37 | −int mxsfb_create_output(struct drm_device *dev); | |
| 46 | +static inline struct mxsfb_drm_private * | |
| 47 | +to_mxsfb_drm_private(struct drm_device *drm) | |
| 48 | +{ | |
| 49 | + return drm->dev_private; | |
| 50 | +} | |
| 38 | 51 | |
| 39 | 52 | void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb); |
| 40 | 53 | void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb); |
| 41 | 54 | |
| 42 | −void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb); | |
| 43 | −void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb); | |
| 44 | −void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb, | |
| 45 | − struct drm_plane_state *state); | |
| 55 | +int mxsfb_kms_init(struct mxsfb_drm_private *mxsfb); | |
| 46 | 56 | |
| 47 | 57 | #endif /* __MXSFB_DRV_H__ */ |
| @@ -0,0 +1,571 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2016 Marek Vasut <marex@denx.de> | |
| 4 | + * | |
| 5 | + * This code is based on drivers/video/fbdev/mxsfb.c : | |
| 6 | + * Copyright (C) 2010 Juergen Beisert, Pengutronix | |
| 7 | + * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. | |
| 8 | + * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved. | |
| 9 | + */ | |
| 10 | + | |
| 11 | +#include <linux/clk.h> | |
| 12 | +#include <linux/io.h> | |
| 13 | +#include <linux/iopoll.h> | |
| 14 | +#include <linux/pm_runtime.h> | |
| 15 | +#include <linux/spinlock.h> | |
| 16 | + | |
| 17 | +#include <drm/drm_atomic.h> | |
| 18 | +#include <drm/drm_atomic_helper.h> | |
| 19 | +#include <drm/drm_bridge.h> | |
| 20 | +#include <drm/drm_crtc.h> | |
| 21 | +#include <drm/drm_encoder.h> | |
| 22 | +#include <drm/drm_fb_cma_helper.h> | |
| 23 | +#include <drm/drm_fourcc.h> | |
| 24 | +#include <drm/drm_gem_cma_helper.h> | |
| 25 | +#include <drm/drm_plane.h> | |
| 26 | +#include <drm/drm_plane_helper.h> | |
| 27 | +#include <drm/drm_vblank.h> | |
| 28 | + | |
| 29 | +#include "mxsfb_drv.h" | |
| 30 | +#include "mxsfb_regs.h" | |
| 31 | + | |
| 32 | +/* 1 second delay should be plenty of time for block reset */ | |
| 33 | +#define RESET_TIMEOUT 1000000 | |
| 34 | + | |
| 35 | +/* ----------------------------------------------------------------------------- | |
| 36 | + * CRTC | |
| 37 | + */ | |
| 38 | + | |
| 39 | +static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val) | |
| 40 | +{ | |
| 41 | + return (val & mxsfb->devdata->hs_wdth_mask) << | |
| 42 | + mxsfb->devdata->hs_wdth_shift; | |
| 43 | +} | |
| 44 | + | |
| 45 | +/* | |
| 46 | + * Setup the MXSFB registers for decoding the pixels out of the framebuffer and | |
| 47 | + * outputting them on the bus. | |
| 48 | + */ | |
| 49 | +static void mxsfb_set_formats(struct mxsfb_drm_private *mxsfb) | |
| 50 | +{ | |
| 51 | + struct drm_device *drm = mxsfb->drm; | |
| 52 | + const u32 format = mxsfb->crtc.primary->state->fb->format->format; | |
| 53 | + u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; | |
| 54 | + u32 ctrl, ctrl1; | |
| 55 | + | |
| 56 | + if (mxsfb->connector->display_info.num_bus_formats) | |
| 57 | + bus_format = mxsfb->connector->display_info.bus_formats[0]; | |
| 58 | + | |
| 59 | + DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n", | |
| 60 | + bus_format); | |
| 61 | + | |
| 62 | + ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER; | |
| 63 | + | |
| 64 | + /* CTRL1 contains IRQ config and status bits, preserve those. */ | |
| 65 | + ctrl1 = readl(mxsfb->base + LCDC_CTRL1); | |
| 66 | + ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ; | |
| 67 | + | |
| 68 | + switch (format) { | |
| 69 | + case DRM_FORMAT_RGB565: | |
| 70 | + dev_dbg(drm->dev, "Setting up RGB565 mode\n"); | |
| 71 | + ctrl |= CTRL_WORD_LENGTH_16; | |
| 72 | + ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf); | |
| 73 | + break; | |
| 74 | + case DRM_FORMAT_XRGB8888: | |
| 75 | + dev_dbg(drm->dev, "Setting up XRGB8888 mode\n"); | |
| 76 | + ctrl |= CTRL_WORD_LENGTH_24; | |
| 77 | + /* Do not use packed pixels = one pixel per word instead. */ | |
| 78 | + ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7); | |
| 79 | + break; | |
| 80 | + } | |
| 81 | + | |
| 82 | + switch (bus_format) { | |
| 83 | + case MEDIA_BUS_FMT_RGB565_1X16: | |
| 84 | + ctrl |= CTRL_BUS_WIDTH_16; | |
| 85 | + break; | |
| 86 | + case MEDIA_BUS_FMT_RGB666_1X18: | |
| 87 | + ctrl |= CTRL_BUS_WIDTH_18; | |
| 88 | + break; | |
| 89 | + case MEDIA_BUS_FMT_RGB888_1X24: | |
| 90 | + ctrl |= CTRL_BUS_WIDTH_24; | |
| 91 | + break; | |
| 92 | + default: | |
| 93 | + dev_err(drm->dev, "Unknown media bus format %d\n", bus_format); | |
| 94 | + break; | |
| 95 | + } | |
| 96 | + | |
| 97 | + writel(ctrl1, mxsfb->base + LCDC_CTRL1); | |
| 98 | + writel(ctrl, mxsfb->base + LCDC_CTRL); | |
| 99 | +} | |
| 100 | + | |
| 101 | +static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb) | |
| 102 | +{ | |
| 103 | + u32 reg; | |
| 104 | + | |
| 105 | + if (mxsfb->clk_disp_axi) | |
| 106 | + clk_prepare_enable(mxsfb->clk_disp_axi); | |
| 107 | + clk_prepare_enable(mxsfb->clk); | |
| 108 | + | |
| 109 | + /* If it was disabled, re-enable the mode again */ | |
| 110 | + writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET); | |
| 111 | + | |
| 112 | + /* Enable the SYNC signals first, then the DMA engine */ | |
| 113 | + reg = readl(mxsfb->base + LCDC_VDCTRL4); | |
| 114 | + reg |= VDCTRL4_SYNC_SIGNALS_ON; | |
| 115 | + writel(reg, mxsfb->base + LCDC_VDCTRL4); | |
| 116 | + | |
| 117 | + writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET); | |
| 118 | +} | |
| 119 | + | |
| 120 | +static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb) | |
| 121 | +{ | |
| 122 | + u32 reg; | |
| 123 | + | |
| 124 | + /* | |
| 125 | + * Even if we disable the controller here, it will still continue | |
| 126 | + * until its FIFOs are running out of data | |
| 127 | + */ | |
| 128 | + writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR); | |
| 129 | + | |
| 130 | + readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN), | |
| 131 | + 0, 1000); | |
| 132 | + | |
| 133 | + reg = readl(mxsfb->base + LCDC_VDCTRL4); | |
| 134 | + reg &= ~VDCTRL4_SYNC_SIGNALS_ON; | |
| 135 | + writel(reg, mxsfb->base + LCDC_VDCTRL4); | |
| 136 | + | |
| 137 | + clk_disable_unprepare(mxsfb->clk); | |
| 138 | + if (mxsfb->clk_disp_axi) | |
| 139 | + clk_disable_unprepare(mxsfb->clk_disp_axi); | |
| 140 | +} | |
| 141 | + | |
| 142 | +/* | |
| 143 | + * Clear the bit and poll it cleared. This is usually called with | |
| 144 | + * a reset address and mask being either SFTRST(bit 31) or CLKGATE | |
| 145 | + * (bit 30). | |
| 146 | + */ | |
| 147 | +static int clear_poll_bit(void __iomem *addr, u32 mask) | |
| 148 | +{ | |
| 149 | + u32 reg; | |
| 150 | + | |
| 151 | + writel(mask, addr + REG_CLR); | |
| 152 | + return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT); | |
| 153 | +} | |
| 154 | + | |
| 155 | +static int mxsfb_reset_block(struct mxsfb_drm_private *mxsfb) | |
| 156 | +{ | |
| 157 | + int ret; | |
| 158 | + | |
| 159 | + ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_SFTRST); | |
| 160 | + if (ret) | |
| 161 | + return ret; | |
| 162 | + | |
| 163 | + writel(CTRL_CLKGATE, mxsfb->base + LCDC_CTRL + REG_CLR); | |
| 164 | + | |
| 165 | + ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_SFTRST); | |
| 166 | + if (ret) | |
| 167 | + return ret; | |
| 168 | + | |
| 169 | + return clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_CLKGATE); | |
| 170 | +} | |
| 171 | + | |
| 172 | +static dma_addr_t mxsfb_get_fb_paddr(struct drm_plane *plane) | |
| 173 | +{ | |
| 174 | + struct drm_framebuffer *fb = plane->state->fb; | |
| 175 | + struct drm_gem_cma_object *gem; | |
| 176 | + | |
| 177 | + if (!fb) | |
| 178 | + return 0; | |
| 179 | + | |
| 180 | + gem = drm_fb_cma_get_gem_obj(fb, 0); | |
| 181 | + if (!gem) | |
| 182 | + return 0; | |
| 183 | + | |
| 184 | + return gem->paddr; | |
| 185 | +} | |
| 186 | + | |
| 187 | +static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) | |
| 188 | +{ | |
| 189 | + struct drm_device *drm = mxsfb->crtc.dev; | |
| 190 | + struct drm_display_mode *m = &mxsfb->crtc.state->adjusted_mode; | |
| 191 | + u32 bus_flags = mxsfb->connector->display_info.bus_flags; | |
| 192 | + u32 vdctrl0, vsync_pulse_len, hsync_pulse_len; | |
| 193 | + int err; | |
| 194 | + | |
| 195 | + /* | |
| 196 | + * It seems, you can't re-program the controller if it is still | |
| 197 | + * running. This may lead to shifted pictures (FIFO issue?), so | |
| 198 | + * first stop the controller and drain its FIFOs. | |
| 199 | + */ | |
| 200 | + | |
| 201 | + /* Mandatory eLCDIF reset as per the Reference Manual */ | |
| 202 | + err = mxsfb_reset_block(mxsfb); | |
| 203 | + if (err) | |
| 204 | + return; | |
| 205 | + | |
| 206 | + /* Clear the FIFOs */ | |
| 207 | + writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET); | |
| 208 | + | |
| 209 | + if (mxsfb->devdata->has_overlay) | |
| 210 | + writel(0, mxsfb->base + LCDC_AS_CTRL); | |
| 211 | + | |
| 212 | + mxsfb_set_formats(mxsfb); | |
| 213 | + | |
| 214 | + clk_set_rate(mxsfb->clk, m->crtc_clock * 1000); | |
| 215 | + | |
| 216 | + if (mxsfb->bridge && mxsfb->bridge->timings) | |
| 217 | + bus_flags = mxsfb->bridge->timings->input_bus_flags; | |
| 218 | + | |
| 219 | + DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n", | |
| 220 | + m->crtc_clock, | |
| 221 | + (int)(clk_get_rate(mxsfb->clk) / 1000)); | |
| 222 | + DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n", | |
| 223 | + bus_flags); | |
| 224 | + DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags); | |
| 225 | + | |
| 226 | + writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) | | |
| 227 | + TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay), | |
| 228 | + mxsfb->base + mxsfb->devdata->transfer_count); | |
| 229 | + | |
| 230 | + vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start; | |
| 231 | + | |
| 232 | + vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* Always in DOTCLOCK mode */ | |
| 233 | + VDCTRL0_VSYNC_PERIOD_UNIT | | |
| 234 | + VDCTRL0_VSYNC_PULSE_WIDTH_UNIT | | |
| 235 | + VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len); | |
| 236 | + if (m->flags & DRM_MODE_FLAG_PHSYNC) | |
| 237 | + vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH; | |
| 238 | + if (m->flags & DRM_MODE_FLAG_PVSYNC) | |
| 239 | + vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH; | |
| 240 | + /* Make sure Data Enable is high active by default */ | |
| 241 | + if (!(bus_flags & DRM_BUS_FLAG_DE_LOW)) | |
| 242 | + vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH; | |
| 243 | + /* | |
| 244 | + * DRM_BUS_FLAG_PIXDATA_DRIVE_ defines are controller centric, | |
| 245 | + * controllers VDCTRL0_DOTCLK is display centric. | |
| 246 | + * Drive on positive edge -> display samples on falling edge | |
| 247 | + * DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING | |
| 248 | + */ | |
| 249 | + if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE) | |
| 250 | + vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING; | |
| 251 | + | |
| 252 | + writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0); | |
| 253 | + | |
| 254 | + /* Frame length in lines. */ | |
| 255 | + writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1); | |
| 256 | + | |
| 257 | + /* Line length in units of clocks or pixels. */ | |
| 258 | + hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start; | |
| 259 | + writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) | | |
| 260 | + VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal), | |
| 261 | + mxsfb->base + LCDC_VDCTRL2); | |
| 262 | + | |
| 263 | + writel(SET_HOR_WAIT_CNT(m->crtc_htotal - m->crtc_hsync_start) | | |
| 264 | + SET_VERT_WAIT_CNT(m->crtc_vtotal - m->crtc_vsync_start), | |
| 265 | + mxsfb->base + LCDC_VDCTRL3); | |
| 266 | + | |
| 267 | + writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay), | |
| 268 | + mxsfb->base + LCDC_VDCTRL4); | |
| 269 | +} | |
| 270 | + | |
| 271 | +static int mxsfb_crtc_atomic_check(struct drm_crtc *crtc, | |
| 272 | + struct drm_crtc_state *state) | |
| 273 | +{ | |
| 274 | + bool has_primary = state->plane_mask & | |
| 275 | + drm_plane_mask(crtc->primary); | |
| 276 | + | |
| 277 | + /* The primary plane has to be enabled when the CRTC is active. */ | |
| 278 | + if (state->active && !has_primary) | |
| 279 | + return -EINVAL; | |
| 280 | + | |
| 281 | + /* TODO: Is this needed ? */ | |
| 282 | + return drm_atomic_add_affected_planes(state->state, crtc); | |
| 283 | +} | |
| 284 | + | |
| 285 | +static void mxsfb_crtc_atomic_flush(struct drm_crtc *crtc, | |
| 286 | + struct drm_crtc_state *old_state) | |
| 287 | +{ | |
| 288 | + struct drm_pending_vblank_event *event; | |
| 289 | + | |
| 290 | + event = crtc->state->event; | |
| 291 | + crtc->state->event = NULL; | |
| 292 | + | |
| 293 | + if (!event) | |
| 294 | + return; | |
| 295 | + | |
| 296 | + spin_lock_irq(&crtc->dev->event_lock); | |
| 297 | + if (drm_crtc_vblank_get(crtc) == 0) | |
| 298 | + drm_crtc_arm_vblank_event(crtc, event); | |
| 299 | + else | |
| 300 | + drm_crtc_send_vblank_event(crtc, event); | |
| 301 | + spin_unlock_irq(&crtc->dev->event_lock); | |
| 302 | +} | |
| 303 | + | |
| 304 | +static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc, | |
| 305 | + struct drm_crtc_state *old_state) | |
| 306 | +{ | |
| 307 | + struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev); | |
| 308 | + struct drm_device *drm = mxsfb->drm; | |
| 309 | + dma_addr_t paddr; | |
| 310 | + | |
| 311 | + pm_runtime_get_sync(drm->dev); | |
| 312 | + mxsfb_enable_axi_clk(mxsfb); | |
| 313 | + | |
| 314 | + drm_crtc_vblank_on(crtc); | |
| 315 | + | |
| 316 | + mxsfb_crtc_mode_set_nofb(mxsfb); | |
| 317 | + | |
| 318 | + /* Write cur_buf as well to avoid an initial corrupt frame */ | |
| 319 | + paddr = mxsfb_get_fb_paddr(crtc->primary); | |
| 320 | + if (paddr) { | |
| 321 | + writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf); | |
| 322 | + writel(paddr, mxsfb->base + mxsfb->devdata->next_buf); | |
| 323 | + } | |
| 324 | + | |
| 325 | + mxsfb_enable_controller(mxsfb); | |
| 326 | +} | |
| 327 | + | |
| 328 | +static void mxsfb_crtc_atomic_disable(struct drm_crtc *crtc, | |
| 329 | + struct drm_crtc_state *old_state) | |
| 330 | +{ | |
| 331 | + struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev); | |
| 332 | + struct drm_device *drm = mxsfb->drm; | |
| 333 | + struct drm_pending_vblank_event *event; | |
| 334 | + | |
| 335 | + mxsfb_disable_controller(mxsfb); | |
| 336 | + | |
| 337 | + spin_lock_irq(&drm->event_lock); | |
| 338 | + event = crtc->state->event; | |
| 339 | + if (event) { | |
| 340 | + crtc->state->event = NULL; | |
| 341 | + drm_crtc_send_vblank_event(crtc, event); | |
| 342 | + } | |
| 343 | + spin_unlock_irq(&drm->event_lock); | |
| 344 | + | |
| 345 | + drm_crtc_vblank_off(crtc); | |
| 346 | + | |
| 347 | + mxsfb_disable_axi_clk(mxsfb); | |
| 348 | + pm_runtime_put_sync(drm->dev); | |
| 349 | +} | |
| 350 | + | |
| 351 | +static int mxsfb_crtc_enable_vblank(struct drm_crtc *crtc) | |
| 352 | +{ | |
| 353 | + struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev); | |
| 354 | + | |
| 355 | + /* Clear and enable VBLANK IRQ */ | |
| 356 | + writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); | |
| 357 | + writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET); | |
| 358 | + | |
| 359 | + return 0; | |
| 360 | +} | |
| 361 | + | |
| 362 | +static void mxsfb_crtc_disable_vblank(struct drm_crtc *crtc) | |
| 363 | +{ | |
| 364 | + struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev); | |
| 365 | + | |
| 366 | + /* Disable and clear VBLANK IRQ */ | |
| 367 | + writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR); | |
| 368 | + writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); | |
| 369 | +} | |
| 370 | + | |
| 371 | +static const struct drm_crtc_helper_funcs mxsfb_crtc_helper_funcs = { | |
| 372 | + .atomic_check = mxsfb_crtc_atomic_check, | |
| 373 | + .atomic_flush = mxsfb_crtc_atomic_flush, | |
| 374 | + .atomic_enable = mxsfb_crtc_atomic_enable, | |
| 375 | + .atomic_disable = mxsfb_crtc_atomic_disable, | |
| 376 | +}; | |
| 377 | + | |
| 378 | +static const struct drm_crtc_funcs mxsfb_crtc_funcs = { | |
| 379 | + .reset = drm_atomic_helper_crtc_reset, | |
| 380 | + .destroy = drm_crtc_cleanup, | |
| 381 | + .set_config = drm_atomic_helper_set_config, | |
| 382 | + .page_flip = drm_atomic_helper_page_flip, | |
| 383 | + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | |
| 384 | + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | |
| 385 | + .enable_vblank = mxsfb_crtc_enable_vblank, | |
| 386 | + .disable_vblank = mxsfb_crtc_disable_vblank, | |
| 387 | +}; | |
| 388 | + | |
| 389 | +/* ----------------------------------------------------------------------------- | |
| 390 | + * Encoder | |
| 391 | + */ | |
| 392 | + | |
| 393 | +static const struct drm_encoder_funcs mxsfb_encoder_funcs = { | |
| 394 | + .destroy = drm_encoder_cleanup, | |
| 395 | +}; | |
| 396 | + | |
| 397 | +/* ----------------------------------------------------------------------------- | |
| 398 | + * Planes | |
| 399 | + */ | |
| 400 | + | |
| 401 | +static int mxsfb_plane_atomic_check(struct drm_plane *plane, | |
| 402 | + struct drm_plane_state *plane_state) | |
| 403 | +{ | |
| 404 | + struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev); | |
| 405 | + struct drm_crtc_state *crtc_state; | |
| 406 | + | |
| 407 | + crtc_state = drm_atomic_get_new_crtc_state(plane_state->state, | |
| 408 | + &mxsfb->crtc); | |
| 409 | + | |
| 410 | + return drm_atomic_helper_check_plane_state(plane_state, crtc_state, | |
| 411 | + DRM_PLANE_HELPER_NO_SCALING, | |
| 412 | + DRM_PLANE_HELPER_NO_SCALING, | |
| 413 | + false, true); | |
| 414 | +} | |
| 415 | + | |
| 416 | +static void mxsfb_plane_primary_atomic_update(struct drm_plane *plane, | |
| 417 | + struct drm_plane_state *old_pstate) | |
| 418 | +{ | |
| 419 | + struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev); | |
| 420 | + dma_addr_t paddr; | |
| 421 | + | |
| 422 | + paddr = mxsfb_get_fb_paddr(plane); | |
| 423 | + if (paddr) | |
| 424 | + writel(paddr, mxsfb->base + mxsfb->devdata->next_buf); | |
| 425 | +} | |
| 426 | + | |
| 427 | +static void mxsfb_plane_overlay_atomic_update(struct drm_plane *plane, | |
| 428 | + struct drm_plane_state *old_pstate) | |
| 429 | +{ | |
| 430 | + struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev); | |
| 431 | + struct drm_plane_state *state = plane->state; | |
| 432 | + dma_addr_t paddr; | |
| 433 | + u32 ctrl; | |
| 434 | + | |
| 435 | + paddr = mxsfb_get_fb_paddr(plane); | |
| 436 | + if (!paddr) { | |
| 437 | + writel(0, mxsfb->base + LCDC_AS_CTRL); | |
| 438 | + return; | |
| 439 | + } | |
| 440 | + | |
| 441 | + /* | |
| 442 | + * HACK: The hardware seems to output 64 bytes of data of unknown | |
| 443 | + * origin, and then to proceed with the framebuffer. Until the reason | |
| 444 | + * is understood, live with the 16 initial invalid pixels on the first | |
| 445 | + * line and start 64 bytes within the framebuffer. | |
| 446 | + */ | |
| 447 | + paddr += 64; | |
| 448 | + | |
| 449 | + writel(paddr, mxsfb->base + LCDC_AS_NEXT_BUF); | |
| 450 | + | |
| 451 | + /* | |
| 452 | + * If the plane was previously disabled, write LCDC_AS_BUF as well to | |
| 453 | + * provide the first buffer. | |
| 454 | + */ | |
| 455 | + if (!old_pstate->fb) | |
| 456 | + writel(paddr, mxsfb->base + LCDC_AS_BUF); | |
| 457 | + | |
| 458 | + ctrl = AS_CTRL_AS_ENABLE | AS_CTRL_ALPHA(255); | |
| 459 | + | |
| 460 | + switch (state->fb->format->format) { | |
| 461 | + case DRM_FORMAT_XRGB4444: | |
| 462 | + ctrl |= AS_CTRL_FORMAT_RGB444 | AS_CTRL_ALPHA_CTRL_OVERRIDE; | |
| 463 | + break; | |
| 464 | + case DRM_FORMAT_ARGB4444: | |
| 465 | + ctrl |= AS_CTRL_FORMAT_ARGB4444 | AS_CTRL_ALPHA_CTRL_EMBEDDED; | |
| 466 | + break; | |
| 467 | + case DRM_FORMAT_XRGB1555: | |
| 468 | + ctrl |= AS_CTRL_FORMAT_RGB555 | AS_CTRL_ALPHA_CTRL_OVERRIDE; | |
| 469 | + break; | |
| 470 | + case DRM_FORMAT_ARGB1555: | |
| 471 | + ctrl |= AS_CTRL_FORMAT_ARGB1555 | AS_CTRL_ALPHA_CTRL_EMBEDDED; | |
| 472 | + break; | |
| 473 | + case DRM_FORMAT_RGB565: | |
| 474 | + ctrl |= AS_CTRL_FORMAT_RGB565 | AS_CTRL_ALPHA_CTRL_OVERRIDE; | |
| 475 | + break; | |
| 476 | + case DRM_FORMAT_XRGB8888: | |
| 477 | + ctrl |= AS_CTRL_FORMAT_RGB888 | AS_CTRL_ALPHA_CTRL_OVERRIDE; | |
| 478 | + break; | |
| 479 | + case DRM_FORMAT_ARGB8888: | |
| 480 | + ctrl |= AS_CTRL_FORMAT_ARGB8888 | AS_CTRL_ALPHA_CTRL_EMBEDDED; | |
| 481 | + break; | |
| 482 | + } | |
| 483 | + | |
| 484 | + writel(ctrl, mxsfb->base + LCDC_AS_CTRL); | |
| 485 | +} | |
| 486 | + | |
| 487 | +static const struct drm_plane_helper_funcs mxsfb_plane_primary_helper_funcs = { | |
| 488 | + .atomic_check = mxsfb_plane_atomic_check, | |
| 489 | + .atomic_update = mxsfb_plane_primary_atomic_update, | |
| 490 | +}; | |
| 491 | + | |
| 492 | +static const struct drm_plane_helper_funcs mxsfb_plane_overlay_helper_funcs = { | |
| 493 | + .atomic_check = mxsfb_plane_atomic_check, | |
| 494 | + .atomic_update = mxsfb_plane_overlay_atomic_update, | |
| 495 | +}; | |
| 496 | + | |
| 497 | +static const struct drm_plane_funcs mxsfb_plane_funcs = { | |
| 498 | + .update_plane = drm_atomic_helper_update_plane, | |
| 499 | + .disable_plane = drm_atomic_helper_disable_plane, | |
| 500 | + .destroy = drm_plane_cleanup, | |
| 501 | + .reset = drm_atomic_helper_plane_reset, | |
| 502 | + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | |
| 503 | + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | |
| 504 | +}; | |
| 505 | + | |
| 506 | +static const uint32_t mxsfb_primary_plane_formats[] = { | |
| 507 | + DRM_FORMAT_RGB565, | |
| 508 | + DRM_FORMAT_XRGB8888, | |
| 509 | +}; | |
| 510 | + | |
| 511 | +static const uint32_t mxsfb_overlay_plane_formats[] = { | |
| 512 | + DRM_FORMAT_XRGB4444, | |
| 513 | + DRM_FORMAT_ARGB4444, | |
| 514 | + DRM_FORMAT_XRGB1555, | |
| 515 | + DRM_FORMAT_ARGB1555, | |
| 516 | + DRM_FORMAT_RGB565, | |
| 517 | + DRM_FORMAT_XRGB8888, | |
| 518 | + DRM_FORMAT_ARGB8888, | |
| 519 | +}; | |
| 520 | + | |
| 521 | +static const uint64_t mxsfb_modifiers[] = { | |
| 522 | + DRM_FORMAT_MOD_LINEAR, | |
| 523 | + DRM_FORMAT_MOD_INVALID | |
| 524 | +}; | |
| 525 | + | |
| 526 | +/* ----------------------------------------------------------------------------- | |
| 527 | + * Initialization | |
| 528 | + */ | |
| 529 | + | |
| 530 | +int mxsfb_kms_init(struct mxsfb_drm_private *mxsfb) | |
| 531 | +{ | |
| 532 | + struct drm_encoder *encoder = &mxsfb->encoder; | |
| 533 | + struct drm_crtc *crtc = &mxsfb->crtc; | |
| 534 | + int ret; | |
| 535 | + | |
| 536 | + drm_plane_helper_add(&mxsfb->planes.primary, | |
| 537 | + &mxsfb_plane_primary_helper_funcs); | |
| 538 | + ret = drm_universal_plane_init(mxsfb->drm, &mxsfb->planes.primary, 1, | |
| 539 | + &mxsfb_plane_funcs, | |
| 540 | + mxsfb_primary_plane_formats, | |
| 541 | + ARRAY_SIZE(mxsfb_primary_plane_formats), | |
| 542 | + mxsfb_modifiers, DRM_PLANE_TYPE_PRIMARY, | |
| 543 | + NULL); | |
| 544 | + if (ret) | |
| 545 | + return ret; | |
| 546 | + | |
| 547 | + if (mxsfb->devdata->has_overlay) { | |
| 548 | + drm_plane_helper_add(&mxsfb->planes.overlay, | |
| 549 | + &mxsfb_plane_overlay_helper_funcs); | |
| 550 | + ret = drm_universal_plane_init(mxsfb->drm, | |
| 551 | + &mxsfb->planes.overlay, 1, | |
| 552 | + &mxsfb_plane_funcs, | |
| 553 | + mxsfb_overlay_plane_formats, | |
| 554 | + ARRAY_SIZE(mxsfb_overlay_plane_formats), | |
| 555 | + mxsfb_modifiers, DRM_PLANE_TYPE_OVERLAY, | |
| 556 | + NULL); | |
| 557 | + if (ret) | |
| 558 | + return ret; | |
| 559 | + } | |
| 560 | + | |
| 561 | + drm_crtc_helper_add(crtc, &mxsfb_crtc_helper_funcs); | |
| 562 | + ret = drm_crtc_init_with_planes(mxsfb->drm, crtc, | |
| 563 | + &mxsfb->planes.primary, NULL, | |
| 564 | + &mxsfb_crtc_funcs, NULL); | |
| 565 | + if (ret) | |
| 566 | + return ret; | |
| 567 | + | |
| 568 | + encoder->possible_crtcs = drm_crtc_mask(crtc); | |
| 569 | + return drm_encoder_init(mxsfb->drm, encoder, &mxsfb_encoder_funcs, | |
| 570 | + DRM_MODE_ENCODER_NONE, NULL); | |
| 571 | +} | |
| @@ -1,99 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | −/* | |
| 3 | − * Copyright (C) 2016 Marek Vasut <marex@denx.de> | |
| 4 | − */ | |
| 5 | − | |
| 6 | −#include <linux/of_graph.h> | |
| 7 | − | |
| 8 | −#include <drm/drm_atomic.h> | |
| 9 | −#include <drm/drm_atomic_helper.h> | |
| 10 | −#include <drm/drm_crtc.h> | |
| 11 | −#include <drm/drm_fb_cma_helper.h> | |
| 12 | −#include <drm/drm_gem_cma_helper.h> | |
| 13 | −#include <drm/drm_of.h> | |
| 14 | −#include <drm/drm_panel.h> | |
| 15 | −#include <drm/drm_plane_helper.h> | |
| 16 | −#include <drm/drm_probe_helper.h> | |
| 17 | −#include <drm/drm_simple_kms_helper.h> | |
| 18 | − | |
| 19 | −#include "mxsfb_drv.h" | |
| 20 | − | |
| 21 | −static struct mxsfb_drm_private * | |
| 22 | −drm_connector_to_mxsfb_drm_private(struct drm_connector *connector) | |
| 23 | −{ | |
| 24 | − return container_of(connector, struct mxsfb_drm_private, | |
| 25 | − panel_connector); | |
| 26 | −} | |
| 27 | − | |
| 28 | −static int mxsfb_panel_get_modes(struct drm_connector *connector) | |
| 29 | −{ | |
| 30 | − struct mxsfb_drm_private *mxsfb = | |
| 31 | − drm_connector_to_mxsfb_drm_private(connector); | |
| 32 | − | |
| 33 | − if (mxsfb->panel) | |
| 34 | − return drm_panel_get_modes(mxsfb->panel, connector); | |
| 35 | − | |
| 36 | − return 0; | |
| 37 | −} | |
| 38 | − | |
| 39 | −static const struct | |
| 40 | −drm_connector_helper_funcs mxsfb_panel_connector_helper_funcs = { | |
| 41 | − .get_modes = mxsfb_panel_get_modes, | |
| 42 | −}; | |
| 43 | − | |
| 44 | −static enum drm_connector_status | |
| 45 | −mxsfb_panel_connector_detect(struct drm_connector *connector, bool force) | |
| 46 | −{ | |
| 47 | − struct mxsfb_drm_private *mxsfb = | |
| 48 | − drm_connector_to_mxsfb_drm_private(connector); | |
| 49 | − | |
| 50 | − if (mxsfb->panel) | |
| 51 | − return connector_status_connected; | |
| 52 | − | |
| 53 | − return connector_status_disconnected; | |
| 54 | −} | |
| 55 | − | |
| 56 | −static void mxsfb_panel_connector_destroy(struct drm_connector *connector) | |
| 57 | −{ | |
| 58 | − struct mxsfb_drm_private *mxsfb = | |
| 59 | − drm_connector_to_mxsfb_drm_private(connector); | |
| 60 | − | |
| 61 | − if (mxsfb->panel) | |
| 62 | − drm_panel_detach(mxsfb->panel); | |
| 63 | − | |
| 64 | − drm_connector_unregister(connector); | |
| 65 | − drm_connector_cleanup(connector); | |
| 66 | −} | |
| 67 | − | |
| 68 | −static const struct drm_connector_funcs mxsfb_panel_connector_funcs = { | |
| 69 | − .detect = mxsfb_panel_connector_detect, | |
| 70 | − .fill_modes = drm_helper_probe_single_connector_modes, | |
| 71 | − .destroy = mxsfb_panel_connector_destroy, | |
| 72 | − .reset = drm_atomic_helper_connector_reset, | |
| 73 | − .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | |
| 74 | − .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | |
| 75 | −}; | |
| 76 | − | |
| 77 | −int mxsfb_create_output(struct drm_device *drm) | |
| 78 | −{ | |
| 79 | − struct mxsfb_drm_private *mxsfb = drm->dev_private; | |
| 80 | − int ret; | |
| 81 | − | |
| 82 | − ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, | |
| 83 | − &mxsfb->panel, &mxsfb->bridge); | |
| 84 | − if (ret) | |
| 85 | − return ret; | |
| 86 | − | |
| 87 | − if (mxsfb->panel) { | |
| 88 | − mxsfb->connector = &mxsfb->panel_connector; | |
| 89 | − mxsfb->connector->dpms = DRM_MODE_DPMS_OFF; | |
| 90 | − mxsfb->connector->polled = 0; | |
| 91 | − drm_connector_helper_add(mxsfb->connector, | |
| 92 | − &mxsfb_panel_connector_helper_funcs); | |
| 93 | − ret = drm_connector_init(drm, mxsfb->connector, | |
| 94 | − &mxsfb_panel_connector_funcs, | |
| 95 | − DRM_MODE_CONNECTOR_Unknown); | |
| 96 | − } | |
| 97 | − | |
| 98 | − return ret; | |
| 99 | −} | |
| @@ -27,52 +27,61 @@ · 26 unmodified lines | ||
| 27 | 27 | #define LCDC_VDCTRL4 0xb0 |
| 28 | 28 | #define LCDC_V4_DEBUG0 0x1d0 |
| 29 | 29 | #define LCDC_V3_DEBUG0 0x1f0 |
| 30 | − | |
| 31 | −#define CTRL_SFTRST (1 << 31) | |
| 32 | −#define CTRL_CLKGATE (1 << 30) | |
| 33 | −#define CTRL_BYPASS_COUNT (1 << 19) | |
| 34 | −#define CTRL_VSYNC_MODE (1 << 18) | |
| 35 | −#define CTRL_DOTCLK_MODE (1 << 17) | |
| 36 | −#define CTRL_DATA_SELECT (1 << 16) | |
| 37 | −#define CTRL_SET_BUS_WIDTH(x) (((x) & 0x3) << 10) | |
| 38 | −#define CTRL_GET_BUS_WIDTH(x) (((x) >> 10) & 0x3) | |
| 30 | +#define LCDC_AS_CTRL 0x210 | |
| 31 | +#define LCDC_AS_BUF 0x220 | |
| 32 | +#define LCDC_AS_NEXT_BUF 0x230 | |
| 33 | +#define LCDC_AS_CLRKEYLOW 0x240 | |
| 34 | +#define LCDC_AS_CLRKEYHIGH 0x250 | |
| 35 | + | |
| 36 | +#define CTRL_SFTRST BIT(31) | |
| 37 | +#define CTRL_CLKGATE BIT(30) | |
| 38 | +#define CTRL_BYPASS_COUNT BIT(19) | |
| 39 | +#define CTRL_VSYNC_MODE BIT(18) | |
| 40 | +#define CTRL_DOTCLK_MODE BIT(17) | |
| 41 | +#define CTRL_DATA_SELECT BIT(16) | |
| 42 | +#define CTRL_BUS_WIDTH_16 (0 << 10) | |
| 43 | +#define CTRL_BUS_WIDTH_8 (1 << 10) | |
| 44 | +#define CTRL_BUS_WIDTH_18 (2 << 10) | |
| 45 | +#define CTRL_BUS_WIDTH_24 (3 << 10) | |
| 39 | 46 | #define CTRL_BUS_WIDTH_MASK (0x3 << 10) |
| 40 | −#define CTRL_SET_WORD_LENGTH(x) (((x) & 0x3) << 8) | |
| 41 | −#define CTRL_GET_WORD_LENGTH(x) (((x) >> 8) & 0x3) | |
| 42 | −#define CTRL_MASTER (1 << 5) | |
| 43 | −#define CTRL_DF16 (1 << 3) | |
| 44 | −#define CTRL_DF18 (1 << 2) | |
| 45 | −#define CTRL_DF24 (1 << 1) | |
| 46 | −#define CTRL_RUN (1 << 0) | |
| 47 | − | |
| 48 | −#define CTRL1_FIFO_CLEAR (1 << 21) | |
| 47 | +#define CTRL_WORD_LENGTH_16 (0 << 8) | |
| 48 | +#define CTRL_WORD_LENGTH_8 (1 << 8) | |
| 49 | +#define CTRL_WORD_LENGTH_18 (2 << 8) | |
| 50 | +#define CTRL_WORD_LENGTH_24 (3 << 8) | |
| 51 | +#define CTRL_MASTER BIT(5) | |
| 52 | +#define CTRL_DF16 BIT(3) | |
| 53 | +#define CTRL_DF18 BIT(2) | |
| 54 | +#define CTRL_DF24 BIT(1) | |
| 55 | +#define CTRL_RUN BIT(0) | |
| 56 | + | |
| 57 | +#define CTRL1_FIFO_CLEAR BIT(21) | |
| 49 | 58 | #define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16) |
| 50 | 59 | #define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf) |
| 51 | −#define CTRL1_CUR_FRAME_DONE_IRQ_EN (1 << 13) | |
| 52 | −#define CTRL1_CUR_FRAME_DONE_IRQ (1 << 9) | |
| 60 | +#define CTRL1_CUR_FRAME_DONE_IRQ_EN BIT(13) | |
| 61 | +#define CTRL1_CUR_FRAME_DONE_IRQ BIT(9) | |
| 53 | 62 | |
| 54 | 63 | #define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16) |
| 55 | 64 | #define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff) |
| 56 | 65 | #define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff) |
| 57 | 66 | #define TRANSFER_COUNT_GET_HCOUNT(x) ((x) & 0xffff) |
| 58 | 67 | |
| 59 | −#define VDCTRL0_ENABLE_PRESENT (1 << 28) | |
| 60 | −#define VDCTRL0_VSYNC_ACT_HIGH (1 << 27) | |
| 61 | −#define VDCTRL0_HSYNC_ACT_HIGH (1 << 26) | |
| 62 | −#define VDCTRL0_DOTCLK_ACT_FALLING (1 << 25) | |
| 63 | −#define VDCTRL0_ENABLE_ACT_HIGH (1 << 24) | |
| 64 | −#define VDCTRL0_VSYNC_PERIOD_UNIT (1 << 21) | |
| 65 | −#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT (1 << 20) | |
| 66 | −#define VDCTRL0_HALF_LINE (1 << 19) | |
| 67 | −#define VDCTRL0_HALF_LINE_MODE (1 << 18) | |
| 68 | +#define VDCTRL0_ENABLE_PRESENT BIT(28) | |
| 69 | +#define VDCTRL0_VSYNC_ACT_HIGH BIT(27) | |
| 70 | +#define VDCTRL0_HSYNC_ACT_HIGH BIT(26) | |
| 71 | +#define VDCTRL0_DOTCLK_ACT_FALLING BIT(25) | |
| 72 | +#define VDCTRL0_ENABLE_ACT_HIGH BIT(24) | |
| 73 | +#define VDCTRL0_VSYNC_PERIOD_UNIT BIT(21) | |
| 74 | +#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT BIT(20) | |
| 75 | +#define VDCTRL0_HALF_LINE BIT(19) | |
| 76 | +#define VDCTRL0_HALF_LINE_MODE BIT(18) | |
| 68 | 77 | #define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff) |
| 69 | 78 | #define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff) |
| 70 | 79 | |
| 71 | 80 | #define VDCTRL2_SET_HSYNC_PERIOD(x) ((x) & 0x3ffff) |
| 72 | 81 | #define VDCTRL2_GET_HSYNC_PERIOD(x) ((x) & 0x3ffff) |
| 73 | 82 | |
| 74 | −#define VDCTRL3_MUX_SYNC_SIGNALS (1 << 29) | |
| 75 | −#define VDCTRL3_VSYNC_ONLY (1 << 28) | |
| 83 | +#define VDCTRL3_MUX_SYNC_SIGNALS BIT(29) | |
| 84 | +#define VDCTRL3_VSYNC_ONLY BIT(28) | |
| 76 | 85 | #define SET_HOR_WAIT_CNT(x) (((x) & 0xfff) << 16) |
| 77 | 86 | #define GET_HOR_WAIT_CNT(x) (((x) >> 16) & 0xfff) |
| 78 | 87 | #define SET_VERT_WAIT_CNT(x) ((x) & 0xffff) |
| @@ -80,28 +89,32 @@ · 1 unmodified line | ||
| 80 | 89 | |
| 81 | 90 | #define VDCTRL4_SET_DOTCLK_DLY(x) (((x) & 0x7) << 29) /* v4 only */ |
| 82 | 91 | #define VDCTRL4_GET_DOTCLK_DLY(x) (((x) >> 29) & 0x7) /* v4 only */ |
| 83 | −#define VDCTRL4_SYNC_SIGNALS_ON (1 << 18) | |
| 92 | +#define VDCTRL4_SYNC_SIGNALS_ON BIT(18) | |
| 84 | 93 | #define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff) |
| 85 | 94 | |
| 86 | −#define DEBUG0_HSYNC (1 < 26) | |
| 87 | −#define DEBUG0_VSYNC (1 < 25) | |
| 95 | +#define DEBUG0_HSYNC BIT(26) | |
| 96 | +#define DEBUG0_VSYNC BIT(25) | |
| 97 | + | |
| 98 | +#define AS_CTRL_PS_DISABLE BIT(23) | |
| 99 | +#define AS_CTRL_ALPHA_INVERT BIT(20) | |
| 100 | +#define AS_CTRL_ALPHA(a) (((a) & 0xff) << 8) | |
| 101 | +#define AS_CTRL_FORMAT_RGB565 (0xe << 4) | |
| 102 | +#define AS_CTRL_FORMAT_RGB444 (0xd << 4) | |
| 103 | +#define AS_CTRL_FORMAT_RGB555 (0xc << 4) | |
| 104 | +#define AS_CTRL_FORMAT_ARGB4444 (0x9 << 4) | |
| 105 | +#define AS_CTRL_FORMAT_ARGB1555 (0x8 << 4) | |
| 106 | +#define AS_CTRL_FORMAT_RGB888 (0x4 << 4) | |
| 107 | +#define AS_CTRL_FORMAT_ARGB8888 (0x0 << 4) | |
| 108 | +#define AS_CTRL_ENABLE_COLORKEY BIT(3) | |
| 109 | +#define AS_CTRL_ALPHA_CTRL_ROP (3 << 1) | |
| 110 | +#define AS_CTRL_ALPHA_CTRL_MULTIPLY (2 << 1) | |
| 111 | +#define AS_CTRL_ALPHA_CTRL_OVERRIDE (1 << 1) | |
| 112 | +#define AS_CTRL_ALPHA_CTRL_EMBEDDED (0 << 1) | |
| 113 | +#define AS_CTRL_AS_ENABLE BIT(0) | |
| 88 | 114 | |
| 89 | 115 | #define MXSFB_MIN_XRES 120 |
| 90 | 116 | #define MXSFB_MIN_YRES 120 |
| 91 | 117 | #define MXSFB_MAX_XRES 0xffff |
| 92 | 118 | #define MXSFB_MAX_YRES 0xffff |
| 93 | 119 | |
| 94 | −#define RED 0 | |
| 95 | −#define GREEN 1 | |
| 96 | −#define BLUE 2 | |
| 97 | −#define TRANSP 3 | |
| 98 | − | |
| 99 | −#define STMLCDIF_8BIT 1 /* pixel data bus to the display is of 8 bit width */ | |
| 100 | −#define STMLCDIF_16BIT 0 /* pixel data bus to the display is of 16 bit width */ | |
| 101 | −#define STMLCDIF_18BIT 2 /* pixel data bus to the display is of 18 bit width */ | |
| 102 | −#define STMLCDIF_24BIT 3 /* pixel data bus to the display is of 24 bit width */ | |
| 103 | − | |
| 104 | −#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT (1 << 6) | |
| 105 | −#define MXSFB_SYNC_DOTCLK_FALLING_ACT (1 << 7) /* negative edge sampling */ | |
| 106 | − | |
| 107 | 120 | #endif /* __MXSFB_REGS_H__ */ |
| @@ -646,66 +646,6 @@ nouveau_ttm_tt_create(struct ttm_buffer_object *bo, uint32_t page_flags) · 645 unmodified lines | ||
| 646 | 646 | return nouveau_sgdma_create_ttm(bo, page_flags); |
| 647 | 647 | } |
| 648 | 648 | |
| 649 | −static int | |
| 650 | −nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | |
| 651 | − struct ttm_mem_type_manager *man) | |
| 652 | −{ | |
| 653 | − struct nouveau_drm *drm = nouveau_bdev(bdev); | |
| 654 | − struct nvif_mmu *mmu = &drm->client.mmu; | |
| 655 | − | |
| 656 | − switch (type) { | |
| 657 | − case TTM_PL_SYSTEM: | |
| 658 | − man->flags = 0; | |
| 659 | − man->available_caching = TTM_PL_MASK_CACHING; | |
| 660 | − man->default_caching = TTM_PL_FLAG_CACHED; | |
| 661 | − break; | |
| 662 | − case TTM_PL_VRAM: | |
| 663 | − man->flags = TTM_MEMTYPE_FLAG_FIXED; | |
| 664 | − man->available_caching = TTM_PL_FLAG_UNCACHED | | |
| 665 | − TTM_PL_FLAG_WC; | |
| 666 | − man->default_caching = TTM_PL_FLAG_WC; | |
| 667 | − | |
| 668 | − if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) { | |
| 669 | − /* Some BARs do not support being ioremapped WC */ | |
| 670 | − const u8 type = mmu->type[drm->ttm.type_vram].type; | |
| 671 | − if (type & NVIF_MEM_UNCACHED) { | |
| 672 | − man->available_caching = TTM_PL_FLAG_UNCACHED; | |
| 673 | − man->default_caching = TTM_PL_FLAG_UNCACHED; | |
| 674 | − } | |
| 675 | − | |
| 676 | − man->func = &nouveau_vram_manager; | |
| 677 | − man->use_io_reserve_lru = true; | |
| 678 | − } else { | |
| 679 | − man->func = &ttm_bo_manager_func; | |
| 680 | − } | |
| 681 | − break; | |
| 682 | − case TTM_PL_TT: | |
| 683 | − if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) | |
| 684 | − man->func = &nouveau_gart_manager; | |
| 685 | − else | |
| 686 | − if (!drm->agp.bridge) | |
| 687 | − man->func = &nv04_gart_manager; | |
| 688 | − else | |
| 689 | − man->func = &ttm_bo_manager_func; | |
| 690 | − | |
| 691 | − if (drm->agp.bridge) { | |
| 692 | − man->flags = 0; | |
| 693 | − man->available_caching = TTM_PL_FLAG_UNCACHED | | |
| 694 | − TTM_PL_FLAG_WC; | |
| 695 | − man->default_caching = TTM_PL_FLAG_WC; | |
| 696 | − } else { | |
| 697 | − man->flags = 0; | |
| 698 | − man->available_caching = TTM_PL_MASK_CACHING; | |
| 699 | − man->default_caching = TTM_PL_FLAG_CACHED; | |
| 700 | − } | |
| 701 | − | |
| 702 | − break; | |
| 703 | − default: | |
| 704 | − return -EINVAL; | |
| 705 | − } | |
| 706 | − return 0; | |
| 707 | −} | |
| 708 | − | |
| 709 | 649 | static void |
| 710 | 650 | nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) |
| 711 | 651 | { |
| @@ -726,7 +666,7 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) · 14 unmodified lines | ||
| 726 | 666 | |
| 727 | 667 | static int |
| 728 | 668 | nouveau_bo_move_prep(struct nouveau_drm *drm, struct ttm_buffer_object *bo, |
| 729 | − struct ttm_mem_reg *reg) | |
| 669 | + struct ttm_resource *reg) | |
| 730 | 670 | { |
| 731 | 671 | struct nouveau_mem *old_mem = nouveau_mem(&bo->mem); |
| 732 | 672 | struct nouveau_mem *new_mem = nouveau_mem(reg); |
| @@ -758,7 +698,7 @@ done: · 25 unmodified lines | ||
| 758 | 698 | |
| 759 | 699 | static int |
| 760 | 700 | nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, |
| 761 | − bool no_wait_gpu, struct ttm_mem_reg *new_reg) | |
| 701 | + bool no_wait_gpu, struct ttm_resource *new_reg) | |
| 762 | 702 | { |
| 763 | 703 | struct nouveau_drm *drm = nouveau_bdev(bo->bdev); |
| 764 | 704 | struct nouveau_channel *chan = drm->ttm.chan; |
| @@ -768,7 +708,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, · 3 unmodified lines | ||
| 768 | 708 | |
| 769 | 709 | /* create temporary vmas for the transfer and attach them to the |
| 770 | 710 | * old nvkm_mem node, these will get cleaned up after ttm has |
| 771 | − * destroyed the ttm_mem_reg | |
| 711 | + * destroyed the ttm_resource | |
| 772 | 712 | */ |
| 773 | 713 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) { |
| 774 | 714 | ret = nouveau_bo_move_prep(drm, bo, new_reg); |
| @@ -804,7 +744,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm) · 29 unmodified lines | ||
| 804 | 744 | s32 oclass; |
| 805 | 745 | int (*exec)(struct nouveau_channel *, |
| 806 | 746 | struct ttm_buffer_object *, |
| 807 | − struct ttm_mem_reg *, struct ttm_mem_reg *); | |
| 747 | + struct ttm_resource *, struct ttm_resource *); | |
| 808 | 748 | int (*init)(struct nouveau_channel *, u32 handle); |
| 809 | 749 | } _methods[] = { |
| 810 | 750 | { "COPY", 4, 0xc5b5, nve0_bo_move_copy, nve0_bo_move_init }, |
| @@ -865,7 +805,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm) · 54 unmodified lines | ||
| 865 | 805 | |
| 866 | 806 | static int |
| 867 | 807 | nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, |
| 868 | − bool no_wait_gpu, struct ttm_mem_reg *new_reg) | |
| 808 | + bool no_wait_gpu, struct ttm_resource *new_reg) | |
| 869 | 809 | { |
| 870 | 810 | struct ttm_operation_ctx ctx = { intr, no_wait_gpu }; |
| 871 | 811 | struct ttm_place placement_memtype = { |
| @@ -874,7 +814,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, · 2 unmodified lines | ||
| 874 | 814 | .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING |
| 875 | 815 | }; |
| 876 | 816 | struct ttm_placement placement; |
| 877 | − struct ttm_mem_reg tmp_reg; | |
| 817 | + struct ttm_resource tmp_reg; | |
| 878 | 818 | int ret; |
| 879 | 819 | |
| 880 | 820 | placement.num_placement = placement.num_busy_placement = 1; |
| @@ -896,13 +836,13 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, · 15 unmodified lines | ||
| 896 | 836 | |
| 897 | 837 | ret = ttm_bo_move_ttm(bo, &ctx, new_reg); |
| 898 | 838 | out: |
| 899 | − ttm_bo_mem_put(bo, &tmp_reg); | |
| 839 | + ttm_resource_free(bo, &tmp_reg); | |
| 900 | 840 | return ret; |
| 901 | 841 | } |
| 902 | 842 | |
| 903 | 843 | static int |
| 904 | 844 | nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, |
| 905 | − bool no_wait_gpu, struct ttm_mem_reg *new_reg) | |
| 845 | + bool no_wait_gpu, struct ttm_resource *new_reg) | |
| 906 | 846 | { |
| 907 | 847 | struct ttm_operation_ctx ctx = { intr, no_wait_gpu }; |
| 908 | 848 | struct ttm_place placement_memtype = { |
| @@ -911,7 +851,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, · 2 unmodified lines | ||
| 911 | 851 | .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING |
| 912 | 852 | }; |
| 913 | 853 | struct ttm_placement placement; |
| 914 | − struct ttm_mem_reg tmp_reg; | |
| 854 | + struct ttm_resource tmp_reg; | |
| 915 | 855 | int ret; |
| 916 | 856 | |
| 917 | 857 | placement.num_placement = placement.num_busy_placement = 1; |
| @@ -932,13 +872,13 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, · 14 unmodified lines | ||
| 932 | 872 | goto out; |
| 933 | 873 | |
| 934 | 874 | out: |
| 935 | − ttm_bo_mem_put(bo, &tmp_reg); | |
| 875 | + ttm_resource_free(bo, &tmp_reg); | |
| 936 | 876 | return ret; |
| 937 | 877 | } |
| 938 | 878 | |
| 939 | 879 | static void |
| 940 | 880 | nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict, |
| 941 | − struct ttm_mem_reg *new_reg) | |
| 881 | + struct ttm_resource *new_reg) | |
| 942 | 882 | { |
| 943 | 883 | struct nouveau_mem *mem = new_reg ? nouveau_mem(new_reg) : NULL; |
| 944 | 884 | struct nouveau_bo *nvbo = nouveau_bo(bo); |
| @@ -970,7 +910,7 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict, · 25 unmodified lines | ||
| 970 | 910 | } |
| 971 | 911 | |
| 972 | 912 | static int |
| 973 | −nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_reg, | |
| 913 | +nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_resource *new_reg, | |
| 974 | 914 | struct nouveau_drm_tile **new_tile) |
| 975 | 915 | { |
| 976 | 916 | struct nouveau_drm *drm = nouveau_bdev(bo->bdev); |
| @@ -1006,11 +946,11 @@ nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo, · 29 unmodified lines | ||
| 1006 | 946 | static int |
| 1007 | 947 | nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, |
| 1008 | 948 | struct ttm_operation_ctx *ctx, |
| 1009 | − struct ttm_mem_reg *new_reg) | |
| 949 | + struct ttm_resource *new_reg) | |
| 1010 | 950 | { |
| 1011 | 951 | struct nouveau_drm *drm = nouveau_bdev(bo->bdev); |
| 1012 | 952 | struct nouveau_bo *nvbo = nouveau_bo(bo); |
| 1013 | − struct ttm_mem_reg *old_reg = &bo->mem; | |
| 953 | + struct ttm_resource *old_reg = &bo->mem; | |
| 1014 | 954 | struct nouveau_drm_tile *new_tile = NULL; |
| 1015 | 955 | int ret = 0; |
| 1016 | 956 | |
| @@ -1079,18 +1019,12 @@ nouveau_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) · 62 unmodified lines | ||
| 1079 | 1019 | } |
| 1080 | 1020 | |
| 1081 | 1021 | static int |
| 1082 | −nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg) | |
| 1022 | +nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *reg) | |
| 1083 | 1023 | { |
| 1084 | 1024 | struct nouveau_drm *drm = nouveau_bdev(bdev); |
| 1085 | 1025 | struct nvkm_device *device = nvxx_device(&drm->client.device); |
| 1086 | 1026 | struct nouveau_mem *mem = nouveau_mem(reg); |
| 1087 | 1027 | |
| 1088 | − reg->bus.addr = NULL; | |
| 1089 | − reg->bus.offset = 0; | |
| 1090 | − reg->bus.size = reg->num_pages << PAGE_SHIFT; | |
| 1091 | − reg->bus.base = 0; | |
| 1092 | − reg->bus.is_iomem = false; | |
| 1093 | − | |
| 1094 | 1028 | switch (reg->mem_type) { |
| 1095 | 1029 | case TTM_PL_SYSTEM: |
| 1096 | 1030 | /* System memory */ |
| @@ -1159,7 +1093,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg) · 62 unmodified lines | ||
| 1159 | 1093 | } |
| 1160 | 1094 | |
| 1161 | 1095 | static void |
| 1162 | −nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg) | |
| 1096 | +nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_resource *reg) | |
| 1163 | 1097 | { |
| 1164 | 1098 | struct nouveau_drm *drm = nouveau_bdev(bdev); |
| 1165 | 1099 | struct nouveau_mem *mem = nouveau_mem(reg); |
| @@ -1231,8 +1165,6 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx) · 65 unmodified lines | ||
| 1231 | 1165 | struct ttm_dma_tt *ttm_dma = (void *)ttm; |
| 1232 | 1166 | struct nouveau_drm *drm; |
| 1233 | 1167 | struct device *dev; |
| 1234 | − unsigned i; | |
| 1235 | − int r; | |
| 1236 | 1168 | bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); |
| 1237 | 1169 | |
| 1238 | 1170 | if (ttm->state != tt_unpopulated) |
| @@ -1260,31 +1192,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm, struct ttm_operation_ctx *ctx) · 21 unmodified lines | ||
| 1260 | 1192 | return ttm_dma_populate((void *)ttm, dev, ctx); |
| 1261 | 1193 | } |
| 1262 | 1194 | #endif |
| 1263 | − | |
| 1264 | − r = ttm_pool_populate(ttm, ctx); | |
| 1265 | − if (r) { | |
| 1266 | − return r; | |
| 1267 | − } | |
| 1268 | − | |
| 1269 | − for (i = 0; i < ttm->num_pages; i++) { | |
| 1270 | − dma_addr_t addr; | |
| 1271 | − | |
| 1272 | − addr = dma_map_page(dev, ttm->pages[i], 0, PAGE_SIZE, | |
| 1273 | − DMA_BIDIRECTIONAL); | |
| 1274 | − | |
| 1275 | − if (dma_mapping_error(dev, addr)) { | |
| 1276 | − while (i--) { | |
| 1277 | − dma_unmap_page(dev, ttm_dma->dma_address[i], | |
| 1278 | − PAGE_SIZE, DMA_BIDIRECTIONAL); | |
| 1279 | − ttm_dma->dma_address[i] = 0; | |
| 1280 | − } | |
| 1281 | − ttm_pool_unpopulate(ttm); | |
| 1282 | − return -EFAULT; | |
| 1283 | − } | |
| 1284 | − | |
| 1285 | − ttm_dma->dma_address[i] = addr; | |
| 1286 | − } | |
| 1287 | − return 0; | |
| 1195 | + return ttm_populate_and_map_pages(dev, ttm_dma, ctx); | |
| 1288 | 1196 | } |
| 1289 | 1197 | |
| 1290 | 1198 | static void |
| @@ -1293,7 +1201,6 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) · 2 unmodified lines | ||
| 1293 | 1201 | struct ttm_dma_tt *ttm_dma = (void *)ttm; |
| 1294 | 1202 | struct nouveau_drm *drm; |
| 1295 | 1203 | struct device *dev; |
| 1296 | − unsigned i; | |
| 1297 | 1204 | bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); |
| 1298 | 1205 | |
| 1299 | 1206 | if (slave) |
| @@ -1316,14 +1223,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) · 16 unmodified lines | ||
| 1316 | 1223 | } |
| 1317 | 1224 | #endif |
| 1318 | 1225 | |
| 1319 | − for (i = 0; i < ttm->num_pages; i++) { | |
| 1320 | − if (ttm_dma->dma_address[i]) { | |
| 1321 | − dma_unmap_page(dev, ttm_dma->dma_address[i], PAGE_SIZE, | |
| 1322 | − DMA_BIDIRECTIONAL); | |
| 1323 | − } | |
| 1324 | − } | |
| 1325 | − | |
| 1326 | − ttm_pool_unpopulate(ttm); | |
| 1226 | + ttm_unmap_and_unpopulate_pages(dev, ttm_dma); | |
| 1327 | 1227 | } |
| 1328 | 1228 | |
| 1329 | 1229 | void |
| @@ -1341,7 +1241,6 @@ struct ttm_bo_driver nouveau_bo_driver = { · 11 unmodified lines | ||
| 1341 | 1241 | .ttm_tt_create = &nouveau_ttm_tt_create, |
| 1342 | 1242 | .ttm_tt_populate = &nouveau_ttm_tt_populate, |
| 1343 | 1243 | .ttm_tt_unpopulate = &nouveau_ttm_tt_unpopulate, |
| 1344 | − .init_mem_type = nouveau_bo_init_mem_type, | |
| 1345 | 1244 | .eviction_valuable = ttm_bo_eviction_valuable, |
| 1346 | 1245 | .evict_flags = nouveau_bo_evict_flags, |
| 1347 | 1246 | .move_notify = nouveau_bo_move_ntfy, |
| @@ -139,28 +139,28 @@ nouveau_bo_new_pin_map(struct nouveau_cli *cli, u64 size, int align, u32 flags, · 138 unmodified lines | ||
| 139 | 139 | |
| 140 | 140 | int nv04_bo_move_init(struct nouveau_channel *, u32); |
| 141 | 141 | int nv04_bo_move_m2mf(struct nouveau_channel *, struct ttm_buffer_object *, |
| 142 | − struct ttm_mem_reg *, struct ttm_mem_reg *); | |
| 142 | + struct ttm_resource *, struct ttm_resource *); | |
| 143 | 143 | |
| 144 | 144 | int nv50_bo_move_init(struct nouveau_channel *, u32); |
| 145 | 145 | int nv50_bo_move_m2mf(struct nouveau_channel *, struct ttm_buffer_object *, |
| 146 | − struct ttm_mem_reg *, struct ttm_mem_reg *); | |
| 146 | + struct ttm_resource *, struct ttm_resource *); | |
| 147 | 147 | |
| 148 | 148 | int nv84_bo_move_exec(struct nouveau_channel *, struct ttm_buffer_object *, |
| 149 | − struct ttm_mem_reg *, struct ttm_mem_reg *); | |
| 149 | + struct ttm_resource *, struct ttm_resource *); | |
| 150 | 150 | |
| 151 | 151 | int nva3_bo_move_copy(struct nouveau_channel *, struct ttm_buffer_object *, |
| 152 | − struct ttm_mem_reg *, struct ttm_mem_reg *); | |
| 152 | + struct ttm_resource *, struct ttm_resource *); | |
| 153 | 153 | |
| 154 | 154 | int nvc0_bo_move_init(struct nouveau_channel *, u32); |
| 155 | 155 | int nvc0_bo_move_m2mf(struct nouveau_channel *, struct ttm_buffer_object *, |
| 156 | − struct ttm_mem_reg *, struct ttm_mem_reg *); | |
| 156 | + struct ttm_resource *, struct ttm_resource *); | |
| 157 | 157 | |
| 158 | 158 | int nvc0_bo_move_copy(struct nouveau_channel *, struct ttm_buffer_object *, |
| 159 | − struct ttm_mem_reg *, struct ttm_mem_reg *); | |
| 159 | + struct ttm_resource *, struct ttm_resource *); | |
| 160 | 160 | |
| 161 | 161 | int nve0_bo_move_init(struct nouveau_channel *, u32); |
| 162 | 162 | int nve0_bo_move_copy(struct nouveau_channel *, struct ttm_buffer_object *, |
| 163 | − struct ttm_mem_reg *, struct ttm_mem_reg *); | |
| 163 | + struct ttm_resource *, struct ttm_resource *); | |
| 164 | 164 | |
| 165 | 165 | #define NVBO_WR32_(b,o,dr,f) nouveau_bo_wr32((b), (o)/4 + (dr), (f)) |
| 166 | 166 | #define NVBO_RD32_(b,o,dr) nouveau_bo_rd32((b), (o)/4 + (dr)) |
| @@ -36,7 +36,7 @@ · 35 unmodified lines | ||
| 36 | 36 | |
| 37 | 37 | static inline uint32_t |
| 38 | 38 | nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo, |
| 39 | − struct nouveau_channel *chan, struct ttm_mem_reg *reg) | |
| 39 | + struct nouveau_channel *chan, struct ttm_resource *reg) | |
| 40 | 40 | { |
| 41 | 41 | if (reg->mem_type == TTM_PL_TT) |
| 42 | 42 | return NvDmaTT; |
| @@ -45,7 +45,7 @@ nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo, · 2 unmodified lines | ||
| 45 | 45 | |
| 46 | 46 | int |
| 47 | 47 | nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, |
| 48 | − struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg) | |
| 48 | + struct ttm_resource *old_reg, struct ttm_resource *new_reg) | |
| 49 | 49 | { |
| 50 | 50 | struct nvif_push *push = chan->chan.push; |
| 51 | 51 | u32 src_ctxdma = nouveau_bo_mem_ctxdma(bo, chan, old_reg); |
| @@ -37,7 +37,7 @@ · 36 unmodified lines | ||
| 37 | 37 | |
| 38 | 38 | int |
| 39 | 39 | nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, |
| 40 | − struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg) | |
| 40 | + struct ttm_resource *old_reg, struct ttm_resource *new_reg) | |
| 41 | 41 | { |
| 42 | 42 | struct nouveau_mem *mem = nouveau_mem(old_reg); |
| 43 | 43 | struct nvif_push *push = chan->chan.push; |
| @@ -34,7 +34,7 @@ · 33 unmodified lines | ||
| 34 | 34 | |
| 35 | 35 | int |
| 36 | 36 | nv84_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo, |
| 37 | − struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg) | |
| 37 | + struct ttm_resource *old_reg, struct ttm_resource *new_reg) | |
| 38 | 38 | { |
| 39 | 39 | struct nouveau_mem *mem = nouveau_mem(old_reg); |
| 40 | 40 | struct nvif_push *push = chan->chan.push; |
| @@ -38,7 +38,7 @@ · 37 unmodified lines | ||
| 38 | 38 | |
| 39 | 39 | int |
| 40 | 40 | nva3_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo, |
| 41 | − struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg) | |
| 41 | + struct ttm_resource *old_reg, struct ttm_resource *new_reg) | |
| 42 | 42 | { |
| 43 | 43 | struct nouveau_mem *mem = nouveau_mem(old_reg); |
| 44 | 44 | struct nvif_push *push = chan->chan.push; |
| @@ -36,7 +36,7 @@ · 35 unmodified lines | ||
| 36 | 36 | |
| 37 | 37 | int |
| 38 | 38 | nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, |
| 39 | − struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg) | |
| 39 | + struct ttm_resource *old_reg, struct ttm_resource *new_reg) | |
| 40 | 40 | { |
| 41 | 41 | struct nvif_push *push = chan->chan.push; |
| 42 | 42 | struct nouveau_mem *mem = nouveau_mem(old_reg); |
| @@ -31,7 +31,7 @@ · 30 unmodified lines | ||
| 31 | 31 | |
| 32 | 32 | int |
| 33 | 33 | nvc0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo, |
| 34 | − struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg) | |
| 34 | + struct ttm_resource *old_reg, struct ttm_resource *new_reg) | |
| 35 | 35 | { |
| 36 | 36 | struct nouveau_mem *mem = nouveau_mem(old_reg); |
| 37 | 37 | struct nvif_push *push = chan->chan.push; |
| @@ -36,7 +36,7 @@ · 35 unmodified lines | ||
| 36 | 36 | |
| 37 | 37 | int |
| 38 | 38 | nve0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo, |
| 39 | − struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg) | |
| 39 | + struct ttm_resource *old_reg, struct ttm_resource *new_reg) | |
| 40 | 40 | { |
| 41 | 41 | struct nouveau_mem *mem = nouveau_mem(old_reg); |
| 42 | 42 | struct nvif_push *push = chan->chan.push; |
| @@ -157,7 +157,7 @@ struct nouveau_drm { · 156 unmodified lines | ||
| 157 | 157 | atomic_t validate_sequence; |
| 158 | 158 | int (*move)(struct nouveau_channel *, |
| 159 | 159 | struct ttm_buffer_object *, |
| 160 | − struct ttm_mem_reg *, struct ttm_mem_reg *); | |
| 160 | + struct ttm_resource *, struct ttm_resource *); | |
| 161 | 161 | struct nouveau_channel *chan; |
| 162 | 162 | struct nvif_object copy; |
| 163 | 163 | int mtrr; |
| @@ -92,7 +92,7 @@ nouveau_mem_fini(struct nouveau_mem *mem) · 91 unmodified lines | ||
| 92 | 92 | } |
| 93 | 93 | |
| 94 | 94 | int |
| 95 | −nouveau_mem_host(struct ttm_mem_reg *reg, struct ttm_dma_tt *tt) | |
| 95 | +nouveau_mem_host(struct ttm_resource *reg, struct ttm_dma_tt *tt) | |
| 96 | 96 | { |
| 97 | 97 | struct nouveau_mem *mem = nouveau_mem(reg); |
| 98 | 98 | struct nouveau_cli *cli = mem->cli; |
| @@ -130,7 +130,7 @@ nouveau_mem_host(struct ttm_mem_reg *reg, struct ttm_dma_tt *tt) · 31 unmodified lines | ||
| 130 | 130 | } |
| 131 | 131 | |
| 132 | 132 | int |
| 133 | −nouveau_mem_vram(struct ttm_mem_reg *reg, bool contig, u8 page) | |
| 133 | +nouveau_mem_vram(struct ttm_resource *reg, bool contig, u8 page) | |
| 134 | 134 | { |
| 135 | 135 | struct nouveau_mem *mem = nouveau_mem(reg); |
| 136 | 136 | struct nouveau_cli *cli = mem->cli; |
| @@ -173,7 +173,7 @@ nouveau_mem_vram(struct ttm_mem_reg *reg, bool contig, u8 page) · 36 unmodified lines | ||
| 173 | 173 | } |
| 174 | 174 | |
| 175 | 175 | void |
| 176 | −nouveau_mem_del(struct ttm_mem_reg *reg) | |
| 176 | +nouveau_mem_del(struct ttm_resource *reg) | |
| 177 | 177 | { |
| 178 | 178 | struct nouveau_mem *mem = nouveau_mem(reg); |
| 179 | 179 | nouveau_mem_fini(mem); |
| @@ -183,7 +183,7 @@ nouveau_mem_del(struct ttm_mem_reg *reg) · 3 unmodified lines | ||
| 183 | 183 | |
| 184 | 184 | int |
| 185 | 185 | nouveau_mem_new(struct nouveau_cli *cli, u8 kind, u8 comp, |
| 186 | − struct ttm_mem_reg *reg) | |
| 186 | + struct ttm_resource *reg) | |
| 187 | 187 | { |
| 188 | 188 | struct nouveau_mem *mem; |
| 189 | 189 | |
| @@ -7,7 +7,7 @@ struct ttm_dma_tt; · 6 unmodified lines | ||
| 7 | 7 | #include <nvif/vmm.h> |
| 8 | 8 | |
| 9 | 9 | static inline struct nouveau_mem * |
| 10 | −nouveau_mem(struct ttm_mem_reg *reg) | |
| 10 | +nouveau_mem(struct ttm_resource *reg) | |
| 11 | 11 | { |
| 12 | 12 | return reg->mm_node; |
| 13 | 13 | } |
| @@ -21,10 +21,10 @@ struct nouveau_mem { · 7 unmodified lines | ||
| 21 | 21 | }; |
| 22 | 22 | |
| 23 | 23 | int nouveau_mem_new(struct nouveau_cli *, u8 kind, u8 comp, |
| 24 | − struct ttm_mem_reg *); | |
| 25 | −void nouveau_mem_del(struct ttm_mem_reg *); | |
| 26 | −int nouveau_mem_vram(struct ttm_mem_reg *, bool contig, u8 page); | |
| 27 | −int nouveau_mem_host(struct ttm_mem_reg *, struct ttm_dma_tt *); | |
| 24 | + struct ttm_resource *); | |
| 25 | +void nouveau_mem_del(struct ttm_resource *); | |
| 26 | +int nouveau_mem_vram(struct ttm_resource *, bool contig, u8 page); | |
| 27 | +int nouveau_mem_host(struct ttm_resource *, struct ttm_dma_tt *); | |
| 28 | 28 | void nouveau_mem_fini(struct nouveau_mem *); |
| 29 | 29 | int nouveau_mem_map(struct nouveau_mem *, struct nvif_vmm *, struct nvif_vma *); |
| 30 | 30 | #endif |
| @@ -26,7 +26,7 @@ nouveau_sgdma_destroy(struct ttm_tt *ttm) · 25 unmodified lines | ||
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | static int |
| 29 | −nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *reg) | |
| 29 | +nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_resource *reg) | |
| 30 | 30 | { |
| 31 | 31 | struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm; |
| 32 | 32 | struct nouveau_mem *mem = nouveau_mem(reg); |
| @@ -60,7 +60,7 @@ static struct ttm_backend_func nv04_sgdma_backend = { · 27 unmodified lines | ||
| 60 | 60 | }; |
| 61 | 61 | |
| 62 | 62 | static int |
| 63 | −nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *reg) | |
| 63 | +nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_resource *reg) | |
| 64 | 64 | { |
| 65 | 65 | struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm; |
| 66 | 66 | struct nouveau_mem *mem = nouveau_mem(reg); |
| @@ -31,35 +31,17 @@ · 30 unmodified lines | ||
| 31 | 31 | |
| 32 | 32 | #include <core/tegra.h> |
| 33 | 33 | |
| 34 | −static int | |
| 35 | −nouveau_manager_init(struct ttm_mem_type_manager *man, unsigned long psize) | |
| 36 | −{ | |
| 37 | − return 0; | |
| 38 | −} | |
| 39 | − | |
| 40 | −static int | |
| 41 | −nouveau_manager_fini(struct ttm_mem_type_manager *man) | |
| 42 | −{ | |
| 43 | − return 0; | |
| 44 | −} | |
| 45 | − | |
| 46 | 34 | static void |
| 47 | −nouveau_manager_del(struct ttm_mem_type_manager *man, struct ttm_mem_reg *reg) | |
| 35 | +nouveau_manager_del(struct ttm_resource_manager *man, struct ttm_resource *reg) | |
| 48 | 36 | { |
| 49 | 37 | nouveau_mem_del(reg); |
| 50 | 38 | } |
| 51 | 39 | |
| 52 | −static void | |
| 53 | −nouveau_manager_debug(struct ttm_mem_type_manager *man, | |
| 54 | − struct drm_printer *printer) | |
| 55 | −{ | |
| 56 | −} | |
| 57 | − | |
| 58 | 40 | static int |
| 59 | −nouveau_vram_manager_new(struct ttm_mem_type_manager *man, | |
| 41 | +nouveau_vram_manager_new(struct ttm_resource_manager *man, | |
| 60 | 42 | struct ttm_buffer_object *bo, |
| 61 | 43 | const struct ttm_place *place, |
| 62 | − struct ttm_mem_reg *reg) | |
| 44 | + struct ttm_resource *reg) | |
| 63 | 45 | { |
| 64 | 46 | struct nouveau_bo *nvbo = nouveau_bo(bo); |
| 65 | 47 | struct nouveau_drm *drm = nouveau_bdev(bo->bdev); |
| @@ -81,19 +63,16 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man, · 15 unmodified lines | ||
| 81 | 63 | return 0; |
| 82 | 64 | } |
| 83 | 65 | |
| 84 | −const struct ttm_mem_type_manager_func nouveau_vram_manager = { | |
| 85 | − .init = nouveau_manager_init, | |
| 86 | − .takedown = nouveau_manager_fini, | |
| 87 | − .get_node = nouveau_vram_manager_new, | |
| 88 | − .put_node = nouveau_manager_del, | |
| 89 | − .debug = nouveau_manager_debug, | |
| 66 | +const struct ttm_resource_manager_func nouveau_vram_manager = { | |
| 67 | + .alloc = nouveau_vram_manager_new, | |
| 68 | + .free = nouveau_manager_del, | |
| 90 | 69 | }; |
| 91 | 70 | |
| 92 | 71 | static int |
| 93 | −nouveau_gart_manager_new(struct ttm_mem_type_manager *man, | |
| 72 | +nouveau_gart_manager_new(struct ttm_resource_manager *man, | |
| 94 | 73 | struct ttm_buffer_object *bo, |
| 95 | 74 | const struct ttm_place *place, |
| 96 | − struct ttm_mem_reg *reg) | |
| 75 | + struct ttm_resource *reg) | |
| 97 | 76 | { |
| 98 | 77 | struct nouveau_bo *nvbo = nouveau_bo(bo); |
| 99 | 78 | struct nouveau_drm *drm = nouveau_bdev(bo->bdev); |
| @@ -107,19 +86,16 @@ nouveau_gart_manager_new(struct ttm_mem_type_manager *man, · 7 unmodified lines | ||
| 107 | 86 | return 0; |
| 108 | 87 | } |
| 109 | 88 | |
| 110 | −const struct ttm_mem_type_manager_func nouveau_gart_manager = { | |
| 111 | − .init = nouveau_manager_init, | |
| 112 | − .takedown = nouveau_manager_fini, | |
| 113 | − .get_node = nouveau_gart_manager_new, | |
| 114 | − .put_node = nouveau_manager_del, | |
| 115 | − .debug = nouveau_manager_debug | |
| 89 | +const struct ttm_resource_manager_func nouveau_gart_manager = { | |
| 90 | + .alloc = nouveau_gart_manager_new, | |
| 91 | + .free = nouveau_manager_del, | |
| 116 | 92 | }; |
| 117 | 93 | |
| 118 | 94 | static int |
| 119 | −nv04_gart_manager_new(struct ttm_mem_type_manager *man, | |
| 95 | +nv04_gart_manager_new(struct ttm_resource_manager *man, | |
| 120 | 96 | struct ttm_buffer_object *bo, |
| 121 | 97 | const struct ttm_place *place, |
| 122 | − struct ttm_mem_reg *reg) | |
| 98 | + struct ttm_resource *reg) | |
| 123 | 99 | { |
| 124 | 100 | struct nouveau_bo *nvbo = nouveau_bo(bo); |
| 125 | 101 | struct nouveau_drm *drm = nouveau_bdev(bo->bdev); |
| @@ -142,12 +118,9 @@ nv04_gart_manager_new(struct ttm_mem_type_manager *man, · 16 unmodified lines | ||
| 142 | 118 | return 0; |
| 143 | 119 | } |
| 144 | 120 | |
| 145 | −const struct ttm_mem_type_manager_func nv04_gart_manager = { | |
| 146 | − .init = nouveau_manager_init, | |
| 147 | − .takedown = nouveau_manager_fini, | |
| 148 | − .get_node = nv04_gart_manager_new, | |
| 149 | − .put_node = nouveau_manager_del, | |
| 150 | − .debug = nouveau_manager_debug | |
| 121 | +const struct ttm_resource_manager_func nv04_gart_manager = { | |
| 122 | + .alloc = nv04_gart_manager_new, | |
| 123 | + .free = nouveau_manager_del, | |
| 151 | 124 | }; |
| 152 | 125 | |
| 153 | 126 | int |
| @@ -180,6 +153,113 @@ nouveau_ttm_init_host(struct nouveau_drm *drm, u8 kind) · 26 unmodified lines | ||
| 180 | 153 | return 0; |
| 181 | 154 | } |
| 182 | 155 | |
| 156 | +static int | |
| 157 | +nouveau_ttm_init_vram(struct nouveau_drm *drm) | |
| 158 | +{ | |
| 159 | + struct nvif_mmu *mmu = &drm->client.mmu; | |
| 160 | + if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) { | |
| 161 | + /* Some BARs do not support being ioremapped WC */ | |
| 162 | + const u8 type = mmu->type[drm->ttm.type_vram].type; | |
| 163 | + struct ttm_resource_manager *man = kzalloc(sizeof(*man), GFP_KERNEL); | |
| 164 | + if (!man) | |
| 165 | + return -ENOMEM; | |
| 166 | + | |
| 167 | + man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; | |
| 168 | + man->default_caching = TTM_PL_FLAG_WC; | |
| 169 | + | |
| 170 | + if (type & NVIF_MEM_UNCACHED) { | |
| 171 | + man->available_caching = TTM_PL_FLAG_UNCACHED; | |
| 172 | + man->default_caching = TTM_PL_FLAG_UNCACHED; | |
| 173 | + } | |
| 174 | + | |
| 175 | + man->func = &nouveau_vram_manager; | |
| 176 | + man->use_io_reserve_lru = true; | |
| 177 | + | |
| 178 | + ttm_resource_manager_init(man, | |
| 179 | + drm->gem.vram_available >> PAGE_SHIFT); | |
| 180 | + ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_VRAM, man); | |
| 181 | + ttm_resource_manager_set_used(man, true); | |
| 182 | + return 0; | |
| 183 | + } else { | |
| 184 | + return ttm_range_man_init(&drm->ttm.bdev, TTM_PL_VRAM, | |
| 185 | + TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC, | |
| 186 | + TTM_PL_FLAG_WC, false, | |
| 187 | + drm->gem.vram_available >> PAGE_SHIFT); | |
| 188 | + } | |
| 189 | +} | |
| 190 | + | |
| 191 | +static void | |
| 192 | +nouveau_ttm_fini_vram(struct nouveau_drm *drm) | |
| 193 | +{ | |
| 194 | + struct ttm_resource_manager *man = ttm_manager_type(&drm->ttm.bdev, TTM_PL_VRAM); | |
| 195 | + | |
| 196 | + if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) { | |
| 197 | + ttm_resource_manager_set_used(man, false); | |
| 198 | + ttm_resource_manager_force_list_clean(&drm->ttm.bdev, man); | |
| 199 | + ttm_resource_manager_cleanup(man); | |
| 200 | + ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_VRAM, NULL); | |
| 201 | + kfree(man); | |
| 202 | + } else | |
| 203 | + ttm_range_man_fini(&drm->ttm.bdev, TTM_PL_VRAM); | |
| 204 | +} | |
| 205 | + | |
| 206 | +static int | |
| 207 | +nouveau_ttm_init_gtt(struct nouveau_drm *drm) | |
| 208 | +{ | |
| 209 | + struct ttm_resource_manager *man; | |
| 210 | + unsigned long size_pages = drm->gem.gart_available >> PAGE_SHIFT; | |
| 211 | + unsigned available_caching, default_caching; | |
| 212 | + const struct ttm_resource_manager_func *func = NULL; | |
| 213 | + if (drm->agp.bridge) { | |
| 214 | + available_caching = TTM_PL_FLAG_UNCACHED | | |
| 215 | + TTM_PL_FLAG_WC; | |
| 216 | + default_caching = TTM_PL_FLAG_WC; | |
| 217 | + } else { | |
| 218 | + available_caching = TTM_PL_MASK_CACHING; | |
| 219 | + default_caching = TTM_PL_FLAG_CACHED; | |
| 220 | + } | |
| 221 | + | |
| 222 | + if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) | |
| 223 | + func = &nouveau_gart_manager; | |
| 224 | + else if (!drm->agp.bridge) | |
| 225 | + func = &nv04_gart_manager; | |
| 226 | + else | |
| 227 | + return ttm_range_man_init(&drm->ttm.bdev, TTM_PL_TT, | |
| 228 | + available_caching, default_caching, | |
| 229 | + true, | |
| 230 | + size_pages); | |
| 231 | + | |
| 232 | + man = kzalloc(sizeof(*man), GFP_KERNEL); | |
| 233 | + if (!man) | |
| 234 | + return -ENOMEM; | |
| 235 | + | |
| 236 | + man->func = func; | |
| 237 | + man->available_caching = available_caching; | |
| 238 | + man->default_caching = default_caching; | |
| 239 | + man->use_tt = true; | |
| 240 | + ttm_resource_manager_init(man, size_pages); | |
| 241 | + ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_TT, man); | |
| 242 | + ttm_resource_manager_set_used(man, true); | |
| 243 | + return 0; | |
| 244 | +} | |
| 245 | + | |
| 246 | +static void | |
| 247 | +nouveau_ttm_fini_gtt(struct nouveau_drm *drm) | |
| 248 | +{ | |
| 249 | + struct ttm_resource_manager *man = ttm_manager_type(&drm->ttm.bdev, TTM_PL_TT); | |
| 250 | + | |
| 251 | + if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA && | |
| 252 | + drm->agp.bridge) | |
| 253 | + ttm_range_man_fini(&drm->ttm.bdev, TTM_PL_TT); | |
| 254 | + else { | |
| 255 | + ttm_resource_manager_set_used(man, false); | |
| 256 | + ttm_resource_manager_force_list_clean(&drm->ttm.bdev, man); | |
| 257 | + ttm_resource_manager_cleanup(man); | |
| 258 | + ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_TT, NULL); | |
| 259 | + kfree(man); | |
| 260 | + } | |
| 261 | +} | |
| 262 | + | |
| 183 | 263 | int |
| 184 | 264 | nouveau_ttm_init(struct nouveau_drm *drm) |
| 185 | 265 | { |
| @@ -237,8 +317,7 @@ nouveau_ttm_init(struct nouveau_drm *drm) · 51 unmodified lines | ||
| 237 | 317 | arch_io_reserve_memtype_wc(device->func->resource_addr(device, 1), |
| 238 | 318 | device->func->resource_size(device, 1)); |
| 239 | 319 | |
| 240 | − ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM, | |
| 241 | − drm->gem.vram_available >> PAGE_SHIFT); | |
| 320 | + ret = nouveau_ttm_init_vram(drm); | |
| 242 | 321 | if (ret) { |
| 243 | 322 | NV_ERROR(drm, "VRAM mm init failed, %d\n", ret); |
| 244 | 323 | return ret; |
| @@ -254,8 +333,7 @@ nouveau_ttm_init(struct nouveau_drm *drm) · 9 unmodified lines | ||
| 254 | 333 | drm->gem.gart_available = drm->agp.size; |
| 255 | 334 | } |
| 256 | 335 | |
| 257 | − ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_TT, | |
| 258 | − drm->gem.gart_available >> PAGE_SHIFT); | |
| 336 | + ret = nouveau_ttm_init_gtt(drm); | |
| 259 | 337 | if (ret) { |
| 260 | 338 | NV_ERROR(drm, "GART mm init failed, %d\n", ret); |
| 261 | 339 | return ret; |
| @@ -271,8 +349,8 @@ nouveau_ttm_fini(struct nouveau_drm *drm) · 9 unmodified lines | ||
| 271 | 349 | { |
| 272 | 350 | struct nvkm_device *device = nvxx_device(&drm->client.device); |
| 273 | 351 | |
| 274 | − ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_VRAM); | |
| 275 | − ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_TT); | |
| 352 | + nouveau_ttm_fini_vram(drm); | |
| 353 | + nouveau_ttm_fini_gtt(drm); | |
| 276 | 354 | |
| 277 | 355 | ttm_bo_device_release(&drm->ttm.bdev); |
| 278 | 356 | |
| @@ -8,9 +8,9 @@ nouveau_bdev(struct ttm_bo_device *bd) · 7 unmodified lines | ||
| 8 | 8 | return container_of(bd, struct nouveau_drm, ttm.bdev); |
| 9 | 9 | } |
| 10 | 10 | |
| 11 | −extern const struct ttm_mem_type_manager_func nouveau_vram_manager; | |
| 12 | −extern const struct ttm_mem_type_manager_func nouveau_gart_manager; | |
| 13 | −extern const struct ttm_mem_type_manager_func nv04_gart_manager; | |
| 11 | +extern const struct ttm_resource_manager_func nouveau_vram_manager; | |
| 12 | +extern const struct ttm_resource_manager_func nouveau_gart_manager; | |
| 13 | +extern const struct ttm_resource_manager_func nv04_gart_manager; | |
| 14 | 14 | |
| 15 | 15 | struct ttm_tt *nouveau_sgdma_create_ttm(struct ttm_buffer_object *bo, |
| 16 | 16 | u32 page_flags); |
| @@ -78,7 +78,7 @@ nv17_fence_context_new(struct nouveau_channel *chan) · 77 unmodified lines | ||
| 78 | 78 | { |
| 79 | 79 | struct nv10_fence_priv *priv = chan->drm->fence; |
| 80 | 80 | struct nv10_fence_chan *fctx; |
| 81 | − struct ttm_mem_reg *reg = &priv->bo->bo.mem; | |
| 81 | + struct ttm_resource *reg = &priv->bo->bo.mem; | |
| 82 | 82 | u32 start = reg->start * PAGE_SIZE; |
| 83 | 83 | u32 limit = start + reg->size - 1; |
| 84 | 84 | int ret = 0; |
| @@ -37,7 +37,7 @@ nv50_fence_context_new(struct nouveau_channel *chan) · 36 unmodified lines | ||
| 37 | 37 | { |
| 38 | 38 | struct nv10_fence_priv *priv = chan->drm->fence; |
| 39 | 39 | struct nv10_fence_chan *fctx; |
| 40 | − struct ttm_mem_reg *reg = &priv->bo->bo.mem; | |
| 40 | + struct ttm_resource *reg = &priv->bo->bo.mem; | |
| 41 | 41 | u32 start = reg->start * PAGE_SIZE; |
| 42 | 42 | u32 limit = start + reg->size - 1; |
| 43 | 43 | int ret; |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <linux/platform_device.h> |
| 21 | 21 | #include <linux/pm_runtime.h> |
| 22 | 22 | #include <linux/clk.h> |
| 23 | −#include <linux/gpio.h> | |
| 24 | 23 | #include <linux/regulator/consumer.h> |
| 25 | 24 | #include <linux/component.h> |
| 26 | 25 | #include <linux/of.h> |
| @@ -24,7 +24,6 @@ · 23 unmodified lines | ||
| 24 | 24 | #include <linux/platform_device.h> |
| 25 | 25 | #include <linux/pm_runtime.h> |
| 26 | 26 | #include <linux/clk.h> |
| 27 | −#include <linux/gpio.h> | |
| 28 | 27 | #include <linux/regulator/consumer.h> |
| 29 | 28 | #include <linux/component.h> |
| 30 | 29 | #include <linux/of.h> |
| @@ -781,7 +781,7 @@ static int venc_probe_of(struct venc_device *venc) · 780 unmodified lines | ||
| 781 | 781 | venc->type = OMAP_DSS_VENC_TYPE_SVIDEO; |
| 782 | 782 | break; |
| 783 | 783 | default: |
| 784 | − dev_err(&venc->pdev->dev, "bad channel propert '%d'\n", | |
| 784 | + dev_err(&venc->pdev->dev, "bad channel property '%d'\n", | |
| 785 | 785 | channels); |
| 786 | 786 | r = -EINVAL; |
| 787 | 787 | goto err; |
| @@ -349,13 +349,6 @@ static int omap_modeset_init(struct drm_device *dev) · 348 unmodified lines | ||
| 349 | 349 | |
| 350 | 350 | drm_connector_attach_encoder(pipe->connector, encoder); |
| 351 | 351 | |
| 352 | − if (pipe->output->panel) { | |
| 353 | − ret = drm_panel_attach(pipe->output->panel, | |
| 354 | − pipe->connector); | |
| 355 | − if (ret < 0) | |
| 356 | − return ret; | |
| 357 | − } | |
| 358 | − | |
| 359 | 352 | crtc = omap_crtc_init(dev, pipe, priv->planes[i]); |
| 360 | 353 | if (IS_ERR(crtc)) |
| 361 | 354 | return PTR_ERR(crtc); |
| @@ -394,18 +387,8 @@ static int omap_modeset_init(struct drm_device *dev) · 32 unmodified lines | ||
| 394 | 387 | |
| 395 | 388 | static void omap_modeset_fini(struct drm_device *ddev) |
| 396 | 389 | { |
| 397 | − struct omap_drm_private *priv = ddev->dev_private; | |
| 398 | − unsigned int i; | |
| 399 | − | |
| 400 | 390 | omap_drm_irq_uninstall(ddev); |
| 401 | 391 | |
| 402 | − for (i = 0; i < priv->num_pipes; i++) { | |
| 403 | − struct omap_drm_pipeline *pipe = &priv->pipes[i]; | |
| 404 | − | |
| 405 | − if (pipe->output->panel) | |
| 406 | − drm_panel_detach(pipe->output->panel); | |
| 407 | − } | |
| 408 | − | |
| 409 | 392 | drm_mode_config_cleanup(ddev); |
| 410 | 393 | } |
| 411 | 394 | |
| @@ -217,6 +217,17 @@ config DRM_PANEL_NOVATEK_NT39016 · 216 unmodified lines | ||
| 217 | 217 | Say Y here if you want to enable support for the panels built |
| 218 | 218 | around the Novatek NT39016 display controller. |
| 219 | 219 | |
| 220 | +config DRM_PANEL_MANTIX_MLAF057WE51 | |
| 221 | + tristate "Mantix MLAF057WE51-X MIPI-DSI LCD panel" | |
| 222 | + depends on OF | |
| 223 | + depends on DRM_MIPI_DSI | |
| 224 | + depends on BACKLIGHT_CLASS_DEVICE | |
| 225 | + help | |
| 226 | + Say Y here if you want to enable support for the Mantix | |
| 227 | + MLAF057WE51-X MIPI DSI panel as e.g. used in the Librem 5. It | |
| 228 | + has a resolution of 720x1440 pixels, a built in backlight and touch | |
| 229 | + controller. | |
| 230 | + | |
| 220 | 231 | config DRM_PANEL_OLIMEX_LCD_OLINUXINO |
| 221 | 232 | tristate "Olimex LCD-OLinuXino panel" |
| 222 | 233 | depends on OF |
| @@ -20,6 +20,7 @@ obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o · 19 unmodified lines | ||
| 20 | 20 | obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o |
| 21 | 21 | obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35510) += panel-novatek-nt35510.o |
| 22 | 22 | obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o |
| 23 | +obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o | |
| 23 | 24 | obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o |
| 24 | 25 | obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o |
| 25 | 26 | obj-$(CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS) += panel-osd-osd101t2587-53ts.o |
| @@ -349,7 +349,9 @@ static int versatile_panel_probe(struct platform_device *pdev) · 348 unmodified lines | ||
| 349 | 349 | drm_panel_init(&vpanel->panel, dev, &versatile_panel_drm_funcs, |
| 350 | 350 | DRM_MODE_CONNECTOR_DPI); |
| 351 | 351 | |
| 352 | − return drm_panel_add(&vpanel->panel); | |
| 352 | + drm_panel_add(&vpanel->panel); | |
| 353 | + | |
| 354 | + return 0; | |
| 353 | 355 | } |
| 354 | 356 | |
| 355 | 357 | static const struct of_device_id versatile_panel_match[] = { |
| @@ -315,11 +315,7 @@ static int tm5p5_nt35596_probe(struct mipi_dsi_device *dsi) · 314 unmodified lines | ||
| 315 | 315 | return ret; |
| 316 | 316 | } |
| 317 | 317 | |
| 318 | − ret = drm_panel_add(&ctx->panel); | |
| 319 | − if (ret < 0) { | |
| 320 | − dev_err(dev, "Failed to add panel: %d\n", ret); | |
| 321 | − return ret; | |
| 322 | − } | |
| 318 | + drm_panel_add(&ctx->panel); | |
| 323 | 319 | |
| 324 | 320 | ret = mipi_dsi_attach(dsi); |
| 325 | 321 | if (ret < 0) { |
| @@ -19,7 +19,6 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <drm/drm_mipi_dsi.h> |
| 20 | 20 | #include <drm/drm_modes.h> |
| 21 | 21 | #include <drm/drm_panel.h> |
| 22 | −#include <drm/drm_print.h> | |
| 23 | 22 | |
| 24 | 23 | #include <video/mipi_display.h> |
| 25 | 24 | |
| @@ -93,8 +92,7 @@ static int boe_panel_disable(struct drm_panel *panel) · 67 unmodified lines | ||
| 93 | 92 | |
| 94 | 93 | err = mipi_dsi_dcs_set_display_off(pinfo->link); |
| 95 | 94 | if (err < 0) { |
| 96 | − DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", | |
| 97 | − err); | |
| 95 | + dev_err(panel->dev, "failed to set display off: %d\n", err); | |
| 98 | 96 | return err; |
| 99 | 97 | } |
| 100 | 98 | |
| @@ -113,13 +111,11 @@ static int boe_panel_unprepare(struct drm_panel *panel) · 12 unmodified lines | ||
| 113 | 111 | |
| 114 | 112 | err = mipi_dsi_dcs_set_display_off(pinfo->link); |
| 115 | 113 | if (err < 0) |
| 116 | − DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", | |
| 117 | − err); | |
| 114 | + dev_err(panel->dev, "failed to set display off: %d\n", err); | |
| 118 | 115 | |
| 119 | 116 | err = mipi_dsi_dcs_enter_sleep_mode(pinfo->link); |
| 120 | 117 | if (err < 0) |
| 121 | − DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", | |
| 122 | − err); | |
| 118 | + dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); | |
| 123 | 119 | |
| 124 | 120 | /* sleep_mode_delay: 1ms - 2ms */ |
| 125 | 121 | usleep_range(1000, 2000); |
| @@ -163,15 +159,13 @@ static int boe_panel_prepare(struct drm_panel *panel) · 37 unmodified lines | ||
| 163 | 159 | /* send init code */ |
| 164 | 160 | err = send_mipi_cmds(panel, pinfo->desc->on_cmds); |
| 165 | 161 | if (err < 0) { |
| 166 | − DRM_DEV_ERROR(panel->dev, "failed to send DCS Init Code: %d\n", | |
| 167 | − err); | |
| 162 | + dev_err(panel->dev, "failed to send DCS Init Code: %d\n", err); | |
| 168 | 163 | goto poweroff; |
| 169 | 164 | } |
| 170 | 165 | |
| 171 | 166 | err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link); |
| 172 | 167 | if (err < 0) { |
| 173 | − DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n", | |
| 174 | − err); | |
| 168 | + dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); | |
| 175 | 169 | goto poweroff; |
| 176 | 170 | } |
| 177 | 171 | |
| @@ -180,8 +174,7 @@ static int boe_panel_prepare(struct drm_panel *panel) · 2 unmodified lines | ||
| 180 | 174 | |
| 181 | 175 | err = mipi_dsi_dcs_set_display_on(pinfo->link); |
| 182 | 176 | if (err < 0) { |
| 183 | − DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", | |
| 184 | − err); | |
| 177 | + dev_err(panel->dev, "failed to set display on: %d\n", err); | |
| 185 | 178 | goto poweroff; |
| 186 | 179 | } |
| 187 | 180 | |
| @@ -209,8 +202,7 @@ static int boe_panel_enable(struct drm_panel *panel) · 21 unmodified lines | ||
| 209 | 202 | |
| 210 | 203 | ret = mipi_dsi_dcs_set_display_on(pinfo->link); |
| 211 | 204 | if (ret < 0) { |
| 212 | − DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", | |
| 213 | − ret); | |
| 205 | + dev_err(panel->dev, "failed to set display on: %d\n", ret); | |
| 214 | 206 | return ret; |
| 215 | 207 | } |
| 216 | 208 | |
| @@ -228,8 +220,8 @@ static int boe_panel_get_modes(struct drm_panel *panel, · 11 unmodified lines | ||
| 228 | 220 | |
| 229 | 221 | mode = drm_mode_duplicate(connector->dev, m); |
| 230 | 222 | if (!mode) { |
| 231 | − DRM_DEV_ERROR(pinfo->base.dev, "failed to add mode %ux%u@%u\n", | |
| 232 | − m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); | |
| 223 | + dev_err(pinfo->base.dev, "failed to add mode %ux%u@%u\n", | |
| 224 | + m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); | |
| 233 | 225 | return -ENOMEM; |
| 234 | 226 | } |
| 235 | 227 | |
| @@ -865,8 +857,7 @@ static int panel_add(struct panel_info *pinfo) · 629 unmodified lines | ||
| 865 | 857 | if (IS_ERR(pinfo->pp18_gpio)) { |
| 866 | 858 | ret = PTR_ERR(pinfo->pp18_gpio); |
| 867 | 859 | if (ret != -EPROBE_DEFER) |
| 868 | − DRM_DEV_ERROR(dev, "failed to get pp18 gpio: %d\n", | |
| 869 | − ret); | |
| 860 | + dev_err(dev, "failed to get pp18 gpio: %d\n", ret); | |
| 870 | 861 | return ret; |
| 871 | 862 | } |
| 872 | 863 | |
| @@ -874,8 +865,7 @@ static int panel_add(struct panel_info *pinfo) · 1 unmodified line | ||
| 874 | 865 | if (IS_ERR(pinfo->pp33_gpio)) { |
| 875 | 866 | ret = PTR_ERR(pinfo->pp33_gpio); |
| 876 | 867 | if (ret != -EPROBE_DEFER) |
| 877 | − DRM_DEV_ERROR(dev, "failed to get pp33 gpio: %d\n", | |
| 878 | − ret); | |
| 868 | + dev_err(dev, "failed to get pp33 gpio: %d\n", ret); | |
| 879 | 869 | return ret; |
| 880 | 870 | } |
| 881 | 871 | |
| @@ -883,8 +873,7 @@ static int panel_add(struct panel_info *pinfo) · 1 unmodified line | ||
| 883 | 873 | if (IS_ERR(pinfo->enable_gpio)) { |
| 884 | 874 | ret = PTR_ERR(pinfo->enable_gpio); |
| 885 | 875 | if (ret != -EPROBE_DEFER) |
| 886 | − DRM_DEV_ERROR(dev, "failed to get enable gpio: %d\n", | |
| 887 | − ret); | |
| 876 | + dev_err(dev, "failed to get enable gpio: %d\n", ret); | |
| 888 | 877 | return ret; |
| 889 | 878 | } |
| 890 | 879 | |
| @@ -895,7 +884,9 @@ static int panel_add(struct panel_info *pinfo) · 4 unmodified lines | ||
| 895 | 884 | if (ret) |
| 896 | 885 | return ret; |
| 897 | 886 | |
| 898 | − return drm_panel_add(&pinfo->base); | |
| 887 | + drm_panel_add(&pinfo->base); | |
| 888 | + | |
| 889 | + return 0; | |
| 899 | 890 | } |
| 900 | 891 | |
| 901 | 892 | static int panel_probe(struct mipi_dsi_device *dsi) |
| @@ -935,18 +926,15 @@ static int panel_remove(struct mipi_dsi_device *dsi) · 33 unmodified lines | ||
| 935 | 926 | |
| 936 | 927 | err = boe_panel_disable(&pinfo->base); |
| 937 | 928 | if (err < 0) |
| 938 | − DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", | |
| 939 | − err); | |
| 929 | + dev_err(&dsi->dev, "failed to disable panel: %d\n", err); | |
| 940 | 930 | |
| 941 | 931 | err = boe_panel_unprepare(&pinfo->base); |
| 942 | 932 | if (err < 0) |
| 943 | − DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n", | |
| 944 | − err); | |
| 933 | + dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err); | |
| 945 | 934 | |
| 946 | 935 | err = mipi_dsi_detach(dsi); |
| 947 | 936 | if (err < 0) |
| 948 | − DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n", | |
| 949 | − err); | |
| 937 | + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); | |
| 950 | 938 | |
| 951 | 939 | drm_panel_remove(&pinfo->base); |
| 952 | 940 | |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <linux/of_device.h> |
| 12 | 12 | #include <linux/regulator/consumer.h> |
| 13 | 13 | |
| 14 | +#include <drm/drm_connector.h> | |
| 14 | 15 | #include <drm/drm_crtc.h> |
| 15 | 16 | #include <drm/drm_mipi_dsi.h> |
| 16 | 17 | #include <drm/drm_panel.h> |
| @@ -43,6 +44,7 @@ struct boe_panel { · 26 unmodified lines | ||
| 43 | 44 | |
| 44 | 45 | const struct panel_desc *desc; |
| 45 | 46 | |
| 47 | + enum drm_panel_orientation orientation; | |
| 46 | 48 | struct regulator *pp1800; |
| 47 | 49 | struct regulator *avee; |
| 48 | 50 | struct regulator *avdd; |
| @@ -740,6 +742,7 @@ static int boe_panel_get_modes(struct drm_panel *panel, · 691 unmodified lines | ||
| 740 | 742 | connector->display_info.width_mm = boe->desc->size.width_mm; |
| 741 | 743 | connector->display_info.height_mm = boe->desc->size.height_mm; |
| 742 | 744 | connector->display_info.bpc = boe->desc->bpc; |
| 745 | + drm_connector_set_panel_orientation(connector, boe->orientation); | |
| 743 | 746 | |
| 744 | 747 | return 1; |
| 745 | 748 | } |
| @@ -779,6 +782,11 @@ static int boe_panel_add(struct boe_panel *boe) · 33 unmodified lines | ||
| 779 | 782 | |
| 780 | 783 | drm_panel_init(&boe->base, dev, &boe_panel_funcs, |
| 781 | 784 | DRM_MODE_CONNECTOR_DSI); |
| 785 | + err = of_drm_get_panel_orientation(dev->of_node, &boe->orientation); | |
| 786 | + if (err < 0) { | |
| 787 | + dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err); | |
| 788 | + return err; | |
| 789 | + } | |
| 782 | 790 | |
| 783 | 791 | err = drm_panel_of_backlight(&boe->base); |
| 784 | 792 | if (err) |
| @@ -787,7 +795,9 @@ static int boe_panel_add(struct boe_panel *boe) · 2 unmodified lines | ||
| 787 | 795 | boe->base.funcs = &boe_panel_funcs; |
| 788 | 796 | boe->base.dev = &boe->dsi->dev; |
| 789 | 797 | |
| 790 | − return drm_panel_add(&boe->base); | |
| 798 | + drm_panel_add(&boe->base); | |
| 799 | + | |
| 800 | + return 0; | |
| 791 | 801 | } |
| 792 | 802 | |
| 793 | 803 | static int boe_panel_probe(struct mipi_dsi_device *dsi) |
| @@ -22,7 +22,6 @@ · 21 unmodified lines | ||
| 22 | 22 | #include <drm/drm_mipi_dsi.h> |
| 23 | 23 | #include <drm/drm_modes.h> |
| 24 | 24 | #include <drm/drm_panel.h> |
| 25 | −#include <drm/drm_print.h> | |
| 26 | 25 | |
| 27 | 26 | /* Manufacturer specific Commands send via DSI */ |
| 28 | 27 | #define KD35T133_CMD_INTERFACEMODECTRL 0xb0 |
| @@ -89,7 +88,7 @@ static int kd35t133_init_sequence(struct kd35t133 *ctx) · 60 unmodified lines | ||
| 89 | 88 | 0xa9, 0x51, 0x2c, 0x82); |
| 90 | 89 | mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_INVERT_MODE, NULL, 0); |
| 91 | 90 | |
| 92 | − DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n"); | |
| 91 | + dev_dbg(dev, "Panel init sequence done\n"); | |
| 93 | 92 | return 0; |
| 94 | 93 | } |
| 95 | 94 | |
| @@ -104,13 +103,11 @@ static int kd35t133_unprepare(struct drm_panel *panel) · 8 unmodified lines | ||
| 104 | 103 | |
| 105 | 104 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 106 | 105 | if (ret < 0) |
| 107 | − DRM_DEV_ERROR(ctx->dev, "failed to set display off: %d\n", | |
| 108 | − ret); | |
| 106 | + dev_err(ctx->dev, "failed to set display off: %d\n", ret); | |
| 109 | 107 | |
| 110 | 108 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 111 | 109 | if (ret < 0) { |
| 112 | − DRM_DEV_ERROR(ctx->dev, "failed to enter sleep mode: %d\n", | |
| 113 | − ret); | |
| 110 | + dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret); | |
| 114 | 111 | return ret; |
| 115 | 112 | } |
| 116 | 113 | |
| @@ -131,18 +128,16 @@ static int kd35t133_prepare(struct drm_panel *panel) · 14 unmodified lines | ||
| 131 | 128 | if (ctx->prepared) |
| 132 | 129 | return 0; |
| 133 | 130 | |
| 134 | − DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n"); | |
| 131 | + dev_dbg(ctx->dev, "Resetting the panel\n"); | |
| 135 | 132 | ret = regulator_enable(ctx->vdd); |
| 136 | 133 | if (ret < 0) { |
| 137 | − DRM_DEV_ERROR(ctx->dev, | |
| 138 | − "Failed to enable vdd supply: %d\n", ret); | |
| 134 | + dev_err(ctx->dev, "Failed to enable vdd supply: %d\n", ret); | |
| 139 | 135 | return ret; |
| 140 | 136 | } |
| 141 | 137 | |
| 142 | 138 | ret = regulator_enable(ctx->iovcc); |
| 143 | 139 | if (ret < 0) { |
| 144 | − DRM_DEV_ERROR(ctx->dev, | |
| 145 | − "Failed to enable iovcc supply: %d\n", ret); | |
| 140 | + dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); | |
| 146 | 141 | goto disable_vdd; |
| 147 | 142 | } |
| 148 | 143 | |
| @@ -156,7 +151,7 @@ static int kd35t133_prepare(struct drm_panel *panel) · 7 unmodified lines | ||
| 156 | 151 | |
| 157 | 152 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 158 | 153 | if (ret < 0) { |
| 159 | − DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret); | |
| 154 | + dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret); | |
| 160 | 155 | goto disable_iovcc; |
| 161 | 156 | } |
| 162 | 157 | |
| @@ -164,14 +159,13 @@ static int kd35t133_prepare(struct drm_panel *panel) · 1 unmodified line | ||
| 164 | 159 | |
| 165 | 160 | ret = kd35t133_init_sequence(ctx); |
| 166 | 161 | if (ret < 0) { |
| 167 | − DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", | |
| 168 | − ret); | |
| 162 | + dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); | |
| 169 | 163 | goto disable_iovcc; |
| 170 | 164 | } |
| 171 | 165 | |
| 172 | 166 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 173 | 167 | if (ret < 0) { |
| 174 | − DRM_DEV_ERROR(ctx->dev, "Failed to set display on: %d\n", ret); | |
| 168 | + dev_err(ctx->dev, "Failed to set display on: %d\n", ret); | |
| 175 | 169 | goto disable_iovcc; |
| 176 | 170 | } |
| 177 | 171 | |
| @@ -210,9 +204,9 @@ static int kd35t133_get_modes(struct drm_panel *panel, · 32 unmodified lines | ||
| 210 | 204 | |
| 211 | 205 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 212 | 206 | if (!mode) { |
| 213 | − DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n", | |
| 214 | − default_mode.hdisplay, default_mode.vdisplay, | |
| 215 | − drm_mode_vrefresh(&default_mode)); | |
| 207 | + dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", | |
| 208 | + default_mode.hdisplay, default_mode.vdisplay, | |
| 209 | + drm_mode_vrefresh(&default_mode)); | |
| 216 | 210 | return -ENOMEM; |
| 217 | 211 | } |
| 218 | 212 | |
| @@ -244,7 +238,7 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi) · 25 unmodified lines | ||
| 244 | 238 | |
| 245 | 239 | ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); |
| 246 | 240 | if (IS_ERR(ctx->reset_gpio)) { |
| 247 | − DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); | |
| 241 | + dev_err(dev, "cannot get reset gpio\n"); | |
| 248 | 242 | return PTR_ERR(ctx->reset_gpio); |
| 249 | 243 | } |
| 250 | 244 | |
| @@ -252,9 +246,7 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi) · 1 unmodified line | ||
| 252 | 246 | if (IS_ERR(ctx->vdd)) { |
| 253 | 247 | ret = PTR_ERR(ctx->vdd); |
| 254 | 248 | if (ret != -EPROBE_DEFER) |
| 255 | − DRM_DEV_ERROR(dev, | |
| 256 | − "Failed to request vdd regulator: %d\n", | |
| 257 | − ret); | |
| 249 | + dev_err(dev, "Failed to request vdd regulator: %d\n", ret); | |
| 258 | 250 | return ret; |
| 259 | 251 | } |
| 260 | 252 | |
| @@ -262,9 +254,7 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi) · 1 unmodified line | ||
| 262 | 254 | if (IS_ERR(ctx->iovcc)) { |
| 263 | 255 | ret = PTR_ERR(ctx->iovcc); |
| 264 | 256 | if (ret != -EPROBE_DEFER) |
| 265 | − DRM_DEV_ERROR(dev, | |
| 266 | − "Failed to request iovcc regulator: %d\n", | |
| 267 | − ret); | |
| 257 | + dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); | |
| 268 | 258 | return ret; |
| 269 | 259 | } |
| 270 | 260 | |
| @@ -288,7 +278,7 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi) · 17 unmodified lines | ||
| 288 | 278 | |
| 289 | 279 | ret = mipi_dsi_attach(dsi); |
| 290 | 280 | if (ret < 0) { |
| 291 | − DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret); | |
| 281 | + dev_err(dev, "mipi_dsi_attach failed: %d\n", ret); | |
| 292 | 282 | drm_panel_remove(&ctx->panel); |
| 293 | 283 | return ret; |
| 294 | 284 | } |
| @@ -303,13 +293,11 @@ static void kd35t133_shutdown(struct mipi_dsi_device *dsi) · 8 unmodified lines | ||
| 303 | 293 | |
| 304 | 294 | ret = drm_panel_unprepare(&ctx->panel); |
| 305 | 295 | if (ret < 0) |
| 306 | − DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", | |
| 307 | − ret); | |
| 296 | + dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); | |
| 308 | 297 | |
| 309 | 298 | ret = drm_panel_disable(&ctx->panel); |
| 310 | 299 | if (ret < 0) |
| 311 | − DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", | |
| 312 | − ret); | |
| 300 | + dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); | |
| 313 | 301 | } |
| 314 | 302 | |
| 315 | 303 | static int kd35t133_remove(struct mipi_dsi_device *dsi) |
| @@ -321,8 +309,7 @@ static int kd35t133_remove(struct mipi_dsi_device *dsi) · 5 unmodified lines | ||
| 321 | 309 | |
| 322 | 310 | ret = mipi_dsi_detach(dsi); |
| 323 | 311 | if (ret < 0) |
| 324 | − DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", | |
| 325 | − ret); | |
| 312 | + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); | |
| 326 | 313 | |
| 327 | 314 | drm_panel_remove(&ctx->panel); |
| 328 | 315 | |
| @@ -13,7 +13,6 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <drm/drm_mipi_dsi.h> |
| 14 | 14 | #include <drm/drm_modes.h> |
| 15 | 15 | #include <drm/drm_panel.h> |
| 16 | −#include <drm/drm_print.h> | |
| 17 | 16 | |
| 18 | 17 | #define K101_IM2BA02_INIT_CMD_LEN 2 |
| 19 | 18 | |
| @@ -374,13 +373,11 @@ static int k101_im2ba02_unprepare(struct drm_panel *panel) · 354 unmodified lines | ||
| 374 | 373 | |
| 375 | 374 | ret = mipi_dsi_dcs_set_display_off(ctx->dsi); |
| 376 | 375 | if (ret < 0) |
| 377 | − DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", | |
| 378 | − ret); | |
| 376 | + dev_err(panel->dev, "failed to set display off: %d\n", ret); | |
| 379 | 377 | |
| 380 | 378 | ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); |
| 381 | 379 | if (ret < 0) |
| 382 | − DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", | |
| 383 | − ret); | |
| 380 | + dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); | |
| 384 | 381 | |
| 385 | 382 | msleep(200); |
| 386 | 383 | |
| @@ -416,10 +413,10 @@ static int k101_im2ba02_get_modes(struct drm_panel *panel, · 29 unmodified lines | ||
| 416 | 413 | |
| 417 | 414 | mode = drm_mode_duplicate(connector->dev, &k101_im2ba02_default_mode); |
| 418 | 415 | if (!mode) { |
| 419 | − DRM_DEV_ERROR(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n", | |
| 420 | − k101_im2ba02_default_mode.hdisplay, | |
| 421 | − k101_im2ba02_default_mode.vdisplay, | |
| 422 | − drm_mode_vrefresh(&k101_im2ba02_default_mode)); | |
| 416 | + dev_err(&ctx->dsi->dev, "failed to add mode %ux%u@%u\n", | |
| 417 | + k101_im2ba02_default_mode.hdisplay, | |
| 418 | + k101_im2ba02_default_mode.vdisplay, | |
| 419 | + drm_mode_vrefresh(&k101_im2ba02_default_mode)); | |
| 423 | 420 | return -ENOMEM; |
| 424 | 421 | } |
| 425 | 422 | |
| @@ -460,13 +457,13 @@ static int k101_im2ba02_dsi_probe(struct mipi_dsi_device *dsi) · 34 unmodified lines | ||
| 460 | 457 | ret = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(ctx->supplies), |
| 461 | 458 | ctx->supplies); |
| 462 | 459 | if (ret < 0) { |
| 463 | − DRM_DEV_ERROR(&dsi->dev, "Couldn't get regulators\n"); | |
| 460 | + dev_err(&dsi->dev, "Couldn't get regulators\n"); | |
| 464 | 461 | return ret; |
| 465 | 462 | } |
| 466 | 463 | |
| 467 | 464 | ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); |
| 468 | 465 | if (IS_ERR(ctx->reset)) { |
| 469 | − DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n"); | |
| 466 | + dev_err(&dsi->dev, "Couldn't get our reset GPIO\n"); | |
| 470 | 467 | return PTR_ERR(ctx->reset); |
| 471 | 468 | } |
| 472 | 469 | |
| @@ -477,9 +474,7 @@ static int k101_im2ba02_dsi_probe(struct mipi_dsi_device *dsi) · 4 unmodified lines | ||
| 477 | 474 | if (ret) |
| 478 | 475 | return ret; |
| 479 | 476 | |
| 480 | − ret = drm_panel_add(&ctx->panel); | |
| 481 | − if (ret < 0) | |
| 482 | − return ret; | |
| 477 | + drm_panel_add(&ctx->panel); | |
| 483 | 478 | |
| 484 | 479 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO; |
| 485 | 480 | dsi->format = MIPI_DSI_FMT_RGB888; |
| @@ -7,7 +7,6 @@ · 6 unmodified lines | ||
| 7 | 7 | #include <drm/drm_mipi_dsi.h> |
| 8 | 8 | #include <drm/drm_modes.h> |
| 9 | 9 | #include <drm/drm_panel.h> |
| 10 | −#include <drm/drm_print.h> | |
| 11 | 10 | |
| 12 | 11 | #include <linux/gpio/consumer.h> |
| 13 | 12 | #include <linux/delay.h> |
| @@ -118,13 +117,11 @@ static int feiyang_unprepare(struct drm_panel *panel) · 104 unmodified lines | ||
| 118 | 117 | |
| 119 | 118 | ret = mipi_dsi_dcs_set_display_off(ctx->dsi); |
| 120 | 119 | if (ret < 0) |
| 121 | − DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", | |
| 122 | − ret); | |
| 120 | + dev_err(panel->dev, "failed to set display off: %d\n", ret); | |
| 123 | 121 | |
| 124 | 122 | ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); |
| 125 | 123 | if (ret < 0) |
| 126 | − DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", | |
| 127 | − ret); | |
| 124 | + dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); | |
| 128 | 125 | |
| 129 | 126 | /* T13 (backlight fall + video & logic signal fall) T13 >= 200ms */ |
| 130 | 127 | msleep(200); |
| @@ -165,10 +162,10 @@ static int feiyang_get_modes(struct drm_panel *panel, · 34 unmodified lines | ||
| 165 | 162 | |
| 166 | 163 | mode = drm_mode_duplicate(connector->dev, &feiyang_default_mode); |
| 167 | 164 | if (!mode) { |
| 168 | − DRM_DEV_ERROR(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n", | |
| 169 | − feiyang_default_mode.hdisplay, | |
| 170 | − feiyang_default_mode.vdisplay, | |
| 171 | − drm_mode_vrefresh(&feiyang_default_mode)); | |
| 165 | + dev_err(&ctx->dsi->dev, "failed to add mode %ux%u@%u\n", | |
| 166 | + feiyang_default_mode.hdisplay, | |
| 167 | + feiyang_default_mode.vdisplay, | |
| 168 | + drm_mode_vrefresh(&feiyang_default_mode)); | |
| 172 | 169 | return -ENOMEM; |
| 173 | 170 | } |
| 174 | 171 | |
| @@ -204,19 +201,19 @@ static int feiyang_dsi_probe(struct mipi_dsi_device *dsi) · 29 unmodified lines | ||
| 204 | 201 | |
| 205 | 202 | ctx->dvdd = devm_regulator_get(&dsi->dev, "dvdd"); |
| 206 | 203 | if (IS_ERR(ctx->dvdd)) { |
| 207 | − DRM_DEV_ERROR(&dsi->dev, "Couldn't get dvdd regulator\n"); | |
| 204 | + dev_err(&dsi->dev, "Couldn't get dvdd regulator\n"); | |
| 208 | 205 | return PTR_ERR(ctx->dvdd); |
| 209 | 206 | } |
| 210 | 207 | |
| 211 | 208 | ctx->avdd = devm_regulator_get(&dsi->dev, "avdd"); |
| 212 | 209 | if (IS_ERR(ctx->avdd)) { |
| 213 | − DRM_DEV_ERROR(&dsi->dev, "Couldn't get avdd regulator\n"); | |
| 210 | + dev_err(&dsi->dev, "Couldn't get avdd regulator\n"); | |
| 214 | 211 | return PTR_ERR(ctx->avdd); |
| 215 | 212 | } |
| 216 | 213 | |
| 217 | 214 | ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); |
| 218 | 215 | if (IS_ERR(ctx->reset)) { |
| 219 | − DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n"); | |
| 216 | + dev_err(&dsi->dev, "Couldn't get our reset GPIO\n"); | |
| 220 | 217 | return PTR_ERR(ctx->reset); |
| 221 | 218 | } |
| 222 | 219 | |
| @@ -224,9 +221,7 @@ static int feiyang_dsi_probe(struct mipi_dsi_device *dsi) · 1 unmodified line | ||
| 224 | 221 | if (ret) |
| 225 | 222 | return ret; |
| 226 | 223 | |
| 227 | − ret = drm_panel_add(&ctx->panel); | |
| 228 | − if (ret < 0) | |
| 229 | − return ret; | |
| 224 | + drm_panel_add(&ctx->panel); | |
| 230 | 225 | |
| 231 | 226 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST; |
| 232 | 227 | dsi->format = MIPI_DSI_FMT_RGB888; |
| @@ -33,7 +33,6 @@ · 32 unmodified lines | ||
| 33 | 33 | |
| 34 | 34 | #include <drm/drm_modes.h> |
| 35 | 35 | #include <drm/drm_panel.h> |
| 36 | −#include <drm/drm_print.h> | |
| 37 | 36 | |
| 38 | 37 | #define ILI9322_CHIP_ID 0x00 |
| 39 | 38 | #define ILI9322_CHIP_ID_MAGIC 0x96 |
| @@ -683,7 +682,7 @@ static int ili9322_get_modes(struct drm_panel *panel, · 643 unmodified lines | ||
| 683 | 682 | break; |
| 684 | 683 | } |
| 685 | 684 | if (!mode) { |
| 686 | − DRM_ERROR("bad mode or failed to add mode\n"); | |
| 685 | + dev_err(panel->dev, "bad mode or failed to add mode\n"); | |
| 687 | 686 | return -EINVAL; |
| 688 | 687 | } |
| 689 | 688 | drm_mode_set_name(mode); |
| @@ -892,7 +891,9 @@ static int ili9322_probe(struct spi_device *spi) · 202 unmodified lines | ||
| 892 | 891 | drm_panel_init(&ili->panel, dev, &ili9322_drm_funcs, |
| 893 | 892 | DRM_MODE_CONNECTOR_DPI); |
| 894 | 893 | |
| 895 | − return drm_panel_add(&ili->panel); | |
| 894 | + drm_panel_add(&ili->panel); | |
| 895 | + | |
| 896 | + return 0; | |
| 896 | 897 | } |
| 897 | 898 | |
| 898 | 899 | static int ili9322_remove(struct spi_device *spi) |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/fb.h> |
| 11 | 11 | #include <linux/kernel.h> |
| 12 | 12 | #include <linux/module.h> |
| 13 | +#include <linux/of_device.h> | |
| 13 | 14 | |
| 14 | 15 | #include <linux/gpio/consumer.h> |
| 15 | 16 | #include <linux/regulator/consumer.h> |
| @@ -20,14 +21,6 @@ · 4 unmodified lines | ||
| 20 | 21 | |
| 21 | 22 | #include <video/mipi_display.h> |
| 22 | 23 | |
| 23 | −struct ili9881c { | |
| 24 | − struct drm_panel panel; | |
| 25 | − struct mipi_dsi_device *dsi; | |
| 26 | − | |
| 27 | − struct regulator *power; | |
| 28 | − struct gpio_desc *reset; | |
| 29 | −}; | |
| 30 | − | |
| 31 | 24 | enum ili9881c_op { |
| 32 | 25 | ILI9881C_SWITCH_PAGE, |
| 33 | 26 | ILI9881C_COMMAND, |
| @@ -45,6 +38,21 @@ struct ili9881c_instr { · 11 unmodified lines | ||
| 45 | 38 | } arg; |
| 46 | 39 | }; |
| 47 | 40 | |
| 41 | +struct ili9881c_desc { | |
| 42 | + const struct ili9881c_instr *init; | |
| 43 | + const size_t init_length; | |
| 44 | + const struct drm_display_mode *mode; | |
| 45 | +}; | |
| 46 | + | |
| 47 | +struct ili9881c { | |
| 48 | + struct drm_panel panel; | |
| 49 | + struct mipi_dsi_device *dsi; | |
| 50 | + const struct ili9881c_desc *desc; | |
| 51 | + | |
| 52 | + struct regulator *power; | |
| 53 | + struct gpio_desc *reset; | |
| 54 | +}; | |
| 55 | + | |
| 48 | 56 | #define ILI9881C_SWITCH_PAGE_INSTR(_page) \ |
| 49 | 57 | { \ |
| 50 | 58 | .op = ILI9881C_SWITCH_PAGE, \ |
| @@ -64,7 +72,7 @@ struct ili9881c_instr { · 13 unmodified lines | ||
| 64 | 72 | }, \ |
| 65 | 73 | } |
| 66 | 74 | |
| 67 | −static const struct ili9881c_instr ili9881c_init[] = { | |
| 75 | +static const struct ili9881c_instr lhr050h41_init[] = { | |
| 68 | 76 | ILI9881C_SWITCH_PAGE_INSTR(3), |
| 69 | 77 | ILI9881C_COMMAND_INSTR(0x01, 0x00), |
| 70 | 78 | ILI9881C_COMMAND_INSTR(0x02, 0x00), |
| @@ -252,6 +260,199 @@ static const struct ili9881c_instr ili9881c_init[] = { · 181 unmodified lines | ||
| 252 | 260 | ILI9881C_COMMAND_INSTR(0xD3, 0x3F), |
| 253 | 261 | }; |
| 254 | 262 | |
| 263 | +static const struct ili9881c_instr k101_im2byl02_init[] = { | |
| 264 | + ILI9881C_SWITCH_PAGE_INSTR(3), | |
| 265 | + ILI9881C_COMMAND_INSTR(0x01, 0x00), | |
| 266 | + ILI9881C_COMMAND_INSTR(0x02, 0x00), | |
| 267 | + ILI9881C_COMMAND_INSTR(0x03, 0x73), | |
| 268 | + ILI9881C_COMMAND_INSTR(0x04, 0x00), | |
| 269 | + ILI9881C_COMMAND_INSTR(0x05, 0x00), | |
| 270 | + ILI9881C_COMMAND_INSTR(0x06, 0x08), | |
| 271 | + ILI9881C_COMMAND_INSTR(0x07, 0x00), | |
| 272 | + ILI9881C_COMMAND_INSTR(0x08, 0x00), | |
| 273 | + ILI9881C_COMMAND_INSTR(0x09, 0x00), | |
| 274 | + ILI9881C_COMMAND_INSTR(0x0A, 0x01), | |
| 275 | + ILI9881C_COMMAND_INSTR(0x0B, 0x01), | |
| 276 | + ILI9881C_COMMAND_INSTR(0x0C, 0x00), | |
| 277 | + ILI9881C_COMMAND_INSTR(0x0D, 0x01), | |
| 278 | + ILI9881C_COMMAND_INSTR(0x0E, 0x01), | |
| 279 | + ILI9881C_COMMAND_INSTR(0x0F, 0x00), | |
| 280 | + ILI9881C_COMMAND_INSTR(0x10, 0x00), | |
| 281 | + ILI9881C_COMMAND_INSTR(0x11, 0x00), | |
| 282 | + ILI9881C_COMMAND_INSTR(0x12, 0x00), | |
| 283 | + ILI9881C_COMMAND_INSTR(0x13, 0x00), | |
| 284 | + ILI9881C_COMMAND_INSTR(0x14, 0x00), | |
| 285 | + ILI9881C_COMMAND_INSTR(0x15, 0x00), | |
| 286 | + ILI9881C_COMMAND_INSTR(0x16, 0x00), | |
| 287 | + ILI9881C_COMMAND_INSTR(0x17, 0x00), | |
| 288 | + ILI9881C_COMMAND_INSTR(0x18, 0x00), | |
| 289 | + ILI9881C_COMMAND_INSTR(0x19, 0x00), | |
| 290 | + ILI9881C_COMMAND_INSTR(0x1A, 0x00), | |
| 291 | + ILI9881C_COMMAND_INSTR(0x1B, 0x00), | |
| 292 | + ILI9881C_COMMAND_INSTR(0x1C, 0x00), | |
| 293 | + ILI9881C_COMMAND_INSTR(0x1D, 0x00), | |
| 294 | + ILI9881C_COMMAND_INSTR(0x1E, 0x40), | |
| 295 | + ILI9881C_COMMAND_INSTR(0x1F, 0xC0), | |
| 296 | + ILI9881C_COMMAND_INSTR(0x20, 0x06), | |
| 297 | + ILI9881C_COMMAND_INSTR(0x21, 0x01), | |
| 298 | + ILI9881C_COMMAND_INSTR(0x22, 0x06), | |
| 299 | + ILI9881C_COMMAND_INSTR(0x23, 0x01), | |
| 300 | + ILI9881C_COMMAND_INSTR(0x24, 0x88), | |
| 301 | + ILI9881C_COMMAND_INSTR(0x25, 0x88), | |
| 302 | + ILI9881C_COMMAND_INSTR(0x26, 0x00), | |
| 303 | + ILI9881C_COMMAND_INSTR(0x27, 0x00), | |
| 304 | + ILI9881C_COMMAND_INSTR(0x28, 0x3B), | |
| 305 | + ILI9881C_COMMAND_INSTR(0x29, 0x03), | |
| 306 | + ILI9881C_COMMAND_INSTR(0x2A, 0x00), | |
| 307 | + ILI9881C_COMMAND_INSTR(0x2B, 0x00), | |
| 308 | + ILI9881C_COMMAND_INSTR(0x2C, 0x00), | |
| 309 | + ILI9881C_COMMAND_INSTR(0x2D, 0x00), | |
| 310 | + ILI9881C_COMMAND_INSTR(0x2E, 0x00), | |
| 311 | + ILI9881C_COMMAND_INSTR(0x2F, 0x00), | |
| 312 | + ILI9881C_COMMAND_INSTR(0x30, 0x00), | |
| 313 | + ILI9881C_COMMAND_INSTR(0x31, 0x00), | |
| 314 | + ILI9881C_COMMAND_INSTR(0x32, 0x00), | |
| 315 | + ILI9881C_COMMAND_INSTR(0x33, 0x00), | |
| 316 | + ILI9881C_COMMAND_INSTR(0x34, 0x00), /* GPWR1/2 non overlap time 2.62us */ | |
| 317 | + ILI9881C_COMMAND_INSTR(0x35, 0x00), | |
| 318 | + ILI9881C_COMMAND_INSTR(0x36, 0x00), | |
| 319 | + ILI9881C_COMMAND_INSTR(0x37, 0x00), | |
| 320 | + ILI9881C_COMMAND_INSTR(0x38, 0x00), | |
| 321 | + ILI9881C_COMMAND_INSTR(0x39, 0x00), | |
| 322 | + ILI9881C_COMMAND_INSTR(0x3A, 0x00), | |
| 323 | + ILI9881C_COMMAND_INSTR(0x3B, 0x00), | |
| 324 | + ILI9881C_COMMAND_INSTR(0x3C, 0x00), | |
| 325 | + ILI9881C_COMMAND_INSTR(0x3D, 0x00), | |
| 326 | + ILI9881C_COMMAND_INSTR(0x3E, 0x00), | |
| 327 | + ILI9881C_COMMAND_INSTR(0x3F, 0x00), | |
| 328 | + ILI9881C_COMMAND_INSTR(0x40, 0x00), | |
| 329 | + ILI9881C_COMMAND_INSTR(0x41, 0x00), | |
| 330 | + ILI9881C_COMMAND_INSTR(0x42, 0x00), | |
| 331 | + ILI9881C_COMMAND_INSTR(0x43, 0x00), | |
| 332 | + ILI9881C_COMMAND_INSTR(0x44, 0x00), | |
| 333 | + ILI9881C_COMMAND_INSTR(0x50, 0x01), | |
| 334 | + ILI9881C_COMMAND_INSTR(0x51, 0x23), | |
| 335 | + ILI9881C_COMMAND_INSTR(0x52, 0x45), | |
| 336 | + ILI9881C_COMMAND_INSTR(0x53, 0x67), | |
| 337 | + ILI9881C_COMMAND_INSTR(0x54, 0x89), | |
| 338 | + ILI9881C_COMMAND_INSTR(0x55, 0xAB), | |
| 339 | + ILI9881C_COMMAND_INSTR(0x56, 0x01), | |
| 340 | + ILI9881C_COMMAND_INSTR(0x57, 0x23), | |
| 341 | + ILI9881C_COMMAND_INSTR(0x58, 0x45), | |
| 342 | + ILI9881C_COMMAND_INSTR(0x59, 0x67), | |
| 343 | + ILI9881C_COMMAND_INSTR(0x5A, 0x89), | |
| 344 | + ILI9881C_COMMAND_INSTR(0x5B, 0xAB), | |
| 345 | + ILI9881C_COMMAND_INSTR(0x5C, 0xCD), | |
| 346 | + ILI9881C_COMMAND_INSTR(0x5D, 0xEF), | |
| 347 | + ILI9881C_COMMAND_INSTR(0x5E, 0x00), | |
| 348 | + ILI9881C_COMMAND_INSTR(0x5F, 0x01), | |
| 349 | + ILI9881C_COMMAND_INSTR(0x60, 0x01), | |
| 350 | + ILI9881C_COMMAND_INSTR(0x61, 0x06), | |
| 351 | + ILI9881C_COMMAND_INSTR(0x62, 0x06), | |
| 352 | + ILI9881C_COMMAND_INSTR(0x63, 0x07), | |
| 353 | + ILI9881C_COMMAND_INSTR(0x64, 0x07), | |
| 354 | + ILI9881C_COMMAND_INSTR(0x65, 0x00), | |
| 355 | + ILI9881C_COMMAND_INSTR(0x66, 0x00), | |
| 356 | + ILI9881C_COMMAND_INSTR(0x67, 0x02), | |
| 357 | + ILI9881C_COMMAND_INSTR(0x68, 0x02), | |
| 358 | + ILI9881C_COMMAND_INSTR(0x69, 0x05), | |
| 359 | + ILI9881C_COMMAND_INSTR(0x6A, 0x05), | |
| 360 | + ILI9881C_COMMAND_INSTR(0x6B, 0x02), | |
| 361 | + ILI9881C_COMMAND_INSTR(0x6C, 0x0D), | |
| 362 | + ILI9881C_COMMAND_INSTR(0x6D, 0x0D), | |
| 363 | + ILI9881C_COMMAND_INSTR(0x6E, 0x0C), | |
| 364 | + ILI9881C_COMMAND_INSTR(0x6F, 0x0C), | |
| 365 | + ILI9881C_COMMAND_INSTR(0x70, 0x0F), | |
| 366 | + ILI9881C_COMMAND_INSTR(0x71, 0x0F), | |
| 367 | + ILI9881C_COMMAND_INSTR(0x72, 0x0E), | |
| 368 | + ILI9881C_COMMAND_INSTR(0x73, 0x0E), | |
| 369 | + ILI9881C_COMMAND_INSTR(0x74, 0x02), | |
| 370 | + ILI9881C_COMMAND_INSTR(0x75, 0x01), | |
| 371 | + ILI9881C_COMMAND_INSTR(0x76, 0x01), | |
| 372 | + ILI9881C_COMMAND_INSTR(0x77, 0x06), | |
| 373 | + ILI9881C_COMMAND_INSTR(0x78, 0x06), | |
| 374 | + ILI9881C_COMMAND_INSTR(0x79, 0x07), | |
| 375 | + ILI9881C_COMMAND_INSTR(0x7A, 0x07), | |
| 376 | + ILI9881C_COMMAND_INSTR(0x7B, 0x00), | |
| 377 | + ILI9881C_COMMAND_INSTR(0x7C, 0x00), | |
| 378 | + ILI9881C_COMMAND_INSTR(0x7D, 0x02), | |
| 379 | + ILI9881C_COMMAND_INSTR(0x7E, 0x02), | |
| 380 | + ILI9881C_COMMAND_INSTR(0x7F, 0x05), | |
| 381 | + ILI9881C_COMMAND_INSTR(0x80, 0x05), | |
| 382 | + ILI9881C_COMMAND_INSTR(0x81, 0x02), | |
| 383 | + ILI9881C_COMMAND_INSTR(0x82, 0x0D), | |
| 384 | + ILI9881C_COMMAND_INSTR(0x83, 0x0D), | |
| 385 | + ILI9881C_COMMAND_INSTR(0x84, 0x0C), | |
| 386 | + ILI9881C_COMMAND_INSTR(0x85, 0x0C), | |
| 387 | + ILI9881C_COMMAND_INSTR(0x86, 0x0F), | |
| 388 | + ILI9881C_COMMAND_INSTR(0x87, 0x0F), | |
| 389 | + ILI9881C_COMMAND_INSTR(0x88, 0x0E), | |
| 390 | + ILI9881C_COMMAND_INSTR(0x89, 0x0E), | |
| 391 | + ILI9881C_COMMAND_INSTR(0x8A, 0x02), | |
| 392 | + ILI9881C_SWITCH_PAGE_INSTR(4), | |
| 393 | + ILI9881C_COMMAND_INSTR(0x3B, 0xC0), /* ILI4003D sel */ | |
| 394 | + ILI9881C_COMMAND_INSTR(0x6C, 0x15), /* Set VCORE voltage = 1.5V */ | |
| 395 | + ILI9881C_COMMAND_INSTR(0x6E, 0x2A), /* di_pwr_reg=0 for power mode 2A, VGH clamp 18V */ | |
| 396 | + ILI9881C_COMMAND_INSTR(0x6F, 0x33), /* pumping ratio VGH=5x VGL=-3x */ | |
| 397 | + ILI9881C_COMMAND_INSTR(0x8D, 0x1B), /* VGL clamp -10V */ | |
| 398 | + ILI9881C_COMMAND_INSTR(0x87, 0xBA), /* ESD */ | |
| 399 | + ILI9881C_COMMAND_INSTR(0x3A, 0x24), /* POWER SAVING */ | |
| 400 | + ILI9881C_COMMAND_INSTR(0x26, 0x76), | |
| 401 | + ILI9881C_COMMAND_INSTR(0xB2, 0xD1), | |
| 402 | + ILI9881C_SWITCH_PAGE_INSTR(1), | |
| 403 | + ILI9881C_COMMAND_INSTR(0x22, 0x0A), /* BGR, SS */ | |
| 404 | + ILI9881C_COMMAND_INSTR(0x31, 0x00), /* Zigzag type3 inversion */ | |
| 405 | + ILI9881C_COMMAND_INSTR(0x40, 0x53), /* ILI4003D sel */ | |
| 406 | + ILI9881C_COMMAND_INSTR(0x43, 0x66), | |
| 407 | + ILI9881C_COMMAND_INSTR(0x53, 0x4C), | |
| 408 | + ILI9881C_COMMAND_INSTR(0x50, 0x87), | |
| 409 | + ILI9881C_COMMAND_INSTR(0x51, 0x82), | |
| 410 | + ILI9881C_COMMAND_INSTR(0x60, 0x15), | |
| 411 | + ILI9881C_COMMAND_INSTR(0x61, 0x01), | |
| 412 | + ILI9881C_COMMAND_INSTR(0x62, 0x0C), | |
| 413 | + ILI9881C_COMMAND_INSTR(0x63, 0x00), | |
| 414 | + ILI9881C_COMMAND_INSTR(0xA0, 0x00), | |
| 415 | + ILI9881C_COMMAND_INSTR(0xA1, 0x13), /* VP251 */ | |
| 416 | + ILI9881C_COMMAND_INSTR(0xA2, 0x23), /* VP247 */ | |
| 417 | + ILI9881C_COMMAND_INSTR(0xA3, 0x14), /* VP243 */ | |
| 418 | + ILI9881C_COMMAND_INSTR(0xA4, 0x16), /* VP239 */ | |
| 419 | + ILI9881C_COMMAND_INSTR(0xA5, 0x29), /* VP231 */ | |
| 420 | + ILI9881C_COMMAND_INSTR(0xA6, 0x1E), /* VP219 */ | |
| 421 | + ILI9881C_COMMAND_INSTR(0xA7, 0x1D), /* VP203 */ | |
| 422 | + ILI9881C_COMMAND_INSTR(0xA8, 0x86), /* VP175 */ | |
| 423 | + ILI9881C_COMMAND_INSTR(0xA9, 0x1E), /* VP144 */ | |
| 424 | + ILI9881C_COMMAND_INSTR(0xAA, 0x29), /* VP111 */ | |
| 425 | + ILI9881C_COMMAND_INSTR(0xAB, 0x74), /* VP80 */ | |
| 426 | + ILI9881C_COMMAND_INSTR(0xAC, 0x19), /* VP52 */ | |
| 427 | + ILI9881C_COMMAND_INSTR(0xAD, 0x17), /* VP36 */ | |
| 428 | + ILI9881C_COMMAND_INSTR(0xAE, 0x4B), /* VP24 */ | |
| 429 | + ILI9881C_COMMAND_INSTR(0xAF, 0x20), /* VP16 */ | |
| 430 | + ILI9881C_COMMAND_INSTR(0xB0, 0x26), /* VP12 */ | |
| 431 | + ILI9881C_COMMAND_INSTR(0xB1, 0x4C), /* VP8 */ | |
| 432 | + ILI9881C_COMMAND_INSTR(0xB2, 0x5D), /* VP4 */ | |
| 433 | + ILI9881C_COMMAND_INSTR(0xB3, 0x3F), /* VP0 */ | |
| 434 | + ILI9881C_COMMAND_INSTR(0xC0, 0x00), /* VN255 GAMMA N */ | |
| 435 | + ILI9881C_COMMAND_INSTR(0xC1, 0x13), /* VN251 */ | |
| 436 | + ILI9881C_COMMAND_INSTR(0xC2, 0x23), /* VN247 */ | |
| 437 | + ILI9881C_COMMAND_INSTR(0xC3, 0x14), /* VN243 */ | |
| 438 | + ILI9881C_COMMAND_INSTR(0xC4, 0x16), /* VN239 */ | |
| 439 | + ILI9881C_COMMAND_INSTR(0xC5, 0x29), /* VN231 */ | |
| 440 | + ILI9881C_COMMAND_INSTR(0xC6, 0x1E), /* VN219 */ | |
| 441 | + ILI9881C_COMMAND_INSTR(0xC7, 0x1D), /* VN203 */ | |
| 442 | + ILI9881C_COMMAND_INSTR(0xC8, 0x86), /* VN175 */ | |
| 443 | + ILI9881C_COMMAND_INSTR(0xC9, 0x1E), /* VN144 */ | |
| 444 | + ILI9881C_COMMAND_INSTR(0xCA, 0x29), /* VN111 */ | |
| 445 | + ILI9881C_COMMAND_INSTR(0xCB, 0x74), /* VN80 */ | |
| 446 | + ILI9881C_COMMAND_INSTR(0xCC, 0x19), /* VN52 */ | |
| 447 | + ILI9881C_COMMAND_INSTR(0xCD, 0x17), /* VN36 */ | |
| 448 | + ILI9881C_COMMAND_INSTR(0xCE, 0x4B), /* VN24 */ | |
| 449 | + ILI9881C_COMMAND_INSTR(0xCF, 0x20), /* VN16 */ | |
| 450 | + ILI9881C_COMMAND_INSTR(0xD0, 0x26), /* VN12 */ | |
| 451 | + ILI9881C_COMMAND_INSTR(0xD1, 0x4C), /* VN8 */ | |
| 452 | + ILI9881C_COMMAND_INSTR(0xD2, 0x5D), /* VN4 */ | |
| 453 | + ILI9881C_COMMAND_INSTR(0xD3, 0x3F), /* VN0 */ | |
| 454 | +}; | |
| 455 | + | |
| 255 | 456 | static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel) |
| 256 | 457 | { |
| 257 | 458 | return container_of(panel, struct ili9881c, panel); |
| @@ -311,8 +512,8 @@ static int ili9881c_prepare(struct drm_panel *panel) · 53 unmodified lines | ||
| 311 | 512 | gpiod_set_value(ctx->reset, 0); |
| 312 | 513 | msleep(20); |
| 313 | 514 | |
| 314 | − for (i = 0; i < ARRAY_SIZE(ili9881c_init); i++) { | |
| 315 | − const struct ili9881c_instr *instr = &ili9881c_init[i]; | |
| 515 | + for (i = 0; i < ctx->desc->init_length; i++) { | |
| 516 | + const struct ili9881c_instr *instr = &ctx->desc->init[i]; | |
| 316 | 517 | |
| 317 | 518 | if (instr->op == ILI9881C_SWITCH_PAGE) |
| 318 | 519 | ret = ili9881c_switch_page(ctx, instr->arg.page); |
| @@ -368,7 +569,7 @@ static int ili9881c_unprepare(struct drm_panel *panel) · 49 unmodified lines | ||
| 368 | 569 | return 0; |
| 369 | 570 | } |
| 370 | 571 | |
| 371 | −static const struct drm_display_mode bananapi_default_mode = { | |
| 572 | +static const struct drm_display_mode lhr050h41_default_mode = { | |
| 372 | 573 | .clock = 62000, |
| 373 | 574 | |
| 374 | 575 | .hdisplay = 720, |
| @@ -380,6 +581,26 @@ static const struct drm_display_mode bananapi_default_mode = { · 5 unmodified lines | ||
| 380 | 581 | .vsync_start = 1280 + 10, |
| 381 | 582 | .vsync_end = 1280 + 10 + 10, |
| 382 | 583 | .vtotal = 1280 + 10 + 10 + 20, |
| 584 | + | |
| 585 | + .width_mm = 62, | |
| 586 | + .height_mm = 110, | |
| 587 | +}; | |
| 588 | + | |
| 589 | +static const struct drm_display_mode k101_im2byl02_default_mode = { | |
| 590 | + .clock = 69700, | |
| 591 | + | |
| 592 | + .hdisplay = 800, | |
| 593 | + .hsync_start = 800 + 6, | |
| 594 | + .hsync_end = 800 + 6 + 15, | |
| 595 | + .htotal = 800 + 6 + 15 + 16, | |
| 596 | + | |
| 597 | + .vdisplay = 1280, | |
| 598 | + .vsync_start = 1280 + 8, | |
| 599 | + .vsync_end = 1280 + 8 + 48, | |
| 600 | + .vtotal = 1280 + 8 + 48 + 52, | |
| 601 | + | |
| 602 | + .width_mm = 135, | |
| 603 | + .height_mm = 217, | |
| 383 | 604 | }; |
| 384 | 605 | |
| 385 | 606 | static int ili9881c_get_modes(struct drm_panel *panel, |
| @@ -388,12 +609,12 @@ static int ili9881c_get_modes(struct drm_panel *panel, · 2 unmodified lines | ||
| 388 | 609 | struct ili9881c *ctx = panel_to_ili9881c(panel); |
| 389 | 610 | struct drm_display_mode *mode; |
| 390 | 611 | |
| 391 | − mode = drm_mode_duplicate(connector->dev, &bananapi_default_mode); | |
| 612 | + mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); | |
| 392 | 613 | if (!mode) { |
| 393 | 614 | dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n", |
| 394 | − bananapi_default_mode.hdisplay, | |
| 395 | − bananapi_default_mode.vdisplay, | |
| 396 | − drm_mode_vrefresh(&bananapi_default_mode)); | |
| 615 | + ctx->desc->mode->hdisplay, | |
| 616 | + ctx->desc->mode->vdisplay, | |
| 617 | + drm_mode_vrefresh(ctx->desc->mode)); | |
| 397 | 618 | return -ENOMEM; |
| 398 | 619 | } |
| 399 | 620 | |
| @@ -402,8 +623,8 @@ static int ili9881c_get_modes(struct drm_panel *panel, · 2 unmodified lines | ||
| 402 | 623 | mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; |
| 403 | 624 | drm_mode_probed_add(connector, mode); |
| 404 | 625 | |
| 405 | − connector->display_info.width_mm = 62; | |
| 406 | − connector->display_info.height_mm = 110; | |
| 626 | + connector->display_info.width_mm = mode->width_mm; | |
| 627 | + connector->display_info.height_mm = mode->height_mm; | |
| 407 | 628 | |
| 408 | 629 | return 1; |
| 409 | 630 | } |
| @@ -426,6 +647,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) · 16 unmodified lines | ||
| 426 | 647 | return -ENOMEM; |
| 427 | 648 | mipi_dsi_set_drvdata(dsi, ctx); |
| 428 | 649 | ctx->dsi = dsi; |
| 650 | + ctx->desc = of_device_get_match_data(&dsi->dev); | |
| 429 | 651 | |
| 430 | 652 | drm_panel_init(&ctx->panel, &dsi->dev, &ili9881c_funcs, |
| 431 | 653 | DRM_MODE_CONNECTOR_DSI); |
| @@ -446,9 +668,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) · 14 unmodified lines | ||
| 446 | 668 | if (ret) |
| 447 | 669 | return ret; |
| 448 | 670 | |
| 449 | − ret = drm_panel_add(&ctx->panel); | |
| 450 | − if (ret < 0) | |
| 451 | − return ret; | |
| 671 | + drm_panel_add(&ctx->panel); | |
| 452 | 672 | |
| 453 | 673 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE; |
| 454 | 674 | dsi->format = MIPI_DSI_FMT_RGB888; |
| @@ -467,8 +687,21 @@ static int ili9881c_dsi_remove(struct mipi_dsi_device *dsi) · 12 unmodified lines | ||
| 467 | 687 | return 0; |
| 468 | 688 | } |
| 469 | 689 | |
| 690 | +static const struct ili9881c_desc lhr050h41_desc = { | |
| 691 | + .init = lhr050h41_init, | |
| 692 | + .init_length = ARRAY_SIZE(lhr050h41_init), | |
| 693 | + .mode = &lhr050h41_default_mode, | |
| 694 | +}; | |
| 695 | + | |
| 696 | +static const struct ili9881c_desc k101_im2byl02_desc = { | |
| 697 | + .init = k101_im2byl02_init, | |
| 698 | + .init_length = ARRAY_SIZE(k101_im2byl02_init), | |
| 699 | + .mode = &k101_im2byl02_default_mode, | |
| 700 | +}; | |
| 701 | + | |
| 470 | 702 | static const struct of_device_id ili9881c_of_match[] = { |
| 471 | − { .compatible = "bananapi,lhr050h41" }, | |
| 703 | + { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc }, | |
| 704 | + { .compatible = "feixin,k101-im2byl02", .data = &k101_im2byl02_desc }, | |
| 472 | 705 | { } |
| 473 | 706 | }; |
| 474 | 707 | MODULE_DEVICE_TABLE(of, ili9881c_of_match); |
| @@ -17,7 +17,6 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <drm/drm_mipi_dsi.h> |
| 18 | 18 | #include <drm/drm_modes.h> |
| 19 | 19 | #include <drm/drm_panel.h> |
| 20 | −#include <drm/drm_print.h> | |
| 21 | 20 | |
| 22 | 21 | struct panel_init_cmd { |
| 23 | 22 | size_t len; |
| @@ -85,13 +84,11 @@ static int innolux_panel_unprepare(struct drm_panel *panel) · 61 unmodified lines | ||
| 85 | 84 | |
| 86 | 85 | err = mipi_dsi_dcs_set_display_off(innolux->link); |
| 87 | 86 | if (err < 0) |
| 88 | − DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", | |
| 89 | − err); | |
| 87 | + dev_err(panel->dev, "failed to set display off: %d\n", err); | |
| 90 | 88 | |
| 91 | 89 | err = mipi_dsi_dcs_enter_sleep_mode(innolux->link); |
| 92 | 90 | if (err < 0) { |
| 93 | − DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", | |
| 94 | − err); | |
| 91 | + dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); | |
| 95 | 92 | return err; |
| 96 | 93 | } |
| 97 | 94 | |
| @@ -147,8 +144,7 @@ static int innolux_panel_prepare(struct drm_panel *panel) · 49 unmodified lines | ||
| 147 | 144 | err = mipi_dsi_generic_write(innolux->link, cmd->data, |
| 148 | 145 | cmd->len); |
| 149 | 146 | if (err < 0) { |
| 150 | − dev_err(panel->dev, | |
| 151 | − "failed to write command %u\n", i); | |
| 147 | + dev_err(panel->dev, "failed to write command %u\n", i); | |
| 152 | 148 | goto poweroff; |
| 153 | 149 | } |
| 154 | 150 | |
| @@ -159,8 +155,7 @@ static int innolux_panel_prepare(struct drm_panel *panel) · 4 unmodified lines | ||
| 159 | 155 | */ |
| 160 | 156 | err = mipi_dsi_dcs_nop(innolux->link); |
| 161 | 157 | if (err < 0) { |
| 162 | − dev_err(panel->dev, | |
| 163 | − "failed to send DCS nop: %d\n", err); | |
| 158 | + dev_err(panel->dev, "failed to send DCS nop: %d\n", err); | |
| 164 | 159 | goto poweroff; |
| 165 | 160 | } |
| 166 | 161 | } |
| @@ -168,8 +163,7 @@ static int innolux_panel_prepare(struct drm_panel *panel) · 1 unmodified line | ||
| 168 | 163 | |
| 169 | 164 | err = mipi_dsi_dcs_exit_sleep_mode(innolux->link); |
| 170 | 165 | if (err < 0) { |
| 171 | − DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n", | |
| 172 | − err); | |
| 166 | + dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); | |
| 173 | 167 | goto poweroff; |
| 174 | 168 | } |
| 175 | 169 | |
| @@ -178,8 +172,7 @@ static int innolux_panel_prepare(struct drm_panel *panel) · 2 unmodified lines | ||
| 178 | 172 | |
| 179 | 173 | err = mipi_dsi_dcs_set_display_on(innolux->link); |
| 180 | 174 | if (err < 0) { |
| 181 | − DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", | |
| 182 | − err); | |
| 175 | + dev_err(panel->dev, "failed to set display on: %d\n", err); | |
| 183 | 176 | goto poweroff; |
| 184 | 177 | } |
| 185 | 178 | |
| @@ -398,8 +391,8 @@ static int innolux_panel_get_modes(struct drm_panel *panel, · 212 unmodified lines | ||
| 398 | 391 | |
| 399 | 392 | mode = drm_mode_duplicate(connector->dev, m); |
| 400 | 393 | if (!mode) { |
| 401 | − DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n", | |
| 402 | − m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); | |
| 394 | + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", | |
| 395 | + m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); | |
| 403 | 396 | return -ENOMEM; |
| 404 | 397 | } |
| 405 | 398 | |
| @@ -475,9 +468,7 @@ static int innolux_panel_add(struct mipi_dsi_device *dsi, · 69 unmodified lines | ||
| 475 | 468 | if (err) |
| 476 | 469 | return err; |
| 477 | 470 | |
| 478 | − err = drm_panel_add(&innolux->base); | |
| 479 | − if (err < 0) | |
| 480 | − return err; | |
| 471 | + drm_panel_add(&innolux->base); | |
| 481 | 472 | |
| 482 | 473 | mipi_dsi_set_drvdata(dsi, innolux); |
| 483 | 474 | innolux->link = dsi; |
| @@ -514,17 +505,15 @@ static int innolux_panel_remove(struct mipi_dsi_device *dsi) · 30 unmodified lines | ||
| 514 | 505 | |
| 515 | 506 | err = drm_panel_unprepare(&innolux->base); |
| 516 | 507 | if (err < 0) |
| 517 | − DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n", | |
| 518 | − err); | |
| 508 | + dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err); | |
| 519 | 509 | |
| 520 | 510 | err = drm_panel_disable(&innolux->base); |
| 521 | 511 | if (err < 0) |
| 522 | − DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", err); | |
| 512 | + dev_err(&dsi->dev, "failed to disable panel: %d\n", err); | |
| 523 | 513 | |
| 524 | 514 | err = mipi_dsi_detach(dsi); |
| 525 | 515 | if (err < 0) |
| 526 | − DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n", | |
| 527 | − err); | |
| 516 | + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); | |
| 528 | 517 | |
| 529 | 518 | innolux_panel_del(innolux); |
| 530 | 519 | |
| @@ -440,9 +440,9 @@ static int jdi_panel_add(struct jdi_panel *jdi) · 439 unmodified lines | ||
| 440 | 440 | drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs, |
| 441 | 441 | DRM_MODE_CONNECTOR_DSI); |
| 442 | 442 | |
| 443 | − ret = drm_panel_add(&jdi->base); | |
| 443 | + drm_panel_add(&jdi->base); | |
| 444 | 444 | |
| 445 | − return ret; | |
| 445 | + return 0; | |
| 446 | 446 | } |
| 447 | 447 | |
| 448 | 448 | static void jdi_panel_del(struct jdi_panel *jdi) |
| @@ -16,7 +16,6 @@ · 15 unmodified lines | ||
| 16 | 16 | #include <drm/drm_mipi_dsi.h> |
| 17 | 17 | #include <drm/drm_modes.h> |
| 18 | 18 | #include <drm/drm_panel.h> |
| 19 | −#include <drm/drm_print.h> | |
| 20 | 19 | |
| 21 | 20 | struct kingdisplay_panel { |
| 22 | 21 | struct drm_panel base; |
| @@ -191,8 +190,7 @@ static int kingdisplay_panel_disable(struct drm_panel *panel) · 168 unmodified lines | ||
| 191 | 190 | |
| 192 | 191 | err = mipi_dsi_dcs_set_display_off(kingdisplay->link); |
| 193 | 192 | if (err < 0) |
| 194 | − DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", | |
| 195 | − err); | |
| 193 | + dev_err(panel->dev, "failed to set display off: %d\n", err); | |
| 196 | 194 | |
| 197 | 195 | kingdisplay->enabled = false; |
| 198 | 196 | |
| @@ -209,8 +207,7 @@ static int kingdisplay_panel_unprepare(struct drm_panel *panel) · 10 unmodified lines | ||
| 209 | 207 | |
| 210 | 208 | err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->link); |
| 211 | 209 | if (err < 0) { |
| 212 | − DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", | |
| 213 | − err); | |
| 210 | + dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); | |
| 214 | 211 | return err; |
| 215 | 212 | } |
| 216 | 213 | |
| @@ -255,16 +252,14 @@ static int kingdisplay_panel_prepare(struct drm_panel *panel) · 38 unmodified lines | ||
| 255 | 252 | err = mipi_dsi_generic_write(kingdisplay->link, &init_code[i], |
| 256 | 253 | sizeof(struct kingdisplay_panel_cmd)); |
| 257 | 254 | if (err < 0) { |
| 258 | − DRM_DEV_ERROR(panel->dev, "failed write init cmds: %d\n", | |
| 259 | − err); | |
| 255 | + dev_err(panel->dev, "failed write init cmds: %d\n", err); | |
| 260 | 256 | goto poweroff; |
| 261 | 257 | } |
| 262 | 258 | } |
| 263 | 259 | |
| 264 | 260 | err = mipi_dsi_dcs_exit_sleep_mode(kingdisplay->link); |
| 265 | 261 | if (err < 0) { |
| 266 | − DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n", | |
| 267 | − err); | |
| 262 | + dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); | |
| 268 | 263 | goto poweroff; |
| 269 | 264 | } |
| 270 | 265 | |
| @@ -273,8 +268,7 @@ static int kingdisplay_panel_prepare(struct drm_panel *panel) · 2 unmodified lines | ||
| 273 | 268 | |
| 274 | 269 | err = mipi_dsi_dcs_set_display_on(kingdisplay->link); |
| 275 | 270 | if (err < 0) { |
| 276 | − DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", | |
| 277 | − err); | |
| 271 | + dev_err(panel->dev, "failed to set display on: %d\n", err); | |
| 278 | 272 | goto poweroff; |
| 279 | 273 | } |
| 280 | 274 | |
| @@ -290,8 +284,7 @@ poweroff: · 9 unmodified lines | ||
| 290 | 284 | |
| 291 | 285 | regulator_err = regulator_disable(kingdisplay->supply); |
| 292 | 286 | if (regulator_err) |
| 293 | − DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", | |
| 294 | − regulator_err); | |
| 287 | + dev_err(panel->dev, "failed to disable regulator: %d\n", regulator_err); | |
| 295 | 288 | |
| 296 | 289 | return err; |
| 297 | 290 | } |
| @@ -327,9 +320,9 @@ static int kingdisplay_panel_get_modes(struct drm_panel *panel, · 29 unmodified lines | ||
| 327 | 320 | |
| 328 | 321 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 329 | 322 | if (!mode) { |
| 330 | − DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n", | |
| 331 | − default_mode.hdisplay, default_mode.vdisplay, | |
| 332 | − drm_mode_vrefresh(&default_mode)); | |
| 323 | + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", | |
| 324 | + default_mode.hdisplay, default_mode.vdisplay, | |
| 325 | + drm_mode_vrefresh(&default_mode)); | |
| 333 | 326 | return -ENOMEM; |
| 334 | 327 | } |
| 335 | 328 | |
| @@ -382,7 +375,9 @@ static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay) · 46 unmodified lines | ||
| 382 | 375 | if (err) |
| 383 | 376 | return err; |
| 384 | 377 | |
| 385 | − return drm_panel_add(&kingdisplay->base); | |
| 378 | + drm_panel_add(&kingdisplay->base); | |
| 379 | + | |
| 380 | + return 0; | |
| 386 | 381 | } |
| 387 | 382 | |
| 388 | 383 | static void kingdisplay_panel_del(struct kingdisplay_panel *kingdisplay) |
| @@ -421,17 +416,15 @@ static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi) · 32 unmodified lines | ||
| 421 | 416 | |
| 422 | 417 | err = drm_panel_unprepare(&kingdisplay->base); |
| 423 | 418 | if (err < 0) |
| 424 | − DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n", | |
| 425 | − err); | |
| 419 | + dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err); | |
| 426 | 420 | |
| 427 | 421 | err = drm_panel_disable(&kingdisplay->base); |
| 428 | 422 | if (err < 0) |
| 429 | − DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", err); | |
| 423 | + dev_err(&dsi->dev, "failed to disable panel: %d\n", err); | |
| 430 | 424 | |
| 431 | 425 | err = mipi_dsi_detach(dsi); |
| 432 | 426 | if (err < 0) |
| 433 | − DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n", | |
| 434 | − err); | |
| 427 | + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); | |
| 435 | 428 | |
| 436 | 429 | kingdisplay_panel_del(kingdisplay); |
| 437 | 430 | |
| @@ -17,7 +17,6 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <drm/drm_mipi_dsi.h> |
| 18 | 18 | #include <drm/drm_modes.h> |
| 19 | 19 | #include <drm/drm_panel.h> |
| 20 | −#include <drm/drm_print.h> | |
| 21 | 20 | |
| 22 | 21 | struct ltk050h3146w_cmd { |
| 23 | 22 | char cmd; |
| @@ -314,8 +313,7 @@ static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx) · 290 unmodified lines | ||
| 314 | 313 | |
| 315 | 314 | ret = mipi_dsi_dcs_set_tear_on(dsi, 1); |
| 316 | 315 | if (ret < 0) { |
| 317 | − DRM_DEV_ERROR(ctx->dev, "failed to set tear on: %d\n", | |
| 318 | − ret); | |
| 316 | + dev_err(ctx->dev, "failed to set tear on: %d\n", ret); | |
| 319 | 317 | return ret; |
| 320 | 318 | } |
| 321 | 319 | |
| @@ -360,8 +358,7 @@ static int ltk050h3146w_a2_write_page(struct ltk050h3146w *ctx, int page, · 38 unmodified lines | ||
| 360 | 358 | |
| 361 | 359 | ret = ltk050h3146w_a2_select_page(ctx, page); |
| 362 | 360 | if (ret < 0) { |
| 363 | − DRM_DEV_ERROR(ctx->dev, "failed to select page %d: %d\n", | |
| 364 | − page, ret); | |
| 361 | + dev_err(ctx->dev, "failed to select page %d: %d\n", page, ret); | |
| 365 | 362 | return ret; |
| 366 | 363 | } |
| 367 | 364 | |
| @@ -369,9 +366,7 @@ static int ltk050h3146w_a2_write_page(struct ltk050h3146w *ctx, int page, · 1 unmodified line | ||
| 369 | 366 | ret = mipi_dsi_generic_write(dsi, &cmds[i], |
| 370 | 367 | sizeof(struct ltk050h3146w_cmd)); |
| 371 | 368 | if (ret < 0) { |
| 372 | − DRM_DEV_ERROR(ctx->dev, | |
| 373 | − "failed to write page %d init cmds: %d\n", | |
| 374 | − page, ret); | |
| 369 | + dev_err(ctx->dev, "failed to write page %d init cmds: %d\n", page, ret); | |
| 375 | 370 | return ret; |
| 376 | 371 | } |
| 377 | 372 | } |
| @@ -405,15 +400,14 @@ static int ltk050h3146w_a2_init_sequence(struct ltk050h3146w *ctx) · 27 unmodified lines | ||
| 405 | 400 | |
| 406 | 401 | ret = ltk050h3146w_a2_select_page(ctx, 0); |
| 407 | 402 | if (ret < 0) { |
| 408 | − DRM_DEV_ERROR(ctx->dev, "failed to select page 0: %d\n", ret); | |
| 403 | + dev_err(ctx->dev, "failed to select page 0: %d\n", ret); | |
| 409 | 404 | return ret; |
| 410 | 405 | } |
| 411 | 406 | |
| 412 | 407 | /* vendor code called this without param, where there should be one */ |
| 413 | 408 | ret = mipi_dsi_dcs_set_tear_on(dsi, 0); |
| 414 | 409 | if (ret < 0) { |
| 415 | − DRM_DEV_ERROR(ctx->dev, "failed to set tear on: %d\n", | |
| 416 | − ret); | |
| 410 | + dev_err(ctx->dev, "failed to set tear on: %d\n", ret); | |
| 417 | 411 | return ret; |
| 418 | 412 | } |
| 419 | 413 | |
| @@ -452,15 +446,13 @@ static int ltk050h3146w_unprepare(struct drm_panel *panel) · 32 unmodified lines | ||
| 452 | 446 | |
| 453 | 447 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 454 | 448 | if (ret < 0) { |
| 455 | − DRM_DEV_ERROR(ctx->dev, "failed to set display off: %d\n", | |
| 456 | − ret); | |
| 449 | + dev_err(ctx->dev, "failed to set display off: %d\n", ret); | |
| 457 | 450 | return ret; |
| 458 | 451 | } |
| 459 | 452 | |
| 460 | 453 | mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 461 | 454 | if (ret < 0) { |
| 462 | − DRM_DEV_ERROR(ctx->dev, "failed to enter sleep mode: %d\n", | |
| 463 | − ret); | |
| 455 | + dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret); | |
| 464 | 456 | return ret; |
| 465 | 457 | } |
| 466 | 458 | |
| @@ -481,17 +473,15 @@ static int ltk050h3146w_prepare(struct drm_panel *panel) · 14 unmodified lines | ||
| 481 | 473 | if (ctx->prepared) |
| 482 | 474 | return 0; |
| 483 | 475 | |
| 484 | − DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n"); | |
| 476 | + dev_dbg(ctx->dev, "Resetting the panel\n"); | |
| 485 | 477 | ret = regulator_enable(ctx->vci); |
| 486 | 478 | if (ret < 0) { |
| 487 | − DRM_DEV_ERROR(ctx->dev, | |
| 488 | − "Failed to enable vci supply: %d\n", ret); | |
| 479 | + dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret); | |
| 489 | 480 | return ret; |
| 490 | 481 | } |
| 491 | 482 | ret = regulator_enable(ctx->iovcc); |
| 492 | 483 | if (ret < 0) { |
| 493 | − DRM_DEV_ERROR(ctx->dev, | |
| 494 | − "Failed to enable iovcc supply: %d\n", ret); | |
| 484 | + dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); | |
| 495 | 485 | goto disable_vci; |
| 496 | 486 | } |
| 497 | 487 | |
| @@ -502,14 +492,13 @@ static int ltk050h3146w_prepare(struct drm_panel *panel) · 4 unmodified lines | ||
| 502 | 492 | |
| 503 | 493 | ret = ctx->panel_desc->init(ctx); |
| 504 | 494 | if (ret < 0) { |
| 505 | − DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", | |
| 506 | − ret); | |
| 495 | + dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); | |
| 507 | 496 | goto disable_iovcc; |
| 508 | 497 | } |
| 509 | 498 | |
| 510 | 499 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 511 | 500 | if (ret < 0) { |
| 512 | − DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret); | |
| 501 | + dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret); | |
| 513 | 502 | goto disable_iovcc; |
| 514 | 503 | } |
| 515 | 504 | |
| @@ -518,7 +507,7 @@ static int ltk050h3146w_prepare(struct drm_panel *panel) · 2 unmodified lines | ||
| 518 | 507 | |
| 519 | 508 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 520 | 509 | if (ret < 0) { |
| 521 | − DRM_DEV_ERROR(ctx->dev, "Failed to set display on: %d\n", ret); | |
| 510 | + dev_err(ctx->dev, "Failed to set display on: %d\n", ret); | |
| 522 | 511 | goto disable_iovcc; |
| 523 | 512 | } |
| 524 | 513 | |
| @@ -577,7 +566,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) · 52 unmodified lines | ||
| 577 | 566 | |
| 578 | 567 | ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); |
| 579 | 568 | if (IS_ERR(ctx->reset_gpio)) { |
| 580 | − DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); | |
| 569 | + dev_err(dev, "cannot get reset gpio\n"); | |
| 581 | 570 | return PTR_ERR(ctx->reset_gpio); |
| 582 | 571 | } |
| 583 | 572 | |
| @@ -585,9 +574,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) · 1 unmodified line | ||
| 585 | 574 | if (IS_ERR(ctx->vci)) { |
| 586 | 575 | ret = PTR_ERR(ctx->vci); |
| 587 | 576 | if (ret != -EPROBE_DEFER) |
| 588 | − DRM_DEV_ERROR(dev, | |
| 589 | − "Failed to request vci regulator: %d\n", | |
| 590 | − ret); | |
| 577 | + dev_err(dev, "Failed to request vci regulator: %d\n", ret); | |
| 591 | 578 | return ret; |
| 592 | 579 | } |
| 593 | 580 | |
| @@ -595,9 +582,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) · 1 unmodified line | ||
| 595 | 582 | if (IS_ERR(ctx->iovcc)) { |
| 596 | 583 | ret = PTR_ERR(ctx->iovcc); |
| 597 | 584 | if (ret != -EPROBE_DEFER) |
| 598 | − DRM_DEV_ERROR(dev, | |
| 599 | − "Failed to request iovcc regulator: %d\n", | |
| 600 | − ret); | |
| 585 | + dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); | |
| 601 | 586 | return ret; |
| 602 | 587 | } |
| 603 | 588 | |
| @@ -621,7 +606,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) · 17 unmodified lines | ||
| 621 | 606 | |
| 622 | 607 | ret = mipi_dsi_attach(dsi); |
| 623 | 608 | if (ret < 0) { |
| 624 | − DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret); | |
| 609 | + dev_err(dev, "mipi_dsi_attach failed: %d\n", ret); | |
| 625 | 610 | drm_panel_remove(&ctx->panel); |
| 626 | 611 | return ret; |
| 627 | 612 | } |
| @@ -636,13 +621,11 @@ static void ltk050h3146w_shutdown(struct mipi_dsi_device *dsi) · 8 unmodified lines | ||
| 636 | 621 | |
| 637 | 622 | ret = drm_panel_unprepare(&ctx->panel); |
| 638 | 623 | if (ret < 0) |
| 639 | − DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", | |
| 640 | − ret); | |
| 624 | + dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); | |
| 641 | 625 | |
| 642 | 626 | ret = drm_panel_disable(&ctx->panel); |
| 643 | 627 | if (ret < 0) |
| 644 | − DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", | |
| 645 | − ret); | |
| 628 | + dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); | |
| 646 | 629 | } |
| 647 | 630 | |
| 648 | 631 | static int ltk050h3146w_remove(struct mipi_dsi_device *dsi) |
| @@ -654,8 +637,7 @@ static int ltk050h3146w_remove(struct mipi_dsi_device *dsi) · 5 unmodified lines | ||
| 654 | 637 | |
| 655 | 638 | ret = mipi_dsi_detach(dsi); |
| 656 | 639 | if (ret < 0) |
| 657 | − DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", | |
| 658 | − ret); | |
| 640 | + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); | |
| 659 | 641 | |
| 660 | 642 | drm_panel_remove(&ctx->panel); |
| 661 | 643 | |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <drm/drm_mipi_dsi.h> |
| 21 | 21 | #include <drm/drm_modes.h> |
| 22 | 22 | #include <drm/drm_panel.h> |
| 23 | −#include <drm/drm_print.h> | |
| 24 | 23 | |
| 25 | 24 | struct ltk500hd1829 { |
| 26 | 25 | struct device *dev; |
| @@ -278,13 +277,11 @@ static int ltk500hd1829_unprepare(struct drm_panel *panel) · 251 unmodified lines | ||
| 278 | 277 | |
| 279 | 278 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 280 | 279 | if (ret < 0) |
| 281 | − DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", | |
| 282 | − ret); | |
| 280 | + dev_err(panel->dev, "failed to set display off: %d\n", ret); | |
| 283 | 281 | |
| 284 | 282 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 285 | 283 | if (ret < 0) { |
| 286 | − DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", | |
| 287 | − ret); | |
| 284 | + dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); | |
| 288 | 285 | } |
| 289 | 286 | |
| 290 | 287 | /* 120ms to enter sleep mode */ |
| @@ -310,14 +307,12 @@ static int ltk500hd1829_prepare(struct drm_panel *panel) · 19 unmodified lines | ||
| 310 | 307 | |
| 311 | 308 | ret = regulator_enable(ctx->vcc); |
| 312 | 309 | if (ret < 0) { |
| 313 | − DRM_DEV_ERROR(ctx->dev, | |
| 314 | − "Failed to enable vci supply: %d\n", ret); | |
| 310 | + dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret); | |
| 315 | 311 | return ret; |
| 316 | 312 | } |
| 317 | 313 | ret = regulator_enable(ctx->iovcc); |
| 318 | 314 | if (ret < 0) { |
| 319 | − DRM_DEV_ERROR(ctx->dev, | |
| 320 | − "Failed to enable iovcc supply: %d\n", ret); | |
| 315 | + dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); | |
| 321 | 316 | goto disable_vcc; |
| 322 | 317 | } |
| 323 | 318 | |
| @@ -333,16 +328,14 @@ static int ltk500hd1829_prepare(struct drm_panel *panel) · 9 unmodified lines | ||
| 333 | 328 | ret = mipi_dsi_generic_write(dsi, &init_code[i], |
| 334 | 329 | sizeof(struct ltk500hd1829_cmd)); |
| 335 | 330 | if (ret < 0) { |
| 336 | − DRM_DEV_ERROR(panel->dev, | |
| 337 | − "failed to write init cmds: %d\n", ret); | |
| 331 | + dev_err(panel->dev, "failed to write init cmds: %d\n", ret); | |
| 338 | 332 | goto disable_iovcc; |
| 339 | 333 | } |
| 340 | 334 | } |
| 341 | 335 | |
| 342 | 336 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 343 | 337 | if (ret < 0) { |
| 344 | − DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n", | |
| 345 | − ret); | |
| 338 | + dev_err(panel->dev, "failed to exit sleep mode: %d\n", ret); | |
| 346 | 339 | goto disable_iovcc; |
| 347 | 340 | } |
| 348 | 341 | |
| @@ -351,8 +344,7 @@ static int ltk500hd1829_prepare(struct drm_panel *panel) · 2 unmodified lines | ||
| 351 | 344 | |
| 352 | 345 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 353 | 346 | if (ret < 0) { |
| 354 | − DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", | |
| 355 | − ret); | |
| 347 | + dev_err(panel->dev, "failed to set display on: %d\n", ret); | |
| 356 | 348 | goto disable_iovcc; |
| 357 | 349 | } |
| 358 | 350 | |
| @@ -389,9 +381,9 @@ static int ltk500hd1829_get_modes(struct drm_panel *panel, · 30 unmodified lines | ||
| 389 | 381 | |
| 390 | 382 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 391 | 383 | if (!mode) { |
| 392 | − DRM_DEV_ERROR(ctx->dev, "failed to add mode %ux%ux@%u\n", | |
| 393 | − default_mode.hdisplay, default_mode.vdisplay, | |
| 394 | − drm_mode_vrefresh(&default_mode)); | |
| 384 | + dev_err(ctx->dev, "failed to add mode %ux%u@%u\n", | |
| 385 | + default_mode.hdisplay, default_mode.vdisplay, | |
| 386 | + drm_mode_vrefresh(&default_mode)); | |
| 395 | 387 | return -ENOMEM; |
| 396 | 388 | } |
| 397 | 389 | |
| @@ -423,7 +415,7 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi) · 25 unmodified lines | ||
| 423 | 415 | |
| 424 | 416 | ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); |
| 425 | 417 | if (IS_ERR(ctx->reset_gpio)) { |
| 426 | − DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); | |
| 418 | + dev_err(dev, "cannot get reset gpio\n"); | |
| 427 | 419 | return PTR_ERR(ctx->reset_gpio); |
| 428 | 420 | } |
| 429 | 421 | |
| @@ -431,9 +423,7 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi) · 1 unmodified line | ||
| 431 | 423 | if (IS_ERR(ctx->vcc)) { |
| 432 | 424 | ret = PTR_ERR(ctx->vcc); |
| 433 | 425 | if (ret != -EPROBE_DEFER) |
| 434 | − DRM_DEV_ERROR(dev, | |
| 435 | − "Failed to request vcc regulator: %d\n", | |
| 436 | − ret); | |
| 426 | + dev_err(dev, "Failed to request vcc regulator: %d\n", ret); | |
| 437 | 427 | return ret; |
| 438 | 428 | } |
| 439 | 429 | |
| @@ -441,9 +431,7 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi) · 1 unmodified line | ||
| 441 | 431 | if (IS_ERR(ctx->iovcc)) { |
| 442 | 432 | ret = PTR_ERR(ctx->iovcc); |
| 443 | 433 | if (ret != -EPROBE_DEFER) |
| 444 | − DRM_DEV_ERROR(dev, | |
| 445 | − "Failed to request iovcc regulator: %d\n", | |
| 446 | − ret); | |
| 434 | + dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); | |
| 447 | 435 | return ret; |
| 448 | 436 | } |
| 449 | 437 | |
| @@ -467,7 +455,7 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi) · 17 unmodified lines | ||
| 467 | 455 | |
| 468 | 456 | ret = mipi_dsi_attach(dsi); |
| 469 | 457 | if (ret < 0) { |
| 470 | − DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret); | |
| 458 | + dev_err(dev, "mipi_dsi_attach failed: %d\n", ret); | |
| 471 | 459 | drm_panel_remove(&ctx->panel); |
| 472 | 460 | return ret; |
| 473 | 461 | } |
| @@ -482,13 +470,11 @@ static void ltk500hd1829_shutdown(struct mipi_dsi_device *dsi) · 8 unmodified lines | ||
| 482 | 470 | |
| 483 | 471 | ret = drm_panel_unprepare(&ctx->panel); |
| 484 | 472 | if (ret < 0) |
| 485 | − DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", | |
| 486 | − ret); | |
| 473 | + dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); | |
| 487 | 474 | |
| 488 | 475 | ret = drm_panel_disable(&ctx->panel); |
| 489 | 476 | if (ret < 0) |
| 490 | − DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", | |
| 491 | − ret); | |
| 477 | + dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); | |
| 492 | 478 | } |
| 493 | 479 | |
| 494 | 480 | static int ltk500hd1829_remove(struct mipi_dsi_device *dsi) |
| @@ -500,8 +486,7 @@ static int ltk500hd1829_remove(struct mipi_dsi_device *dsi) · 5 unmodified lines | ||
| 500 | 486 | |
| 501 | 487 | ret = mipi_dsi_detach(dsi); |
| 502 | 488 | if (ret < 0) |
| 503 | − DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n", | |
| 504 | − ret); | |
| 489 | + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); | |
| 505 | 490 | |
| 506 | 491 | drm_panel_remove(&ctx->panel); |
| 507 | 492 | |
| @@ -198,7 +198,9 @@ static int lb035q02_probe(struct spi_device *spi) · 197 unmodified lines | ||
| 198 | 198 | drm_panel_init(&lcd->panel, &lcd->spi->dev, &lb035q02_funcs, |
| 199 | 199 | DRM_MODE_CONNECTOR_DPI); |
| 200 | 200 | |
| 201 | − return drm_panel_add(&lcd->panel); | |
| 201 | + drm_panel_add(&lcd->panel); | |
| 202 | + | |
| 203 | + return 0; | |
| 202 | 204 | } |
| 203 | 205 | |
| 204 | 206 | static int lb035q02_remove(struct spi_device *spi) |
| @@ -261,7 +261,9 @@ static int lg4573_probe(struct spi_device *spi) · 260 unmodified lines | ||
| 261 | 261 | drm_panel_init(&ctx->panel, &spi->dev, &lg4573_drm_funcs, |
| 262 | 262 | DRM_MODE_CONNECTOR_DPI); |
| 263 | 263 | |
| 264 | − return drm_panel_add(&ctx->panel); | |
| 264 | + drm_panel_add(&ctx->panel); | |
| 265 | + | |
| 266 | + return 0; | |
| 265 | 267 | } |
| 266 | 268 | |
| 267 | 269 | static int lg4573_remove(struct spi_device *spi) |
| @@ -37,6 +37,8 @@ struct panel_lvds { · 36 unmodified lines | ||
| 37 | 37 | |
| 38 | 38 | struct gpio_desc *enable_gpio; |
| 39 | 39 | struct gpio_desc *reset_gpio; |
| 40 | + | |
| 41 | + enum drm_panel_orientation orientation; | |
| 40 | 42 | }; |
| 41 | 43 | |
| 42 | 44 | static inline struct panel_lvds *to_panel_lvds(struct drm_panel *panel) |
| @@ -99,6 +101,7 @@ static int panel_lvds_get_modes(struct drm_panel *panel, · 56 unmodified lines | ||
| 99 | 101 | connector->display_info.bus_flags = lvds->data_mirror |
| 100 | 102 | ? DRM_BUS_FLAG_DATA_LSB_TO_MSB |
| 101 | 103 | : DRM_BUS_FLAG_DATA_MSB_TO_LSB; |
| 104 | + drm_connector_set_panel_orientation(connector, lvds->orientation); | |
| 102 | 105 | |
| 103 | 106 | return 1; |
| 104 | 107 | } |
| @@ -116,6 +119,12 @@ static int panel_lvds_parse_dt(struct panel_lvds *lvds) · 11 unmodified lines | ||
| 116 | 119 | const char *mapping; |
| 117 | 120 | int ret; |
| 118 | 121 | |
| 122 | + ret = of_drm_get_panel_orientation(np, &lvds->orientation); | |
| 123 | + if (ret < 0) { | |
| 124 | + dev_err(lvds->dev, "%pOF: failed to get orientation %d\n", np, ret); | |
| 125 | + return ret; | |
| 126 | + } | |
| 127 | + | |
| 119 | 128 | ret = of_get_display_timing(np, "panel-timing", &timing); |
| 120 | 129 | if (ret < 0) { |
| 121 | 130 | dev_err(lvds->dev, "%pOF: problems parsing panel-timing (%d)\n", |
| @@ -227,9 +236,7 @@ static int panel_lvds_probe(struct platform_device *pdev) · 105 unmodified lines | ||
| 227 | 236 | if (ret) |
| 228 | 237 | return ret; |
| 229 | 238 | |
| 230 | − ret = drm_panel_add(&lvds->panel); | |
| 231 | − if (ret < 0) | |
| 232 | − return ret; | |
| 239 | + drm_panel_add(&lvds->panel); | |
| 233 | 240 | |
| 234 | 241 | dev_set_drvdata(lvds->dev, lvds); |
| 235 | 242 | return 0; |
| @@ -0,0 +1,328 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Mantix MLAF057WE51 5.7" MIPI-DSI panel driver | |
| 4 | + * | |
| 5 | + * Copyright (C) Purism SPC 2020 | |
| 6 | + */ | |
| 7 | + | |
| 8 | +#include <linux/backlight.h> | |
| 9 | +#include <linux/delay.h> | |
| 10 | +#include <linux/gpio/consumer.h> | |
| 11 | +#include <linux/module.h> | |
| 12 | +#include <linux/regulator/consumer.h> | |
| 13 | + | |
| 14 | +#include <video/mipi_display.h> | |
| 15 | + | |
| 16 | +#include <drm/drm_mipi_dsi.h> | |
| 17 | +#include <drm/drm_modes.h> | |
| 18 | +#include <drm/drm_panel.h> | |
| 19 | + | |
| 20 | +#define DRV_NAME "panel-mantix-mlaf057we51" | |
| 21 | + | |
| 22 | +/* Manufacturer specific Commands send via DSI */ | |
| 23 | +#define MANTIX_CMD_OTP_STOP_RELOAD_MIPI 0x41 | |
| 24 | +#define MANTIX_CMD_INT_CANCEL 0x4C | |
| 25 | + | |
| 26 | +struct mantix { | |
| 27 | + struct device *dev; | |
| 28 | + struct drm_panel panel; | |
| 29 | + struct gpio_desc *reset_gpio; | |
| 30 | + | |
| 31 | + struct regulator *avdd; | |
| 32 | + struct regulator *avee; | |
| 33 | + struct regulator *vddi; | |
| 34 | +}; | |
| 35 | + | |
| 36 | +static inline struct mantix *panel_to_mantix(struct drm_panel *panel) | |
| 37 | +{ | |
| 38 | + return container_of(panel, struct mantix, panel); | |
| 39 | +} | |
| 40 | + | |
| 41 | +#define dsi_generic_write_seq(dsi, seq...) do { \ | |
| 42 | + static const u8 d[] = { seq }; \ | |
| 43 | + int ret; \ | |
| 44 | + ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \ | |
| 45 | + if (ret < 0) \ | |
| 46 | + return ret; \ | |
| 47 | + } while (0) | |
| 48 | + | |
| 49 | +static int mantix_init_sequence(struct mantix *ctx) | |
| 50 | +{ | |
| 51 | + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | |
| 52 | + struct device *dev = ctx->dev; | |
| 53 | + | |
| 54 | + /* | |
| 55 | + * Init sequence was supplied by the panel vendor. | |
| 56 | + */ | |
| 57 | + dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A); | |
| 58 | + | |
| 59 | + dsi_generic_write_seq(dsi, MANTIX_CMD_INT_CANCEL, 0x03); | |
| 60 | + dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x03); | |
| 61 | + dsi_generic_write_seq(dsi, 0x80, 0xA9, 0x00); | |
| 62 | + | |
| 63 | + dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x09); | |
| 64 | + dsi_generic_write_seq(dsi, 0x80, 0x64, 0x00, 0x64, 0x00, 0x00); | |
| 65 | + msleep(20); | |
| 66 | + | |
| 67 | + dev_dbg(dev, "Panel init sequence done\n"); | |
| 68 | + return 0; | |
| 69 | +} | |
| 70 | + | |
| 71 | +static int mantix_enable(struct drm_panel *panel) | |
| 72 | +{ | |
| 73 | + struct mantix *ctx = panel_to_mantix(panel); | |
| 74 | + struct device *dev = ctx->dev; | |
| 75 | + struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); | |
| 76 | + int ret; | |
| 77 | + | |
| 78 | + ret = mantix_init_sequence(ctx); | |
| 79 | + if (ret < 0) { | |
| 80 | + dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); | |
| 81 | + return ret; | |
| 82 | + } | |
| 83 | + | |
| 84 | + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | |
| 85 | + if (ret < 0) { | |
| 86 | + dev_err(dev, "Failed to exit sleep mode\n"); | |
| 87 | + return ret; | |
| 88 | + } | |
| 89 | + msleep(20); | |
| 90 | + | |
| 91 | + ret = mipi_dsi_dcs_set_display_on(dsi); | |
| 92 | + if (ret) | |
| 93 | + return ret; | |
| 94 | + usleep_range(10000, 12000); | |
| 95 | + | |
| 96 | + ret = mipi_dsi_turn_on_peripheral(dsi); | |
| 97 | + if (ret < 0) { | |
| 98 | + dev_err(dev, "Failed to turn on peripheral\n"); | |
| 99 | + return ret; | |
| 100 | + } | |
| 101 | + | |
| 102 | + return 0; | |
| 103 | +} | |
| 104 | + | |
| 105 | +static int mantix_disable(struct drm_panel *panel) | |
| 106 | +{ | |
| 107 | + struct mantix *ctx = panel_to_mantix(panel); | |
| 108 | + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | |
| 109 | + int ret; | |
| 110 | + | |
| 111 | + ret = mipi_dsi_dcs_set_display_off(dsi); | |
| 112 | + if (ret < 0) | |
| 113 | + dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret); | |
| 114 | + | |
| 115 | + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); | |
| 116 | + if (ret < 0) | |
| 117 | + dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret); | |
| 118 | + | |
| 119 | + | |
| 120 | + return 0; | |
| 121 | +} | |
| 122 | + | |
| 123 | +static int mantix_unprepare(struct drm_panel *panel) | |
| 124 | +{ | |
| 125 | + struct mantix *ctx = panel_to_mantix(panel); | |
| 126 | + | |
| 127 | + regulator_disable(ctx->avee); | |
| 128 | + regulator_disable(ctx->avdd); | |
| 129 | + /* T11 */ | |
| 130 | + usleep_range(5000, 6000); | |
| 131 | + regulator_disable(ctx->vddi); | |
| 132 | + /* T14 */ | |
| 133 | + msleep(50); | |
| 134 | + | |
| 135 | + return 0; | |
| 136 | +} | |
| 137 | + | |
| 138 | +static int mantix_prepare(struct drm_panel *panel) | |
| 139 | +{ | |
| 140 | + struct mantix *ctx = panel_to_mantix(panel); | |
| 141 | + int ret; | |
| 142 | + | |
| 143 | + /* Focaltech FT8006P, section 7.3.1 and 7.3.4 */ | |
| 144 | + dev_dbg(ctx->dev, "Resetting the panel\n"); | |
| 145 | + ret = regulator_enable(ctx->vddi); | |
| 146 | + if (ret < 0) { | |
| 147 | + dev_err(ctx->dev, "Failed to enable vddi supply: %d\n", ret); | |
| 148 | + return ret; | |
| 149 | + } | |
| 150 | + | |
| 151 | + /* T1 + T2 */ | |
| 152 | + usleep_range(8000, 10000); | |
| 153 | + | |
| 154 | + ret = regulator_enable(ctx->avdd); | |
| 155 | + if (ret < 0) { | |
| 156 | + dev_err(ctx->dev, "Failed to enable avdd supply: %d\n", ret); | |
| 157 | + return ret; | |
| 158 | + } | |
| 159 | + | |
| 160 | + /* T2d */ | |
| 161 | + usleep_range(3500, 4000); | |
| 162 | + ret = regulator_enable(ctx->avee); | |
| 163 | + if (ret < 0) { | |
| 164 | + dev_err(ctx->dev, "Failed to enable avee supply: %d\n", ret); | |
| 165 | + return ret; | |
| 166 | + } | |
| 167 | + | |
| 168 | + /* T3+T5 */ | |
| 169 | + usleep_range(10000, 12000); | |
| 170 | + | |
| 171 | + gpiod_set_value_cansleep(ctx->reset_gpio, 1); | |
| 172 | + usleep_range(5150, 7000); | |
| 173 | + | |
| 174 | + gpiod_set_value_cansleep(ctx->reset_gpio, 0); | |
| 175 | + | |
| 176 | + /* T6 */ | |
| 177 | + msleep(50); | |
| 178 | + | |
| 179 | + return 0; | |
| 180 | +} | |
| 181 | + | |
| 182 | +static const struct drm_display_mode default_mode = { | |
| 183 | + .hdisplay = 720, | |
| 184 | + .hsync_start = 720 + 45, | |
| 185 | + .hsync_end = 720 + 45 + 14, | |
| 186 | + .htotal = 720 + 45 + 14 + 25, | |
| 187 | + .vdisplay = 1440, | |
| 188 | + .vsync_start = 1440 + 130, | |
| 189 | + .vsync_end = 1440 + 130 + 8, | |
| 190 | + .vtotal = 1440 + 130 + 8 + 106, | |
| 191 | + .clock = 85298, | |
| 192 | + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, | |
| 193 | + .width_mm = 65, | |
| 194 | + .height_mm = 130, | |
| 195 | +}; | |
| 196 | + | |
| 197 | +static int mantix_get_modes(struct drm_panel *panel, | |
| 198 | + struct drm_connector *connector) | |
| 199 | +{ | |
| 200 | + struct mantix *ctx = panel_to_mantix(panel); | |
| 201 | + struct drm_display_mode *mode; | |
| 202 | + | |
| 203 | + mode = drm_mode_duplicate(connector->dev, &default_mode); | |
| 204 | + if (!mode) { | |
| 205 | + dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", | |
| 206 | + default_mode.hdisplay, default_mode.vdisplay, | |
| 207 | + drm_mode_vrefresh(mode)); | |
| 208 | + return -ENOMEM; | |
| 209 | + } | |
| 210 | + | |
| 211 | + drm_mode_set_name(mode); | |
| 212 | + | |
| 213 | + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; | |
| 214 | + connector->display_info.width_mm = mode->width_mm; | |
| 215 | + connector->display_info.height_mm = mode->height_mm; | |
| 216 | + drm_mode_probed_add(connector, mode); | |
| 217 | + | |
| 218 | + return 1; | |
| 219 | +} | |
| 220 | + | |
| 221 | +static const struct drm_panel_funcs mantix_drm_funcs = { | |
| 222 | + .disable = mantix_disable, | |
| 223 | + .unprepare = mantix_unprepare, | |
| 224 | + .prepare = mantix_prepare, | |
| 225 | + .enable = mantix_enable, | |
| 226 | + .get_modes = mantix_get_modes, | |
| 227 | +}; | |
| 228 | + | |
| 229 | +static int mantix_probe(struct mipi_dsi_device *dsi) | |
| 230 | +{ | |
| 231 | + struct device *dev = &dsi->dev; | |
| 232 | + struct mantix *ctx; | |
| 233 | + int ret; | |
| 234 | + | |
| 235 | + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); | |
| 236 | + if (!ctx) | |
| 237 | + return -ENOMEM; | |
| 238 | + | |
| 239 | + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); | |
| 240 | + if (IS_ERR(ctx->reset_gpio)) { | |
| 241 | + dev_err(dev, "cannot get reset gpio\n"); | |
| 242 | + return PTR_ERR(ctx->reset_gpio); | |
| 243 | + } | |
| 244 | + | |
| 245 | + mipi_dsi_set_drvdata(dsi, ctx); | |
| 246 | + ctx->dev = dev; | |
| 247 | + | |
| 248 | + dsi->lanes = 4; | |
| 249 | + dsi->format = MIPI_DSI_FMT_RGB888; | |
| 250 | + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | | |
| 251 | + MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; | |
| 252 | + | |
| 253 | + ctx->avdd = devm_regulator_get(dev, "avdd"); | |
| 254 | + if (IS_ERR(ctx->avdd)) | |
| 255 | + return dev_err_probe(dev, PTR_ERR(ctx->avdd), "Failed to request avdd regulator\n"); | |
| 256 | + | |
| 257 | + ctx->avee = devm_regulator_get(dev, "avee"); | |
| 258 | + if (IS_ERR(ctx->avee)) | |
| 259 | + return dev_err_probe(dev, PTR_ERR(ctx->avee), "Failed to request avee regulator\n"); | |
| 260 | + | |
| 261 | + ctx->vddi = devm_regulator_get(dev, "vddi"); | |
| 262 | + if (IS_ERR(ctx->vddi)) | |
| 263 | + return dev_err_probe(dev, PTR_ERR(ctx->vddi), "Failed to request vddi regulator\n"); | |
| 264 | + | |
| 265 | + drm_panel_init(&ctx->panel, dev, &mantix_drm_funcs, | |
| 266 | + DRM_MODE_CONNECTOR_DSI); | |
| 267 | + | |
| 268 | + ret = drm_panel_of_backlight(&ctx->panel); | |
| 269 | + if (ret) | |
| 270 | + return ret; | |
| 271 | + | |
| 272 | + drm_panel_add(&ctx->panel); | |
| 273 | + | |
| 274 | + ret = mipi_dsi_attach(dsi); | |
| 275 | + if (ret < 0) { | |
| 276 | + dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret); | |
| 277 | + drm_panel_remove(&ctx->panel); | |
| 278 | + return ret; | |
| 279 | + } | |
| 280 | + | |
| 281 | + dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n", | |
| 282 | + default_mode.hdisplay, default_mode.vdisplay, | |
| 283 | + drm_mode_vrefresh(&default_mode), | |
| 284 | + mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); | |
| 285 | + | |
| 286 | + return 0; | |
| 287 | +} | |
| 288 | + | |
| 289 | +static void mantix_shutdown(struct mipi_dsi_device *dsi) | |
| 290 | +{ | |
| 291 | + struct mantix *ctx = mipi_dsi_get_drvdata(dsi); | |
| 292 | + | |
| 293 | + drm_panel_unprepare(&ctx->panel); | |
| 294 | + drm_panel_disable(&ctx->panel); | |
| 295 | +} | |
| 296 | + | |
| 297 | +static int mantix_remove(struct mipi_dsi_device *dsi) | |
| 298 | +{ | |
| 299 | + struct mantix *ctx = mipi_dsi_get_drvdata(dsi); | |
| 300 | + | |
| 301 | + mantix_shutdown(dsi); | |
| 302 | + | |
| 303 | + mipi_dsi_detach(dsi); | |
| 304 | + drm_panel_remove(&ctx->panel); | |
| 305 | + | |
| 306 | + return 0; | |
| 307 | +} | |
| 308 | + | |
| 309 | +static const struct of_device_id mantix_of_match[] = { | |
| 310 | + { .compatible = "mantix,mlaf057we51-x" }, | |
| 311 | + { /* sentinel */ } | |
| 312 | +}; | |
| 313 | +MODULE_DEVICE_TABLE(of, mantix_of_match); | |
| 314 | + | |
| 315 | +static struct mipi_dsi_driver mantix_driver = { | |
| 316 | + .probe = mantix_probe, | |
| 317 | + .remove = mantix_remove, | |
| 318 | + .shutdown = mantix_shutdown, | |
| 319 | + .driver = { | |
| 320 | + .name = DRV_NAME, | |
| 321 | + .of_match_table = mantix_of_match, | |
| 322 | + }, | |
| 323 | +}; | |
| 324 | +module_mipi_dsi_driver(mantix_driver); | |
| 325 | + | |
| 326 | +MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>"); | |
| 327 | +MODULE_DESCRIPTION("DRM driver for Mantix MLAF057WE51-X MIPI DSI panel"); | |
| 328 | +MODULE_LICENSE("GPL v2"); | |
| @@ -207,7 +207,9 @@ static int nl8048_probe(struct spi_device *spi) · 206 unmodified lines | ||
| 207 | 207 | drm_panel_init(&lcd->panel, &lcd->spi->dev, &nl8048_funcs, |
| 208 | 208 | DRM_MODE_CONNECTOR_DPI); |
| 209 | 209 | |
| 210 | − return drm_panel_add(&lcd->panel); | |
| 210 | + drm_panel_add(&lcd->panel); | |
| 211 | + | |
| 212 | + return 0; | |
| 211 | 213 | } |
| 212 | 214 | |
| 213 | 215 | static int nl8048_remove(struct spi_device *spi) |
| @@ -35,7 +35,6 @@ · 34 unmodified lines | ||
| 35 | 35 | #include <drm/drm_mipi_dsi.h> |
| 36 | 36 | #include <drm/drm_modes.h> |
| 37 | 37 | #include <drm/drm_panel.h> |
| 38 | −#include <drm/drm_print.h> | |
| 39 | 38 | |
| 40 | 39 | #define MCS_CMD_MAUCCTR 0xF0 /* Manufacturer command enable */ |
| 41 | 40 | #define MCS_CMD_READ_ID1 0xDA |
| @@ -376,6 +375,10 @@ struct nt35510 { · 334 unmodified lines | ||
| 376 | 375 | }; |
| 377 | 376 | |
| 378 | 377 | /* Manufacturer command has strictly this byte sequence */ |
| 378 | +static const u8 nt35510_mauc_mtp_read_param[] = { 0xAA, 0x55, 0x25, 0x01 }; | |
| 379 | +static const u8 nt35510_mauc_mtp_read_setting[] = { 0x01, 0x02, 0x00, 0x20, | |
| 380 | + 0x33, 0x13, 0x00, 0x40, | |
| 381 | + 0x00, 0x00, 0x23, 0x02 }; | |
| 379 | 382 | static const u8 nt35510_mauc_select_page_0[] = { 0x55, 0xAA, 0x52, 0x08, 0x00 }; |
| 380 | 383 | static const u8 nt35510_mauc_select_page_1[] = { 0x55, 0xAA, 0x52, 0x08, 0x01 }; |
| 381 | 384 | static const u8 nt35510_vgh_on[] = { 0x01 }; |
| @@ -400,9 +403,7 @@ static int nt35510_send_long(struct nt35510 *nt, struct mipi_dsi_device *dsi, · 18 unmodified lines | ||
| 400 | 403 | chunk = 15; |
| 401 | 404 | ret = mipi_dsi_dcs_write(dsi, cmd, seqp, chunk); |
| 402 | 405 | if (ret < 0) { |
| 403 | − DRM_DEV_ERROR(nt->dev, | |
| 404 | − "error sending DCS command seq cmd %02x\n", | |
| 405 | − cmd); | |
| 406 | + dev_err(nt->dev, "error sending DCS command seq cmd %02x\n", cmd); | |
| 406 | 407 | return ret; |
| 407 | 408 | } |
| 408 | 409 | cmdwritten += chunk; |
| @@ -414,16 +415,13 @@ static int nt35510_send_long(struct nt35510 *nt, struct mipi_dsi_device *dsi, · 5 unmodified lines | ||
| 414 | 415 | chunk = 15; |
| 415 | 416 | ret = mipi_dsi_generic_write(dsi, seqp, chunk); |
| 416 | 417 | if (ret < 0) { |
| 417 | − DRM_DEV_ERROR(nt->dev, | |
| 418 | − "error sending generic write seq %02x\n", | |
| 419 | − cmd); | |
| 418 | + dev_err(nt->dev, "error sending generic write seq %02x\n", cmd); | |
| 420 | 419 | return ret; |
| 421 | 420 | } |
| 422 | 421 | cmdwritten += chunk; |
| 423 | 422 | seqp += chunk; |
| 424 | 423 | } |
| 425 | − DRM_DEV_DEBUG(nt->dev, "sent command %02x %02x bytes\n", | |
| 426 | − cmd, cmdlen); | |
| 424 | + dev_dbg(nt->dev, "sent command %02x %02x bytes\n", cmd, cmdlen); | |
| 427 | 425 | return 0; |
| 428 | 426 | } |
| 429 | 427 | |
| @@ -435,17 +433,17 @@ static int nt35510_read_id(struct nt35510 *nt) · 5 unmodified lines | ||
| 435 | 433 | |
| 436 | 434 | ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID1, &id1, 1); |
| 437 | 435 | if (ret < 0) { |
| 438 | − DRM_DEV_ERROR(nt->dev, "could not read MTP ID1\n"); | |
| 436 | + dev_err(nt->dev, "could not read MTP ID1\n"); | |
| 439 | 437 | return ret; |
| 440 | 438 | } |
| 441 | 439 | ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID2, &id2, 1); |
| 442 | 440 | if (ret < 0) { |
| 443 | − DRM_DEV_ERROR(nt->dev, "could not read MTP ID2\n"); | |
| 441 | + dev_err(nt->dev, "could not read MTP ID2\n"); | |
| 444 | 442 | return ret; |
| 445 | 443 | } |
| 446 | 444 | ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID3, &id3, 1); |
| 447 | 445 | if (ret < 0) { |
| 448 | − DRM_DEV_ERROR(nt->dev, "could not read MTP ID3\n"); | |
| 446 | + dev_err(nt->dev, "could not read MTP ID3\n"); | |
| 449 | 447 | return ret; |
| 450 | 448 | } |
| 451 | 449 | |
| @@ -454,9 +452,7 @@ static int nt35510_read_id(struct nt35510 *nt) · 2 unmodified lines | ||
| 454 | 452 | * ID (e.g. Hydis 0x55), driver ID (e.g. NT35510 0xc0) and |
| 455 | 453 | * version. |
| 456 | 454 | */ |
| 457 | − DRM_DEV_INFO(nt->dev, | |
| 458 | − "MTP ID manufacturer: %02x version: %02x driver: %02x\n", | |
| 459 | − id1, id2, id3); | |
| 455 | + dev_info(nt->dev, "MTP ID manufacturer: %02x version: %02x driver: %02x\n", id1, id2, id3); | |
| 460 | 456 | |
| 461 | 457 | return 0; |
| 462 | 458 | } |
| @@ -657,7 +653,7 @@ static int nt35510_set_brightness(struct backlight_device *bl) · 194 unmodified lines | ||
| 657 | 653 | u8 brightness = bl->props.brightness; |
| 658 | 654 | int ret; |
| 659 | 655 | |
| 660 | − DRM_DEV_DEBUG(nt->dev, "set brightness %d\n", brightness); | |
| 656 | + dev_dbg(nt->dev, "set brightness %d\n", brightness); | |
| 661 | 657 | ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, |
| 662 | 658 | &brightness, |
| 663 | 659 | sizeof(brightness)); |
| @@ -698,6 +694,18 @@ static int nt35510_power_on(struct nt35510 *nt) · 34 unmodified lines | ||
| 698 | 694 | usleep_range(120000, 140000); |
| 699 | 695 | } |
| 700 | 696 | |
| 697 | + ret = nt35510_send_long(nt, dsi, MCS_CMD_MTP_READ_PARAM, | |
| 698 | + ARRAY_SIZE(nt35510_mauc_mtp_read_param), | |
| 699 | + nt35510_mauc_mtp_read_param); | |
| 700 | + if (ret) | |
| 701 | + return ret; | |
| 702 | + | |
| 703 | + ret = nt35510_send_long(nt, dsi, MCS_CMD_MTP_READ_SETTING, | |
| 704 | + ARRAY_SIZE(nt35510_mauc_mtp_read_setting), | |
| 705 | + nt35510_mauc_mtp_read_setting); | |
| 706 | + if (ret) | |
| 707 | + return ret; | |
| 708 | + | |
| 701 | 709 | ret = nt35510_read_id(nt); |
| 702 | 710 | if (ret) |
| 703 | 711 | return ret; |
| @@ -780,8 +788,7 @@ static int nt35510_unprepare(struct drm_panel *panel) · 76 unmodified lines | ||
| 780 | 788 | |
| 781 | 789 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 782 | 790 | if (ret) { |
| 783 | − DRM_DEV_ERROR(nt->dev, "failed to turn display off (%d)\n", | |
| 784 | − ret); | |
| 791 | + dev_err(nt->dev, "failed to turn display off (%d)\n", ret); | |
| 785 | 792 | return ret; |
| 786 | 793 | } |
| 787 | 794 | usleep_range(10000, 20000); |
| @@ -789,8 +796,7 @@ static int nt35510_unprepare(struct drm_panel *panel) · 1 unmodified line | ||
| 789 | 796 | /* Enter sleep mode */ |
| 790 | 797 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 791 | 798 | if (ret) { |
| 792 | − DRM_DEV_ERROR(nt->dev, "failed to enter sleep mode (%d)\n", | |
| 793 | − ret); | |
| 799 | + dev_err(nt->dev, "failed to enter sleep mode (%d)\n", ret); | |
| 794 | 800 | return ret; |
| 795 | 801 | } |
| 796 | 802 | |
| @@ -817,8 +823,7 @@ static int nt35510_prepare(struct drm_panel *panel) · 20 unmodified lines | ||
| 817 | 823 | /* Exit sleep mode */ |
| 818 | 824 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 819 | 825 | if (ret) { |
| 820 | − DRM_DEV_ERROR(nt->dev, "failed to exit sleep mode (%d)\n", | |
| 821 | − ret); | |
| 826 | + dev_err(nt->dev, "failed to exit sleep mode (%d)\n", ret); | |
| 822 | 827 | return ret; |
| 823 | 828 | } |
| 824 | 829 | /* Up to 120 ms */ |
| @@ -826,8 +831,7 @@ static int nt35510_prepare(struct drm_panel *panel) · 1 unmodified line | ||
| 826 | 831 | |
| 827 | 832 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 828 | 833 | if (ret) { |
| 829 | − DRM_DEV_ERROR(nt->dev, "failed to turn display on (%d)\n", | |
| 830 | − ret); | |
| 834 | + dev_err(nt->dev, "failed to turn display on (%d)\n", ret); | |
| 831 | 835 | return ret; |
| 832 | 836 | } |
| 833 | 837 | /* Some 10 ms */ |
| @@ -848,7 +852,7 @@ static int nt35510_get_modes(struct drm_panel *panel, · 14 unmodified lines | ||
| 848 | 852 | info->height_mm = nt->conf->height_mm; |
| 849 | 853 | mode = drm_mode_duplicate(connector->dev, &nt->conf->mode); |
| 850 | 854 | if (!mode) { |
| 851 | − DRM_ERROR("bad mode or failed to add mode\n"); | |
| 855 | + dev_err(panel->dev, "bad mode or failed to add mode\n"); | |
| 852 | 856 | return -EINVAL; |
| 853 | 857 | } |
| 854 | 858 | drm_mode_set_name(mode); |
| @@ -947,7 +951,7 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) · 92 unmodified lines | ||
| 947 | 951 | bl = devm_backlight_device_register(dev, "nt35510", dev, nt, |
| 948 | 952 | &nt35510_bl_ops, NULL); |
| 949 | 953 | if (IS_ERR(bl)) { |
| 950 | − DRM_DEV_ERROR(dev, "failed to register backlight device\n"); | |
| 954 | + dev_err(dev, "failed to register backlight device\n"); | |
| 951 | 955 | return PTR_ERR(bl); |
| 952 | 956 | } |
| 953 | 957 | bl->props.max_brightness = 255; |
| @@ -956,9 +960,7 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) · 2 unmodified lines | ||
| 956 | 960 | nt->panel.backlight = bl; |
| 957 | 961 | } |
| 958 | 962 | |
| 959 | − ret = drm_panel_add(&nt->panel); | |
| 960 | − if (ret < 0) | |
| 961 | − return ret; | |
| 963 | + drm_panel_add(&nt->panel); | |
| 962 | 964 | |
| 963 | 965 | ret = mipi_dsi_attach(dsi); |
| 964 | 966 | if (ret < 0) |
| @@ -6,7 +6,6 @@ · 5 unmodified lines | ||
| 6 | 6 | * Copyright (C) 2019, Paul Cercueil <paul@crapouillou.net> |
| 7 | 7 | */ |
| 8 | 8 | |
| 9 | −#include <linux/backlight.h> | |
| 10 | 9 | #include <linux/delay.h> |
| 11 | 10 | #include <linux/device.h> |
| 12 | 11 | #include <linux/gpio/consumer.h> |
| @@ -57,14 +56,11 @@ struct nt39016_panel_info { · 44 unmodified lines | ||
| 57 | 56 | |
| 58 | 57 | struct nt39016 { |
| 59 | 58 | struct drm_panel drm_panel; |
| 60 | − struct device *dev; | |
| 61 | 59 | struct regmap *map; |
| 62 | 60 | struct regulator *supply; |
| 63 | 61 | const struct nt39016_panel_info *panel_info; |
| 64 | 62 | |
| 65 | 63 | struct gpio_desc *reset_gpio; |
| 66 | − | |
| 67 | − struct backlight_device *backlight; | |
| 68 | 64 | }; |
| 69 | 65 | |
| 70 | 66 | static inline struct nt39016 *to_nt39016(struct drm_panel *panel) |
| @@ -127,7 +123,7 @@ static int nt39016_prepare(struct drm_panel *drm_panel) · 56 unmodified lines | ||
| 127 | 123 | |
| 128 | 124 | err = regulator_enable(panel->supply); |
| 129 | 125 | if (err) { |
| 130 | − dev_err(panel->dev, "Failed to enable power supply: %d", err); | |
| 126 | + dev_err(drm_panel->dev, "Failed to enable power supply: %d\n", err); | |
| 131 | 127 | return err; |
| 132 | 128 | } |
| 133 | 129 | |
| @@ -146,7 +142,7 @@ static int nt39016_prepare(struct drm_panel *drm_panel) · 12 unmodified lines | ||
| 146 | 142 | err = regmap_multi_reg_write(panel->map, nt39016_panel_regs, |
| 147 | 143 | ARRAY_SIZE(nt39016_panel_regs)); |
| 148 | 144 | if (err) { |
| 149 | − dev_err(panel->dev, "Failed to init registers: %d", err); | |
| 145 | + dev_err(drm_panel->dev, "Failed to init registers: %d\n", err); | |
| 150 | 146 | goto err_disable_regulator; |
| 151 | 147 | } |
| 152 | 148 | |
| @@ -176,18 +172,16 @@ static int nt39016_enable(struct drm_panel *drm_panel) · 23 unmodified lines | ||
| 176 | 172 | ret = regmap_write(panel->map, NT39016_REG_SYSTEM, |
| 177 | 173 | NT39016_SYSTEM_RESET_N | NT39016_SYSTEM_STANDBY); |
| 178 | 174 | if (ret) { |
| 179 | − dev_err(panel->dev, "Unable to enable panel: %d", ret); | |
| 175 | + dev_err(drm_panel->dev, "Unable to enable panel: %d\n", ret); | |
| 180 | 176 | return ret; |
| 181 | 177 | } |
| 182 | 178 | |
| 183 | − if (panel->backlight) { | |
| 179 | + if (drm_panel->backlight) { | |
| 184 | 180 | /* Wait for the picture to be ready before enabling backlight */ |
| 185 | 181 | msleep(150); |
| 186 | − | |
| 187 | − ret = backlight_enable(panel->backlight); | |
| 188 | 182 | } |
| 189 | 183 | |
| 190 | − return ret; | |
| 184 | + return 0; | |
| 191 | 185 | } |
| 192 | 186 | |
| 193 | 187 | static int nt39016_disable(struct drm_panel *drm_panel) |
| @@ -195,12 +189,10 @@ static int nt39016_disable(struct drm_panel *drm_panel) · 1 unmodified line | ||
| 195 | 189 | struct nt39016 *panel = to_nt39016(drm_panel); |
| 196 | 190 | int err; |
| 197 | 191 | |
| 198 | − backlight_disable(panel->backlight); | |
| 199 | − | |
| 200 | 192 | err = regmap_write(panel->map, NT39016_REG_SYSTEM, |
| 201 | 193 | NT39016_SYSTEM_RESET_N); |
| 202 | 194 | if (err) { |
| 203 | − dev_err(panel->dev, "Unable to disable panel: %d", err); | |
| 195 | + dev_err(drm_panel->dev, "Unable to disable panel: %d\n", err); | |
| 204 | 196 | return err; |
| 205 | 197 | } |
| 206 | 198 | |
| @@ -259,7 +251,6 @@ static int nt39016_probe(struct spi_device *spi) · 52 unmodified lines | ||
| 259 | 251 | if (!panel) |
| 260 | 252 | return -ENOMEM; |
| 261 | 253 | |
| 262 | − panel->dev = dev; | |
| 263 | 254 | spi_set_drvdata(spi, panel); |
| 264 | 255 | |
| 265 | 256 | panel->panel_info = of_device_get_match_data(dev); |
| @@ -268,13 +259,13 @@ static int nt39016_probe(struct spi_device *spi) · 2 unmodified lines | ||
| 268 | 259 | |
| 269 | 260 | panel->supply = devm_regulator_get(dev, "power"); |
| 270 | 261 | if (IS_ERR(panel->supply)) { |
| 271 | − dev_err(dev, "Failed to get power supply"); | |
| 262 | + dev_err(dev, "Failed to get power supply\n"); | |
| 272 | 263 | return PTR_ERR(panel->supply); |
| 273 | 264 | } |
| 274 | 265 | |
| 275 | 266 | panel->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); |
| 276 | 267 | if (IS_ERR(panel->reset_gpio)) { |
| 277 | − dev_err(dev, "Failed to get reset GPIO"); | |
| 268 | + dev_err(dev, "Failed to get reset GPIO\n"); | |
| 278 | 269 | return PTR_ERR(panel->reset_gpio); |
| 279 | 270 | } |
| 280 | 271 | |
| @@ -282,33 +273,28 @@ static int nt39016_probe(struct spi_device *spi) · 1 unmodified line | ||
| 282 | 273 | spi->mode = SPI_MODE_3 | SPI_3WIRE; |
| 283 | 274 | err = spi_setup(spi); |
| 284 | 275 | if (err) { |
| 285 | − dev_err(dev, "Failed to setup SPI"); | |
| 276 | + dev_err(dev, "Failed to setup SPI\n"); | |
| 286 | 277 | return err; |
| 287 | 278 | } |
| 288 | 279 | |
| 289 | 280 | panel->map = devm_regmap_init_spi(spi, &nt39016_regmap_config); |
| 290 | 281 | if (IS_ERR(panel->map)) { |
| 291 | − dev_err(dev, "Failed to init regmap"); | |
| 282 | + dev_err(dev, "Failed to init regmap\n"); | |
| 292 | 283 | return PTR_ERR(panel->map); |
| 293 | 284 | } |
| 294 | 285 | |
| 295 | − panel->backlight = devm_of_find_backlight(dev); | |
| 296 | − if (IS_ERR(panel->backlight)) { | |
| 297 | − err = PTR_ERR(panel->backlight); | |
| 298 | − if (err != -EPROBE_DEFER) | |
| 299 | − dev_err(dev, "Failed to get backlight handle"); | |
| 300 | − return err; | |
| 301 | − } | |
| 302 | − | |
| 303 | 286 | drm_panel_init(&panel->drm_panel, dev, &nt39016_funcs, |
| 304 | 287 | DRM_MODE_CONNECTOR_DPI); |
| 305 | 288 | |
| 306 | − err = drm_panel_add(&panel->drm_panel); | |
| 307 | − if (err < 0) { | |
| 308 | − dev_err(dev, "Failed to register panel"); | |
| 289 | + err = drm_panel_of_backlight(&panel->drm_panel); | |
| 290 | + if (err) { | |
| 291 | + if (err != -EPROBE_DEFER) | |
| 292 | + dev_err(dev, "Failed to get backlight handle\n"); | |
| 309 | 293 | return err; |
| 310 | 294 | } |
| 311 | 295 | |
| 296 | + drm_panel_add(&panel->drm_panel); | |
| 297 | + | |
| 312 | 298 | return 0; |
| 313 | 299 | } |
| 314 | 300 | |
| @@ -283,7 +283,9 @@ static int lcd_olinuxino_probe(struct i2c_client *client, · 282 unmodified lines | ||
| 283 | 283 | if (ret) |
| 284 | 284 | return ret; |
| 285 | 285 | |
| 286 | − return drm_panel_add(&lcd->panel); | |
| 286 | + drm_panel_add(&lcd->panel); | |
| 287 | + | |
| 288 | + return 0; | |
| 287 | 289 | } |
| 288 | 290 | |
| 289 | 291 | static int lcd_olinuxino_remove(struct i2c_client *client) |
| @@ -17,7 +17,6 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <drm/drm_mipi_dsi.h> |
| 18 | 18 | #include <drm/drm_modes.h> |
| 19 | 19 | #include <drm/drm_panel.h> |
| 20 | −#include <drm/drm_print.h> | |
| 21 | 20 | |
| 22 | 21 | #define OTM8009A_BACKLIGHT_DEFAULT 240 |
| 23 | 22 | #define OTM8009A_BACKLIGHT_MAX 255 |
| @@ -97,7 +96,7 @@ static void otm8009a_dcs_write_buf(struct otm8009a *ctx, const void *data, · 73 unmodified lines | ||
| 97 | 96 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); |
| 98 | 97 | |
| 99 | 98 | if (mipi_dsi_dcs_write_buffer(dsi, data, len) < 0) |
| 100 | − DRM_WARN("mipi dsi dcs write buffer failed\n"); | |
| 99 | + dev_warn(ctx->dev, "mipi dsi dcs write buffer failed\n"); | |
| 101 | 100 | } |
| 102 | 101 | |
| 103 | 102 | static void otm8009a_dcs_write_buf_hs(struct otm8009a *ctx, const void *data, |
| @@ -313,7 +312,7 @@ static int otm8009a_prepare(struct drm_panel *panel) · 209 unmodified lines | ||
| 313 | 312 | |
| 314 | 313 | ret = regulator_enable(ctx->supply); |
| 315 | 314 | if (ret < 0) { |
| 316 | − DRM_ERROR("failed to enable supply: %d\n", ret); | |
| 315 | + dev_err(panel->dev, "failed to enable supply: %d\n", ret); | |
| 317 | 316 | return ret; |
| 318 | 317 | } |
| 319 | 318 | |
| @@ -355,9 +354,9 @@ static int otm8009a_get_modes(struct drm_panel *panel, · 35 unmodified lines | ||
| 355 | 354 | |
| 356 | 355 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 357 | 356 | if (!mode) { |
| 358 | − DRM_ERROR("failed to add mode %ux%ux@%u\n", | |
| 359 | − default_mode.hdisplay, default_mode.vdisplay, | |
| 360 | − drm_mode_vrefresh(&default_mode)); | |
| 357 | + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", | |
| 358 | + default_mode.hdisplay, default_mode.vdisplay, | |
| 359 | + drm_mode_vrefresh(&default_mode)); | |
| 361 | 360 | return -ENOMEM; |
| 362 | 361 | } |
| 363 | 362 | |
| @@ -390,7 +389,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd) · 26 unmodified lines | ||
| 390 | 389 | u8 data[2]; |
| 391 | 390 | |
| 392 | 391 | if (!ctx->prepared) { |
| 393 | − DRM_DEBUG("lcd not ready yet for setting its backlight!\n"); | |
| 392 | + dev_dbg(&bd->dev, "lcd not ready yet for setting its backlight!\n"); | |
| 394 | 393 | return -ENXIO; |
| 395 | 394 | } |
| 396 | 395 | |
| @@ -164,7 +164,9 @@ static int osd101t2587_panel_add(struct osd101t2587_panel *osd101t2587) · 163 unmodified lines | ||
| 164 | 164 | if (ret) |
| 165 | 165 | return ret; |
| 166 | 166 | |
| 167 | − return drm_panel_add(&osd101t2587->base); | |
| 167 | + drm_panel_add(&osd101t2587->base); | |
| 168 | + | |
| 169 | + return 0; | |
| 168 | 170 | } |
| 169 | 171 | |
| 170 | 172 | static int osd101t2587_panel_probe(struct mipi_dsi_device *dsi) |
| @@ -206,7 +206,9 @@ static int wuxga_nt_panel_add(struct wuxga_nt_panel *wuxga_nt) · 205 unmodified lines | ||
| 206 | 206 | if (ret) |
| 207 | 207 | return ret; |
| 208 | 208 | |
| 209 | − return drm_panel_add(&wuxga_nt->base); | |
| 209 | + drm_panel_add(&wuxga_nt->base); | |
| 210 | + | |
| 211 | + return 0; | |
| 210 | 212 | } |
| 211 | 213 | |
| 212 | 214 | static void wuxga_nt_panel_del(struct wuxga_nt_panel *wuxga_nt) |
| @@ -361,7 +361,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c, · 360 unmodified lines | ||
| 361 | 361 | struct rpi_touchscreen *ts; |
| 362 | 362 | struct device_node *endpoint, *dsi_host_node; |
| 363 | 363 | struct mipi_dsi_host *host; |
| 364 | − int ret, ver; | |
| 364 | + int ver; | |
| 365 | 365 | struct mipi_dsi_device_info info = { |
| 366 | 366 | .type = RPI_DSI_DRIVER_NAME, |
| 367 | 367 | .channel = 0, |
| @@ -429,9 +429,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c, · 61 unmodified lines | ||
| 429 | 429 | /* This appears last, as it's what will unblock the DSI host |
| 430 | 430 | * driver's component bind function. |
| 431 | 431 | */ |
| 432 | − ret = drm_panel_add(&ts->base); | |
| 433 | − if (ret) | |
| 434 | − return ret; | |
| 432 | + drm_panel_add(&ts->base); | |
| 435 | 433 | |
| 436 | 434 | return 0; |
| 437 | 435 | |
| @@ -19,7 +19,6 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <drm/drm_crtc.h> |
| 20 | 20 | #include <drm/drm_mipi_dsi.h> |
| 21 | 21 | #include <drm/drm_panel.h> |
| 22 | −#include <drm/drm_print.h> | |
| 23 | 22 | |
| 24 | 23 | /* Panel specific color-format bits */ |
| 25 | 24 | #define COL_FMT_16BPP 0x55 |
| @@ -329,7 +328,7 @@ static int rad_panel_enable(struct drm_panel *panel) · 303 unmodified lines | ||
| 329 | 328 | |
| 330 | 329 | ret = rad_panel_push_cmd_list(dsi); |
| 331 | 330 | if (ret < 0) { |
| 332 | − DRM_DEV_ERROR(dev, "Failed to send MCS (%d)\n", ret); | |
| 331 | + dev_err(dev, "Failed to send MCS (%d)\n", ret); | |
| 333 | 332 | goto fail; |
| 334 | 333 | } |
| 335 | 334 | |
| @@ -341,7 +340,7 @@ static int rad_panel_enable(struct drm_panel *panel) · 5 unmodified lines | ||
| 341 | 340 | /* Software reset */ |
| 342 | 341 | ret = mipi_dsi_dcs_soft_reset(dsi); |
| 343 | 342 | if (ret < 0) { |
| 344 | − DRM_DEV_ERROR(dev, "Failed to do Software Reset (%d)\n", ret); | |
| 343 | + dev_err(dev, "Failed to do Software Reset (%d)\n", ret); | |
| 345 | 344 | goto fail; |
| 346 | 345 | } |
| 347 | 346 | |
| @@ -350,33 +349,32 @@ static int rad_panel_enable(struct drm_panel *panel) · 2 unmodified lines | ||
| 350 | 349 | /* Set DSI mode */ |
| 351 | 350 | ret = mipi_dsi_generic_write(dsi, (u8[]){ 0xC2, 0x0B }, 2); |
| 352 | 351 | if (ret < 0) { |
| 353 | − DRM_DEV_ERROR(dev, "Failed to set DSI mode (%d)\n", ret); | |
| 352 | + dev_err(dev, "Failed to set DSI mode (%d)\n", ret); | |
| 354 | 353 | goto fail; |
| 355 | 354 | } |
| 356 | 355 | /* Set tear ON */ |
| 357 | 356 | ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); |
| 358 | 357 | if (ret < 0) { |
| 359 | − DRM_DEV_ERROR(dev, "Failed to set tear ON (%d)\n", ret); | |
| 358 | + dev_err(dev, "Failed to set tear ON (%d)\n", ret); | |
| 360 | 359 | goto fail; |
| 361 | 360 | } |
| 362 | 361 | /* Set tear scanline */ |
| 363 | 362 | ret = mipi_dsi_dcs_set_tear_scanline(dsi, 0x380); |
| 364 | 363 | if (ret < 0) { |
| 365 | − DRM_DEV_ERROR(dev, "Failed to set tear scanline (%d)\n", ret); | |
| 364 | + dev_err(dev, "Failed to set tear scanline (%d)\n", ret); | |
| 366 | 365 | goto fail; |
| 367 | 366 | } |
| 368 | 367 | /* Set pixel format */ |
| 369 | 368 | ret = mipi_dsi_dcs_set_pixel_format(dsi, color_format); |
| 370 | − DRM_DEV_DEBUG_DRIVER(dev, "Interface color format set to 0x%x\n", | |
| 371 | − color_format); | |
| 369 | + dev_dbg(dev, "Interface color format set to 0x%x\n", color_format); | |
| 372 | 370 | if (ret < 0) { |
| 373 | − DRM_DEV_ERROR(dev, "Failed to set pixel format (%d)\n", ret); | |
| 371 | + dev_err(dev, "Failed to set pixel format (%d)\n", ret); | |
| 374 | 372 | goto fail; |
| 375 | 373 | } |
| 376 | 374 | /* Exit sleep mode */ |
| 377 | 375 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 378 | 376 | if (ret < 0) { |
| 379 | − DRM_DEV_ERROR(dev, "Failed to exit sleep mode (%d)\n", ret); | |
| 377 | + dev_err(dev, "Failed to exit sleep mode (%d)\n", ret); | |
| 380 | 378 | goto fail; |
| 381 | 379 | } |
| 382 | 380 | |
| @@ -384,7 +382,7 @@ static int rad_panel_enable(struct drm_panel *panel) · 1 unmodified line | ||
| 384 | 382 | |
| 385 | 383 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 386 | 384 | if (ret < 0) { |
| 387 | − DRM_DEV_ERROR(dev, "Failed to set display ON (%d)\n", ret); | |
| 385 | + dev_err(dev, "Failed to set display ON (%d)\n", ret); | |
| 388 | 386 | goto fail; |
| 389 | 387 | } |
| 390 | 388 | |
| @@ -418,7 +416,7 @@ static int rad_panel_disable(struct drm_panel *panel) · 27 unmodified lines | ||
| 418 | 416 | |
| 419 | 417 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 420 | 418 | if (ret < 0) { |
| 421 | − DRM_DEV_ERROR(dev, "Failed to set display OFF (%d)\n", ret); | |
| 419 | + dev_err(dev, "Failed to set display OFF (%d)\n", ret); | |
| 422 | 420 | return ret; |
| 423 | 421 | } |
| 424 | 422 | |
| @@ -426,7 +424,7 @@ static int rad_panel_disable(struct drm_panel *panel) · 1 unmodified line | ||
| 426 | 424 | |
| 427 | 425 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 428 | 426 | if (ret < 0) { |
| 429 | − DRM_DEV_ERROR(dev, "Failed to enter sleep mode (%d)\n", ret); | |
| 427 | + dev_err(dev, "Failed to enter sleep mode (%d)\n", ret); | |
| 430 | 428 | return ret; |
| 431 | 429 | } |
| 432 | 430 | |
| @@ -442,9 +440,9 @@ static int rad_panel_get_modes(struct drm_panel *panel, · 9 unmodified lines | ||
| 442 | 440 | |
| 443 | 441 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 444 | 442 | if (!mode) { |
| 445 | − DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n", | |
| 446 | − default_mode.hdisplay, default_mode.vdisplay, | |
| 447 | − drm_mode_vrefresh(&default_mode)); | |
| 443 | + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", | |
| 444 | + default_mode.hdisplay, default_mode.vdisplay, | |
| 445 | + drm_mode_vrefresh(&default_mode)); | |
| 448 | 446 | return -ENOMEM; |
| 449 | 447 | } |
| 450 | 448 | |
| @@ -609,9 +607,7 @@ static int rad_panel_probe(struct mipi_dsi_device *dsi) · 158 unmodified lines | ||
| 609 | 607 | DRM_MODE_CONNECTOR_DSI); |
| 610 | 608 | dev_set_drvdata(dev, panel); |
| 611 | 609 | |
| 612 | − ret = drm_panel_add(&panel->panel); | |
| 613 | − if (ret) | |
| 614 | − return ret; | |
| 610 | + drm_panel_add(&panel->panel); | |
| 615 | 611 | |
| 616 | 612 | ret = mipi_dsi_attach(dsi); |
| 617 | 613 | if (ret) |
| @@ -628,8 +624,7 @@ static int rad_panel_remove(struct mipi_dsi_device *dsi) · 10 unmodified lines | ||
| 628 | 624 | |
| 629 | 625 | ret = mipi_dsi_detach(dsi); |
| 630 | 626 | if (ret) |
| 631 | − DRM_DEV_ERROR(dev, "Failed to detach from host (%d)\n", | |
| 632 | − ret); | |
| 627 | + dev_err(dev, "Failed to detach from host (%d)\n", ret); | |
| 633 | 628 | |
| 634 | 629 | drm_panel_remove(&rad->panel); |
| 635 | 630 | |
| @@ -17,7 +17,6 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <drm/drm_mipi_dsi.h> |
| 18 | 18 | #include <drm/drm_modes.h> |
| 19 | 19 | #include <drm/drm_panel.h> |
| 20 | −#include <drm/drm_print.h> | |
| 21 | 20 | |
| 22 | 21 | /*** Manufacturer Command Set ***/ |
| 23 | 22 | #define MCS_CMD_MODE_SW 0xFE /* CMD Mode Switch */ |
| @@ -110,8 +109,7 @@ static void rm68200_dcs_write_buf(struct rm68200 *ctx, const void *data, · 86 unmodified lines | ||
| 110 | 109 | |
| 111 | 110 | err = mipi_dsi_dcs_write_buffer(dsi, data, len); |
| 112 | 111 | if (err < 0) |
| 113 | − DRM_ERROR_RATELIMITED("MIPI DSI DCS write buffer failed: %d\n", | |
| 114 | − err); | |
| 112 | + dev_err_ratelimited(ctx->dev, "MIPI DSI DCS write buffer failed: %d\n", err); | |
| 115 | 113 | } |
| 116 | 114 | |
| 117 | 115 | static void rm68200_dcs_write_cmd(struct rm68200 *ctx, u8 cmd, u8 value) |
| @@ -121,7 +119,7 @@ static void rm68200_dcs_write_cmd(struct rm68200 *ctx, u8 cmd, u8 value) · 3 unmodified lines | ||
| 121 | 119 | |
| 122 | 120 | err = mipi_dsi_dcs_write(dsi, cmd, &value, 1); |
| 123 | 121 | if (err < 0) |
| 124 | − DRM_ERROR_RATELIMITED("MIPI DSI DCS write failed: %d\n", err); | |
| 122 | + dev_err_ratelimited(ctx->dev, "MIPI DSI DCS write failed: %d\n", err); | |
| 125 | 123 | } |
| 126 | 124 | |
| 127 | 125 | #define dcs_write_seq(ctx, seq...) \ |
| @@ -256,11 +254,11 @@ static int rm68200_unprepare(struct drm_panel *panel) · 128 unmodified lines | ||
| 256 | 254 | |
| 257 | 255 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 258 | 256 | if (ret) |
| 259 | − DRM_WARN("failed to set display off: %d\n", ret); | |
| 257 | + dev_warn(panel->dev, "failed to set display off: %d\n", ret); | |
| 260 | 258 | |
| 261 | 259 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 262 | 260 | if (ret) |
| 263 | − DRM_WARN("failed to enter sleep mode: %d\n", ret); | |
| 261 | + dev_warn(panel->dev, "failed to enter sleep mode: %d\n", ret); | |
| 264 | 262 | |
| 265 | 263 | msleep(120); |
| 266 | 264 | |
| @@ -287,7 +285,7 @@ static int rm68200_prepare(struct drm_panel *panel) · 20 unmodified lines | ||
| 287 | 285 | |
| 288 | 286 | ret = regulator_enable(ctx->supply); |
| 289 | 287 | if (ret < 0) { |
| 290 | − DRM_ERROR("failed to enable supply: %d\n", ret); | |
| 288 | + dev_err(ctx->dev, "failed to enable supply: %d\n", ret); | |
| 291 | 289 | return ret; |
| 292 | 290 | } |
| 293 | 291 | |
| @@ -336,9 +334,9 @@ static int rm68200_get_modes(struct drm_panel *panel, · 42 unmodified lines | ||
| 336 | 334 | |
| 337 | 335 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 338 | 336 | if (!mode) { |
| 339 | − DRM_ERROR("failed to add mode %ux%ux@%u\n", | |
| 340 | − default_mode.hdisplay, default_mode.vdisplay, | |
| 341 | − drm_mode_vrefresh(&default_mode)); | |
| 337 | + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", | |
| 338 | + default_mode.hdisplay, default_mode.vdisplay, | |
| 339 | + drm_mode_vrefresh(&default_mode)); | |
| 342 | 340 | return -ENOMEM; |
| 343 | 341 | } |
| 344 | 342 | |
| @@ -23,7 +23,6 @@ · 22 unmodified lines | ||
| 23 | 23 | #include <drm/drm_mipi_dsi.h> |
| 24 | 24 | #include <drm/drm_modes.h> |
| 25 | 25 | #include <drm/drm_panel.h> |
| 26 | −#include <drm/drm_print.h> | |
| 27 | 26 | |
| 28 | 27 | struct rb070d30_panel { |
| 29 | 28 | struct drm_panel panel; |
| @@ -50,7 +49,7 @@ static int rb070d30_panel_prepare(struct drm_panel *panel) · 20 unmodified lines | ||
| 50 | 49 | |
| 51 | 50 | ret = regulator_enable(ctx->supply); |
| 52 | 51 | if (ret < 0) { |
| 53 | − DRM_DEV_ERROR(&ctx->dsi->dev, "Failed to enable supply: %d\n", ret); | |
| 52 | + dev_err(&ctx->dsi->dev, "Failed to enable supply: %d\n", ret); | |
| 54 | 53 | return ret; |
| 55 | 54 | } |
| 56 | 55 | |
| @@ -117,9 +116,8 @@ static int rb070d30_panel_get_modes(struct drm_panel *panel, · 60 unmodified lines | ||
| 117 | 116 | |
| 118 | 117 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 119 | 118 | if (!mode) { |
| 120 | − DRM_DEV_ERROR(&ctx->dsi->dev, | |
| 121 | − "Failed to add mode " DRM_MODE_FMT "\n", | |
| 122 | − DRM_MODE_ARG(&default_mode)); | |
| 119 | + dev_err(&ctx->dsi->dev, "Failed to add mode " DRM_MODE_FMT "\n", | |
| 120 | + DRM_MODE_ARG(&default_mode)); | |
| 123 | 121 | return -EINVAL; |
| 124 | 122 | } |
| 125 | 123 | |
| @@ -166,13 +164,13 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi) · 40 unmodified lines | ||
| 166 | 164 | |
| 167 | 165 | ctx->gpios.reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); |
| 168 | 166 | if (IS_ERR(ctx->gpios.reset)) { |
| 169 | − DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n"); | |
| 167 | + dev_err(&dsi->dev, "Couldn't get our reset GPIO\n"); | |
| 170 | 168 | return PTR_ERR(ctx->gpios.reset); |
| 171 | 169 | } |
| 172 | 170 | |
| 173 | 171 | ctx->gpios.power = devm_gpiod_get(&dsi->dev, "power", GPIOD_OUT_LOW); |
| 174 | 172 | if (IS_ERR(ctx->gpios.power)) { |
| 175 | − DRM_DEV_ERROR(&dsi->dev, "Couldn't get our power GPIO\n"); | |
| 173 | + dev_err(&dsi->dev, "Couldn't get our power GPIO\n"); | |
| 176 | 174 | return PTR_ERR(ctx->gpios.power); |
| 177 | 175 | } |
| 178 | 176 | |
| @@ -182,7 +180,7 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi) · 3 unmodified lines | ||
| 182 | 180 | */ |
| 183 | 181 | ctx->gpios.updn = devm_gpiod_get(&dsi->dev, "updn", GPIOD_OUT_LOW); |
| 184 | 182 | if (IS_ERR(ctx->gpios.updn)) { |
| 185 | − DRM_DEV_ERROR(&dsi->dev, "Couldn't get our updn GPIO\n"); | |
| 183 | + dev_err(&dsi->dev, "Couldn't get our updn GPIO\n"); | |
| 186 | 184 | return PTR_ERR(ctx->gpios.updn); |
| 187 | 185 | } |
| 188 | 186 | |
| @@ -192,7 +190,7 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi) · 3 unmodified lines | ||
| 192 | 190 | */ |
| 193 | 191 | ctx->gpios.shlr = devm_gpiod_get(&dsi->dev, "shlr", GPIOD_OUT_LOW); |
| 194 | 192 | if (IS_ERR(ctx->gpios.shlr)) { |
| 195 | − DRM_DEV_ERROR(&dsi->dev, "Couldn't get our shlr GPIO\n"); | |
| 193 | + dev_err(&dsi->dev, "Couldn't get our shlr GPIO\n"); | |
| 196 | 194 | return PTR_ERR(ctx->gpios.shlr); |
| 197 | 195 | } |
| 198 | 196 | |
| @@ -200,9 +198,7 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi) · 1 unmodified line | ||
| 200 | 198 | if (ret) |
| 201 | 199 | return ret; |
| 202 | 200 | |
| 203 | − ret = drm_panel_add(&ctx->panel); | |
| 204 | − if (ret < 0) | |
| 205 | − return ret; | |
| 201 | + drm_panel_add(&ctx->panel); | |
| 206 | 202 | |
| 207 | 203 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM; |
| 208 | 204 | dsi->format = MIPI_DSI_FMT_RGB888; |
| @@ -21,7 +21,6 @@ · 20 unmodified lines | ||
| 21 | 21 | |
| 22 | 22 | #include <drm/drm_modes.h> |
| 23 | 23 | #include <drm/drm_panel.h> |
| 24 | −#include <drm/drm_print.h> | |
| 25 | 24 | |
| 26 | 25 | /* Manufacturer Command Set */ |
| 27 | 26 | #define MCS_MANPWR 0xb0 |
| @@ -269,7 +268,7 @@ static int ld9040_get_modes(struct drm_panel *panel, · 241 unmodified lines | ||
| 269 | 268 | |
| 270 | 269 | mode = drm_mode_create(connector->dev); |
| 271 | 270 | if (!mode) { |
| 272 | − DRM_ERROR("failed to create a new display mode\n"); | |
| 271 | + dev_err(panel->dev, "failed to create a new display mode\n"); | |
| 273 | 272 | return 0; |
| 274 | 273 | } |
| 275 | 274 | |
| @@ -354,7 +353,9 @@ static int ld9040_probe(struct spi_device *spi) · 78 unmodified lines | ||
| 354 | 353 | drm_panel_init(&ctx->panel, dev, &ld9040_drm_funcs, |
| 355 | 354 | DRM_MODE_CONNECTOR_DPI); |
| 356 | 355 | |
| 357 | − return drm_panel_add(&ctx->panel); | |
| 356 | + drm_panel_add(&ctx->panel); | |
| 357 | + | |
| 358 | + return 0; | |
| 358 | 359 | } |
| 359 | 360 | |
| 360 | 361 | static int ld9040_remove(struct spi_device *spi) |
| @@ -7,7 +7,6 @@ · 6 unmodified lines | ||
| 7 | 7 | #include <drm/drm_modes.h> |
| 8 | 8 | #include <drm/drm_mipi_dsi.h> |
| 9 | 9 | #include <drm/drm_panel.h> |
| 10 | −#include <drm/drm_print.h> | |
| 11 | 10 | |
| 12 | 11 | #include <linux/gpio/consumer.h> |
| 13 | 12 | #include <linux/regulator/consumer.h> |
| @@ -55,8 +54,7 @@ static int s6d16d0_unprepare(struct drm_panel *panel) · 41 unmodified lines | ||
| 55 | 54 | /* Enter sleep mode */ |
| 56 | 55 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 57 | 56 | if (ret) { |
| 58 | − DRM_DEV_ERROR(s6->dev, "failed to enter sleep mode (%d)\n", | |
| 59 | − ret); | |
| 57 | + dev_err(s6->dev, "failed to enter sleep mode (%d)\n", ret); | |
| 60 | 58 | return ret; |
| 61 | 59 | } |
| 62 | 60 | |
| @@ -75,7 +73,7 @@ static int s6d16d0_prepare(struct drm_panel *panel) · 12 unmodified lines | ||
| 75 | 73 | |
| 76 | 74 | ret = regulator_enable(s6->supply); |
| 77 | 75 | if (ret) { |
| 78 | − DRM_DEV_ERROR(s6->dev, "failed to enable supply (%d)\n", ret); | |
| 76 | + dev_err(s6->dev, "failed to enable supply (%d)\n", ret); | |
| 79 | 77 | return ret; |
| 80 | 78 | } |
| 81 | 79 | |
| @@ -90,15 +88,13 @@ static int s6d16d0_prepare(struct drm_panel *panel) · 8 unmodified lines | ||
| 90 | 88 | ret = mipi_dsi_dcs_set_tear_on(dsi, |
| 91 | 89 | MIPI_DSI_DCS_TEAR_MODE_VBLANK); |
| 92 | 90 | if (ret) { |
| 93 | − DRM_DEV_ERROR(s6->dev, "failed to enable vblank TE (%d)\n", | |
| 94 | − ret); | |
| 91 | + dev_err(s6->dev, "failed to enable vblank TE (%d)\n", ret); | |
| 95 | 92 | return ret; |
| 96 | 93 | } |
| 97 | 94 | /* Exit sleep mode and power on */ |
| 98 | 95 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 99 | 96 | if (ret) { |
| 100 | − DRM_DEV_ERROR(s6->dev, "failed to exit sleep mode (%d)\n", | |
| 101 | − ret); | |
| 97 | + dev_err(s6->dev, "failed to exit sleep mode (%d)\n", ret); | |
| 102 | 98 | return ret; |
| 103 | 99 | } |
| 104 | 100 | |
| @@ -113,8 +109,7 @@ static int s6d16d0_enable(struct drm_panel *panel) · 8 unmodified lines | ||
| 113 | 109 | |
| 114 | 110 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 115 | 111 | if (ret) { |
| 116 | − DRM_DEV_ERROR(s6->dev, "failed to turn display on (%d)\n", | |
| 117 | − ret); | |
| 112 | + dev_err(s6->dev, "failed to turn display on (%d)\n", ret); | |
| 118 | 113 | return ret; |
| 119 | 114 | } |
| 120 | 115 | |
| @@ -129,8 +124,7 @@ static int s6d16d0_disable(struct drm_panel *panel) · 8 unmodified lines | ||
| 129 | 124 | |
| 130 | 125 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 131 | 126 | if (ret) { |
| 132 | − DRM_DEV_ERROR(s6->dev, "failed to turn display off (%d)\n", | |
| 133 | − ret); | |
| 127 | + dev_err(s6->dev, "failed to turn display off (%d)\n", ret); | |
| 134 | 128 | return ret; |
| 135 | 129 | } |
| 136 | 130 | |
| @@ -144,7 +138,7 @@ static int s6d16d0_get_modes(struct drm_panel *panel, · 7 unmodified lines | ||
| 144 | 138 | |
| 145 | 139 | mode = drm_mode_duplicate(connector->dev, &samsung_s6d16d0_mode); |
| 146 | 140 | if (!mode) { |
| 147 | − DRM_ERROR("bad mode or failed to add mode\n"); | |
| 141 | + dev_err(panel->dev, "bad mode or failed to add mode\n"); | |
| 148 | 142 | return -EINVAL; |
| 149 | 143 | } |
| 150 | 144 | drm_mode_set_name(mode); |
| @@ -204,17 +198,14 @@ static int s6d16d0_probe(struct mipi_dsi_device *dsi) · 53 unmodified lines | ||
| 204 | 198 | if (IS_ERR(s6->reset_gpio)) { |
| 205 | 199 | ret = PTR_ERR(s6->reset_gpio); |
| 206 | 200 | if (ret != -EPROBE_DEFER) |
| 207 | − DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n", | |
| 208 | − ret); | |
| 201 | + dev_err(dev, "failed to request GPIO (%d)\n", ret); | |
| 209 | 202 | return ret; |
| 210 | 203 | } |
| 211 | 204 | |
| 212 | 205 | drm_panel_init(&s6->panel, dev, &s6d16d0_drm_funcs, |
| 213 | 206 | DRM_MODE_CONNECTOR_DSI); |
| 214 | 207 | |
| 215 | − ret = drm_panel_add(&s6->panel); | |
| 216 | − if (ret < 0) | |
| 217 | − return ret; | |
| 208 | + drm_panel_add(&s6->panel); | |
| 218 | 209 | |
| 219 | 210 | ret = mipi_dsi_attach(dsi); |
| 220 | 211 | if (ret < 0) |
| @@ -18,7 +18,6 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <drm/drm_mipi_dsi.h> |
| 19 | 19 | #include <drm/drm_modes.h> |
| 20 | 20 | #include <drm/drm_panel.h> |
| 21 | −#include <drm/drm_print.h> | |
| 22 | 21 | |
| 23 | 22 | #define S6E3HA2_MIN_BRIGHTNESS 0 |
| 24 | 23 | #define S6E3HA2_MAX_BRIGHTNESS 100 |
| @@ -651,7 +650,7 @@ static int s6e3ha2_get_modes(struct drm_panel *panel, · 626 unmodified lines | ||
| 651 | 650 | |
| 652 | 651 | mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); |
| 653 | 652 | if (!mode) { |
| 654 | − DRM_ERROR("failed to add mode %ux%ux@%u\n", | |
| 653 | + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", | |
| 655 | 654 | ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, |
| 656 | 655 | drm_mode_vrefresh(ctx->desc->mode)); |
| 657 | 656 | return -ENOMEM; |
| @@ -733,9 +732,7 @@ static int s6e3ha2_probe(struct mipi_dsi_device *dsi) · 75 unmodified lines | ||
| 733 | 732 | drm_panel_init(&ctx->panel, dev, &s6e3ha2_drm_funcs, |
| 734 | 733 | DRM_MODE_CONNECTOR_DSI); |
| 735 | 734 | |
| 736 | − ret = drm_panel_add(&ctx->panel); | |
| 737 | − if (ret < 0) | |
| 738 | − goto unregister_backlight; | |
| 735 | + drm_panel_add(&ctx->panel); | |
| 739 | 736 | |
| 740 | 737 | ret = mipi_dsi_attach(dsi); |
| 741 | 738 | if (ret < 0) |
| @@ -745,8 +742,6 @@ static int s6e3ha2_probe(struct mipi_dsi_device *dsi) · 3 unmodified lines | ||
| 745 | 742 | |
| 746 | 743 | remove_panel: |
| 747 | 744 | drm_panel_remove(&ctx->panel); |
| 748 | − | |
| 749 | −unregister_backlight: | |
| 750 | 745 | backlight_device_unregister(ctx->bl_dev); |
| 751 | 746 | |
| 752 | 747 | return ret; |
| @@ -19,7 +19,6 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <drm/drm_mipi_dsi.h> |
| 20 | 20 | #include <drm/drm_modes.h> |
| 21 | 21 | #include <drm/drm_panel.h> |
| 22 | −#include <drm/drm_print.h> | |
| 23 | 22 | |
| 24 | 23 | #define MCS_LEVEL2_KEY 0xf0 |
| 25 | 24 | #define MCS_MTP_KEY 0xf1 |
| @@ -406,7 +405,7 @@ static int s6e63j0x03_get_modes(struct drm_panel *panel, · 380 unmodified lines | ||
| 406 | 405 | |
| 407 | 406 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 408 | 407 | if (!mode) { |
| 409 | − DRM_ERROR("failed to add mode %ux%ux@%u\n", | |
| 408 | + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", | |
| 410 | 409 | default_mode.hdisplay, default_mode.vdisplay, |
| 411 | 410 | drm_mode_vrefresh(&default_mode)); |
| 412 | 411 | return -ENOMEM; |
| @@ -479,9 +478,7 @@ static int s6e63j0x03_probe(struct mipi_dsi_device *dsi) · 66 unmodified lines | ||
| 479 | 478 | ctx->bl_dev->props.brightness = DEFAULT_BRIGHTNESS; |
| 480 | 479 | ctx->bl_dev->props.power = FB_BLANK_POWERDOWN; |
| 481 | 480 | |
| 482 | − ret = drm_panel_add(&ctx->panel); | |
| 483 | − if (ret < 0) | |
| 484 | − goto unregister_backlight; | |
| 481 | + drm_panel_add(&ctx->panel); | |
| 485 | 482 | |
| 486 | 483 | ret = mipi_dsi_attach(dsi); |
| 487 | 484 | if (ret < 0) |
| @@ -491,8 +488,6 @@ static int s6e63j0x03_probe(struct mipi_dsi_device *dsi) · 3 unmodified lines | ||
| 491 | 488 | |
| 492 | 489 | remove_panel: |
| 493 | 490 | drm_panel_remove(&ctx->panel); |
| 494 | − | |
| 495 | −unregister_backlight: | |
| 496 | 491 | backlight_device_unregister(ctx->bl_dev); |
| 497 | 492 | |
| 498 | 493 | return ret; |
| @@ -10,7 +10,6 @@ · 9 unmodified lines | ||
| 10 | 10 | |
| 11 | 11 | #include <drm/drm_modes.h> |
| 12 | 12 | #include <drm/drm_panel.h> |
| 13 | −#include <drm/drm_print.h> | |
| 14 | 13 | |
| 15 | 14 | #include <linux/backlight.h> |
| 16 | 15 | #include <linux/delay.h> |
| @@ -157,7 +156,7 @@ static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len) · 140 unmodified lines | ||
| 157 | 156 | if (ctx->error < 0 || len == 0) |
| 158 | 157 | return; |
| 159 | 158 | |
| 160 | − DRM_DEV_DEBUG(ctx->dev, "writing dcs seq: %*ph\n", (int)len, data); | |
| 159 | + dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", (int)len, data); | |
| 161 | 160 | ret = s6e63m0_spi_write_word(ctx, *data); |
| 162 | 161 | |
| 163 | 162 | while (!ret && --len) { |
| @@ -166,8 +165,7 @@ static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len) · 2 unmodified lines | ||
| 166 | 165 | } |
| 167 | 166 | |
| 168 | 167 | if (ret) { |
| 169 | − DRM_DEV_ERROR(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, | |
| 170 | − (int)len, data); | |
| 168 | + dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, (int)len, data); | |
| 171 | 169 | ctx->error = ret; |
| 172 | 170 | } |
| 173 | 171 | |
| @@ -368,9 +366,9 @@ static int s6e63m0_get_modes(struct drm_panel *panel, · 194 unmodified lines | ||
| 368 | 366 | |
| 369 | 367 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 370 | 368 | if (!mode) { |
| 371 | − DRM_ERROR("failed to add mode %ux%ux@%u\n", | |
| 372 | − default_mode.hdisplay, default_mode.vdisplay, | |
| 373 | − drm_mode_vrefresh(&default_mode)); | |
| 369 | + dev_err(panel->dev, "failed to add mode %ux%u@%u\n", | |
| 370 | + default_mode.hdisplay, default_mode.vdisplay, | |
| 371 | + drm_mode_vrefresh(&default_mode)); | |
| 374 | 372 | return -ENOMEM; |
| 375 | 373 | } |
| 376 | 374 | |
| @@ -425,8 +423,7 @@ static int s6e63m0_backlight_register(struct s6e63m0 *ctx) · 48 unmodified lines | ||
| 425 | 423 | &props); |
| 426 | 424 | if (IS_ERR(ctx->bl_dev)) { |
| 427 | 425 | ret = PTR_ERR(ctx->bl_dev); |
| 428 | − DRM_DEV_ERROR(dev, "error registering backlight device (%d)\n", | |
| 429 | − ret); | |
| 426 | + dev_err(dev, "error registering backlight device (%d)\n", ret); | |
| 430 | 427 | } |
| 431 | 428 | |
| 432 | 429 | return ret; |
| @@ -453,14 +450,13 @@ static int s6e63m0_probe(struct spi_device *spi) · 20 unmodified lines | ||
| 453 | 450 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), |
| 454 | 451 | ctx->supplies); |
| 455 | 452 | if (ret < 0) { |
| 456 | − DRM_DEV_ERROR(dev, "failed to get regulators: %d\n", ret); | |
| 453 | + dev_err(dev, "failed to get regulators: %d\n", ret); | |
| 457 | 454 | return ret; |
| 458 | 455 | } |
| 459 | 456 | |
| 460 | 457 | ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); |
| 461 | 458 | if (IS_ERR(ctx->reset_gpio)) { |
| 462 | − DRM_DEV_ERROR(dev, "cannot get reset-gpios %ld\n", | |
| 463 | − PTR_ERR(ctx->reset_gpio)); | |
| 459 | + dev_err(dev, "cannot get reset-gpios %ld\n", PTR_ERR(ctx->reset_gpio)); | |
| 464 | 460 | return PTR_ERR(ctx->reset_gpio); |
| 465 | 461 | } |
| 466 | 462 | |
| @@ -468,7 +464,7 @@ static int s6e63m0_probe(struct spi_device *spi) · 1 unmodified line | ||
| 468 | 464 | spi->mode = SPI_MODE_3; |
| 469 | 465 | ret = spi_setup(spi); |
| 470 | 466 | if (ret < 0) { |
| 471 | − DRM_DEV_ERROR(dev, "spi setup failed.\n"); | |
| 467 | + dev_err(dev, "spi setup failed.\n"); | |
| 472 | 468 | return ret; |
| 473 | 469 | } |
| 474 | 470 | |
| @@ -479,7 +475,9 @@ static int s6e63m0_probe(struct spi_device *spi) · 4 unmodified lines | ||
| 479 | 475 | if (ret < 0) |
| 480 | 476 | return ret; |
| 481 | 477 | |
| 482 | − return drm_panel_add(&ctx->panel); | |
| 478 | + drm_panel_add(&ctx->panel); | |
| 479 | + | |
| 480 | + return 0; | |
| 483 | 481 | } |
| 484 | 482 | |
| 485 | 483 | static int s6e63m0_remove(struct spi_device *spi) |
| @@ -242,11 +242,7 @@ static int s6e88a0_ams452ef01_probe(struct mipi_dsi_device *dsi) · 241 unmodified lines | ||
| 242 | 242 | drm_panel_init(&ctx->panel, dev, &s6e88a0_ams452ef01_panel_funcs, |
| 243 | 243 | DRM_MODE_CONNECTOR_DSI); |
| 244 | 244 | |
| 245 | − ret = drm_panel_add(&ctx->panel); | |
| 246 | − if (ret < 0) { | |
| 247 | − dev_err(dev, "Failed to add panel: %d\n", ret); | |
| 248 | − return ret; | |
| 249 | − } | |
| 245 | + drm_panel_add(&ctx->panel); | |
| 250 | 246 | |
| 251 | 247 | ret = mipi_dsi_attach(dsi); |
| 252 | 248 | if (ret < 0) { |
| @@ -25,7 +25,6 @@ · 24 unmodified lines | ||
| 25 | 25 | #include <drm/drm_mipi_dsi.h> |
| 26 | 26 | #include <drm/drm_modes.h> |
| 27 | 27 | #include <drm/drm_panel.h> |
| 28 | −#include <drm/drm_print.h> | |
| 29 | 28 | |
| 30 | 29 | #define LDI_MTP_LENGTH 24 |
| 31 | 30 | #define GAMMA_LEVEL_NUM 25 |
| @@ -928,7 +927,7 @@ static int s6e8aa0_get_modes(struct drm_panel *panel, · 896 unmodified lines | ||
| 928 | 927 | |
| 929 | 928 | mode = drm_mode_create(connector->dev); |
| 930 | 929 | if (!mode) { |
| 931 | − DRM_ERROR("failed to create a new display mode\n"); | |
| 930 | + dev_err(panel->dev, "failed to create a new display mode\n"); | |
| 932 | 931 | return 0; |
| 933 | 932 | } |
| 934 | 933 | |
| @@ -1020,9 +1019,7 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi) · 85 unmodified lines | ||
| 1020 | 1019 | drm_panel_init(&ctx->panel, dev, &s6e8aa0_drm_funcs, |
| 1021 | 1020 | DRM_MODE_CONNECTOR_DSI); |
| 1022 | 1021 | |
| 1023 | − ret = drm_panel_add(&ctx->panel); | |
| 1024 | − if (ret < 0) | |
| 1025 | − return ret; | |
| 1022 | + drm_panel_add(&ctx->panel); | |
| 1026 | 1023 | |
| 1027 | 1024 | ret = mipi_dsi_attach(dsi); |
| 1028 | 1025 | if (ret < 0) |
| @@ -258,9 +258,7 @@ static int seiko_panel_probe(struct device *dev, · 257 unmodified lines | ||
| 258 | 258 | if (err) |
| 259 | 259 | return err; |
| 260 | 260 | |
| 261 | − err = drm_panel_add(&panel->base); | |
| 262 | − if (err < 0) | |
| 263 | − return err; | |
| 261 | + drm_panel_add(&panel->base); | |
| 264 | 262 | |
| 265 | 263 | dev_set_drvdata(dev, panel); |
| 266 | 264 | |
| @@ -325,7 +325,9 @@ static int sharp_panel_add(struct sharp_panel *sharp) · 324 unmodified lines | ||
| 325 | 325 | if (ret) |
| 326 | 326 | return ret; |
| 327 | 327 | |
| 328 | − return drm_panel_add(&sharp->base); | |
| 328 | + drm_panel_add(&sharp->base); | |
| 329 | + | |
| 330 | + return 0; | |
| 329 | 331 | } |
| 330 | 332 | |
| 331 | 333 | static void sharp_panel_del(struct sharp_panel *sharp) |
| @@ -187,7 +187,9 @@ static int ls037v7dw01_probe(struct platform_device *pdev) · 186 unmodified lines | ||
| 187 | 187 | drm_panel_init(&lcd->panel, &pdev->dev, &ls037v7dw01_funcs, |
| 188 | 188 | DRM_MODE_CONNECTOR_DPI); |
| 189 | 189 | |
| 190 | − return drm_panel_add(&lcd->panel); | |
| 190 | + drm_panel_add(&lcd->panel); | |
| 191 | + | |
| 192 | + return 0; | |
| 191 | 193 | } |
| 192 | 194 | |
| 193 | 195 | static int ls037v7dw01_remove(struct platform_device *pdev) |
| @@ -261,7 +261,9 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt) · 260 unmodified lines | ||
| 261 | 261 | if (ret) |
| 262 | 262 | return ret; |
| 263 | 263 | |
| 264 | − return drm_panel_add(&sharp_nt->base); | |
| 264 | + drm_panel_add(&sharp_nt->base); | |
| 265 | + | |
| 266 | + return 0; | |
| 265 | 267 | } |
| 266 | 268 | |
| 267 | 269 | static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt) |
| @@ -112,6 +112,8 @@ struct panel_simple { · 111 unmodified lines | ||
| 112 | 112 | struct gpio_desc *hpd_gpio; |
| 113 | 113 | |
| 114 | 114 | struct drm_display_mode override_mode; |
| 115 | + | |
| 116 | + enum drm_panel_orientation orientation; | |
| 115 | 117 | }; |
| 116 | 118 | |
| 117 | 119 | static inline struct panel_simple *to_panel_simple(struct drm_panel *panel) |
| @@ -371,6 +373,9 @@ static int panel_simple_get_modes(struct drm_panel *panel, · 253 unmodified lines | ||
| 371 | 373 | /* add hard-coded panel modes */ |
| 372 | 374 | num += panel_simple_get_non_edid_modes(p, connector); |
| 373 | 375 | |
| 376 | + /* set up connector's "panel orientation" property */ | |
| 377 | + drm_connector_set_panel_orientation(connector, p->orientation); | |
| 378 | + | |
| 374 | 379 | return num; |
| 375 | 380 | } |
| 376 | 381 | |
| @@ -500,6 +505,8 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) · 123 unmodified lines | ||
| 500 | 505 | struct panel_simple *panel; |
| 501 | 506 | struct display_timing dt; |
| 502 | 507 | struct device_node *ddc; |
| 508 | + int connector_type; | |
| 509 | + u32 bus_flags; | |
| 503 | 510 | int err; |
| 504 | 511 | |
| 505 | 512 | panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); |
| @@ -530,6 +537,12 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) · 24 unmodified lines | ||
| 530 | 537 | return err; |
| 531 | 538 | } |
| 532 | 539 | |
| 540 | + err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation); | |
| 541 | + if (err) { | |
| 542 | + dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err); | |
| 543 | + return err; | |
| 544 | + } | |
| 545 | + | |
| 533 | 546 | ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0); |
| 534 | 547 | if (ddc) { |
| 535 | 548 | panel->ddc = of_find_i2c_adapter_by_node(ddc); |
| @@ -549,8 +562,14 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) · 13 unmodified lines | ||
| 549 | 562 | panel_simple_parse_panel_timing_node(dev, panel, &dt); |
| 550 | 563 | } |
| 551 | 564 | |
| 552 | − if (desc->connector_type == DRM_MODE_CONNECTOR_LVDS) { | |
| 553 | − /* Catch common mistakes for LVDS panels. */ | |
| 565 | + connector_type = desc->connector_type; | |
| 566 | + /* Catch common mistakes for panels. */ | |
| 567 | + switch (connector_type) { | |
| 568 | + case 0: | |
| 569 | + dev_warn(dev, "Specify missing connector_type\n"); | |
| 570 | + connector_type = DRM_MODE_CONNECTOR_DPI; | |
| 571 | + break; | |
| 572 | + case DRM_MODE_CONNECTOR_LVDS: | |
| 554 | 573 | WARN_ON(desc->bus_flags & |
| 555 | 574 | ~(DRM_BUS_FLAG_DE_LOW | |
| 556 | 575 | DRM_BUS_FLAG_DE_HIGH | |
| @@ -564,18 +583,48 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) · 7 unmodified lines | ||
| 564 | 583 | WARN_ON((desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_SPWG || |
| 565 | 584 | desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA) && |
| 566 | 585 | desc->bpc != 8); |
| 586 | + break; | |
| 587 | + case DRM_MODE_CONNECTOR_eDP: | |
| 588 | + if (desc->bus_format == 0) | |
| 589 | + dev_warn(dev, "Specify missing bus_format\n"); | |
| 590 | + if (desc->bpc != 6 && desc->bpc != 8) | |
| 591 | + dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc); | |
| 592 | + break; | |
| 593 | + case DRM_MODE_CONNECTOR_DSI: | |
| 594 | + if (desc->bpc != 6 && desc->bpc != 8) | |
| 595 | + dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc); | |
| 596 | + break; | |
| 597 | + case DRM_MODE_CONNECTOR_DPI: | |
| 598 | + bus_flags = DRM_BUS_FLAG_DE_LOW | | |
| 599 | + DRM_BUS_FLAG_DE_HIGH | | |
| 600 | + DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE | | |
| 601 | + DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE | | |
| 602 | + DRM_BUS_FLAG_DATA_MSB_TO_LSB | | |
| 603 | + DRM_BUS_FLAG_DATA_LSB_TO_MSB | | |
| 604 | + DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE | | |
| 605 | + DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE; | |
| 606 | + if (desc->bus_flags & ~bus_flags) | |
| 607 | + dev_warn(dev, "Unexpected bus_flags(%d)\n", desc->bus_flags & ~bus_flags); | |
| 608 | + if (!(desc->bus_flags & bus_flags)) | |
| 609 | + dev_warn(dev, "Specify missing bus_flags\n"); | |
| 610 | + if (desc->bus_format == 0) | |
| 611 | + dev_warn(dev, "Specify missing bus_format\n"); | |
| 612 | + if (desc->bpc != 6 && desc->bpc != 8) | |
| 613 | + dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc); | |
| 614 | + break; | |
| 615 | + default: | |
| 616 | + dev_warn(dev, "Specify a valid connector_type: %d\n", desc->connector_type); | |
| 617 | + connector_type = DRM_MODE_CONNECTOR_DPI; | |
| 618 | + break; | |
| 567 | 619 | } |
| 568 | 620 | |
| 569 | − drm_panel_init(&panel->base, dev, &panel_simple_funcs, | |
| 570 | − desc->connector_type); | |
| 621 | + drm_panel_init(&panel->base, dev, &panel_simple_funcs, connector_type); | |
| 571 | 622 | |
| 572 | 623 | err = drm_panel_of_backlight(&panel->base); |
| 573 | 624 | if (err) |
| 574 | 625 | goto free_ddc; |
| 575 | 626 | |
| 576 | − err = drm_panel_add(&panel->base); | |
| 577 | − if (err < 0) | |
| 578 | − goto free_ddc; | |
| 627 | + drm_panel_add(&panel->base); | |
| 579 | 628 | |
| 580 | 629 | dev_set_drvdata(dev, panel); |
| 581 | 630 | |
| @@ -1191,10 +1240,14 @@ static const struct drm_display_mode boe_hv070wsa_mode = { · 609 unmodified lines | ||
| 1191 | 1240 | static const struct panel_desc boe_hv070wsa = { |
| 1192 | 1241 | .modes = &boe_hv070wsa_mode, |
| 1193 | 1242 | .num_modes = 1, |
| 1243 | + .bpc = 8, | |
| 1194 | 1244 | .size = { |
| 1195 | 1245 | .width = 154, |
| 1196 | 1246 | .height = 90, |
| 1197 | 1247 | }, |
| 1248 | + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, | |
| 1249 | + .bus_flags = DRM_BUS_FLAG_DE_HIGH, | |
| 1250 | + .connector_type = DRM_MODE_CONNECTOR_LVDS, | |
| 1198 | 1251 | }; |
| 1199 | 1252 | |
| 1200 | 1253 | static const struct drm_display_mode boe_nv101wxmn51_modes[] = { |
| @@ -1414,6 +1467,36 @@ static const struct panel_desc cdtech_s070wv95_ct16 = { · 213 unmodified lines | ||
| 1414 | 1467 | }, |
| 1415 | 1468 | }; |
| 1416 | 1469 | |
| 1470 | +static const struct display_timing chefree_ch101olhlwh_002_timing = { | |
| 1471 | + .pixelclock = { 68900000, 71100000, 73400000 }, | |
| 1472 | + .hactive = { 1280, 1280, 1280 }, | |
| 1473 | + .hfront_porch = { 65, 80, 95 }, | |
| 1474 | + .hback_porch = { 64, 79, 94 }, | |
| 1475 | + .hsync_len = { 1, 1, 1 }, | |
| 1476 | + .vactive = { 800, 800, 800 }, | |
| 1477 | + .vfront_porch = { 7, 11, 14 }, | |
| 1478 | + .vback_porch = { 7, 11, 14 }, | |
| 1479 | + .vsync_len = { 1, 1, 1 }, | |
| 1480 | + .flags = DISPLAY_FLAGS_DE_HIGH, | |
| 1481 | +}; | |
| 1482 | + | |
| 1483 | +static const struct panel_desc chefree_ch101olhlwh_002 = { | |
| 1484 | + .timings = &chefree_ch101olhlwh_002_timing, | |
| 1485 | + .num_timings = 1, | |
| 1486 | + .bpc = 8, | |
| 1487 | + .size = { | |
| 1488 | + .width = 217, | |
| 1489 | + .height = 135, | |
| 1490 | + }, | |
| 1491 | + .delay = { | |
| 1492 | + .enable = 200, | |
| 1493 | + .disable = 200, | |
| 1494 | + }, | |
| 1495 | + .bus_flags = DRM_BUS_FLAG_DE_HIGH, | |
| 1496 | + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, | |
| 1497 | + .connector_type = DRM_MODE_CONNECTOR_LVDS, | |
| 1498 | +}; | |
| 1499 | + | |
| 1417 | 1500 | static const struct drm_display_mode chunghwa_claa070wp03xg_mode = { |
| 1418 | 1501 | .clock = 66770, |
| 1419 | 1502 | .hdisplay = 800, |
| @@ -2258,6 +2341,34 @@ static const struct panel_desc ivo_m133nwf4_r0 = { · 838 unmodified lines | ||
| 2258 | 2341 | .connector_type = DRM_MODE_CONNECTOR_eDP, |
| 2259 | 2342 | }; |
| 2260 | 2343 | |
| 2344 | +static const struct drm_display_mode kingdisplay_kd116n21_30nv_a010_mode = { | |
| 2345 | + .clock = 81000, | |
| 2346 | + .hdisplay = 1366, | |
| 2347 | + .hsync_start = 1366 + 40, | |
| 2348 | + .hsync_end = 1366 + 40 + 32, | |
| 2349 | + .htotal = 1366 + 40 + 32 + 62, | |
| 2350 | + .vdisplay = 768, | |
| 2351 | + .vsync_start = 768 + 5, | |
| 2352 | + .vsync_end = 768 + 5 + 5, | |
| 2353 | + .vtotal = 768 + 5 + 5 + 122, | |
| 2354 | + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, | |
| 2355 | +}; | |
| 2356 | + | |
| 2357 | +static const struct panel_desc kingdisplay_kd116n21_30nv_a010 = { | |
| 2358 | + .modes = &kingdisplay_kd116n21_30nv_a010_mode, | |
| 2359 | + .num_modes = 1, | |
| 2360 | + .bpc = 6, | |
| 2361 | + .size = { | |
| 2362 | + .width = 256, | |
| 2363 | + .height = 144, | |
| 2364 | + }, | |
| 2365 | + .delay = { | |
| 2366 | + .hpd_absent_delay = 200, | |
| 2367 | + }, | |
| 2368 | + .bus_format = MEDIA_BUS_FMT_RGB666_1X18, | |
| 2369 | + .connector_type = DRM_MODE_CONNECTOR_eDP, | |
| 2370 | +}; | |
| 2371 | + | |
| 2261 | 2372 | static const struct display_timing koe_tx14d24vm1bpa_timing = { |
| 2262 | 2373 | .pixelclock = { 5580000, 5850000, 6200000 }, |
| 2263 | 2374 | .hactive = { 320, 320, 320 }, |
| @@ -2946,7 +3057,7 @@ static const struct panel_desc ortustech_com43h4m85ulc = { · 682 unmodified lines | ||
| 2946 | 3057 | .width = 56, |
| 2947 | 3058 | .height = 93, |
| 2948 | 3059 | }, |
| 2949 | − .bus_format = MEDIA_BUS_FMT_RGB888_1X24, | |
| 3060 | + .bus_format = MEDIA_BUS_FMT_RGB666_1X18, | |
| 2950 | 3061 | .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, |
| 2951 | 3062 | .connector_type = DRM_MODE_CONNECTOR_DPI, |
| 2952 | 3063 | }; |
| @@ -3000,6 +3111,31 @@ static const struct panel_desc pda_91_00156_a0 = { · 47 unmodified lines | ||
| 3000 | 3111 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, |
| 3001 | 3112 | }; |
| 3002 | 3113 | |
| 3114 | +static const struct drm_display_mode powertip_ph800480t013_idf02_mode = { | |
| 3115 | + .clock = 24750, | |
| 3116 | + .hdisplay = 800, | |
| 3117 | + .hsync_start = 800 + 54, | |
| 3118 | + .hsync_end = 800 + 54 + 2, | |
| 3119 | + .htotal = 800 + 54 + 2 + 44, | |
| 3120 | + .vdisplay = 480, | |
| 3121 | + .vsync_start = 480 + 49, | |
| 3122 | + .vsync_end = 480 + 49 + 2, | |
| 3123 | + .vtotal = 480 + 49 + 2 + 22, | |
| 3124 | +}; | |
| 3125 | + | |
| 3126 | +static const struct panel_desc powertip_ph800480t013_idf02 = { | |
| 3127 | + .modes = &powertip_ph800480t013_idf02_mode, | |
| 3128 | + .num_modes = 1, | |
| 3129 | + .size = { | |
| 3130 | + .width = 152, | |
| 3131 | + .height = 91, | |
| 3132 | + }, | |
| 3133 | + .bus_flags = DRM_BUS_FLAG_DE_HIGH | | |
| 3134 | + DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE | | |
| 3135 | + DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE, | |
| 3136 | + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, | |
| 3137 | + .connector_type = DRM_MODE_CONNECTOR_DPI, | |
| 3138 | +}; | |
| 3003 | 3139 | |
| 3004 | 3140 | static const struct drm_display_mode qd43003c0_40_mode = { |
| 3005 | 3141 | .clock = 9000, |
| @@ -3301,22 +3437,36 @@ static const struct panel_desc sharp_lq123p1jx31 = { · 295 unmodified lines | ||
| 3301 | 3437 | }, |
| 3302 | 3438 | }; |
| 3303 | 3439 | |
| 3304 | −static const struct display_timing sharp_ls020b1dd01d_timing = { | |
| 3305 | − .pixelclock = { 2000000, 4200000, 5000000 }, | |
| 3306 | − .hactive = { 240, 240, 240 }, | |
| 3307 | − .hfront_porch = { 66, 66, 66 }, | |
| 3308 | − .hback_porch = { 1, 1, 1 }, | |
| 3309 | − .hsync_len = { 1, 1, 1 }, | |
| 3310 | − .vactive = { 160, 160, 160 }, | |
| 3311 | − .vfront_porch = { 52, 52, 52 }, | |
| 3312 | − .vback_porch = { 6, 6, 6 }, | |
| 3313 | − .vsync_len = { 10, 10, 10 }, | |
| 3314 | − .flags = DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW, | |
| 3440 | +static const struct drm_display_mode sharp_ls020b1dd01d_modes[] = { | |
| 3441 | + { /* 50 Hz */ | |
| 3442 | + .clock = 3000, | |
| 3443 | + .hdisplay = 240, | |
| 3444 | + .hsync_start = 240 + 58, | |
| 3445 | + .hsync_end = 240 + 58 + 1, | |
| 3446 | + .htotal = 240 + 58 + 1 + 1, | |
| 3447 | + .vdisplay = 160, | |
| 3448 | + .vsync_start = 160 + 24, | |
| 3449 | + .vsync_end = 160 + 24 + 10, | |
| 3450 | + .vtotal = 160 + 24 + 10 + 6, | |
| 3451 | + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC, | |
| 3452 | + }, | |
| 3453 | + { /* 60 Hz */ | |
| 3454 | + .clock = 3000, | |
| 3455 | + .hdisplay = 240, | |
| 3456 | + .hsync_start = 240 + 8, | |
| 3457 | + .hsync_end = 240 + 8 + 1, | |
| 3458 | + .htotal = 240 + 8 + 1 + 1, | |
| 3459 | + .vdisplay = 160, | |
| 3460 | + .vsync_start = 160 + 24, | |
| 3461 | + .vsync_end = 160 + 24 + 10, | |
| 3462 | + .vtotal = 160 + 24 + 10 + 6, | |
| 3463 | + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC, | |
| 3464 | + }, | |
| 3315 | 3465 | }; |
| 3316 | 3466 | |
| 3317 | 3467 | static const struct panel_desc sharp_ls020b1dd01d = { |
| 3318 | − .timings = &sharp_ls020b1dd01d_timing, | |
| 3319 | − .num_timings = 1, | |
| 3468 | + .modes = sharp_ls020b1dd01d_modes, | |
| 3469 | + .num_modes = ARRAY_SIZE(sharp_ls020b1dd01d_modes), | |
| 3320 | 3470 | .bpc = 6, |
| 3321 | 3471 | .size = { |
| 3322 | 3472 | .width = 42, |
| @@ -3820,6 +3970,9 @@ static const struct of_device_id platform_of_match[] = { · 497 unmodified lines | ||
| 3820 | 3970 | }, { |
| 3821 | 3971 | .compatible = "cdtech,s070wv95-ct16", |
| 3822 | 3972 | .data = &cdtech_s070wv95_ct16, |
| 3973 | + }, { | |
| 3974 | + .compatible = "chefree,ch101olhlwh-002", | |
| 3975 | + .data = &chefree_ch101olhlwh_002, | |
| 3823 | 3976 | }, { |
| 3824 | 3977 | .compatible = "chunghwa,claa070wp03xg", |
| 3825 | 3978 | .data = &chunghwa_claa070wp03xg, |
| @@ -3922,6 +4075,9 @@ static const struct of_device_id platform_of_match[] = { · 96 unmodified lines | ||
| 3922 | 4075 | }, { |
| 3923 | 4076 | .compatible = "ivo,m133nwf4-r0", |
| 3924 | 4077 | .data = &ivo_m133nwf4_r0, |
| 4078 | + }, { | |
| 4079 | + .compatible = "kingdisplay,kd116n21-30nv-a010", | |
| 4080 | + .data = &kingdisplay_kd116n21_30nv_a010, | |
| 3925 | 4081 | }, { |
| 3926 | 4082 | .compatible = "koe,tx14d24vm1bpa", |
| 3927 | 4083 | .data = &koe_tx14d24vm1bpa, |
| @@ -4012,6 +4168,9 @@ static const struct of_device_id platform_of_match[] = { · 84 unmodified lines | ||
| 4012 | 4168 | }, { |
| 4013 | 4169 | .compatible = "pda,91-00156-a0", |
| 4014 | 4170 | .data = &pda_91_00156_a0, |
| 4171 | + }, { | |
| 4172 | + .compatible = "powertip,ph800480t013-idf02", | |
| 4173 | + .data = &powertip_ph800480t013_idf02, | |
| 4015 | 4174 | }, { |
| 4016 | 4175 | .compatible = "qiaodian,qd43003c0-40", |
| 4017 | 4176 | .data = &qd43003c0_40, |
| @@ -7,7 +7,6 @@ · 6 unmodified lines | ||
| 7 | 7 | #include <drm/drm_mipi_dsi.h> |
| 8 | 8 | #include <drm/drm_modes.h> |
| 9 | 9 | #include <drm/drm_panel.h> |
| 10 | −#include <drm/drm_print.h> | |
| 11 | 10 | |
| 12 | 11 | #include <linux/gpio/consumer.h> |
| 13 | 12 | #include <linux/delay.h> |
| @@ -269,10 +268,9 @@ static int st7701_get_modes(struct drm_panel *panel, · 255 unmodified lines | ||
| 269 | 268 | |
| 270 | 269 | mode = drm_mode_duplicate(connector->dev, desc_mode); |
| 271 | 270 | if (!mode) { |
| 272 | − DRM_DEV_ERROR(&st7701->dsi->dev, | |
| 273 | − "failed to add mode %ux%ux@%u\n", | |
| 274 | − desc_mode->hdisplay, desc_mode->vdisplay, | |
| 275 | − drm_mode_vrefresh(desc_mode)); | |
| 271 | + dev_err(&st7701->dsi->dev, "failed to add mode %ux%u@%u\n", | |
| 272 | + desc_mode->hdisplay, desc_mode->vdisplay, | |
| 273 | + drm_mode_vrefresh(desc_mode)); | |
| 276 | 274 | return -ENOMEM; |
| 277 | 275 | } |
| 278 | 276 | |
| @@ -358,7 +356,7 @@ static int st7701_dsi_probe(struct mipi_dsi_device *dsi) · 79 unmodified lines | ||
| 358 | 356 | |
| 359 | 357 | st7701->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); |
| 360 | 358 | if (IS_ERR(st7701->reset)) { |
| 361 | − DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n"); | |
| 359 | + dev_err(&dsi->dev, "Couldn't get our reset GPIO\n"); | |
| 362 | 360 | return PTR_ERR(st7701->reset); |
| 363 | 361 | } |
| 364 | 362 | |
| @@ -380,9 +378,7 @@ static int st7701_dsi_probe(struct mipi_dsi_device *dsi) · 15 unmodified lines | ||
| 380 | 378 | if (ret) |
| 381 | 379 | return ret; |
| 382 | 380 | |
| 383 | − ret = drm_panel_add(&st7701->panel); | |
| 384 | − if (ret < 0) | |
| 385 | − return ret; | |
| 381 | + drm_panel_add(&st7701->panel); | |
| 386 | 382 | |
| 387 | 383 | mipi_dsi_set_drvdata(dsi, st7701); |
| 388 | 384 | st7701->dsi = dsi; |
| @@ -22,7 +22,6 @@ · 21 unmodified lines | ||
| 22 | 22 | #include <drm/drm_mipi_dsi.h> |
| 23 | 23 | #include <drm/drm_modes.h> |
| 24 | 24 | #include <drm/drm_panel.h> |
| 25 | −#include <drm/drm_print.h> | |
| 26 | 25 | |
| 27 | 26 | #define DRV_NAME "panel-sitronix-st7703" |
| 28 | 27 | |
| @@ -364,8 +363,7 @@ static int st7703_enable(struct drm_panel *panel) · 335 unmodified lines | ||
| 364 | 363 | |
| 365 | 364 | ret = ctx->desc->init_sequence(ctx); |
| 366 | 365 | if (ret < 0) { |
| 367 | − DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", | |
| 368 | − ret); | |
| 366 | + dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); | |
| 369 | 367 | return ret; |
| 370 | 368 | } |
| 371 | 369 | |
| @@ -373,7 +371,7 @@ static int st7703_enable(struct drm_panel *panel) · 1 unmodified line | ||
| 373 | 371 | |
| 374 | 372 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 375 | 373 | if (ret < 0) { |
| 376 | − DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret); | |
| 374 | + dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret); | |
| 377 | 375 | return ret; |
| 378 | 376 | } |
| 379 | 377 | |
| @@ -384,7 +382,7 @@ static int st7703_enable(struct drm_panel *panel) · 4 unmodified lines | ||
| 384 | 382 | if (ret) |
| 385 | 383 | return ret; |
| 386 | 384 | |
| 387 | − DRM_DEV_DEBUG_DRIVER(ctx->dev, "Panel init sequence done\n"); | |
| 385 | + dev_dbg(ctx->dev, "Panel init sequence done\n"); | |
| 388 | 386 | |
| 389 | 387 | return 0; |
| 390 | 388 | } |
| @@ -397,13 +395,11 @@ static int st7703_disable(struct drm_panel *panel) · 6 unmodified lines | ||
| 397 | 395 | |
| 398 | 396 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 399 | 397 | if (ret < 0) |
| 400 | − DRM_DEV_ERROR(ctx->dev, | |
| 401 | − "Failed to turn off the display: %d\n", ret); | |
| 398 | + dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret); | |
| 402 | 399 | |
| 403 | 400 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 404 | 401 | if (ret < 0) |
| 405 | − DRM_DEV_ERROR(ctx->dev, | |
| 406 | − "Failed to enter sleep mode: %d\n", ret); | |
| 402 | + dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret); | |
| 407 | 403 | |
| 408 | 404 | return 0; |
| 409 | 405 | } |
| @@ -431,17 +427,15 @@ static int st7703_prepare(struct drm_panel *panel) · 21 unmodified lines | ||
| 431 | 427 | if (ctx->prepared) |
| 432 | 428 | return 0; |
| 433 | 429 | |
| 434 | − DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n"); | |
| 430 | + dev_dbg(ctx->dev, "Resetting the panel\n"); | |
| 435 | 431 | ret = regulator_enable(ctx->vcc); |
| 436 | 432 | if (ret < 0) { |
| 437 | − DRM_DEV_ERROR(ctx->dev, | |
| 438 | − "Failed to enable vcc supply: %d\n", ret); | |
| 433 | + dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret); | |
| 439 | 434 | return ret; |
| 440 | 435 | } |
| 441 | 436 | ret = regulator_enable(ctx->iovcc); |
| 442 | 437 | if (ret < 0) { |
| 443 | − DRM_DEV_ERROR(ctx->dev, | |
| 444 | − "Failed to enable iovcc supply: %d\n", ret); | |
| 438 | + dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); | |
| 445 | 439 | goto disable_vcc; |
| 446 | 440 | } |
| 447 | 441 | |
| @@ -467,9 +461,9 @@ static int st7703_get_modes(struct drm_panel *panel, · 19 unmodified lines | ||
| 467 | 461 | |
| 468 | 462 | mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); |
| 469 | 463 | if (!mode) { |
| 470 | − DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n", | |
| 471 | − ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, | |
| 472 | − drm_mode_vrefresh(ctx->desc->mode)); | |
| 464 | + dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", | |
| 465 | + ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, | |
| 466 | + drm_mode_vrefresh(ctx->desc->mode)); | |
| 473 | 467 | return -ENOMEM; |
| 474 | 468 | } |
| 475 | 469 | |
| @@ -496,7 +490,7 @@ static int allpixelson_set(void *data, u64 val) · 20 unmodified lines | ||
| 496 | 490 | struct st7703 *ctx = data; |
| 497 | 491 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); |
| 498 | 492 | |
| 499 | − DRM_DEV_DEBUG_DRIVER(ctx->dev, "Setting all pixels on\n"); | |
| 493 | + dev_dbg(ctx->dev, "Setting all pixels on\n"); | |
| 500 | 494 | dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON); |
| 501 | 495 | msleep(val * 1000); |
| 502 | 496 | /* Reset the panel to get video back */ |
| @@ -537,7 +531,7 @@ static int st7703_probe(struct mipi_dsi_device *dsi) · 34 unmodified lines | ||
| 537 | 531 | |
| 538 | 532 | ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); |
| 539 | 533 | if (IS_ERR(ctx->reset_gpio)) { |
| 540 | − DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); | |
| 534 | + dev_err(dev, "cannot get reset gpio\n"); | |
| 541 | 535 | return PTR_ERR(ctx->reset_gpio); |
| 542 | 536 | } |
| 543 | 537 | |
| @@ -554,18 +548,14 @@ static int st7703_probe(struct mipi_dsi_device *dsi) · 10 unmodified lines | ||
| 554 | 548 | if (IS_ERR(ctx->vcc)) { |
| 555 | 549 | ret = PTR_ERR(ctx->vcc); |
| 556 | 550 | if (ret != -EPROBE_DEFER) |
| 557 | − DRM_DEV_ERROR(dev, | |
| 558 | − "Failed to request vcc regulator: %d\n", | |
| 559 | − ret); | |
| 551 | + dev_err(dev, "Failed to request vcc regulator: %d\n", ret); | |
| 560 | 552 | return ret; |
| 561 | 553 | } |
| 562 | 554 | ctx->iovcc = devm_regulator_get(dev, "iovcc"); |
| 563 | 555 | if (IS_ERR(ctx->iovcc)) { |
| 564 | 556 | ret = PTR_ERR(ctx->iovcc); |
| 565 | 557 | if (ret != -EPROBE_DEFER) |
| 566 | − DRM_DEV_ERROR(dev, | |
| 567 | − "Failed to request iovcc regulator: %d\n", | |
| 568 | − ret); | |
| 558 | + dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); | |
| 569 | 559 | return ret; |
| 570 | 560 | } |
| 571 | 561 | |
| @@ -580,17 +570,15 @@ static int st7703_probe(struct mipi_dsi_device *dsi) · 8 unmodified lines | ||
| 580 | 570 | |
| 581 | 571 | ret = mipi_dsi_attach(dsi); |
| 582 | 572 | if (ret < 0) { |
| 583 | − DRM_DEV_ERROR(dev, | |
| 584 | − "mipi_dsi_attach failed (%d). Is host ready?\n", | |
| 585 | − ret); | |
| 573 | + dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret); | |
| 586 | 574 | drm_panel_remove(&ctx->panel); |
| 587 | 575 | return ret; |
| 588 | 576 | } |
| 589 | 577 | |
| 590 | − DRM_DEV_INFO(dev, "%ux%u@%u %ubpp dsi %udl - ready\n", | |
| 591 | − ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, | |
| 592 | − drm_mode_vrefresh(ctx->desc->mode), | |
| 593 | − mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); | |
| 578 | + dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n", | |
| 579 | + ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, | |
| 580 | + drm_mode_vrefresh(ctx->desc->mode), | |
| 581 | + mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); | |
| 594 | 582 | |
| 595 | 583 | st7703_debugfs_init(ctx); |
| 596 | 584 | return 0; |
| @@ -603,13 +591,11 @@ static void st7703_shutdown(struct mipi_dsi_device *dsi) · 6 unmodified lines | ||
| 603 | 591 | |
| 604 | 592 | ret = drm_panel_unprepare(&ctx->panel); |
| 605 | 593 | if (ret < 0) |
| 606 | − DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", | |
| 607 | − ret); | |
| 594 | + dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); | |
| 608 | 595 | |
| 609 | 596 | ret = drm_panel_disable(&ctx->panel); |
| 610 | 597 | if (ret < 0) |
| 611 | − DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", | |
| 612 | − ret); | |
| 598 | + dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); | |
| 613 | 599 | } |
| 614 | 600 | |
| 615 | 601 | static int st7703_remove(struct mipi_dsi_device *dsi) |
| @@ -621,8 +607,7 @@ static int st7703_remove(struct mipi_dsi_device *dsi) · 5 unmodified lines | ||
| 621 | 607 | |
| 622 | 608 | ret = mipi_dsi_detach(dsi); |
| 623 | 609 | if (ret < 0) |
| 624 | − DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", | |
| 625 | − ret); | |
| 610 | + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); | |
| 626 | 611 | |
| 627 | 612 | drm_panel_remove(&ctx->panel); |
| 628 | 613 | |
| @@ -382,9 +382,7 @@ static int st7789v_probe(struct spi_device *spi) · 381 unmodified lines | ||
| 382 | 382 | if (ret) |
| 383 | 383 | return ret; |
| 384 | 384 | |
| 385 | − ret = drm_panel_add(&ctx->panel); | |
| 386 | − if (ret < 0) | |
| 387 | − return ret; | |
| 385 | + drm_panel_add(&ctx->panel); | |
| 388 | 386 | |
| 389 | 387 | return 0; |
| 390 | 388 | } |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <drm/drm_mipi_dsi.h> |
| 21 | 21 | #include <drm/drm_modes.h> |
| 22 | 22 | #include <drm/drm_panel.h> |
| 23 | −#include <drm/drm_print.h> | |
| 24 | 23 | |
| 25 | 24 | #define ACX424_DCS_READ_ID1 0xDA |
| 26 | 25 | #define ACX424_DCS_READ_ID2 0xDB |
| @@ -110,13 +109,11 @@ static int acx424akp_set_brightness(struct backlight_device *bl) · 83 unmodified lines | ||
| 110 | 109 | SCALE_FACTOR_NS_DIV_MHZ); |
| 111 | 110 | |
| 112 | 111 | /* Set up PWM dutycycle ONE byte (differs from the standard) */ |
| 113 | − DRM_DEV_DEBUG(acx->dev, "calculated duty cycle %02x\n", pwm_ratio); | |
| 112 | + dev_dbg(acx->dev, "calculated duty cycle %02x\n", pwm_ratio); | |
| 114 | 113 | ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, |
| 115 | 114 | &pwm_ratio, 1); |
| 116 | 115 | if (ret < 0) { |
| 117 | − DRM_DEV_ERROR(acx->dev, | |
| 118 | − "failed to set display PWM ratio (%d)\n", | |
| 119 | − ret); | |
| 116 | + dev_err(acx->dev, "failed to set display PWM ratio (%d)\n", ret); | |
| 120 | 117 | return ret; |
| 121 | 118 | } |
| 122 | 119 | |
| @@ -132,40 +129,30 @@ static int acx424akp_set_brightness(struct backlight_device *bl) · 9 unmodified lines | ||
| 132 | 129 | par = 0xaa; |
| 133 | 130 | ret = mipi_dsi_dcs_write(dsi, 0xf3, &par, 1); |
| 134 | 131 | if (ret < 0) { |
| 135 | − DRM_DEV_ERROR(acx->dev, | |
| 136 | − "failed to unlock CMD 2 (%d)\n", | |
| 137 | − ret); | |
| 132 | + dev_err(acx->dev, "failed to unlock CMD 2 (%d)\n", ret); | |
| 138 | 133 | return ret; |
| 139 | 134 | } |
| 140 | 135 | par = 0x01; |
| 141 | 136 | ret = mipi_dsi_dcs_write(dsi, 0x00, &par, 1); |
| 142 | 137 | if (ret < 0) { |
| 143 | − DRM_DEV_ERROR(acx->dev, | |
| 144 | − "failed to enter page 1 (%d)\n", | |
| 145 | − ret); | |
| 138 | + dev_err(acx->dev, "failed to enter page 1 (%d)\n", ret); | |
| 146 | 139 | return ret; |
| 147 | 140 | } |
| 148 | 141 | par = 0x01; |
| 149 | 142 | ret = mipi_dsi_dcs_write(dsi, 0x7d, &par, 1); |
| 150 | 143 | if (ret < 0) { |
| 151 | − DRM_DEV_ERROR(acx->dev, | |
| 152 | − "failed to disable MTP reload (%d)\n", | |
| 153 | − ret); | |
| 144 | + dev_err(acx->dev, "failed to disable MTP reload (%d)\n", ret); | |
| 154 | 145 | return ret; |
| 155 | 146 | } |
| 156 | 147 | ret = mipi_dsi_dcs_write(dsi, 0x22, &pwm_div, 1); |
| 157 | 148 | if (ret < 0) { |
| 158 | − DRM_DEV_ERROR(acx->dev, | |
| 159 | − "failed to set PWM divisor (%d)\n", | |
| 160 | − ret); | |
| 149 | + dev_err(acx->dev, "failed to set PWM divisor (%d)\n", ret); | |
| 161 | 150 | return ret; |
| 162 | 151 | } |
| 163 | 152 | par = 0xaa; |
| 164 | 153 | ret = mipi_dsi_dcs_write(dsi, 0x7f, &par, 1); |
| 165 | 154 | if (ret < 0) { |
| 166 | − DRM_DEV_ERROR(acx->dev, | |
| 167 | − "failed to lock CMD 2 (%d)\n", | |
| 168 | − ret); | |
| 155 | + dev_err(acx->dev, "failed to lock CMD 2 (%d)\n", ret); | |
| 169 | 156 | return ret; |
| 170 | 157 | } |
| 171 | 158 | |
| @@ -174,9 +161,7 @@ static int acx424akp_set_brightness(struct backlight_device *bl) · 2 unmodified lines | ||
| 174 | 161 | ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, |
| 175 | 162 | &par, 1); |
| 176 | 163 | if (ret < 0) { |
| 177 | − DRM_DEV_ERROR(acx->dev, | |
| 178 | − "failed to enable display backlight (%d)\n", | |
| 179 | − ret); | |
| 164 | + dev_err(acx->dev, "failed to enable display backlight (%d)\n", ret); | |
| 180 | 165 | return ret; |
| 181 | 166 | } |
| 182 | 167 | |
| @@ -196,22 +181,22 @@ static int acx424akp_read_id(struct acx424akp *acx) · 13 unmodified lines | ||
| 196 | 181 | |
| 197 | 182 | ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID1, &vendor, 1); |
| 198 | 183 | if (ret < 0) { |
| 199 | − DRM_DEV_ERROR(acx->dev, "could not vendor ID byte\n"); | |
| 184 | + dev_err(acx->dev, "could not vendor ID byte\n"); | |
| 200 | 185 | return ret; |
| 201 | 186 | } |
| 202 | 187 | ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID2, &version, 1); |
| 203 | 188 | if (ret < 0) { |
| 204 | − DRM_DEV_ERROR(acx->dev, "could not read device version byte\n"); | |
| 189 | + dev_err(acx->dev, "could not read device version byte\n"); | |
| 205 | 190 | return ret; |
| 206 | 191 | } |
| 207 | 192 | ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID3, &panel, 1); |
| 208 | 193 | if (ret < 0) { |
| 209 | − DRM_DEV_ERROR(acx->dev, "could not read panel ID byte\n"); | |
| 194 | + dev_err(acx->dev, "could not read panel ID byte\n"); | |
| 210 | 195 | return ret; |
| 211 | 196 | } |
| 212 | 197 | |
| 213 | 198 | if (vendor == 0x00) { |
| 214 | − DRM_DEV_ERROR(acx->dev, "device vendor ID is zero\n"); | |
| 199 | + dev_err(acx->dev, "device vendor ID is zero\n"); | |
| 215 | 200 | return -ENODEV; |
| 216 | 201 | } |
| 217 | 202 | |
| @@ -220,14 +205,12 @@ static int acx424akp_read_id(struct acx424akp *acx) · 2 unmodified lines | ||
| 220 | 205 | case DISPLAY_SONY_ACX424AKP_ID1: |
| 221 | 206 | case DISPLAY_SONY_ACX424AKP_ID2: |
| 222 | 207 | case DISPLAY_SONY_ACX424AKP_ID3: |
| 223 | − DRM_DEV_INFO(acx->dev, | |
| 224 | − "MTP vendor: %02x, version: %02x, panel: %02x\n", | |
| 225 | − vendor, version, panel); | |
| 208 | + dev_info(acx->dev, "MTP vendor: %02x, version: %02x, panel: %02x\n", | |
| 209 | + vendor, version, panel); | |
| 226 | 210 | break; |
| 227 | 211 | default: |
| 228 | − DRM_DEV_INFO(acx->dev, | |
| 229 | − "unknown vendor: %02x, version: %02x, panel: %02x\n", | |
| 230 | − vendor, version, panel); | |
| 212 | + dev_info(acx->dev, "unknown vendor: %02x, version: %02x, panel: %02x\n", | |
| 213 | + vendor, version, panel); | |
| 231 | 214 | break; |
| 232 | 215 | } |
| 233 | 216 | |
| @@ -240,7 +223,7 @@ static int acx424akp_power_on(struct acx424akp *acx) · 6 unmodified lines | ||
| 240 | 223 | |
| 241 | 224 | ret = regulator_enable(acx->supply); |
| 242 | 225 | if (ret) { |
| 243 | − DRM_DEV_ERROR(acx->dev, "failed to enable supply (%d)\n", ret); | |
| 226 | + dev_err(acx->dev, "failed to enable supply (%d)\n", ret); | |
| 244 | 227 | return ret; |
| 245 | 228 | } |
| 246 | 229 | |
| @@ -276,7 +259,7 @@ static int acx424akp_prepare(struct drm_panel *panel) · 29 unmodified lines | ||
| 276 | 259 | |
| 277 | 260 | ret = acx424akp_read_id(acx); |
| 278 | 261 | if (ret) { |
| 279 | − DRM_DEV_ERROR(acx->dev, "failed to read panel ID (%d)\n", ret); | |
| 262 | + dev_err(acx->dev, "failed to read panel ID (%d)\n", ret); | |
| 280 | 263 | goto err_power_off; |
| 281 | 264 | } |
| 282 | 265 | |
| @@ -284,8 +267,7 @@ static int acx424akp_prepare(struct drm_panel *panel) · 1 unmodified line | ||
| 284 | 267 | ret = mipi_dsi_dcs_set_tear_on(dsi, |
| 285 | 268 | MIPI_DSI_DCS_TEAR_MODE_VBLANK); |
| 286 | 269 | if (ret) { |
| 287 | − DRM_DEV_ERROR(acx->dev, "failed to enable vblank TE (%d)\n", | |
| 288 | − ret); | |
| 270 | + dev_err(acx->dev, "failed to enable vblank TE (%d)\n", ret); | |
| 289 | 271 | goto err_power_off; |
| 290 | 272 | } |
| 291 | 273 | |
| @@ -302,23 +284,21 @@ static int acx424akp_prepare(struct drm_panel *panel) · 10 unmodified lines | ||
| 302 | 284 | ret = mipi_dsi_dcs_write(dsi, ACX424_DCS_SET_MDDI, |
| 303 | 285 | &mddi, sizeof(mddi)); |
| 304 | 286 | if (ret < 0) { |
| 305 | − DRM_DEV_ERROR(acx->dev, "failed to set MDDI (%d)\n", ret); | |
| 287 | + dev_err(acx->dev, "failed to set MDDI (%d)\n", ret); | |
| 306 | 288 | goto err_power_off; |
| 307 | 289 | } |
| 308 | 290 | |
| 309 | 291 | /* Exit sleep mode */ |
| 310 | 292 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 311 | 293 | if (ret) { |
| 312 | − DRM_DEV_ERROR(acx->dev, "failed to exit sleep mode (%d)\n", | |
| 313 | − ret); | |
| 294 | + dev_err(acx->dev, "failed to exit sleep mode (%d)\n", ret); | |
| 314 | 295 | goto err_power_off; |
| 315 | 296 | } |
| 316 | 297 | msleep(140); |
| 317 | 298 | |
| 318 | 299 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 319 | 300 | if (ret) { |
| 320 | − DRM_DEV_ERROR(acx->dev, "failed to turn display on (%d)\n", | |
| 321 | − ret); | |
| 301 | + dev_err(acx->dev, "failed to turn display on (%d)\n", ret); | |
| 322 | 302 | goto err_power_off; |
| 323 | 303 | } |
| 324 | 304 | if (acx->video_mode) { |
| @@ -351,24 +331,20 @@ static int acx424akp_unprepare(struct drm_panel *panel) · 26 unmodified lines | ||
| 351 | 331 | ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, |
| 352 | 332 | &par, 1); |
| 353 | 333 | if (ret) { |
| 354 | − DRM_DEV_ERROR(acx->dev, | |
| 355 | − "failed to disable display backlight (%d)\n", | |
| 356 | − ret); | |
| 334 | + dev_err(acx->dev, "failed to disable display backlight (%d)\n", ret); | |
| 357 | 335 | return ret; |
| 358 | 336 | } |
| 359 | 337 | |
| 360 | 338 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 361 | 339 | if (ret) { |
| 362 | − DRM_DEV_ERROR(acx->dev, "failed to turn display off (%d)\n", | |
| 363 | − ret); | |
| 340 | + dev_err(acx->dev, "failed to turn display off (%d)\n", ret); | |
| 364 | 341 | return ret; |
| 365 | 342 | } |
| 366 | 343 | |
| 367 | 344 | /* Enter sleep mode */ |
| 368 | 345 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 369 | 346 | if (ret) { |
| 370 | − DRM_DEV_ERROR(acx->dev, "failed to enter sleep mode (%d)\n", | |
| 371 | − ret); | |
| 347 | + dev_err(acx->dev, "failed to enter sleep mode (%d)\n", ret); | |
| 372 | 348 | return ret; |
| 373 | 349 | } |
| 374 | 350 | msleep(85); |
| @@ -418,7 +394,7 @@ static int acx424akp_get_modes(struct drm_panel *panel, · 43 unmodified lines | ||
| 418 | 394 | mode = drm_mode_duplicate(connector->dev, |
| 419 | 395 | &sony_acx424akp_cmd_mode); |
| 420 | 396 | if (!mode) { |
| 421 | − DRM_ERROR("bad mode or failed to add mode\n"); | |
| 397 | + dev_err(panel->dev, "bad mode or failed to add mode\n"); | |
| 422 | 398 | return -EINVAL; |
| 423 | 399 | } |
| 424 | 400 | drm_mode_set_name(mode); |
| @@ -486,8 +462,7 @@ static int acx424akp_probe(struct mipi_dsi_device *dsi) · 61 unmodified lines | ||
| 486 | 462 | if (IS_ERR(acx->reset_gpio)) { |
| 487 | 463 | ret = PTR_ERR(acx->reset_gpio); |
| 488 | 464 | if (ret != -EPROBE_DEFER) |
| 489 | − DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n", | |
| 490 | − ret); | |
| 465 | + dev_err(dev, "failed to request GPIO (%d)\n", ret); | |
| 491 | 466 | return ret; |
| 492 | 467 | } |
| 493 | 468 | |
| @@ -497,16 +472,14 @@ static int acx424akp_probe(struct mipi_dsi_device *dsi) · 3 unmodified lines | ||
| 497 | 472 | acx->bl = devm_backlight_device_register(dev, "acx424akp", dev, acx, |
| 498 | 473 | &acx424akp_bl_ops, NULL); |
| 499 | 474 | if (IS_ERR(acx->bl)) { |
| 500 | − DRM_DEV_ERROR(dev, "failed to register backlight device\n"); | |
| 475 | + dev_err(dev, "failed to register backlight device\n"); | |
| 501 | 476 | return PTR_ERR(acx->bl); |
| 502 | 477 | } |
| 503 | 478 | acx->bl->props.max_brightness = 1023; |
| 504 | 479 | acx->bl->props.brightness = 512; |
| 505 | 480 | acx->bl->props.power = FB_BLANK_POWERDOWN; |
| 506 | 481 | |
| 507 | − ret = drm_panel_add(&acx->panel); | |
| 508 | − if (ret < 0) | |
| 509 | − return ret; | |
| 482 | + drm_panel_add(&acx->panel); | |
| 510 | 483 | |
| 511 | 484 | ret = mipi_dsi_attach(dsi); |
| 512 | 485 | if (ret < 0) { |
| @@ -650,12 +650,7 @@ static int acx565akm_probe(struct spi_device *spi) · 649 unmodified lines | ||
| 650 | 650 | drm_panel_init(&lcd->panel, &lcd->spi->dev, &acx565akm_funcs, |
| 651 | 651 | DRM_MODE_CONNECTOR_DPI); |
| 652 | 652 | |
| 653 | − ret = drm_panel_add(&lcd->panel); | |
| 654 | − if (ret < 0) { | |
| 655 | − if (lcd->has_bc) | |
| 656 | − acx565akm_backlight_cleanup(lcd); | |
| 657 | − return ret; | |
| 658 | − } | |
| 653 | + drm_panel_add(&lcd->panel); | |
| 659 | 654 | |
| 660 | 655 | return 0; |
| 661 | 656 | } |
| @@ -350,7 +350,9 @@ static int td028ttec1_probe(struct spi_device *spi) · 349 unmodified lines | ||
| 350 | 350 | if (ret) |
| 351 | 351 | return ret; |
| 352 | 352 | |
| 353 | − return drm_panel_add(&lcd->panel); | |
| 353 | + drm_panel_add(&lcd->panel); | |
| 354 | + | |
| 355 | + return 0; | |
| 354 | 356 | } |
| 355 | 357 | |
| 356 | 358 | static int td028ttec1_remove(struct spi_device *spi) |
| @@ -460,11 +460,7 @@ static int td043mtea1_probe(struct spi_device *spi) · 459 unmodified lines | ||
| 460 | 460 | drm_panel_init(&lcd->panel, &lcd->spi->dev, &td043mtea1_funcs, |
| 461 | 461 | DRM_MODE_CONNECTOR_DPI); |
| 462 | 462 | |
| 463 | − ret = drm_panel_add(&lcd->panel); | |
| 464 | − if (ret < 0) { | |
| 465 | − sysfs_remove_group(&spi->dev.kobj, &td043mtea1_attr_group); | |
| 466 | − return ret; | |
| 467 | − } | |
| 463 | + drm_panel_add(&lcd->panel); | |
| 468 | 464 | |
| 469 | 465 | return 0; |
| 470 | 466 | } |
| @@ -12,7 +12,6 @@ · 11 unmodified lines | ||
| 12 | 12 | */ |
| 13 | 13 | #include <drm/drm_modes.h> |
| 14 | 14 | #include <drm/drm_panel.h> |
| 15 | −#include <drm/drm_print.h> | |
| 16 | 15 | |
| 17 | 16 | #include <linux/bitops.h> |
| 18 | 17 | #include <linux/delay.h> |
| @@ -238,7 +237,7 @@ static u8 tpg110_readwrite_reg(struct tpg110 *tpg, bool write, · 219 unmodified lines | ||
| 238 | 237 | spi_message_add_tail(&t[1], &m); |
| 239 | 238 | ret = spi_sync(tpg->spi, &m); |
| 240 | 239 | if (ret) { |
| 241 | − DRM_DEV_ERROR(tpg->dev, "SPI message error %d\n", ret); | |
| 240 | + dev_err(tpg->dev, "SPI message error %d\n", ret); | |
| 242 | 241 | return ret; |
| 243 | 242 | } |
| 244 | 243 | if (write) |
| @@ -265,18 +264,18 @@ static int tpg110_startup(struct tpg110 *tpg) · 20 unmodified lines | ||
| 265 | 264 | /* De-assert the reset signal */ |
| 266 | 265 | gpiod_set_value_cansleep(tpg->grestb, 0); |
| 267 | 266 | usleep_range(1000, 2000); |
| 268 | − DRM_DEV_DEBUG(tpg->dev, "de-asserted GRESTB\n"); | |
| 267 | + dev_dbg(tpg->dev, "de-asserted GRESTB\n"); | |
| 269 | 268 | |
| 270 | 269 | /* Test display communication */ |
| 271 | 270 | tpg110_write_reg(tpg, TPG110_TEST, 0x55); |
| 272 | 271 | val = tpg110_read_reg(tpg, TPG110_TEST); |
| 273 | 272 | if (val != 0x55) { |
| 274 | − DRM_DEV_ERROR(tpg->dev, "failed communication test\n"); | |
| 273 | + dev_err(tpg->dev, "failed communication test\n"); | |
| 275 | 274 | return -ENODEV; |
| 276 | 275 | } |
| 277 | 276 | |
| 278 | 277 | val = tpg110_read_reg(tpg, TPG110_CHIPID); |
| 279 | − DRM_DEV_INFO(tpg->dev, "TPG110 chip ID: %d version: %d\n", | |
| 278 | + dev_info(tpg->dev, "TPG110 chip ID: %d version: %d\n", | |
| 280 | 279 | val >> 4, val & 0x0f); |
| 281 | 280 | |
| 282 | 281 | /* Show display resolution */ |
| @@ -284,27 +283,25 @@ static int tpg110_startup(struct tpg110 *tpg) · 1 unmodified line | ||
| 284 | 283 | val &= TPG110_RES_MASK; |
| 285 | 284 | switch (val) { |
| 286 | 285 | case TPG110_RES_400X240_D: |
| 287 | − DRM_DEV_INFO(tpg->dev, | |
| 288 | − "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)\n"); | |
| 286 | + dev_info(tpg->dev, "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)\n"); | |
| 289 | 287 | break; |
| 290 | 288 | case TPG110_RES_480X272_D: |
| 291 | − DRM_DEV_INFO(tpg->dev, | |
| 292 | − "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)\n"); | |
| 289 | + dev_info(tpg->dev, "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)\n"); | |
| 293 | 290 | break; |
| 294 | 291 | case TPG110_RES_480X640: |
| 295 | − DRM_DEV_INFO(tpg->dev, "480x640 RGB\n"); | |
| 292 | + dev_info(tpg->dev, "480x640 RGB\n"); | |
| 296 | 293 | break; |
| 297 | 294 | case TPG110_RES_480X272: |
| 298 | − DRM_DEV_INFO(tpg->dev, "480x272 RGB\n"); | |
| 295 | + dev_info(tpg->dev, "480x272 RGB\n"); | |
| 299 | 296 | break; |
| 300 | 297 | case TPG110_RES_640X480: |
| 301 | − DRM_DEV_INFO(tpg->dev, "640x480 RGB\n"); | |
| 298 | + dev_info(tpg->dev, "640x480 RGB\n"); | |
| 302 | 299 | break; |
| 303 | 300 | case TPG110_RES_800X480: |
| 304 | − DRM_DEV_INFO(tpg->dev, "800x480 RGB\n"); | |
| 301 | + dev_info(tpg->dev, "800x480 RGB\n"); | |
| 305 | 302 | break; |
| 306 | 303 | default: |
| 307 | − DRM_DEV_ERROR(tpg->dev, "ILLEGAL RESOLUTION 0x%02x\n", val); | |
| 304 | + dev_err(tpg->dev, "ILLEGAL RESOLUTION 0x%02x\n", val); | |
| 308 | 305 | break; |
| 309 | 306 | } |
| 310 | 307 | |
| @@ -322,13 +319,12 @@ static int tpg110_startup(struct tpg110 *tpg) · 11 unmodified lines | ||
| 322 | 319 | } |
| 323 | 320 | } |
| 324 | 321 | if (i == ARRAY_SIZE(tpg110_modes)) { |
| 325 | − DRM_DEV_ERROR(tpg->dev, "unsupported mode (%02x) detected\n", | |
| 326 | − val); | |
| 322 | + dev_err(tpg->dev, "unsupported mode (%02x) detected\n", val); | |
| 327 | 323 | return -ENODEV; |
| 328 | 324 | } |
| 329 | 325 | |
| 330 | 326 | val = tpg110_read_reg(tpg, TPG110_CTRL2); |
| 331 | − DRM_DEV_INFO(tpg->dev, "resolution and standby is controlled by %s\n", | |
| 327 | + dev_info(tpg->dev, "resolution and standby is controlled by %s\n", | |
| 332 | 328 | (val & TPG110_CTRL2_RES_PM_CTRL) ? "software" : "hardware"); |
| 333 | 329 | /* Take control over resolution and standby */ |
| 334 | 330 | val |= TPG110_CTRL2_RES_PM_CTRL; |
| @@ -414,15 +410,15 @@ static int tpg110_probe(struct spi_device *spi) · 79 unmodified lines | ||
| 414 | 410 | /* We get the physical display dimensions from the DT */ |
| 415 | 411 | ret = of_property_read_u32(np, "width-mm", &tpg->width); |
| 416 | 412 | if (ret) |
| 417 | − DRM_DEV_ERROR(dev, "no panel width specified\n"); | |
| 413 | + dev_err(dev, "no panel width specified\n"); | |
| 418 | 414 | ret = of_property_read_u32(np, "height-mm", &tpg->height); |
| 419 | 415 | if (ret) |
| 420 | − DRM_DEV_ERROR(dev, "no panel height specified\n"); | |
| 416 | + dev_err(dev, "no panel height specified\n"); | |
| 421 | 417 | |
| 422 | 418 | /* This asserts the GRESTB signal, putting the display into reset */ |
| 423 | 419 | tpg->grestb = devm_gpiod_get(dev, "grestb", GPIOD_OUT_HIGH); |
| 424 | 420 | if (IS_ERR(tpg->grestb)) { |
| 425 | − DRM_DEV_ERROR(dev, "no GRESTB GPIO\n"); | |
| 421 | + dev_err(dev, "no GRESTB GPIO\n"); | |
| 426 | 422 | return -ENODEV; |
| 427 | 423 | } |
| 428 | 424 | |
| @@ -430,7 +426,7 @@ static int tpg110_probe(struct spi_device *spi) · 1 unmodified line | ||
| 430 | 426 | spi->mode |= SPI_3WIRE_HIZ; |
| 431 | 427 | ret = spi_setup(spi); |
| 432 | 428 | if (ret < 0) { |
| 433 | − DRM_DEV_ERROR(dev, "spi setup failed.\n"); | |
| 429 | + dev_err(dev, "spi setup failed.\n"); | |
| 434 | 430 | return ret; |
| 435 | 431 | } |
| 436 | 432 | tpg->spi = spi; |
| @@ -448,7 +444,9 @@ static int tpg110_probe(struct spi_device *spi) · 11 unmodified lines | ||
| 448 | 444 | |
| 449 | 445 | spi_set_drvdata(spi, tpg); |
| 450 | 446 | |
| 451 | − return drm_panel_add(&tpg->panel); | |
| 447 | + drm_panel_add(&tpg->panel); | |
| 448 | + | |
| 449 | + return 0; | |
| 452 | 450 | } |
| 453 | 451 | |
| 454 | 452 | static int tpg110_remove(struct spi_device *spi) |
| @@ -17,7 +17,6 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <drm/drm_mipi_dsi.h> |
| 18 | 18 | #include <drm/drm_modes.h> |
| 19 | 19 | #include <drm/drm_panel.h> |
| 20 | −#include <drm/drm_print.h> | |
| 21 | 20 | |
| 22 | 21 | static const char * const regulator_names[] = { |
| 23 | 22 | "vdda", |
| @@ -231,9 +230,7 @@ static int truly_dcs_write(struct drm_panel *panel, u32 command) · 207 unmodified lines | ||
| 231 | 230 | for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) { |
| 232 | 231 | ret = mipi_dsi_dcs_write(ctx->dsi[i], command, NULL, 0); |
| 233 | 232 | if (ret < 0) { |
| 234 | − DRM_DEV_ERROR(ctx->dev, | |
| 235 | − "cmd 0x%x failed for dsi = %d\n", | |
| 236 | − command, i); | |
| 233 | + dev_err(ctx->dev, "cmd 0x%x failed for dsi = %d\n", command, i); | |
| 237 | 234 | } |
| 238 | 235 | } |
| 239 | 236 | |
| @@ -250,8 +247,7 @@ static int truly_dcs_write_buf(struct drm_panel *panel, · 10 unmodified lines | ||
| 250 | 247 | for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) { |
| 251 | 248 | ret = mipi_dsi_dcs_write_buffer(ctx->dsi[i], buf, size); |
| 252 | 249 | if (ret < 0) { |
| 253 | − DRM_DEV_ERROR(ctx->dev, | |
| 254 | − "failed to tx cmd [%d], err: %d\n", i, ret); | |
| 250 | + dev_err(ctx->dev, "failed to tx cmd [%d], err: %d\n", i, ret); | |
| 255 | 251 | return ret; |
| 256 | 252 | } |
| 257 | 253 | } |
| @@ -300,16 +296,14 @@ static int truly_nt35597_power_off(struct truly_nt35597 *ctx) · 42 unmodified lines | ||
| 300 | 296 | ret = regulator_set_load(ctx->supplies[i].consumer, |
| 301 | 297 | regulator_disable_loads[i]); |
| 302 | 298 | if (ret) { |
| 303 | − DRM_DEV_ERROR(ctx->dev, | |
| 304 | − "regulator_set_load failed %d\n", ret); | |
| 299 | + dev_err(ctx->dev, "regulator_set_load failed %d\n", ret); | |
| 305 | 300 | return ret; |
| 306 | 301 | } |
| 307 | 302 | } |
| 308 | 303 | |
| 309 | 304 | ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); |
| 310 | 305 | if (ret) { |
| 311 | − DRM_DEV_ERROR(ctx->dev, | |
| 312 | − "regulator_bulk_disable failed %d\n", ret); | |
| 306 | + dev_err(ctx->dev, "regulator_bulk_disable failed %d\n", ret); | |
| 313 | 307 | } |
| 314 | 308 | return ret; |
| 315 | 309 | } |
| @@ -325,8 +319,7 @@ static int truly_nt35597_disable(struct drm_panel *panel) · 9 unmodified lines | ||
| 325 | 319 | if (ctx->backlight) { |
| 326 | 320 | ret = backlight_disable(ctx->backlight); |
| 327 | 321 | if (ret < 0) |
| 328 | − DRM_DEV_ERROR(ctx->dev, "backlight disable failed %d\n", | |
| 329 | − ret); | |
| 322 | + dev_err(ctx->dev, "backlight disable failed %d\n", ret); | |
| 330 | 323 | } |
| 331 | 324 | |
| 332 | 325 | ctx->enabled = false; |
| @@ -346,9 +339,7 @@ static int truly_nt35597_unprepare(struct drm_panel *panel) · 13 unmodified lines | ||
| 346 | 339 | |
| 347 | 340 | ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_OFF); |
| 348 | 341 | if (ret < 0) { |
| 349 | − DRM_DEV_ERROR(ctx->dev, | |
| 350 | − "set_display_off cmd failed ret = %d\n", | |
| 351 | − ret); | |
| 342 | + dev_err(ctx->dev, "set_display_off cmd failed ret = %d\n", ret); | |
| 352 | 343 | } |
| 353 | 344 | |
| 354 | 345 | /* 120ms delay required here as per DCS spec */ |
| @@ -356,13 +347,12 @@ static int truly_nt35597_unprepare(struct drm_panel *panel) · 1 unmodified line | ||
| 356 | 347 | |
| 357 | 348 | ret = truly_dcs_write(panel, MIPI_DCS_ENTER_SLEEP_MODE); |
| 358 | 349 | if (ret < 0) { |
| 359 | − DRM_DEV_ERROR(ctx->dev, | |
| 360 | − "enter_sleep cmd failed ret = %d\n", ret); | |
| 350 | + dev_err(ctx->dev, "enter_sleep cmd failed ret = %d\n", ret); | |
| 361 | 351 | } |
| 362 | 352 | |
| 363 | 353 | ret = truly_nt35597_power_off(ctx); |
| 364 | 354 | if (ret < 0) |
| 365 | − DRM_DEV_ERROR(ctx->dev, "power_off failed ret = %d\n", ret); | |
| 355 | + dev_err(ctx->dev, "power_off failed ret = %d\n", ret); | |
| 366 | 356 | |
| 367 | 357 | ctx->prepared = false; |
| 368 | 358 | return ret; |
| @@ -396,18 +386,14 @@ static int truly_nt35597_prepare(struct drm_panel *panel) · 27 unmodified lines | ||
| 396 | 386 | panel_on_cmds[i].size, |
| 397 | 387 | panel_on_cmds[i].commands); |
| 398 | 388 | if (ret < 0) { |
| 399 | − DRM_DEV_ERROR(ctx->dev, | |
| 400 | − "cmd set tx failed i = %d ret = %d\n", | |
| 401 | − i, ret); | |
| 389 | + dev_err(ctx->dev, "cmd set tx failed i = %d ret = %d\n", i, ret); | |
| 402 | 390 | goto power_off; |
| 403 | 391 | } |
| 404 | 392 | } |
| 405 | 393 | |
| 406 | 394 | ret = truly_dcs_write(panel, MIPI_DCS_EXIT_SLEEP_MODE); |
| 407 | 395 | if (ret < 0) { |
| 408 | − DRM_DEV_ERROR(ctx->dev, | |
| 409 | − "exit_sleep_mode cmd failed ret = %d\n", | |
| 410 | − ret); | |
| 396 | + dev_err(ctx->dev, "exit_sleep_mode cmd failed ret = %d\n", ret); | |
| 411 | 397 | goto power_off; |
| 412 | 398 | } |
| 413 | 399 | |
| @@ -416,8 +402,7 @@ static int truly_nt35597_prepare(struct drm_panel *panel) · 2 unmodified lines | ||
| 416 | 402 | |
| 417 | 403 | ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_ON); |
| 418 | 404 | if (ret < 0) { |
| 419 | − DRM_DEV_ERROR(ctx->dev, | |
| 420 | − "set_display_on cmd failed ret = %d\n", ret); | |
| 405 | + dev_err(ctx->dev, "set_display_on cmd failed ret = %d\n", ret); | |
| 421 | 406 | goto power_off; |
| 422 | 407 | } |
| 423 | 408 | |
| @@ -430,7 +415,7 @@ static int truly_nt35597_prepare(struct drm_panel *panel) · 6 unmodified lines | ||
| 430 | 415 | |
| 431 | 416 | power_off: |
| 432 | 417 | if (truly_nt35597_power_off(ctx)) |
| 433 | − DRM_DEV_ERROR(ctx->dev, "power_off failed\n"); | |
| 418 | + dev_err(ctx->dev, "power_off failed\n"); | |
| 434 | 419 | return ret; |
| 435 | 420 | } |
| 436 | 421 | |
| @@ -445,8 +430,7 @@ static int truly_nt35597_enable(struct drm_panel *panel) · 8 unmodified lines | ||
| 445 | 430 | if (ctx->backlight) { |
| 446 | 431 | ret = backlight_enable(ctx->backlight); |
| 447 | 432 | if (ret < 0) |
| 448 | − DRM_DEV_ERROR(ctx->dev, "backlight enable failed %d\n", | |
| 449 | − ret); | |
| 433 | + dev_err(ctx->dev, "backlight enable failed %d\n", ret); | |
| 450 | 434 | } |
| 451 | 435 | |
| 452 | 436 | ctx->enabled = true; |
| @@ -464,8 +448,7 @@ static int truly_nt35597_get_modes(struct drm_panel *panel, · 11 unmodified lines | ||
| 464 | 448 | config = ctx->config; |
| 465 | 449 | mode = drm_mode_create(connector->dev); |
| 466 | 450 | if (!mode) { |
| 467 | − DRM_DEV_ERROR(ctx->dev, | |
| 468 | − "failed to create a new display mode\n"); | |
| 451 | + dev_err(ctx->dev, "failed to create a new display mode\n"); | |
| 469 | 452 | return 0; |
| 470 | 453 | } |
| 471 | 454 | |
| @@ -501,15 +484,13 @@ static int truly_nt35597_panel_add(struct truly_nt35597 *ctx) · 29 unmodified lines | ||
| 501 | 484 | |
| 502 | 485 | ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); |
| 503 | 486 | if (IS_ERR(ctx->reset_gpio)) { |
| 504 | − DRM_DEV_ERROR(dev, "cannot get reset gpio %ld\n", | |
| 505 | − PTR_ERR(ctx->reset_gpio)); | |
| 487 | + dev_err(dev, "cannot get reset gpio %ld\n", PTR_ERR(ctx->reset_gpio)); | |
| 506 | 488 | return PTR_ERR(ctx->reset_gpio); |
| 507 | 489 | } |
| 508 | 490 | |
| 509 | 491 | ctx->mode_gpio = devm_gpiod_get(dev, "mode", GPIOD_OUT_LOW); |
| 510 | 492 | if (IS_ERR(ctx->mode_gpio)) { |
| 511 | − DRM_DEV_ERROR(dev, "cannot get mode gpio %ld\n", | |
| 512 | − PTR_ERR(ctx->mode_gpio)); | |
| 493 | + dev_err(dev, "cannot get mode gpio %ld\n", PTR_ERR(ctx->mode_gpio)); | |
| 513 | 494 | return PTR_ERR(ctx->mode_gpio); |
| 514 | 495 | } |
| 515 | 496 | |
| @@ -584,22 +565,21 @@ static int truly_nt35597_probe(struct mipi_dsi_device *dsi) · 68 unmodified lines | ||
| 584 | 565 | |
| 585 | 566 | dsi1 = of_graph_get_remote_node(dsi->dev.of_node, 1, -1); |
| 586 | 567 | if (!dsi1) { |
| 587 | − DRM_DEV_ERROR(dev, | |
| 588 | − "failed to get remote node for dsi1_device\n"); | |
| 568 | + dev_err(dev, "failed to get remote node for dsi1_device\n"); | |
| 589 | 569 | return -ENODEV; |
| 590 | 570 | } |
| 591 | 571 | |
| 592 | 572 | dsi1_host = of_find_mipi_dsi_host_by_node(dsi1); |
| 593 | 573 | of_node_put(dsi1); |
| 594 | 574 | if (!dsi1_host) { |
| 595 | − DRM_DEV_ERROR(dev, "failed to find dsi host\n"); | |
| 575 | + dev_err(dev, "failed to find dsi host\n"); | |
| 596 | 576 | return -EPROBE_DEFER; |
| 597 | 577 | } |
| 598 | 578 | |
| 599 | 579 | /* register the second DSI device */ |
| 600 | 580 | dsi1_device = mipi_dsi_device_register_full(dsi1_host, &info); |
| 601 | 581 | if (IS_ERR(dsi1_device)) { |
| 602 | − DRM_DEV_ERROR(dev, "failed to create dsi device\n"); | |
| 582 | + dev_err(dev, "failed to create dsi device\n"); | |
| 603 | 583 | return PTR_ERR(dsi1_device); |
| 604 | 584 | } |
| 605 | 585 | |
| @@ -611,7 +591,7 @@ static int truly_nt35597_probe(struct mipi_dsi_device *dsi) · 5 unmodified lines | ||
| 611 | 591 | |
| 612 | 592 | ret = truly_nt35597_panel_add(ctx); |
| 613 | 593 | if (ret) { |
| 614 | − DRM_DEV_ERROR(dev, "failed to add panel\n"); | |
| 594 | + dev_err(dev, "failed to add panel\n"); | |
| 615 | 595 | goto err_panel_add; |
| 616 | 596 | } |
| 617 | 597 | |
| @@ -623,8 +603,7 @@ static int truly_nt35597_probe(struct mipi_dsi_device *dsi) · 5 unmodified lines | ||
| 623 | 603 | MIPI_DSI_CLOCK_NON_CONTINUOUS; |
| 624 | 604 | ret = mipi_dsi_attach(dsi_dev); |
| 625 | 605 | if (ret < 0) { |
| 626 | − DRM_DEV_ERROR(dev, | |
| 627 | − "dsi attach failed i = %d\n", i); | |
| 606 | + dev_err(dev, "dsi attach failed i = %d\n", i); | |
| 628 | 607 | goto err_dsi_attach; |
| 629 | 608 | } |
| 630 | 609 | } |
| @@ -14,7 +14,6 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <drm/drm_mipi_dsi.h> |
| 15 | 15 | #include <drm/drm_modes.h> |
| 16 | 16 | #include <drm/drm_panel.h> |
| 17 | −#include <drm/drm_print.h> | |
| 18 | 17 | |
| 19 | 18 | struct visionox_rm69299 { |
| 20 | 19 | struct drm_panel panel; |
| @@ -69,16 +68,14 @@ static int visionox_rm69299_unprepare(struct drm_panel *panel) · 48 unmodified lines | ||
| 69 | 68 | |
| 70 | 69 | ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0); |
| 71 | 70 | if (ret < 0) |
| 72 | − DRM_DEV_ERROR(ctx->panel.dev, | |
| 73 | − "set_display_off cmd failed ret = %d\n", ret); | |
| 71 | + dev_err(ctx->panel.dev, "set_display_off cmd failed ret = %d\n", ret); | |
| 74 | 72 | |
| 75 | 73 | /* 120ms delay required here as per DCS spec */ |
| 76 | 74 | msleep(120); |
| 77 | 75 | |
| 78 | 76 | ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0); |
| 79 | 77 | if (ret < 0) { |
| 80 | − DRM_DEV_ERROR(ctx->panel.dev, | |
| 81 | − "enter_sleep cmd failed ret = %d\n", ret); | |
| 78 | + dev_err(ctx->panel.dev, "enter_sleep cmd failed ret = %d\n", ret); | |
| 82 | 79 | } |
| 83 | 80 | |
| 84 | 81 | ret = visionox_rm69299_power_off(ctx); |
| @@ -103,36 +100,31 @@ static int visionox_rm69299_prepare(struct drm_panel *panel) · 18 unmodified lines | ||
| 103 | 100 | |
| 104 | 101 | ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xfe, 0x00 }, 2); |
| 105 | 102 | if (ret < 0) { |
| 106 | − DRM_DEV_ERROR(ctx->panel.dev, | |
| 107 | − "cmd set tx 0 failed, ret = %d\n", ret); | |
| 103 | + dev_err(ctx->panel.dev, "cmd set tx 0 failed, ret = %d\n", ret); | |
| 108 | 104 | goto power_off; |
| 109 | 105 | } |
| 110 | 106 | |
| 111 | 107 | ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xc2, 0x08 }, 2); |
| 112 | 108 | if (ret < 0) { |
| 113 | − DRM_DEV_ERROR(ctx->panel.dev, | |
| 114 | − "cmd set tx 1 failed, ret = %d\n", ret); | |
| 109 | + dev_err(ctx->panel.dev, "cmd set tx 1 failed, ret = %d\n", ret); | |
| 115 | 110 | goto power_off; |
| 116 | 111 | } |
| 117 | 112 | |
| 118 | 113 | ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x35, 0x00 }, 2); |
| 119 | 114 | if (ret < 0) { |
| 120 | − DRM_DEV_ERROR(ctx->panel.dev, | |
| 121 | − "cmd set tx 2 failed, ret = %d\n", ret); | |
| 115 | + dev_err(ctx->panel.dev, "cmd set tx 2 failed, ret = %d\n", ret); | |
| 122 | 116 | goto power_off; |
| 123 | 117 | } |
| 124 | 118 | |
| 125 | 119 | ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x51, 0xff }, 2); |
| 126 | 120 | if (ret < 0) { |
| 127 | − DRM_DEV_ERROR(ctx->panel.dev, | |
| 128 | − "cmd set tx 3 failed, ret = %d\n", ret); | |
| 121 | + dev_err(ctx->panel.dev, "cmd set tx 3 failed, ret = %d\n", ret); | |
| 129 | 122 | goto power_off; |
| 130 | 123 | } |
| 131 | 124 | |
| 132 | 125 | ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); |
| 133 | 126 | if (ret < 0) { |
| 134 | − DRM_DEV_ERROR(ctx->panel.dev, | |
| 135 | − "exit_sleep_mode cmd failed ret = %d\n", ret); | |
| 127 | + dev_err(ctx->panel.dev, "exit_sleep_mode cmd failed ret = %d\n", ret); | |
| 136 | 128 | goto power_off; |
| 137 | 129 | } |
| 138 | 130 | |
| @@ -141,8 +133,7 @@ static int visionox_rm69299_prepare(struct drm_panel *panel) · 2 unmodified lines | ||
| 141 | 133 | |
| 142 | 134 | ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); |
| 143 | 135 | if (ret < 0) { |
| 144 | − DRM_DEV_ERROR(ctx->panel.dev, | |
| 145 | − "set_display_on cmd failed ret = %d\n", ret); | |
| 136 | + dev_err(ctx->panel.dev, "set_display_on cmd failed ret = %d\n", ret); | |
| 146 | 137 | goto power_off; |
| 147 | 138 | } |
| 148 | 139 | |
| @@ -179,8 +170,7 @@ static int visionox_rm69299_get_modes(struct drm_panel *panel, · 30 unmodified lines | ||
| 179 | 170 | |
| 180 | 171 | mode = drm_mode_create(connector->dev); |
| 181 | 172 | if (!mode) { |
| 182 | − DRM_DEV_ERROR(ctx->panel.dev, | |
| 183 | − "failed to create a new display mode\n"); | |
| 173 | + dev_err(ctx->panel.dev, "failed to create a new display mode\n"); | |
| 184 | 174 | return 0; |
| 185 | 175 | } |
| 186 | 176 | |
| @@ -225,8 +215,7 @@ static int visionox_rm69299_probe(struct mipi_dsi_device *dsi) · 38 unmodified lines | ||
| 225 | 215 | ctx->reset_gpio = devm_gpiod_get(ctx->panel.dev, |
| 226 | 216 | "reset", GPIOD_OUT_LOW); |
| 227 | 217 | if (IS_ERR(ctx->reset_gpio)) { |
| 228 | − DRM_DEV_ERROR(dev, "cannot get reset gpio %ld\n", | |
| 229 | − PTR_ERR(ctx->reset_gpio)); | |
| 218 | + dev_err(dev, "cannot get reset gpio %ld\n", PTR_ERR(ctx->reset_gpio)); | |
| 230 | 219 | return PTR_ERR(ctx->reset_gpio); |
| 231 | 220 | } |
| 232 | 221 | |
| @@ -242,23 +231,19 @@ static int visionox_rm69299_probe(struct mipi_dsi_device *dsi) · 9 unmodified lines | ||
| 242 | 231 | MIPI_DSI_CLOCK_NON_CONTINUOUS; |
| 243 | 232 | ret = mipi_dsi_attach(dsi); |
| 244 | 233 | if (ret < 0) { |
| 245 | − DRM_DEV_ERROR(dev, "dsi attach failed ret = %d\n", ret); | |
| 234 | + dev_err(dev, "dsi attach failed ret = %d\n", ret); | |
| 246 | 235 | goto err_dsi_attach; |
| 247 | 236 | } |
| 248 | 237 | |
| 249 | 238 | ret = regulator_set_load(ctx->supplies[0].consumer, 32000); |
| 250 | 239 | if (ret) { |
| 251 | − DRM_DEV_ERROR(dev, | |
| 252 | − "regulator set load failed for vdda supply ret = %d\n", | |
| 253 | − ret); | |
| 240 | + dev_err(dev, "regulator set load failed for vdda supply ret = %d\n", ret); | |
| 254 | 241 | goto err_set_load; |
| 255 | 242 | } |
| 256 | 243 | |
| 257 | 244 | ret = regulator_set_load(ctx->supplies[1].consumer, 13200); |
| 258 | 245 | if (ret) { |
| 259 | − DRM_DEV_ERROR(dev, | |
| 260 | − "regulator set load failed for vdd3p3 supply ret = %d\n", | |
| 261 | − ret); | |
| 246 | + dev_err(dev, "regulator set load failed for vdd3p3 supply ret = %d\n", ret); | |
| 262 | 247 | goto err_set_load; |
| 263 | 248 | } |
| 264 | 249 | |
| @@ -12,7 +12,6 @@ · 11 unmodified lines | ||
| 12 | 12 | #include <drm/drm_mipi_dsi.h> |
| 13 | 13 | #include <drm/drm_modes.h> |
| 14 | 14 | #include <drm/drm_panel.h> |
| 15 | −#include <drm/drm_print.h> | |
| 16 | 15 | |
| 17 | 16 | #include <video/display_timing.h> |
| 18 | 17 | #include <video/mipi_display.h> |
| @@ -135,7 +134,7 @@ static int xpp055c272_init_sequence(struct xpp055c272 *ctx) · 116 unmodified lines | ||
| 135 | 134 | |
| 136 | 135 | msleep(60); |
| 137 | 136 | |
| 138 | − DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n"); | |
| 137 | + dev_dbg(dev, "Panel init sequence done\n"); | |
| 139 | 138 | return 0; |
| 140 | 139 | } |
| 141 | 140 | |
| @@ -150,13 +149,11 @@ static int xpp055c272_unprepare(struct drm_panel *panel) · 8 unmodified lines | ||
| 150 | 149 | |
| 151 | 150 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 152 | 151 | if (ret < 0) |
| 153 | − DRM_DEV_ERROR(ctx->dev, "failed to set display off: %d\n", | |
| 154 | − ret); | |
| 152 | + dev_err(ctx->dev, "failed to set display off: %d\n", ret); | |
| 155 | 153 | |
| 156 | 154 | mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 157 | 155 | if (ret < 0) { |
| 158 | − DRM_DEV_ERROR(ctx->dev, "failed to enter sleep mode: %d\n", | |
| 159 | − ret); | |
| 156 | + dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret); | |
| 160 | 157 | return ret; |
| 161 | 158 | } |
| 162 | 159 | |
| @@ -177,17 +174,15 @@ static int xpp055c272_prepare(struct drm_panel *panel) · 14 unmodified lines | ||
| 177 | 174 | if (ctx->prepared) |
| 178 | 175 | return 0; |
| 179 | 176 | |
| 180 | − DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n"); | |
| 177 | + dev_dbg(ctx->dev, "Resetting the panel\n"); | |
| 181 | 178 | ret = regulator_enable(ctx->vci); |
| 182 | 179 | if (ret < 0) { |
| 183 | − DRM_DEV_ERROR(ctx->dev, | |
| 184 | − "Failed to enable vci supply: %d\n", ret); | |
| 180 | + dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret); | |
| 185 | 181 | return ret; |
| 186 | 182 | } |
| 187 | 183 | ret = regulator_enable(ctx->iovcc); |
| 188 | 184 | if (ret < 0) { |
| 189 | − DRM_DEV_ERROR(ctx->dev, | |
| 190 | − "Failed to enable iovcc supply: %d\n", ret); | |
| 185 | + dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); | |
| 191 | 186 | goto disable_vci; |
| 192 | 187 | } |
| 193 | 188 | |
| @@ -201,14 +196,13 @@ static int xpp055c272_prepare(struct drm_panel *panel) · 7 unmodified lines | ||
| 201 | 196 | |
| 202 | 197 | ret = xpp055c272_init_sequence(ctx); |
| 203 | 198 | if (ret < 0) { |
| 204 | − DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", | |
| 205 | − ret); | |
| 199 | + dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); | |
| 206 | 200 | goto disable_iovcc; |
| 207 | 201 | } |
| 208 | 202 | |
| 209 | 203 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 210 | 204 | if (ret < 0) { |
| 211 | − DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret); | |
| 205 | + dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret); | |
| 212 | 206 | goto disable_iovcc; |
| 213 | 207 | } |
| 214 | 208 | |
| @@ -217,7 +211,7 @@ static int xpp055c272_prepare(struct drm_panel *panel) · 2 unmodified lines | ||
| 217 | 211 | |
| 218 | 212 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 219 | 213 | if (ret < 0) { |
| 220 | − DRM_DEV_ERROR(ctx->dev, "Failed to set display on: %d\n", ret); | |
| 214 | + dev_err(ctx->dev, "Failed to set display on: %d\n", ret); | |
| 221 | 215 | goto disable_iovcc; |
| 222 | 216 | } |
| 223 | 217 | |
| @@ -256,9 +250,9 @@ static int xpp055c272_get_modes(struct drm_panel *panel, · 32 unmodified lines | ||
| 256 | 250 | |
| 257 | 251 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 258 | 252 | if (!mode) { |
| 259 | − DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n", | |
| 260 | − default_mode.hdisplay, default_mode.vdisplay, | |
| 261 | − drm_mode_vrefresh(&default_mode)); | |
| 253 | + dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", | |
| 254 | + default_mode.hdisplay, default_mode.vdisplay, | |
| 255 | + drm_mode_vrefresh(&default_mode)); | |
| 262 | 256 | return -ENOMEM; |
| 263 | 257 | } |
| 264 | 258 | |
| @@ -290,7 +284,7 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi) · 25 unmodified lines | ||
| 290 | 284 | |
| 291 | 285 | ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); |
| 292 | 286 | if (IS_ERR(ctx->reset_gpio)) { |
| 293 | − DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); | |
| 287 | + dev_err(dev, "cannot get reset gpio\n"); | |
| 294 | 288 | return PTR_ERR(ctx->reset_gpio); |
| 295 | 289 | } |
| 296 | 290 | |
| @@ -298,9 +292,7 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi) · 1 unmodified line | ||
| 298 | 292 | if (IS_ERR(ctx->vci)) { |
| 299 | 293 | ret = PTR_ERR(ctx->vci); |
| 300 | 294 | if (ret != -EPROBE_DEFER) |
| 301 | − DRM_DEV_ERROR(dev, | |
| 302 | − "Failed to request vci regulator: %d\n", | |
| 303 | − ret); | |
| 295 | + dev_err(dev, "Failed to request vci regulator: %d\n", ret); | |
| 304 | 296 | return ret; |
| 305 | 297 | } |
| 306 | 298 | |
| @@ -308,9 +300,7 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi) · 1 unmodified line | ||
| 308 | 300 | if (IS_ERR(ctx->iovcc)) { |
| 309 | 301 | ret = PTR_ERR(ctx->iovcc); |
| 310 | 302 | if (ret != -EPROBE_DEFER) |
| 311 | − DRM_DEV_ERROR(dev, | |
| 312 | − "Failed to request iovcc regulator: %d\n", | |
| 313 | − ret); | |
| 303 | + dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); | |
| 314 | 304 | return ret; |
| 315 | 305 | } |
| 316 | 306 | |
| @@ -334,7 +324,7 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi) · 17 unmodified lines | ||
| 334 | 324 | |
| 335 | 325 | ret = mipi_dsi_attach(dsi); |
| 336 | 326 | if (ret < 0) { |
| 337 | − DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret); | |
| 327 | + dev_err(dev, "mipi_dsi_attach failed: %d\n", ret); | |
| 338 | 328 | drm_panel_remove(&ctx->panel); |
| 339 | 329 | return ret; |
| 340 | 330 | } |
| @@ -349,13 +339,11 @@ static void xpp055c272_shutdown(struct mipi_dsi_device *dsi) · 8 unmodified lines | ||
| 349 | 339 | |
| 350 | 340 | ret = drm_panel_unprepare(&ctx->panel); |
| 351 | 341 | if (ret < 0) |
| 352 | − DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", | |
| 353 | − ret); | |
| 342 | + dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); | |
| 354 | 343 | |
| 355 | 344 | ret = drm_panel_disable(&ctx->panel); |
| 356 | 345 | if (ret < 0) |
| 357 | − DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", | |
| 358 | − ret); | |
| 346 | + dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); | |
| 359 | 347 | } |
| 360 | 348 | |
| 361 | 349 | static int xpp055c272_remove(struct mipi_dsi_device *dsi) |
| @@ -367,8 +355,7 @@ static int xpp055c272_remove(struct mipi_dsi_device *dsi) · 5 unmodified lines | ||
| 367 | 355 | |
| 368 | 356 | ret = mipi_dsi_detach(dsi); |
| 369 | 357 | if (ret < 0) |
| 370 | − DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", | |
| 371 | − ret); | |
| 358 | + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); | |
| 372 | 359 | |
| 373 | 360 | drm_panel_remove(&ctx->panel); |
| 374 | 361 | |
| @@ -1,20 +1,29 @@ | ||
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | 2 | /* Copyright 2019 Collabora ltd. */ |
| 3 | + | |
| 4 | +#include <linux/clk.h> | |
| 3 | 5 | #include <linux/devfreq.h> |
| 4 | 6 | #include <linux/devfreq_cooling.h> |
| 5 | 7 | #include <linux/platform_device.h> |
| 6 | 8 | #include <linux/pm_opp.h> |
| 7 | −#include <linux/clk.h> | |
| 8 | −#include <linux/regulator/consumer.h> | |
| 9 | 9 | |
| 10 | 10 | #include "panfrost_device.h" |
| 11 | 11 | #include "panfrost_devfreq.h" |
| 12 | −#include "panfrost_features.h" | |
| 13 | −#include "panfrost_issues.h" | |
| 14 | −#include "panfrost_gpu.h" | |
| 15 | −#include "panfrost_regs.h" | |
| 16 | 12 | |
| 17 | −static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev); | |
| 13 | +static void panfrost_devfreq_update_utilization(struct panfrost_devfreq *pfdevfreq) | |
| 14 | +{ | |
| 15 | + ktime_t now, last; | |
| 16 | + | |
| 17 | + now = ktime_get(); | |
| 18 | + last = pfdevfreq->time_last_update; | |
| 19 | + | |
| 20 | + if (pfdevfreq->busy_count > 0) | |
| 21 | + pfdevfreq->busy_time += ktime_sub(now, last); | |
| 22 | + else | |
| 23 | + pfdevfreq->idle_time += ktime_sub(now, last); | |
| 24 | + | |
| 25 | + pfdevfreq->time_last_update = now; | |
| 26 | +} | |
| 18 | 27 | |
| 19 | 28 | static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, |
| 20 | 29 | u32 flags) |
| @@ -34,30 +43,37 @@ static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, · 13 unmodified lines | ||
| 34 | 43 | return 0; |
| 35 | 44 | } |
| 36 | 45 | |
| 37 | −static void panfrost_devfreq_reset(struct panfrost_device *pfdev) | |
| 46 | +static void panfrost_devfreq_reset(struct panfrost_devfreq *pfdevfreq) | |
| 38 | 47 | { |
| 39 | − pfdev->devfreq.busy_time = 0; | |
| 40 | − pfdev->devfreq.idle_time = 0; | |
| 41 | − pfdev->devfreq.time_last_update = ktime_get(); | |
| 48 | + pfdevfreq->busy_time = 0; | |
| 49 | + pfdevfreq->idle_time = 0; | |
| 50 | + pfdevfreq->time_last_update = ktime_get(); | |
| 42 | 51 | } |
| 43 | 52 | |
| 44 | 53 | static int panfrost_devfreq_get_dev_status(struct device *dev, |
| 45 | 54 | struct devfreq_dev_status *status) |
| 46 | 55 | { |
| 47 | 56 | struct panfrost_device *pfdev = dev_get_drvdata(dev); |
| 48 | − | |
| 49 | − panfrost_devfreq_update_utilization(pfdev); | |
| 57 | + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; | |
| 58 | + unsigned long irqflags; | |
| 50 | 59 | |
| 51 | 60 | status->current_frequency = clk_get_rate(pfdev->clock); |
| 52 | − status->total_time = ktime_to_ns(ktime_add(pfdev->devfreq.busy_time, | |
| 53 | − pfdev->devfreq.idle_time)); | |
| 54 | 61 | |
| 55 | − status->busy_time = ktime_to_ns(pfdev->devfreq.busy_time); | |
| 62 | + spin_lock_irqsave(&pfdevfreq->lock, irqflags); | |
| 63 | + | |
| 64 | + panfrost_devfreq_update_utilization(pfdevfreq); | |
| 65 | + | |
| 66 | + status->total_time = ktime_to_ns(ktime_add(pfdevfreq->busy_time, | |
| 67 | + pfdevfreq->idle_time)); | |
| 68 | + | |
| 69 | + status->busy_time = ktime_to_ns(pfdevfreq->busy_time); | |
| 70 | + | |
| 71 | + panfrost_devfreq_reset(pfdevfreq); | |
| 56 | 72 | |
| 57 | − panfrost_devfreq_reset(pfdev); | |
| 73 | + spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); | |
| 58 | 74 | |
| 59 | − dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", status->busy_time, | |
| 60 | − status->total_time, | |
| 75 | + dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", | |
| 76 | + status->busy_time, status->total_time, | |
| 61 | 77 | status->busy_time / (status->total_time / 100), |
| 62 | 78 | status->current_frequency / 1000 / 1000); |
| 63 | 79 | |
| @@ -77,21 +93,43 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) · 13 unmodified lines | ||
| 77 | 93 | unsigned long cur_freq; |
| 78 | 94 | struct device *dev = &pfdev->pdev->dev; |
| 79 | 95 | struct devfreq *devfreq; |
| 96 | + struct opp_table *opp_table; | |
| 80 | 97 | struct thermal_cooling_device *cooling; |
| 98 | + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; | |
| 99 | + | |
| 100 | + opp_table = dev_pm_opp_set_regulators(dev, pfdev->comp->supply_names, | |
| 101 | + pfdev->comp->num_supplies); | |
| 102 | + if (IS_ERR(opp_table)) { | |
| 103 | + ret = PTR_ERR(opp_table); | |
| 104 | + /* Continue if the optional regulator is missing */ | |
| 105 | + if (ret != -ENODEV) { | |
| 106 | + DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n"); | |
| 107 | + goto err_fini; | |
| 108 | + } | |
| 109 | + } else { | |
| 110 | + pfdevfreq->regulators_opp_table = opp_table; | |
| 111 | + } | |
| 81 | 112 | |
| 82 | 113 | ret = dev_pm_opp_of_add_table(dev); |
| 83 | − if (ret == -ENODEV) /* Optional, continue without devfreq */ | |
| 84 | − return 0; | |
| 85 | − else if (ret) | |
| 86 | − return ret; | |
| 114 | + if (ret) { | |
| 115 | + /* Optional, continue without devfreq */ | |
| 116 | + if (ret == -ENODEV) | |
| 117 | + ret = 0; | |
| 118 | + goto err_fini; | |
| 119 | + } | |
| 120 | + pfdevfreq->opp_of_table_added = true; | |
| 121 | + | |
| 122 | + spin_lock_init(&pfdevfreq->lock); | |
| 87 | 123 | |
| 88 | − panfrost_devfreq_reset(pfdev); | |
| 124 | + panfrost_devfreq_reset(pfdevfreq); | |
| 89 | 125 | |
| 90 | 126 | cur_freq = clk_get_rate(pfdev->clock); |
| 91 | 127 | |
| 92 | 128 | opp = devfreq_recommended_opp(dev, &cur_freq, 0); |
| 93 | − if (IS_ERR(opp)) | |
| 94 | − return PTR_ERR(opp); | |
| 129 | + if (IS_ERR(opp)) { | |
| 130 | + ret = PTR_ERR(opp); | |
| 131 | + goto err_fini; | |
| 132 | + } | |
| 95 | 133 | |
| 96 | 134 | panfrost_devfreq_profile.initial_freq = cur_freq; |
| 97 | 135 | dev_pm_opp_put(opp); |
| @@ -100,75 +138,94 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) · 2 unmodified lines | ||
| 100 | 138 | DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL); |
| 101 | 139 | if (IS_ERR(devfreq)) { |
| 102 | 140 | DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n"); |
| 103 | − dev_pm_opp_of_remove_table(dev); | |
| 104 | − return PTR_ERR(devfreq); | |
| 141 | + ret = PTR_ERR(devfreq); | |
| 142 | + goto err_fini; | |
| 105 | 143 | } |
| 106 | − pfdev->devfreq.devfreq = devfreq; | |
| 144 | + pfdevfreq->devfreq = devfreq; | |
| 107 | 145 | |
| 108 | 146 | cooling = of_devfreq_cooling_register(dev->of_node, devfreq); |
| 109 | 147 | if (IS_ERR(cooling)) |
| 110 | 148 | DRM_DEV_INFO(dev, "Failed to register cooling device\n"); |
| 111 | 149 | else |
| 112 | − pfdev->devfreq.cooling = cooling; | |
| 150 | + pfdevfreq->cooling = cooling; | |
| 113 | 151 | |
| 114 | 152 | return 0; |
| 153 | + | |
| 154 | +err_fini: | |
| 155 | + panfrost_devfreq_fini(pfdev); | |
| 156 | + return ret; | |
| 115 | 157 | } |
| 116 | 158 | |
| 117 | 159 | void panfrost_devfreq_fini(struct panfrost_device *pfdev) |
| 118 | 160 | { |
| 119 | − if (pfdev->devfreq.cooling) | |
| 120 | − devfreq_cooling_unregister(pfdev->devfreq.cooling); | |
| 121 | − dev_pm_opp_of_remove_table(&pfdev->pdev->dev); | |
| 161 | + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; | |
| 162 | + | |
| 163 | + if (pfdevfreq->cooling) { | |
| 164 | + devfreq_cooling_unregister(pfdevfreq->cooling); | |
| 165 | + pfdevfreq->cooling = NULL; | |
| 166 | + } | |
| 167 | + | |
| 168 | + if (pfdevfreq->opp_of_table_added) { | |
| 169 | + dev_pm_opp_of_remove_table(&pfdev->pdev->dev); | |
| 170 | + pfdevfreq->opp_of_table_added = false; | |
| 171 | + } | |
| 172 | + | |
| 173 | + if (pfdevfreq->regulators_opp_table) { | |
| 174 | + dev_pm_opp_put_regulators(pfdevfreq->regulators_opp_table); | |
| 175 | + pfdevfreq->regulators_opp_table = NULL; | |
| 176 | + } | |
| 122 | 177 | } |
| 123 | 178 | |
| 124 | 179 | void panfrost_devfreq_resume(struct panfrost_device *pfdev) |
| 125 | 180 | { |
| 126 | − if (!pfdev->devfreq.devfreq) | |
| 181 | + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; | |
| 182 | + | |
| 183 | + if (!pfdevfreq->devfreq) | |
| 127 | 184 | return; |
| 128 | 185 | |
| 129 | − panfrost_devfreq_reset(pfdev); | |
| 186 | + panfrost_devfreq_reset(pfdevfreq); | |
| 130 | 187 | |
| 131 | − devfreq_resume_device(pfdev->devfreq.devfreq); | |
| 188 | + devfreq_resume_device(pfdevfreq->devfreq); | |
| 132 | 189 | } |
| 133 | 190 | |
| 134 | 191 | void panfrost_devfreq_suspend(struct panfrost_device *pfdev) |
| 135 | 192 | { |
| 136 | − if (!pfdev->devfreq.devfreq) | |
| 193 | + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; | |
| 194 | + | |
| 195 | + if (!pfdevfreq->devfreq) | |
| 137 | 196 | return; |
| 138 | 197 | |
| 139 | − devfreq_suspend_device(pfdev->devfreq.devfreq); | |
| 198 | + devfreq_suspend_device(pfdevfreq->devfreq); | |
| 140 | 199 | } |
| 141 | 200 | |
| 142 | −static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev) | |
| 201 | +void panfrost_devfreq_record_busy(struct panfrost_devfreq *pfdevfreq) | |
| 143 | 202 | { |
| 144 | − ktime_t now; | |
| 145 | − ktime_t last; | |
| 203 | + unsigned long irqflags; | |
| 146 | 204 | |
| 147 | − if (!pfdev->devfreq.devfreq) | |
| 205 | + if (!pfdevfreq->devfreq) | |
| 148 | 206 | return; |
| 149 | 207 | |
| 150 | − now = ktime_get(); | |
| 151 | − last = pfdev->devfreq.time_last_update; | |
| 208 | + spin_lock_irqsave(&pfdevfreq->lock, irqflags); | |
| 152 | 209 | |
| 153 | − if (atomic_read(&pfdev->devfreq.busy_count) > 0) | |
| 154 | − pfdev->devfreq.busy_time += ktime_sub(now, last); | |
| 155 | − else | |
| 156 | − pfdev->devfreq.idle_time += ktime_sub(now, last); | |
| 210 | + panfrost_devfreq_update_utilization(pfdevfreq); | |
| 157 | 211 | |
| 158 | − pfdev->devfreq.time_last_update = now; | |
| 159 | −} | |
| 212 | + pfdevfreq->busy_count++; | |
| 160 | 213 | |
| 161 | −void panfrost_devfreq_record_busy(struct panfrost_device *pfdev) | |
| 162 | −{ | |
| 163 | − panfrost_devfreq_update_utilization(pfdev); | |
| 164 | − atomic_inc(&pfdev->devfreq.busy_count); | |
| 214 | + spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); | |
| 165 | 215 | } |
| 166 | 216 | |
| 167 | −void panfrost_devfreq_record_idle(struct panfrost_device *pfdev) | |
| 217 | +void panfrost_devfreq_record_idle(struct panfrost_devfreq *pfdevfreq) | |
| 168 | 218 | { |
| 169 | − int count; | |
| 219 | + unsigned long irqflags; | |
| 220 | + | |
| 221 | + if (!pfdevfreq->devfreq) | |
| 222 | + return; | |
| 223 | + | |
| 224 | + spin_lock_irqsave(&pfdevfreq->lock, irqflags); | |
| 225 | + | |
| 226 | + panfrost_devfreq_update_utilization(pfdevfreq); | |
| 227 | + | |
| 228 | + WARN_ON(--pfdevfreq->busy_count < 0); | |
| 170 | 229 | |
| 171 | − panfrost_devfreq_update_utilization(pfdev); | |
| 172 | − count = atomic_dec_if_positive(&pfdev->devfreq.busy_count); | |
| 173 | − WARN_ON(count < 0); | |
| 230 | + spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); | |
| 174 | 231 | } |
| @@ -4,13 +4,39 @@ · 3 unmodified lines | ||
| 4 | 4 | #ifndef __PANFROST_DEVFREQ_H__ |
| 5 | 5 | #define __PANFROST_DEVFREQ_H__ |
| 6 | 6 | |
| 7 | +#include <linux/spinlock.h> | |
| 8 | +#include <linux/ktime.h> | |
| 9 | + | |
| 10 | +struct devfreq; | |
| 11 | +struct opp_table; | |
| 12 | +struct thermal_cooling_device; | |
| 13 | + | |
| 14 | +struct panfrost_device; | |
| 15 | + | |
| 16 | +struct panfrost_devfreq { | |
| 17 | + struct devfreq *devfreq; | |
| 18 | + struct opp_table *regulators_opp_table; | |
| 19 | + struct thermal_cooling_device *cooling; | |
| 20 | + bool opp_of_table_added; | |
| 21 | + | |
| 22 | + ktime_t busy_time; | |
| 23 | + ktime_t idle_time; | |
| 24 | + ktime_t time_last_update; | |
| 25 | + int busy_count; | |
| 26 | + /* | |
| 27 | + * Protect busy_time, idle_time, time_last_update and busy_count | |
| 28 | + * because these can be updated concurrently between multiple jobs. | |
| 29 | + */ | |
| 30 | + spinlock_t lock; | |
| 31 | +}; | |
| 32 | + | |
| 7 | 33 | int panfrost_devfreq_init(struct panfrost_device *pfdev); |
| 8 | 34 | void panfrost_devfreq_fini(struct panfrost_device *pfdev); |
| 9 | 35 | |
| 10 | 36 | void panfrost_devfreq_resume(struct panfrost_device *pfdev); |
| 11 | 37 | void panfrost_devfreq_suspend(struct panfrost_device *pfdev); |
| 12 | 38 | |
| 13 | −void panfrost_devfreq_record_busy(struct panfrost_device *pfdev); | |
| 14 | −void panfrost_devfreq_record_idle(struct panfrost_device *pfdev); | |
| 39 | +void panfrost_devfreq_record_busy(struct panfrost_devfreq *devfreq); | |
| 40 | +void panfrost_devfreq_record_idle(struct panfrost_devfreq *devfreq); | |
| 15 | 41 | |
| 16 | 42 | #endif /* __PANFROST_DEVFREQ_H__ */ |
| @@ -90,9 +90,11 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev) · 89 unmodified lines | ||
| 90 | 90 | { |
| 91 | 91 | int ret, i; |
| 92 | 92 | |
| 93 | − if (WARN(pfdev->comp->num_supplies > ARRAY_SIZE(pfdev->regulators), | |
| 94 | − "Too many supplies in compatible structure.\n")) | |
| 95 | − return -EINVAL; | |
| 93 | + pfdev->regulators = devm_kcalloc(pfdev->dev, pfdev->comp->num_supplies, | |
| 94 | + sizeof(*pfdev->regulators), | |
| 95 | + GFP_KERNEL); | |
| 96 | + if (!pfdev->regulators) | |
| 97 | + return -ENOMEM; | |
| 96 | 98 | |
| 97 | 99 | for (i = 0; i < pfdev->comp->num_supplies; i++) |
| 98 | 100 | pfdev->regulators[i].supply = pfdev->comp->supply_names[i]; |
| @@ -119,8 +121,10 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev) · 20 unmodified lines | ||
| 119 | 121 | |
| 120 | 122 | static void panfrost_regulator_fini(struct panfrost_device *pfdev) |
| 121 | 123 | { |
| 122 | − regulator_bulk_disable(pfdev->comp->num_supplies, | |
| 123 | − pfdev->regulators); | |
| 124 | + if (!pfdev->regulators) | |
| 125 | + return; | |
| 126 | + | |
| 127 | + regulator_bulk_disable(pfdev->comp->num_supplies, pfdev->regulators); | |
| 124 | 128 | } |
| 125 | 129 | |
| 126 | 130 | static void panfrost_pm_domain_fini(struct panfrost_device *pfdev) |
| @@ -214,58 +218,70 @@ int panfrost_device_init(struct panfrost_device *pfdev) · 87 unmodified lines | ||
| 214 | 218 | return err; |
| 215 | 219 | } |
| 216 | 220 | |
| 217 | − err = panfrost_regulator_init(pfdev); | |
| 218 | − if (err) | |
| 219 | − goto err_out0; | |
| 221 | + err = panfrost_devfreq_init(pfdev); | |
| 222 | + if (err) { | |
| 223 | + if (err != -EPROBE_DEFER) | |
| 224 | + dev_err(pfdev->dev, "devfreq init failed %d\n", err); | |
| 225 | + goto out_clk; | |
| 226 | + } | |
| 227 | + | |
| 228 | + /* OPP will handle regulators */ | |
| 229 | + if (!pfdev->pfdevfreq.opp_of_table_added) { | |
| 230 | + err = panfrost_regulator_init(pfdev); | |
| 231 | + if (err) | |
| 232 | + goto out_devfreq; | |
| 233 | + } | |
| 220 | 234 | |
| 221 | 235 | err = panfrost_reset_init(pfdev); |
| 222 | 236 | if (err) { |
| 223 | 237 | dev_err(pfdev->dev, "reset init failed %d\n", err); |
| 224 | − goto err_out1; | |
| 238 | + goto out_regulator; | |
| 225 | 239 | } |
| 226 | 240 | |
| 227 | 241 | err = panfrost_pm_domain_init(pfdev); |
| 228 | 242 | if (err) |
| 229 | − goto err_out2; | |
| 243 | + goto out_reset; | |
| 230 | 244 | |
| 231 | 245 | res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0); |
| 232 | 246 | pfdev->iomem = devm_ioremap_resource(pfdev->dev, res); |
| 233 | 247 | if (IS_ERR(pfdev->iomem)) { |
| 234 | 248 | dev_err(pfdev->dev, "failed to ioremap iomem\n"); |
| 235 | 249 | err = PTR_ERR(pfdev->iomem); |
| 236 | − goto err_out3; | |
| 250 | + goto out_pm_domain; | |
| 237 | 251 | } |
| 238 | 252 | |
| 239 | 253 | err = panfrost_gpu_init(pfdev); |
| 240 | 254 | if (err) |
| 241 | − goto err_out3; | |
| 255 | + goto out_pm_domain; | |
| 242 | 256 | |
| 243 | 257 | err = panfrost_mmu_init(pfdev); |
| 244 | 258 | if (err) |
| 245 | − goto err_out4; | |
| 259 | + goto out_gpu; | |
| 246 | 260 | |
| 247 | 261 | err = panfrost_job_init(pfdev); |
| 248 | 262 | if (err) |
| 249 | − goto err_out5; | |
| 263 | + goto out_mmu; | |
| 250 | 264 | |
| 251 | 265 | err = panfrost_perfcnt_init(pfdev); |
| 252 | 266 | if (err) |
| 253 | − goto err_out6; | |
| 267 | + goto out_job; | |
| 254 | 268 | |
| 255 | 269 | return 0; |
| 256 | −err_out6: | |
| 270 | +out_job: | |
| 257 | 271 | panfrost_job_fini(pfdev); |
| 258 | −err_out5: | |
| 272 | +out_mmu: | |
| 259 | 273 | panfrost_mmu_fini(pfdev); |
| 260 | −err_out4: | |
| 274 | +out_gpu: | |
| 261 | 275 | panfrost_gpu_fini(pfdev); |
| 262 | −err_out3: | |
| 276 | +out_pm_domain: | |
| 263 | 277 | panfrost_pm_domain_fini(pfdev); |
| 264 | −err_out2: | |
| 278 | +out_reset: | |
| 265 | 279 | panfrost_reset_fini(pfdev); |
| 266 | −err_out1: | |
| 280 | +out_regulator: | |
| 267 | 281 | panfrost_regulator_fini(pfdev); |
| 268 | −err_out0: | |
| 282 | +out_devfreq: | |
| 283 | + panfrost_devfreq_fini(pfdev); | |
| 284 | +out_clk: | |
| 269 | 285 | panfrost_clk_fini(pfdev); |
| 270 | 286 | return err; |
| 271 | 287 | } |
| @@ -278,6 +294,7 @@ void panfrost_device_fini(struct panfrost_device *pfdev) · 6 unmodified lines | ||
| 278 | 294 | panfrost_gpu_fini(pfdev); |
| 279 | 295 | panfrost_pm_domain_fini(pfdev); |
| 280 | 296 | panfrost_reset_fini(pfdev); |
| 297 | + panfrost_devfreq_fini(pfdev); | |
| 281 | 298 | panfrost_regulator_fini(pfdev); |
| 282 | 299 | panfrost_clk_fini(pfdev); |
| 283 | 300 | } |
| @@ -13,6 +13,8 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <drm/drm_mm.h> |
| 14 | 14 | #include <drm/gpu_scheduler.h> |
| 15 | 15 | |
| 16 | +#include "panfrost_devfreq.h" | |
| 17 | + | |
| 16 | 18 | struct panfrost_device; |
| 17 | 19 | struct panfrost_mmu; |
| 18 | 20 | struct panfrost_job_slot; |
| @@ -20,7 +22,6 @@ struct panfrost_job; · 1 unmodified line | ||
| 20 | 22 | struct panfrost_perfcnt; |
| 21 | 23 | |
| 22 | 24 | #define NUM_JOB_SLOTS 3 |
| 23 | −#define MAX_REGULATORS 2 | |
| 24 | 25 | #define MAX_PM_DOMAINS 3 |
| 25 | 26 | |
| 26 | 27 | struct panfrost_features { |
| @@ -79,7 +80,7 @@ struct panfrost_device { · 52 unmodified lines | ||
| 79 | 80 | void __iomem *iomem; |
| 80 | 81 | struct clk *clock; |
| 81 | 82 | struct clk *bus_clock; |
| 82 | − struct regulator_bulk_data regulators[MAX_REGULATORS]; | |
| 83 | + struct regulator_bulk_data *regulators; | |
| 83 | 84 | struct reset_control *rstc; |
| 84 | 85 | /* pm_domains for devices with more than one. */ |
| 85 | 86 | struct device *pm_domain_devs[MAX_PM_DOMAINS]; |
| @@ -107,14 +108,7 @@ struct panfrost_device { · 21 unmodified lines | ||
| 107 | 108 | struct list_head shrinker_list; |
| 108 | 109 | struct shrinker shrinker; |
| 109 | 110 | |
| 110 | − struct { | |
| 111 | − struct devfreq *devfreq; | |
| 112 | − struct thermal_cooling_device *cooling; | |
| 113 | − ktime_t busy_time; | |
| 114 | − ktime_t idle_time; | |
| 115 | − ktime_t time_last_update; | |
| 116 | − atomic_t busy_count; | |
| 117 | − } devfreq; | |
| 111 | + struct panfrost_devfreq pfdevfreq; | |
| 118 | 112 | }; |
| 119 | 113 | |
| 120 | 114 | struct panfrost_mmu { |
| @@ -14,7 +14,6 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <drm/drm_utils.h> |
| 15 | 15 | |
| 16 | 16 | #include "panfrost_device.h" |
| 17 | −#include "panfrost_devfreq.h" | |
| 18 | 17 | #include "panfrost_gem.h" |
| 19 | 18 | #include "panfrost_mmu.h" |
| 20 | 19 | #include "panfrost_job.h" |
| @@ -606,13 +605,6 @@ static int panfrost_probe(struct platform_device *pdev) · 585 unmodified lines | ||
| 606 | 605 | goto err_out0; |
| 607 | 606 | } |
| 608 | 607 | |
| 609 | − err = panfrost_devfreq_init(pfdev); | |
| 610 | − if (err) { | |
| 611 | − if (err != -EPROBE_DEFER) | |
| 612 | − dev_err(&pdev->dev, "Fatal error during devfreq init\n"); | |
| 613 | − goto err_out1; | |
| 614 | − } | |
| 615 | − | |
| 616 | 608 | pm_runtime_set_active(pfdev->dev); |
| 617 | 609 | pm_runtime_mark_last_busy(pfdev->dev); |
| 618 | 610 | pm_runtime_enable(pfdev->dev); |
| @@ -625,16 +617,14 @@ static int panfrost_probe(struct platform_device *pdev) · 6 unmodified lines | ||
| 625 | 617 | */ |
| 626 | 618 | err = drm_dev_register(ddev, 0); |
| 627 | 619 | if (err < 0) |
| 628 | − goto err_out2; | |
| 620 | + goto err_out1; | |
| 629 | 621 | |
| 630 | 622 | panfrost_gem_shrinker_init(ddev); |
| 631 | 623 | |
| 632 | 624 | return 0; |
| 633 | 625 | |
| 634 | −err_out2: | |
| 635 | − pm_runtime_disable(pfdev->dev); | |
| 636 | − panfrost_devfreq_fini(pfdev); | |
| 637 | 626 | err_out1: |
| 627 | + pm_runtime_disable(pfdev->dev); | |
| 638 | 628 | panfrost_device_fini(pfdev); |
| 639 | 629 | err_out0: |
| 640 | 630 | drm_dev_put(ddev); |
| @@ -650,7 +640,6 @@ static int panfrost_remove(struct platform_device *pdev) · 9 unmodified lines | ||
| 650 | 640 | panfrost_gem_shrinker_cleanup(ddev); |
| 651 | 641 | |
| 652 | 642 | pm_runtime_get_sync(pfdev->dev); |
| 653 | − panfrost_devfreq_fini(pfdev); | |
| 654 | 643 | panfrost_device_fini(pfdev); |
| 655 | 644 | pm_runtime_put_sync_suspend(pfdev->dev); |
| 656 | 645 | pm_runtime_disable(pfdev->dev); |
| @@ -677,6 +666,7 @@ static const struct of_device_id dt_match[] = { · 20 unmodified lines | ||
| 677 | 666 | { .compatible = "arm,mali-t830", .data = &default_data, }, |
| 678 | 667 | { .compatible = "arm,mali-t860", .data = &default_data, }, |
| 679 | 668 | { .compatible = "arm,mali-t880", .data = &default_data, }, |
| 669 | + { .compatible = "arm,mali-bifrost", .data = &default_data, }, | |
| 680 | 670 | {} |
| 681 | 671 | }; |
| 682 | 672 | MODULE_DEVICE_TABLE(of, dt_match); |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/io.h> |
| 11 | 11 | #include <linux/iopoll.h> |
| 12 | 12 | #include <linux/platform_device.h> |
| 13 | +#include <linux/pm_runtime.h> | |
| 13 | 14 | |
| 14 | 15 | #include "panfrost_device.h" |
| 15 | 16 | #include "panfrost_features.h" |
| @@ -368,7 +369,16 @@ void panfrost_gpu_fini(struct panfrost_device *pfdev) · 352 unmodified lines | ||
| 368 | 369 | |
| 369 | 370 | u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev) |
| 370 | 371 | { |
| 371 | − if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) | |
| 372 | − return gpu_read(pfdev, GPU_LATEST_FLUSH_ID); | |
| 372 | + u32 flush_id; | |
| 373 | + | |
| 374 | + if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) { | |
| 375 | + /* Flush reduction only makes sense when the GPU is kept powered on between jobs */ | |
| 376 | + if (pm_runtime_get_if_in_use(pfdev->dev)) { | |
| 377 | + flush_id = gpu_read(pfdev, GPU_LATEST_FLUSH_ID); | |
| 378 | + pm_runtime_put(pfdev->dev); | |
| 379 | + return flush_id; | |
| 380 | + } | |
| 381 | + } | |
| 382 | + | |
| 373 | 383 | return 0; |
| 374 | 384 | } |
| @@ -145,7 +145,7 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js) · 144 unmodified lines | ||
| 145 | 145 | u64 jc_head = job->jc; |
| 146 | 146 | int ret; |
| 147 | 147 | |
| 148 | − panfrost_devfreq_record_busy(pfdev); | |
| 148 | + panfrost_devfreq_record_busy(&pfdev->pfdevfreq); | |
| 149 | 149 | |
| 150 | 150 | ret = pm_runtime_get_sync(pfdev->dev); |
| 151 | 151 | if (ret < 0) |
| @@ -410,7 +410,7 @@ static void panfrost_job_timedout(struct drm_sched_job *sched_job) · 258 unmodified lines | ||
| 410 | 410 | for (i = 0; i < NUM_JOB_SLOTS; i++) { |
| 411 | 411 | if (pfdev->jobs[i]) { |
| 412 | 412 | pm_runtime_put_noidle(pfdev->dev); |
| 413 | − panfrost_devfreq_record_idle(pfdev); | |
| 413 | + panfrost_devfreq_record_idle(&pfdev->pfdevfreq); | |
| 414 | 414 | pfdev->jobs[i] = NULL; |
| 415 | 415 | } |
| 416 | 416 | } |
| @@ -478,7 +478,7 @@ static irqreturn_t panfrost_job_irq_handler(int irq, void *data) · 61 unmodified lines | ||
| 478 | 478 | pfdev->jobs[j] = NULL; |
| 479 | 479 | |
| 480 | 480 | panfrost_mmu_as_put(pfdev, &job->file_priv->mmu); |
| 481 | − panfrost_devfreq_record_idle(pfdev); | |
| 481 | + panfrost_devfreq_record_idle(&pfdev->pfdevfreq); | |
| 482 | 482 | |
| 483 | 483 | dma_fence_signal_locked(job->done_fence); |
| 484 | 484 | pm_runtime_put_autosuspend(pfdev->dev); |
| @@ -581,10 +581,6 @@ int panfrost_job_is_idle(struct panfrost_device *pfdev) · 96 unmodified lines | ||
| 581 | 581 | struct panfrost_job_slot *js = pfdev->js; |
| 582 | 582 | int i; |
| 583 | 583 | |
| 584 | − /* Check whether the hardware is idle */ | |
| 585 | − if (atomic_read(&pfdev->devfreq.busy_count)) | |
| 586 | − return false; | |
| 587 | − | |
| 588 | 584 | for (i = 0; i < NUM_JOB_SLOTS; i++) { |
| 589 | 585 | /* If there are any jobs in the HW queue, we're not idle */ |
| 590 | 586 | if (atomic_read(&js->queue[i].sched.hw_rq_count)) |
| @@ -83,11 +83,13 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev, · 82 unmodified lines | ||
| 83 | 83 | |
| 84 | 84 | ret = pm_runtime_get_sync(pfdev->dev); |
| 85 | 85 | if (ret < 0) |
| 86 | − return ret; | |
| 86 | + goto err_put_pm; | |
| 87 | 87 | |
| 88 | 88 | bo = drm_gem_shmem_create(pfdev->ddev, perfcnt->bosize); |
| 89 | − if (IS_ERR(bo)) | |
| 90 | − return PTR_ERR(bo); | |
| 89 | + if (IS_ERR(bo)) { | |
| 90 | + ret = PTR_ERR(bo); | |
| 91 | + goto err_put_pm; | |
| 92 | + } | |
| 91 | 93 | |
| 92 | 94 | /* Map the perfcnt buf in the address space attached to file_priv. */ |
| 93 | 95 | ret = panfrost_gem_open(&bo->base, file_priv); |
| @@ -168,6 +170,8 @@ err_close_bo: · 74 unmodified lines | ||
| 168 | 170 | panfrost_gem_close(&bo->base, file_priv); |
| 169 | 171 | err_put_bo: |
| 170 | 172 | drm_gem_object_put(&bo->base); |
| 173 | +err_put_pm: | |
| 174 | + pm_runtime_put(pfdev->dev); | |
| 171 | 175 | return ret; |
| 172 | 176 | } |
| 173 | 177 | |
| @@ -10,18 +10,11 @@ · 9 unmodified lines | ||
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | 12 | /** |
| 13 | − * DOC: ARM PrimeCell PL111 CLCD Driver | |
| 13 | + * DOC: ARM PrimeCell PL110 and PL111 CLCD Driver | |
| 14 | 14 | * |
| 15 | − * The PL111 is a simple LCD controller that can support TFT and STN | |
| 16 | − * displays. This driver exposes a standard KMS interface for them. | |
| 17 | − * | |
| 18 | − * This driver uses the same Device Tree binding as the fbdev CLCD | |
| 19 | − * driver. While the fbdev driver supports panels that may be | |
| 20 | − * connected to the CLCD internally to the CLCD driver, in DRM the | |
| 21 | − * panels get split out to drivers/gpu/drm/panels/. This means that, | |
| 22 | − * in converting from using fbdev to using DRM, you also need to write | |
| 23 | − * a panel driver (which may be as simple as an entry in | |
| 24 | − * panel-simple.c). | |
| 15 | + * The PL110/PL111 is a simple LCD controller that can support TFT | |
| 16 | + * and STN displays. This driver exposes a standard KMS interface | |
| 17 | + * for them. | |
| 25 | 18 | * |
| 26 | 19 | * The driver currently doesn't expose the cursor. The DRM API for |
| 27 | 20 | * cursors requires support for 64x64 ARGB8888 cursor images, while |
| @@ -29,16 +22,13 @@ · 1 unmodified line | ||
| 29 | 22 | * cursors. While one could imagine trying to hack something together |
| 30 | 23 | * to look at the ARGB8888 and program reasonable in monochrome, we |
| 31 | 24 | * just don't expose the cursor at all instead, and leave cursor |
| 32 | − * support to the X11 software cursor layer. | |
| 25 | + * support to the application software cursor layer. | |
| 33 | 26 | * |
| 34 | 27 | * TODO: |
| 35 | 28 | * |
| 36 | 29 | * - Fix race between setting plane base address and getting IRQ for |
| 37 | 30 | * vsync firing the pageflip completion. |
| 38 | 31 | * |
| 39 | − * - Use the "max-memory-bandwidth" DT property to filter the | |
| 40 | − * supported formats. | |
| 41 | − * | |
| 42 | 32 | * - Read back hardware state at boot to skip reprogramming the |
| 43 | 33 | * hardware when doing a no-op modeset. |
| 44 | 34 | * |
| @@ -588,7 +588,7 @@ static int qxl_reap_surf(struct qxl_device *qdev, struct qxl_bo *surf, bool stal · 587 unmodified lines | ||
| 588 | 588 | { |
| 589 | 589 | int ret; |
| 590 | 590 | |
| 591 | − ret = qxl_bo_reserve(surf, false); | |
| 591 | + ret = qxl_bo_reserve(surf); | |
| 592 | 592 | if (ret) |
| 593 | 593 | return ret; |
| 594 | 594 | |
| @@ -162,7 +162,8 @@ static void qxl_update_offset_props(struct qxl_device *qdev) · 161 unmodified lines | ||
| 162 | 162 | void qxl_display_read_client_monitors_config(struct qxl_device *qdev) |
| 163 | 163 | { |
| 164 | 164 | struct drm_device *dev = &qdev->ddev; |
| 165 | − int status, retries; | |
| 165 | + struct drm_modeset_acquire_ctx ctx; | |
| 166 | + int status, retries, ret; | |
| 166 | 167 | |
| 167 | 168 | for (retries = 0; retries < 10; retries++) { |
| 168 | 169 | status = qxl_display_copy_rom_client_monitors_config(qdev); |
| @@ -183,9 +184,9 @@ void qxl_display_read_client_monitors_config(struct qxl_device *qdev) · 14 unmodified lines | ||
| 183 | 184 | return; |
| 184 | 185 | } |
| 185 | 186 | |
| 186 | − drm_modeset_lock_all(dev); | |
| 187 | + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret); | |
| 187 | 188 | qxl_update_offset_props(qdev); |
| 188 | − drm_modeset_unlock_all(dev); | |
| 189 | + DRM_MODESET_LOCK_ALL_END(ctx, ret); | |
| 189 | 190 | if (!drm_helper_hpd_irq_event(dev)) { |
| 190 | 191 | /* notify that the monitor configuration changed, to |
| 191 | 192 | adjust at the arbitrary resolution */ |
| @@ -403,18 +404,17 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, · 211 unmodified lines | ||
| 403 | 404 | struct qxl_device *qdev = to_qxl(fb->dev); |
| 404 | 405 | struct drm_clip_rect norect; |
| 405 | 406 | struct qxl_bo *qobj; |
| 407 | + struct drm_modeset_acquire_ctx ctx; | |
| 406 | 408 | bool is_primary; |
| 407 | − int inc = 1; | |
| 409 | + int inc = 1, ret; | |
| 408 | 410 | |
| 409 | − drm_modeset_lock_all(fb->dev); | |
| 411 | + DRM_MODESET_LOCK_ALL_BEGIN(fb->dev, ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret); | |
| 410 | 412 | |
| 411 | 413 | qobj = gem_to_qxl_bo(fb->obj[0]); |
| 412 | 414 | /* if we aren't primary surface ignore this */ |
| 413 | 415 | is_primary = qobj->shadow ? qobj->shadow->is_primary : qobj->is_primary; |
| 414 | − if (!is_primary) { | |
| 415 | − drm_modeset_unlock_all(fb->dev); | |
| 416 | − return 0; | |
| 417 | − } | |
| 416 | + if (!is_primary) | |
| 417 | + goto out_lock_end; | |
| 418 | 418 | |
| 419 | 419 | if (!num_clips) { |
| 420 | 420 | num_clips = 1; |
| @@ -430,7 +430,8 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, · 9 unmodified lines | ||
| 430 | 430 | qxl_draw_dirty_fb(qdev, fb, qobj, flags, color, |
| 431 | 431 | clips, num_clips, inc, 0); |
| 432 | 432 | |
| 433 | − drm_modeset_unlock_all(fb->dev); | |
| 433 | +out_lock_end: | |
| 434 | + DRM_MODESET_LOCK_ALL_END(ctx, ret); | |
| 434 | 435 | |
| 435 | 436 | return 0; |
| 436 | 437 | } |
| @@ -96,7 +96,7 @@ qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) · 95 unmodified lines | ||
| 96 | 96 | if (ret) |
| 97 | 97 | goto disable_pci; |
| 98 | 98 | |
| 99 | − if (is_vga(pdev)) { | |
| 99 | + if (is_vga(pdev) && pdev->revision < 5) { | |
| 100 | 100 | ret = vga_get_interruptible(pdev, VGA_RSRC_LEGACY_IO); |
| 101 | 101 | if (ret) { |
| 102 | 102 | DRM_ERROR("can't get legacy vga ioports\n"); |
| @@ -127,7 +127,7 @@ modeset_cleanup: · 24 unmodified lines | ||
| 127 | 127 | unload: |
| 128 | 128 | qxl_device_fini(qdev); |
| 129 | 129 | put_vga: |
| 130 | − if (is_vga(pdev)) | |
| 130 | + if (is_vga(pdev) && pdev->revision < 5) | |
| 131 | 131 | vga_put(pdev, VGA_RSRC_LEGACY_IO); |
| 132 | 132 | disable_pci: |
| 133 | 133 | pci_disable_device(pdev); |
| @@ -155,7 +155,7 @@ qxl_pci_remove(struct pci_dev *pdev) · 21 unmodified lines | ||
| 155 | 155 | |
| 156 | 156 | drm_dev_unregister(dev); |
| 157 | 157 | drm_atomic_helper_shutdown(dev); |
| 158 | − if (is_vga(pdev)) | |
| 158 | + if (is_vga(pdev) && pdev->revision < 5) | |
| 159 | 159 | vga_put(pdev, VGA_RSRC_LEGACY_IO); |
| 160 | 160 | } |
| 161 | 161 | |
| @@ -350,7 +350,7 @@ int qxl_mode_dumb_mmap(struct drm_file *filp, · 349 unmodified lines | ||
| 350 | 350 | int qxl_ttm_init(struct qxl_device *qdev); |
| 351 | 351 | void qxl_ttm_fini(struct qxl_device *qdev); |
| 352 | 352 | int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev, |
| 353 | − struct ttm_mem_reg *mem); | |
| 353 | + struct ttm_resource *mem); | |
| 354 | 354 | |
| 355 | 355 | /* qxl image */ |
| 356 | 356 | |
| @@ -322,7 +322,7 @@ static int qxl_update_area_ioctl(struct drm_device *dev, void *data, · 321 unmodified lines | ||
| 322 | 322 | |
| 323 | 323 | qobj = gem_to_qxl_bo(gobj); |
| 324 | 324 | |
| 325 | − ret = qxl_bo_reserve(qobj, false); | |
| 325 | + ret = qxl_bo_reserve(qobj); | |
| 326 | 326 | if (ret) |
| 327 | 327 | goto out; |
| 328 | 328 | |
| @@ -284,7 +284,7 @@ int qxl_bo_pin(struct qxl_bo *bo) · 283 unmodified lines | ||
| 284 | 284 | { |
| 285 | 285 | int r; |
| 286 | 286 | |
| 287 | − r = qxl_bo_reserve(bo, false); | |
| 287 | + r = qxl_bo_reserve(bo); | |
| 288 | 288 | if (r) |
| 289 | 289 | return r; |
| 290 | 290 | |
| @@ -302,7 +302,7 @@ int qxl_bo_unpin(struct qxl_bo *bo) · 11 unmodified lines | ||
| 302 | 302 | { |
| 303 | 303 | int r; |
| 304 | 304 | |
| 305 | − r = qxl_bo_reserve(bo, false); | |
| 305 | + r = qxl_bo_reserve(bo); | |
| 306 | 306 | if (r) |
| 307 | 307 | return r; |
| 308 | 308 | |
| @@ -27,11 +27,11 @@ · 26 unmodified lines | ||
| 27 | 27 | |
| 28 | 28 | #include "qxl_drv.h" |
| 29 | 29 | |
| 30 | −static inline int qxl_bo_reserve(struct qxl_bo *bo, bool no_wait) | |
| 30 | +static inline int qxl_bo_reserve(struct qxl_bo *bo) | |
| 31 | 31 | { |
| 32 | 32 | int r; |
| 33 | 33 | |
| 34 | − r = ttm_bo_reserve(&bo->tbo, true, no_wait, NULL); | |
| 34 | + r = ttm_bo_reserve(&bo->tbo, true, false, NULL); | |
| 35 | 35 | if (unlikely(r != 0)) { |
| 36 | 36 | if (r != -ERESTARTSYS) { |
| 37 | 37 | struct drm_device *ddev = bo->tbo.base.dev; |
| @@ -48,31 +48,6 @@ static struct qxl_device *qxl_get_qdev(struct ttm_bo_device *bdev) · 47 unmodified lines | ||
| 48 | 48 | return qdev; |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | −static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | |
| 52 | − struct ttm_mem_type_manager *man) | |
| 53 | −{ | |
| 54 | − switch (type) { | |
| 55 | − case TTM_PL_SYSTEM: | |
| 56 | − /* System memory */ | |
| 57 | − man->flags = 0; | |
| 58 | − man->available_caching = TTM_PL_MASK_CACHING; | |
| 59 | − man->default_caching = TTM_PL_FLAG_CACHED; | |
| 60 | − break; | |
| 61 | − case TTM_PL_VRAM: | |
| 62 | − case TTM_PL_PRIV: | |
| 63 | − /* "On-card" video ram */ | |
| 64 | − man->func = &ttm_bo_manager_func; | |
| 65 | − man->flags = TTM_MEMTYPE_FLAG_FIXED; | |
| 66 | − man->available_caching = TTM_PL_MASK_CACHING; | |
| 67 | − man->default_caching = TTM_PL_FLAG_CACHED; | |
| 68 | − break; | |
| 69 | − default: | |
| 70 | − DRM_ERROR("Unsupported memory type %u\n", (unsigned int)type); | |
| 71 | − return -EINVAL; | |
| 72 | − } | |
| 73 | − return 0; | |
| 74 | −} | |
| 75 | − | |
| 76 | 51 | static void qxl_evict_flags(struct ttm_buffer_object *bo, |
| 77 | 52 | struct ttm_placement *placement) |
| 78 | 53 | { |
| @@ -96,16 +71,10 @@ static void qxl_evict_flags(struct ttm_buffer_object *bo, · 17 unmodified lines | ||
| 96 | 71 | } |
| 97 | 72 | |
| 98 | 73 | int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev, |
| 99 | − struct ttm_mem_reg *mem) | |
| 74 | + struct ttm_resource *mem) | |
| 100 | 75 | { |
| 101 | 76 | struct qxl_device *qdev = qxl_get_qdev(bdev); |
| 102 | 77 | |
| 103 | − mem->bus.addr = NULL; | |
| 104 | − mem->bus.offset = 0; | |
| 105 | − mem->bus.size = mem->num_pages << PAGE_SHIFT; | |
| 106 | − mem->bus.base = 0; | |
| 107 | − mem->bus.is_iomem = false; | |
| 108 | − | |
| 109 | 78 | switch (mem->mem_type) { |
| 110 | 79 | case TTM_PL_SYSTEM: |
| 111 | 80 | /* system memory */ |
| @@ -136,7 +105,7 @@ struct qxl_ttm_tt { · 24 unmodified lines | ||
| 136 | 105 | }; |
| 137 | 106 | |
| 138 | 107 | static int qxl_ttm_backend_bind(struct ttm_tt *ttm, |
| 139 | − struct ttm_mem_reg *bo_mem) | |
| 108 | + struct ttm_resource *bo_mem) | |
| 140 | 109 | { |
| 141 | 110 | struct qxl_ttm_tt *gtt = (void *)ttm; |
| 142 | 111 | |
| @@ -188,9 +157,9 @@ static struct ttm_tt *qxl_ttm_tt_create(struct ttm_buffer_object *bo, · 45 unmodified lines | ||
| 188 | 157 | } |
| 189 | 158 | |
| 190 | 159 | static void qxl_move_null(struct ttm_buffer_object *bo, |
| 191 | − struct ttm_mem_reg *new_mem) | |
| 160 | + struct ttm_resource *new_mem) | |
| 192 | 161 | { |
| 193 | − struct ttm_mem_reg *old_mem = &bo->mem; | |
| 162 | + struct ttm_resource *old_mem = &bo->mem; | |
| 194 | 163 | |
| 195 | 164 | BUG_ON(old_mem->mm_node != NULL); |
| 196 | 165 | *old_mem = *new_mem; |
| @@ -199,9 +168,9 @@ static void qxl_move_null(struct ttm_buffer_object *bo, · 2 unmodified lines | ||
| 199 | 168 | |
| 200 | 169 | static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict, |
| 201 | 170 | struct ttm_operation_ctx *ctx, |
| 202 | − struct ttm_mem_reg *new_mem) | |
| 171 | + struct ttm_resource *new_mem) | |
| 203 | 172 | { |
| 204 | − struct ttm_mem_reg *old_mem = &bo->mem; | |
| 173 | + struct ttm_resource *old_mem = &bo->mem; | |
| 205 | 174 | int ret; |
| 206 | 175 | |
| 207 | 176 | ret = ttm_bo_wait(bo, ctx->interruptible, ctx->no_wait_gpu); |
| @@ -217,7 +186,7 @@ static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict, · 9 unmodified lines | ||
| 217 | 186 | |
| 218 | 187 | static void qxl_bo_move_notify(struct ttm_buffer_object *bo, |
| 219 | 188 | bool evict, |
| 220 | − struct ttm_mem_reg *new_mem) | |
| 189 | + struct ttm_resource *new_mem) | |
| 221 | 190 | { |
| 222 | 191 | struct qxl_bo *qbo; |
| 223 | 192 | struct qxl_device *qdev; |
| @@ -233,7 +202,6 @@ static void qxl_bo_move_notify(struct ttm_buffer_object *bo, · 9 unmodified lines | ||
| 233 | 202 | |
| 234 | 203 | static struct ttm_bo_driver qxl_bo_driver = { |
| 235 | 204 | .ttm_tt_create = &qxl_ttm_tt_create, |
| 236 | − .init_mem_type = &qxl_init_mem_type, | |
| 237 | 205 | .eviction_valuable = ttm_bo_eviction_valuable, |
| 238 | 206 | .evict_flags = &qxl_evict_flags, |
| 239 | 207 | .move = &qxl_bo_move, |
| @@ -241,6 +209,14 @@ static struct ttm_bo_driver qxl_bo_driver = { · 1 unmodified line | ||
| 241 | 209 | .move_notify = &qxl_bo_move_notify, |
| 242 | 210 | }; |
| 243 | 211 | |
| 212 | +static int qxl_ttm_init_mem_type(struct qxl_device *qdev, | |
| 213 | + unsigned int type, | |
| 214 | + uint64_t size) | |
| 215 | +{ | |
| 216 | + return ttm_range_man_init(&qdev->mman.bdev, type, TTM_PL_MASK_CACHING, | |
| 217 | + TTM_PL_FLAG_CACHED, false, size); | |
| 218 | +} | |
| 219 | + | |
| 244 | 220 | int qxl_ttm_init(struct qxl_device *qdev) |
| 245 | 221 | { |
| 246 | 222 | int r; |
| @@ -258,14 +234,13 @@ int qxl_ttm_init(struct qxl_device *qdev) · 11 unmodified lines | ||
| 258 | 234 | } |
| 259 | 235 | /* NOTE: this includes the framebuffer (aka surface 0) */ |
| 260 | 236 | num_io_pages = qdev->rom->ram_header_offset / PAGE_SIZE; |
| 261 | − r = ttm_bo_init_mm(&qdev->mman.bdev, TTM_PL_VRAM, | |
| 262 | − num_io_pages); | |
| 237 | + r = qxl_ttm_init_mem_type(qdev, TTM_PL_VRAM, num_io_pages); | |
| 263 | 238 | if (r) { |
| 264 | 239 | DRM_ERROR("Failed initializing VRAM heap.\n"); |
| 265 | 240 | return r; |
| 266 | 241 | } |
| 267 | − r = ttm_bo_init_mm(&qdev->mman.bdev, TTM_PL_PRIV, | |
| 268 | − qdev->surfaceram_size / PAGE_SIZE); | |
| 242 | + r = qxl_ttm_init_mem_type(qdev, TTM_PL_PRIV, | |
| 243 | + qdev->surfaceram_size / PAGE_SIZE); | |
| 269 | 244 | if (r) { |
| 270 | 245 | DRM_ERROR("Failed initializing Surfaces heap.\n"); |
| 271 | 246 | return r; |
| @@ -281,8 +256,8 @@ int qxl_ttm_init(struct qxl_device *qdev) · 9 unmodified lines | ||
| 281 | 256 | |
| 282 | 257 | void qxl_ttm_fini(struct qxl_device *qdev) |
| 283 | 258 | { |
| 284 | − ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_VRAM); | |
| 285 | − ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_PRIV); | |
| 259 | + ttm_range_man_fini(&qdev->mman.bdev, TTM_PL_VRAM); | |
| 260 | + ttm_range_man_fini(&qdev->mman.bdev, TTM_PL_PRIV); | |
| 286 | 261 | ttm_bo_device_release(&qdev->mman.bdev); |
| 287 | 262 | DRM_INFO("qxl: ttm finalized\n"); |
| 288 | 263 | } |
| @@ -293,12 +268,10 @@ void qxl_ttm_fini(struct qxl_device *qdev) · 4 unmodified lines | ||
| 293 | 268 | static int qxl_mm_dump_table(struct seq_file *m, void *data) |
| 294 | 269 | { |
| 295 | 270 | struct drm_info_node *node = (struct drm_info_node *)m->private; |
| 296 | − struct drm_mm *mm = (struct drm_mm *)node->info_ent->data; | |
| 271 | + struct ttm_resource_manager *man = (struct ttm_resource_manager *)node->info_ent->data; | |
| 297 | 272 | struct drm_printer p = drm_seq_file_printer(m); |
| 298 | 273 | |
| 299 | − spin_lock(&ttm_bo_glob.lru_lock); | |
| 300 | − drm_mm_print(mm, &p); | |
| 301 | − spin_unlock(&ttm_bo_glob.lru_lock); | |
| 274 | + ttm_resource_manager_debug(man, &p); | |
| 302 | 275 | return 0; |
| 303 | 276 | } |
| 304 | 277 | #endif |
| @@ -319,9 +292,9 @@ void qxl_ttm_debugfs_init(struct qxl_device *qdev) · 14 unmodified lines | ||
| 319 | 292 | qxl_mem_types_list[i].show = &qxl_mm_dump_table; |
| 320 | 293 | qxl_mem_types_list[i].driver_features = 0; |
| 321 | 294 | if (i == 0) |
| 322 | − qxl_mem_types_list[i].data = qdev->mman.bdev.man[TTM_PL_VRAM].priv; | |
| 295 | + qxl_mem_types_list[i].data = ttm_manager_type(&qdev->mman.bdev, TTM_PL_VRAM); | |
| 323 | 296 | else |
| 324 | − qxl_mem_types_list[i].data = qdev->mman.bdev.man[TTM_PL_PRIV].priv; | |
| 297 | + qxl_mem_types_list[i].data = ttm_manager_type(&qdev->mman.bdev, TTM_PL_PRIV); | |
| 325 | 298 | |
| 326 | 299 | } |
| 327 | 300 | qxl_debugfs_add_files(qdev, qxl_mem_types_list, i); |
| @@ -2857,7 +2857,7 @@ int radeon_vm_clear_invalids(struct radeon_device *rdev, · 2856 unmodified lines | ||
| 2857 | 2857 | struct radeon_vm *vm); |
| 2858 | 2858 | int radeon_vm_bo_update(struct radeon_device *rdev, |
| 2859 | 2859 | struct radeon_bo_va *bo_va, |
| 2860 | − struct ttm_mem_reg *mem); | |
| 2860 | + struct ttm_resource *mem); | |
| 2861 | 2861 | void radeon_vm_bo_invalidate(struct radeon_device *rdev, |
| 2862 | 2862 | struct radeon_bo *bo); |
| 2863 | 2863 | struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, |
| @@ -224,9 +224,9 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data, · 223 unmodified lines | ||
| 224 | 224 | { |
| 225 | 225 | struct radeon_device *rdev = dev->dev_private; |
| 226 | 226 | struct drm_radeon_gem_info *args = data; |
| 227 | − struct ttm_mem_type_manager *man; | |
| 227 | + struct ttm_resource_manager *man; | |
| 228 | 228 | |
| 229 | − man = &rdev->mman.bdev.man[TTM_PL_VRAM]; | |
| 229 | + man = ttm_manager_type(&rdev->mman.bdev, TTM_PL_VRAM); | |
| 230 | 230 | |
| 231 | 231 | args->vram_size = (u64)man->size << PAGE_SHIFT; |
| 232 | 232 | args->vram_visible = rdev->mc.visible_vram_size; |
| @@ -775,7 +775,7 @@ int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved, · 774 unmodified lines | ||
| 775 | 775 | |
| 776 | 776 | void radeon_bo_move_notify(struct ttm_buffer_object *bo, |
| 777 | 777 | bool evict, |
| 778 | − struct ttm_mem_reg *new_mem) | |
| 778 | + struct ttm_resource *new_mem) | |
| 779 | 779 | { |
| 780 | 780 | struct radeon_bo *rbo; |
| 781 | 781 | |
| @@ -165,7 +165,7 @@ extern int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved, · 164 unmodified lines | ||
| 165 | 165 | bool force_drop); |
| 166 | 166 | extern void radeon_bo_move_notify(struct ttm_buffer_object *bo, |
| 167 | 167 | bool evict, |
| 168 | − struct ttm_mem_reg *new_mem); | |
| 168 | + struct ttm_resource *new_mem); | |
| 169 | 169 | extern int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo); |
| 170 | 170 | extern int radeon_bo_get_surface_reg(struct radeon_bo *bo); |
| 171 | 171 | extern void radeon_bo_fence(struct radeon_bo *bo, struct radeon_fence *fence, |
| @@ -66,53 +66,20 @@ struct radeon_device *radeon_get_rdev(struct ttm_bo_device *bdev) · 65 unmodified lines | ||
| 66 | 66 | return rdev; |
| 67 | 67 | } |
| 68 | 68 | |
| 69 | −static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | |
| 70 | − struct ttm_mem_type_manager *man) | |
| 69 | +static int radeon_ttm_init_vram(struct radeon_device *rdev) | |
| 71 | 70 | { |
| 72 | − struct radeon_device *rdev; | |
| 73 | − | |
| 74 | − rdev = radeon_get_rdev(bdev); | |
| 71 | + return ttm_range_man_init(&rdev->mman.bdev, TTM_PL_VRAM, | |
| 72 | + TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC, | |
| 73 | + TTM_PL_FLAG_WC, false, | |
| 74 | + rdev->mc.real_vram_size >> PAGE_SHIFT); | |
| 75 | +} | |
| 75 | 76 | |
| 76 | − switch (type) { | |
| 77 | − case TTM_PL_SYSTEM: | |
| 78 | − /* System memory */ | |
| 79 | − man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | |
| 80 | − man->available_caching = TTM_PL_MASK_CACHING; | |
| 81 | − man->default_caching = TTM_PL_FLAG_CACHED; | |
| 82 | − break; | |
| 83 | − case TTM_PL_TT: | |
| 84 | − man->func = &ttm_bo_manager_func; | |
| 85 | − man->available_caching = TTM_PL_MASK_CACHING; | |
| 86 | − man->default_caching = TTM_PL_FLAG_CACHED; | |
| 87 | − man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | |
| 88 | −#if IS_ENABLED(CONFIG_AGP) | |
| 89 | − if (rdev->flags & RADEON_IS_AGP) { | |
| 90 | − if (!rdev->ddev->agp) { | |
| 91 | − DRM_ERROR("AGP is not enabled for memory type %u\n", | |
| 92 | − (unsigned)type); | |
| 93 | − return -EINVAL; | |
| 94 | − } | |
| 95 | − if (!rdev->ddev->agp->cant_use_aperture) | |
| 96 | − man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | |
| 97 | − man->available_caching = TTM_PL_FLAG_UNCACHED | | |
| 98 | − TTM_PL_FLAG_WC; | |
| 99 | − man->default_caching = TTM_PL_FLAG_WC; | |
| 100 | − } | |
| 101 | −#endif | |
| 102 | − break; | |
| 103 | − case TTM_PL_VRAM: | |
| 104 | − /* "On-card" video ram */ | |
| 105 | − man->func = &ttm_bo_manager_func; | |
| 106 | − man->flags = TTM_MEMTYPE_FLAG_FIXED | | |
| 107 | − TTM_MEMTYPE_FLAG_MAPPABLE; | |
| 108 | − man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; | |
| 109 | − man->default_caching = TTM_PL_FLAG_WC; | |
| 110 | − break; | |
| 111 | − default: | |
| 112 | − DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); | |
| 113 | − return -EINVAL; | |
| 114 | − } | |
| 115 | − return 0; | |
| 77 | +static int radeon_ttm_init_gtt(struct radeon_device *rdev) | |
| 78 | +{ | |
| 79 | + return ttm_range_man_init(&rdev->mman.bdev, TTM_PL_TT, | |
| 80 | + TTM_PL_MASK_CACHING, | |
| 81 | + TTM_PL_FLAG_CACHED, true, | |
| 82 | + rdev->mc.gtt_size >> PAGE_SHIFT); | |
| 116 | 83 | } |
| 117 | 84 | |
| 118 | 85 | static void radeon_evict_flags(struct ttm_buffer_object *bo, |
| @@ -182,9 +149,9 @@ static int radeon_verify_access(struct ttm_buffer_object *bo, struct file *filp) · 63 unmodified lines | ||
| 182 | 149 | } |
| 183 | 150 | |
| 184 | 151 | static void radeon_move_null(struct ttm_buffer_object *bo, |
| 185 | − struct ttm_mem_reg *new_mem) | |
| 152 | + struct ttm_resource *new_mem) | |
| 186 | 153 | { |
| 187 | − struct ttm_mem_reg *old_mem = &bo->mem; | |
| 154 | + struct ttm_resource *old_mem = &bo->mem; | |
| 188 | 155 | |
| 189 | 156 | BUG_ON(old_mem->mm_node != NULL); |
| 190 | 157 | *old_mem = *new_mem; |
| @@ -193,8 +160,8 @@ static void radeon_move_null(struct ttm_buffer_object *bo, · 2 unmodified lines | ||
| 193 | 160 | |
| 194 | 161 | static int radeon_move_blit(struct ttm_buffer_object *bo, |
| 195 | 162 | bool evict, bool no_wait_gpu, |
| 196 | − struct ttm_mem_reg *new_mem, | |
| 197 | − struct ttm_mem_reg *old_mem) | |
| 163 | + struct ttm_resource *new_mem, | |
| 164 | + struct ttm_resource *old_mem) | |
| 198 | 165 | { |
| 199 | 166 | struct radeon_device *rdev; |
| 200 | 167 | uint64_t old_start, new_start; |
| @@ -249,11 +216,11 @@ static int radeon_move_blit(struct ttm_buffer_object *bo, · 48 unmodified lines | ||
| 249 | 216 | static int radeon_move_vram_ram(struct ttm_buffer_object *bo, |
| 250 | 217 | bool evict, bool interruptible, |
| 251 | 218 | bool no_wait_gpu, |
| 252 | − struct ttm_mem_reg *new_mem) | |
| 219 | + struct ttm_resource *new_mem) | |
| 253 | 220 | { |
| 254 | 221 | struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu }; |
| 255 | − struct ttm_mem_reg *old_mem = &bo->mem; | |
| 256 | − struct ttm_mem_reg tmp_mem; | |
| 222 | + struct ttm_resource *old_mem = &bo->mem; | |
| 223 | + struct ttm_resource tmp_mem; | |
| 257 | 224 | struct ttm_place placements; |
| 258 | 225 | struct ttm_placement placement; |
| 259 | 226 | int r; |
| @@ -287,18 +254,18 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo, · 27 unmodified lines | ||
| 287 | 254 | } |
| 288 | 255 | r = ttm_bo_move_ttm(bo, &ctx, new_mem); |
| 289 | 256 | out_cleanup: |
| 290 | − ttm_bo_mem_put(bo, &tmp_mem); | |
| 257 | + ttm_resource_free(bo, &tmp_mem); | |
| 291 | 258 | return r; |
| 292 | 259 | } |
| 293 | 260 | |
| 294 | 261 | static int radeon_move_ram_vram(struct ttm_buffer_object *bo, |
| 295 | 262 | bool evict, bool interruptible, |
| 296 | 263 | bool no_wait_gpu, |
| 297 | − struct ttm_mem_reg *new_mem) | |
| 264 | + struct ttm_resource *new_mem) | |
| 298 | 265 | { |
| 299 | 266 | struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu }; |
| 300 | − struct ttm_mem_reg *old_mem = &bo->mem; | |
| 301 | − struct ttm_mem_reg tmp_mem; | |
| 267 | + struct ttm_resource *old_mem = &bo->mem; | |
| 268 | + struct ttm_resource tmp_mem; | |
| 302 | 269 | struct ttm_placement placement; |
| 303 | 270 | struct ttm_place placements; |
| 304 | 271 | int r; |
| @@ -325,17 +292,17 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo, · 20 unmodified lines | ||
| 325 | 292 | goto out_cleanup; |
| 326 | 293 | } |
| 327 | 294 | out_cleanup: |
| 328 | − ttm_bo_mem_put(bo, &tmp_mem); | |
| 295 | + ttm_resource_free(bo, &tmp_mem); | |
| 329 | 296 | return r; |
| 330 | 297 | } |
| 331 | 298 | |
| 332 | 299 | static int radeon_bo_move(struct ttm_buffer_object *bo, bool evict, |
| 333 | 300 | struct ttm_operation_ctx *ctx, |
| 334 | − struct ttm_mem_reg *new_mem) | |
| 301 | + struct ttm_resource *new_mem) | |
| 335 | 302 | { |
| 336 | 303 | struct radeon_device *rdev; |
| 337 | 304 | struct radeon_bo *rbo; |
| 338 | − struct ttm_mem_reg *old_mem = &bo->mem; | |
| 305 | + struct ttm_resource *old_mem = &bo->mem; | |
| 339 | 306 | int r; |
| 340 | 307 | |
| 341 | 308 | r = ttm_bo_wait(bo, ctx->interruptible, ctx->no_wait_gpu); |
| @@ -392,18 +359,11 @@ memcpy: · 50 unmodified lines | ||
| 392 | 359 | return 0; |
| 393 | 360 | } |
| 394 | 361 | |
| 395 | −static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) | |
| 362 | +static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *mem) | |
| 396 | 363 | { |
| 397 | − struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; | |
| 398 | 364 | struct radeon_device *rdev = radeon_get_rdev(bdev); |
| 365 | + size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT; | |
| 399 | 366 | |
| 400 | − mem->bus.addr = NULL; | |
| 401 | − mem->bus.offset = 0; | |
| 402 | − mem->bus.size = mem->num_pages << PAGE_SHIFT; | |
| 403 | − mem->bus.base = 0; | |
| 404 | − mem->bus.is_iomem = false; | |
| 405 | − if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) | |
| 406 | − return -EINVAL; | |
| 407 | 367 | switch (mem->mem_type) { |
| 408 | 368 | case TTM_PL_SYSTEM: |
| 409 | 369 | /* system memory */ |
| @@ -421,7 +381,7 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_ · 11 unmodified lines | ||
| 421 | 381 | case TTM_PL_VRAM: |
| 422 | 382 | mem->bus.offset = mem->start << PAGE_SHIFT; |
| 423 | 383 | /* check if it's visible */ |
| 424 | − if ((mem->bus.offset + mem->bus.size) > rdev->mc.visible_vram_size) | |
| 384 | + if ((mem->bus.offset + bus_size) > rdev->mc.visible_vram_size) | |
| 425 | 385 | return -EINVAL; |
| 426 | 386 | mem->bus.base = rdev->mc.aper_base; |
| 427 | 387 | mem->bus.is_iomem = true; |
| @@ -433,11 +393,11 @@ static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_ · 5 unmodified lines | ||
| 433 | 393 | if (mem->placement & TTM_PL_FLAG_WC) |
| 434 | 394 | mem->bus.addr = |
| 435 | 395 | ioremap_wc(mem->bus.base + mem->bus.offset, |
| 436 | − mem->bus.size); | |
| 396 | + bus_size); | |
| 437 | 397 | else |
| 438 | 398 | mem->bus.addr = |
| 439 | 399 | ioremap(mem->bus.base + mem->bus.offset, |
| 440 | − mem->bus.size); | |
| 400 | + bus_size); | |
| 441 | 401 | if (!mem->bus.addr) |
| 442 | 402 | return -ENOMEM; |
| 443 | 403 | |
| @@ -562,7 +522,7 @@ static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm) · 118 unmodified lines | ||
| 562 | 522 | } |
| 563 | 523 | |
| 564 | 524 | static int radeon_ttm_backend_bind(struct ttm_tt *ttm, |
| 565 | − struct ttm_mem_reg *bo_mem) | |
| 525 | + struct ttm_resource *bo_mem) | |
| 566 | 526 | { |
| 567 | 527 | struct radeon_ttm_tt *gtt = (void*)ttm; |
| 568 | 528 | uint32_t flags = RADEON_GART_PAGE_VALID | RADEON_GART_PAGE_READ | |
| @@ -760,7 +720,6 @@ static struct ttm_bo_driver radeon_bo_driver = { · 191 unmodified lines | ||
| 760 | 720 | .ttm_tt_create = &radeon_ttm_tt_create, |
| 761 | 721 | .ttm_tt_populate = &radeon_ttm_tt_populate, |
| 762 | 722 | .ttm_tt_unpopulate = &radeon_ttm_tt_unpopulate, |
| 763 | − .init_mem_type = &radeon_init_mem_type, | |
| 764 | 723 | .eviction_valuable = ttm_bo_eviction_valuable, |
| 765 | 724 | .evict_flags = &radeon_evict_flags, |
| 766 | 725 | .move = &radeon_bo_move, |
| @@ -785,8 +744,8 @@ int radeon_ttm_init(struct radeon_device *rdev) · 18 unmodified lines | ||
| 785 | 744 | return r; |
| 786 | 745 | } |
| 787 | 746 | rdev->mman.initialized = true; |
| 788 | − r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_VRAM, | |
| 789 | − rdev->mc.real_vram_size >> PAGE_SHIFT); | |
| 747 | + | |
| 748 | + r = radeon_ttm_init_vram(rdev); | |
| 790 | 749 | if (r) { |
| 791 | 750 | DRM_ERROR("Failed initializing VRAM heap.\n"); |
| 792 | 751 | return r; |
| @@ -811,8 +770,8 @@ int radeon_ttm_init(struct radeon_device *rdev) · 18 unmodified lines | ||
| 811 | 770 | } |
| 812 | 771 | DRM_INFO("radeon: %uM of VRAM memory ready\n", |
| 813 | 772 | (unsigned) (rdev->mc.real_vram_size / (1024 * 1024))); |
| 814 | − r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_TT, | |
| 815 | − rdev->mc.gtt_size >> PAGE_SHIFT); | |
| 773 | + | |
| 774 | + r = radeon_ttm_init_gtt(rdev); | |
| 816 | 775 | if (r) { |
| 817 | 776 | DRM_ERROR("Failed initializing GTT heap.\n"); |
| 818 | 777 | return r; |
| @@ -843,8 +802,8 @@ void radeon_ttm_fini(struct radeon_device *rdev) · 24 unmodified lines | ||
| 843 | 802 | } |
| 844 | 803 | radeon_bo_unref(&rdev->stolen_vga_memory); |
| 845 | 804 | } |
| 846 | − ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_VRAM); | |
| 847 | − ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_TT); | |
| 805 | + ttm_range_man_fini(&rdev->mman.bdev, TTM_PL_VRAM); | |
| 806 | + ttm_range_man_fini(&rdev->mman.bdev, TTM_PL_TT); | |
| 848 | 807 | ttm_bo_device_release(&rdev->mman.bdev); |
| 849 | 808 | radeon_gart_fini(rdev); |
| 850 | 809 | rdev->mman.initialized = false; |
| @@ -855,12 +814,12 @@ void radeon_ttm_fini(struct radeon_device *rdev) · 4 unmodified lines | ||
| 855 | 814 | * isn't running */ |
| 856 | 815 | void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size) |
| 857 | 816 | { |
| 858 | − struct ttm_mem_type_manager *man; | |
| 817 | + struct ttm_resource_manager *man; | |
| 859 | 818 | |
| 860 | 819 | if (!rdev->mman.initialized) |
| 861 | 820 | return; |
| 862 | 821 | |
| 863 | − man = &rdev->mman.bdev.man[TTM_PL_VRAM]; | |
| 822 | + man = ttm_manager_type(&rdev->mman.bdev, TTM_PL_VRAM); | |
| 864 | 823 | /* this just adjusts TTM size idea, which sets lpfn to the correct value */ |
| 865 | 824 | man->size = size >> PAGE_SHIFT; |
| 866 | 825 | } |
| @@ -914,7 +873,7 @@ static int radeon_mm_dump_table(struct seq_file *m, void *data) · 47 unmodified lines | ||
| 914 | 873 | unsigned ttm_pl = *(int*)node->info_ent->data; |
| 915 | 874 | struct drm_device *dev = node->minor->dev; |
| 916 | 875 | struct radeon_device *rdev = dev->dev_private; |
| 917 | − struct ttm_mem_type_manager *man = &rdev->mman.bdev.man[ttm_pl]; | |
| 876 | + struct ttm_resource_manager *man = ttm_manager_type(&rdev->mman.bdev, ttm_pl); | |
| 918 | 877 | struct drm_printer p = drm_seq_file_printer(m); |
| 919 | 878 | |
| 920 | 879 | man->func->debug(man, &p); |
| @@ -911,7 +911,7 @@ static void radeon_vm_fence_pts(struct radeon_vm *vm, · 910 unmodified lines | ||
| 911 | 911 | */ |
| 912 | 912 | int radeon_vm_bo_update(struct radeon_device *rdev, |
| 913 | 913 | struct radeon_bo_va *bo_va, |
| 914 | − struct ttm_mem_reg *mem) | |
| 914 | + struct ttm_resource *mem) | |
| 915 | 915 | { |
| 916 | 916 | struct radeon_vm *vm = bo_va->vm; |
| 917 | 917 | struct radeon_ib ib; |
| @@ -677,15 +677,11 @@ static int rcar_lvds_attach(struct drm_bridge *bridge, · 676 unmodified lines | ||
| 677 | 677 | if (ret < 0) |
| 678 | 678 | return ret; |
| 679 | 679 | |
| 680 | − return drm_panel_attach(lvds->panel, connector); | |
| 680 | + return 0; | |
| 681 | 681 | } |
| 682 | 682 | |
| 683 | 683 | static void rcar_lvds_detach(struct drm_bridge *bridge) |
| 684 | 684 | { |
| 685 | − struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); | |
| 686 | − | |
| 687 | − if (lvds->panel) | |
| 688 | − drm_panel_detach(lvds->panel); | |
| 689 | 685 | } |
| 690 | 686 | |
| 691 | 687 | static const struct drm_bridge_funcs rcar_lvds_bridge_ops = { |
| @@ -634,13 +634,6 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, · 633 unmodified lines | ||
| 634 | 634 | "failed to attach encoder: %d\n", ret); |
| 635 | 635 | goto err_free_connector; |
| 636 | 636 | } |
| 637 | − | |
| 638 | − ret = drm_panel_attach(lvds->panel, connector); | |
| 639 | − if (ret < 0) { | |
| 640 | − DRM_DEV_ERROR(drm_dev->dev, | |
| 641 | − "failed to attach panel: %d\n", ret); | |
| 642 | − goto err_free_connector; | |
| 643 | − } | |
| 644 | 637 | } else { |
| 645 | 638 | ret = drm_bridge_attach(encoder, lvds->bridge, NULL, 0); |
| 646 | 639 | if (ret) { |
| @@ -676,8 +669,6 @@ static void rockchip_lvds_unbind(struct device *dev, struct device *master, · 29 unmodified lines | ||
| 676 | 669 | |
| 677 | 670 | encoder_funcs = lvds->soc_data->helper_funcs; |
| 678 | 671 | encoder_funcs->disable(&lvds->encoder); |
| 679 | − if (lvds->panel) | |
| 680 | − drm_panel_detach(lvds->panel); | |
| 681 | 672 | pm_runtime_disable(dev); |
| 682 | 673 | drm_connector_cleanup(&lvds->connector); |
| 683 | 674 | drm_encoder_cleanup(&lvds->encoder); |
| @@ -389,8 +389,6 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force) · 388 unmodified lines | ||
| 389 | 389 | dvo->panel = of_drm_find_panel(dvo->panel_node); |
| 390 | 390 | if (IS_ERR(dvo->panel)) |
| 391 | 391 | dvo->panel = NULL; |
| 392 | − else | |
| 393 | − drm_panel_attach(dvo->panel, connector); | |
| 394 | 392 | } |
| 395 | 393 | |
| 396 | 394 | if (dvo->panel) |
| @@ -769,7 +769,7 @@ static const struct sunxi_engine_ops sun4i_backend_engine_ops = { · 768 unmodified lines | ||
| 769 | 769 | .vblank_quirk = sun4i_backend_vblank_quirk, |
| 770 | 770 | }; |
| 771 | 771 | |
| 772 | −static struct regmap_config sun4i_backend_regmap_config = { | |
| 772 | +static const struct regmap_config sun4i_backend_regmap_config = { | |
| 773 | 773 | .reg_bits = 32, |
| 774 | 774 | .val_bits = 32, |
| 775 | 775 | .reg_stride = 4, |
| @@ -35,7 +35,7 @@ static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = { · 34 unmodified lines | ||
| 35 | 35 | .fb_create = drm_gem_fb_create, |
| 36 | 36 | }; |
| 37 | 37 | |
| 38 | −static struct drm_mode_config_helper_funcs sun4i_de_mode_config_helpers = { | |
| 38 | +static const struct drm_mode_config_helper_funcs sun4i_de_mode_config_helpers = { | |
| 39 | 39 | .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, |
| 40 | 40 | }; |
| 41 | 41 | |
| @@ -545,7 +545,7 @@ int sun4i_frontend_enable(struct sun4i_frontend *frontend) · 544 unmodified lines | ||
| 545 | 545 | } |
| 546 | 546 | EXPORT_SYMBOL(sun4i_frontend_enable); |
| 547 | 547 | |
| 548 | −static struct regmap_config sun4i_frontend_regmap_config = { | |
| 548 | +static const struct regmap_config sun4i_frontend_regmap_config = { | |
| 549 | 549 | .reg_bits = 32, |
| 550 | 550 | .val_bits = 32, |
| 551 | 551 | .reg_stride = 4, |
| @@ -47,16 +47,13 @@ static int sun4i_lvds_get_modes(struct drm_connector *connector) · 46 unmodified lines | ||
| 47 | 47 | return drm_panel_get_modes(lvds->panel, connector); |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | −static struct drm_connector_helper_funcs sun4i_lvds_con_helper_funcs = { | |
| 50 | +static const struct drm_connector_helper_funcs sun4i_lvds_con_helper_funcs = { | |
| 51 | 51 | .get_modes = sun4i_lvds_get_modes, |
| 52 | 52 | }; |
| 53 | 53 | |
| 54 | 54 | static void |
| 55 | 55 | sun4i_lvds_connector_destroy(struct drm_connector *connector) |
| 56 | 56 | { |
| 57 | − struct sun4i_lvds *lvds = drm_connector_to_sun4i_lvds(connector); | |
| 58 | − | |
| 59 | − drm_panel_detach(lvds->panel); | |
| 60 | 57 | drm_connector_cleanup(connector); |
| 61 | 58 | } |
| 62 | 59 | |
| @@ -141,12 +138,6 @@ int sun4i_lvds_init(struct drm_device *drm, struct sun4i_tcon *tcon) · 78 unmodified lines | ||
| 141 | 138 | |
| 142 | 139 | drm_connector_attach_encoder(&lvds->connector, |
| 143 | 140 | &lvds->encoder); |
| 144 | − | |
| 145 | − ret = drm_panel_attach(lvds->panel, &lvds->connector); | |
| 146 | − if (ret) { | |
| 147 | − dev_err(drm->dev, "Couldn't attach our panel\n"); | |
| 148 | − goto err_cleanup_connector; | |
| 149 | − } | |
| 150 | 141 | } |
| 151 | 142 | |
| 152 | 143 | if (bridge) { |
| @@ -138,16 +138,13 @@ out: · 137 unmodified lines | ||
| 138 | 138 | return MODE_OK; |
| 139 | 139 | } |
| 140 | 140 | |
| 141 | −static struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = { | |
| 141 | +static const struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = { | |
| 142 | 142 | .get_modes = sun4i_rgb_get_modes, |
| 143 | 143 | }; |
| 144 | 144 | |
| 145 | 145 | static void |
| 146 | 146 | sun4i_rgb_connector_destroy(struct drm_connector *connector) |
| 147 | 147 | { |
| 148 | − struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector); | |
| 149 | − | |
| 150 | − drm_panel_detach(rgb->panel); | |
| 151 | 148 | drm_connector_cleanup(connector); |
| 152 | 149 | } |
| 153 | 150 | |
| @@ -183,7 +180,7 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder) · 29 unmodified lines | ||
| 183 | 180 | } |
| 184 | 181 | } |
| 185 | 182 | |
| 186 | −static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = { | |
| 183 | +static const struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = { | |
| 187 | 184 | .disable = sun4i_rgb_encoder_disable, |
| 188 | 185 | .enable = sun4i_rgb_encoder_enable, |
| 189 | 186 | .mode_valid = sun4i_rgb_mode_valid, |
| @@ -233,12 +230,6 @@ int sun4i_rgb_init(struct drm_device *drm, struct sun4i_tcon *tcon) · 43 unmodified lines | ||
| 233 | 230 | |
| 234 | 231 | drm_connector_attach_encoder(&rgb->connector, |
| 235 | 232 | &rgb->encoder); |
| 236 | − | |
| 237 | − ret = drm_panel_attach(rgb->panel, &rgb->connector); | |
| 238 | − if (ret) { | |
| 239 | − dev_err(drm->dev, "Couldn't attach our panel\n"); | |
| 240 | − goto err_cleanup_connector; | |
| 241 | − } | |
| 242 | 233 | } |
| 243 | 234 | |
| 244 | 235 | if (rgb->bridge) { |
| @@ -825,7 +825,7 @@ static int sun4i_tcon_init_irq(struct device *dev, · 824 unmodified lines | ||
| 825 | 825 | return 0; |
| 826 | 826 | } |
| 827 | 827 | |
| 828 | −static struct regmap_config sun4i_tcon_regmap_config = { | |
| 828 | +static const struct regmap_config sun4i_tcon_regmap_config = { | |
| 829 | 829 | .reg_bits = 32, |
| 830 | 830 | .val_bits = 32, |
| 831 | 831 | .reg_stride = 4, |
| @@ -468,7 +468,7 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder, · 467 unmodified lines | ||
| 468 | 468 | regmap_write(tv->regs, SUN4I_TVE_SLAVE_REG, 0); |
| 469 | 469 | } |
| 470 | 470 | |
| 471 | −static struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = { | |
| 471 | +static const struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = { | |
| 472 | 472 | .disable = sun4i_tv_disable, |
| 473 | 473 | .enable = sun4i_tv_enable, |
| 474 | 474 | .mode_set = sun4i_tv_mode_set, |
| @@ -504,7 +504,7 @@ static int sun4i_tv_comp_mode_valid(struct drm_connector *connector, · 29 unmodified lines | ||
| 504 | 504 | return MODE_OK; |
| 505 | 505 | } |
| 506 | 506 | |
| 507 | −static struct drm_connector_helper_funcs sun4i_tv_comp_connector_helper_funcs = { | |
| 507 | +static const struct drm_connector_helper_funcs sun4i_tv_comp_connector_helper_funcs = { | |
| 508 | 508 | .get_modes = sun4i_tv_comp_get_modes, |
| 509 | 509 | .mode_valid = sun4i_tv_comp_mode_valid, |
| 510 | 510 | }; |
| @@ -523,7 +523,7 @@ static const struct drm_connector_funcs sun4i_tv_comp_connector_funcs = { · 12 unmodified lines | ||
| 523 | 523 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
| 524 | 524 | }; |
| 525 | 525 | |
| 526 | −static struct regmap_config sun4i_tv_regmap_config = { | |
| 526 | +static const struct regmap_config sun4i_tv_regmap_config = { | |
| 527 | 527 | .reg_bits = 32, |
| 528 | 528 | .val_bits = 32, |
| 529 | 529 | .reg_stride = 4, |
| @@ -820,7 +820,7 @@ static int sun6i_dsi_get_modes(struct drm_connector *connector) · 819 unmodified lines | ||
| 820 | 820 | return drm_panel_get_modes(dsi->panel, connector); |
| 821 | 821 | } |
| 822 | 822 | |
| 823 | −static struct drm_connector_helper_funcs sun6i_dsi_connector_helper_funcs = { | |
| 823 | +static const struct drm_connector_helper_funcs sun6i_dsi_connector_helper_funcs = { | |
| 824 | 824 | .get_modes = sun6i_dsi_get_modes, |
| 825 | 825 | }; |
| 826 | 826 | |
| @@ -973,7 +973,6 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host, · 146 unmodified lines | ||
| 973 | 973 | dsi->panel = panel; |
| 974 | 974 | dsi->device = device; |
| 975 | 975 | |
| 976 | − drm_panel_attach(dsi->panel, &dsi->connector); | |
| 977 | 976 | drm_kms_helper_hotplug_event(dsi->drm); |
| 978 | 977 | |
| 979 | 978 | dev_info(host->dev, "Attached device %s\n", device->name); |
| @@ -985,12 +984,10 @@ static int sun6i_dsi_detach(struct mipi_dsi_host *host, · 5 unmodified lines | ||
| 985 | 984 | struct mipi_dsi_device *device) |
| 986 | 985 | { |
| 987 | 986 | struct sun6i_dsi *dsi = host_to_sun6i_dsi(host); |
| 988 | − struct drm_panel *panel = dsi->panel; | |
| 989 | 987 | |
| 990 | 988 | dsi->panel = NULL; |
| 991 | 989 | dsi->device = NULL; |
| 992 | 990 | |
| 993 | − drm_panel_detach(panel); | |
| 994 | 991 | drm_kms_helper_hotplug_event(dsi->drm); |
| 995 | 992 | |
| 996 | 993 | return 0; |
| @@ -534,7 +534,7 @@ void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy, · 533 unmodified lines | ||
| 534 | 534 | } |
| 535 | 535 | } |
| 536 | 536 | |
| 537 | −static struct regmap_config sun8i_hdmi_phy_regmap_config = { | |
| 537 | +static const struct regmap_config sun8i_hdmi_phy_regmap_config = { | |
| 538 | 538 | .reg_bits = 32, |
| 539 | 539 | .val_bits = 32, |
| 540 | 540 | .reg_stride = 4, |
| @@ -303,7 +303,7 @@ static const struct sunxi_engine_ops sun8i_engine_ops = { · 302 unmodified lines | ||
| 303 | 303 | .layers_init = sun8i_layers_init, |
| 304 | 304 | }; |
| 305 | 305 | |
| 306 | −static struct regmap_config sun8i_mixer_regmap_config = { | |
| 306 | +static const struct regmap_config sun8i_mixer_regmap_config = { | |
| 307 | 307 | .reg_bits = 32, |
| 308 | 308 | .val_bits = 32, |
| 309 | 309 | .reg_stride = 4, |
| @@ -298,7 +298,7 @@ static void sun8i_ui_layer_atomic_update(struct drm_plane *plane, · 297 unmodified lines | ||
| 298 | 298 | true, zpos, old_zpos); |
| 299 | 299 | } |
| 300 | 300 | |
| 301 | −static struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = { | |
| 301 | +static const struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = { | |
| 302 | 302 | .prepare_fb = drm_gem_fb_prepare_fb, |
| 303 | 303 | .atomic_check = sun8i_ui_layer_atomic_check, |
| 304 | 304 | .atomic_disable = sun8i_ui_layer_atomic_disable, |
| @@ -401,7 +401,7 @@ static void sun8i_vi_layer_atomic_update(struct drm_plane *plane, · 400 unmodified lines | ||
| 401 | 401 | true, zpos, old_zpos); |
| 402 | 402 | } |
| 403 | 403 | |
| 404 | −static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = { | |
| 404 | +static const struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = { | |
| 405 | 405 | .prepare_fb = drm_gem_fb_prepare_fb, |
| 406 | 406 | .atomic_check = sun8i_vi_layer_atomic_check, |
| 407 | 407 | .atomic_disable = sun8i_vi_layer_atomic_disable, |
| @@ -1498,10 +1498,8 @@ static int tegra_dsi_host_attach(struct mipi_dsi_host *host, · 1497 unmodified lines | ||
| 1498 | 1498 | if (IS_ERR(output->panel)) |
| 1499 | 1499 | output->panel = NULL; |
| 1500 | 1500 | |
| 1501 | − if (output->panel && output->connector.dev) { | |
| 1502 | − drm_panel_attach(output->panel, &output->connector); | |
| 1501 | + if (output->panel && output->connector.dev) | |
| 1503 | 1502 | drm_helper_hpd_irq_event(output->connector.dev); |
| 1504 | − } | |
| 1505 | 1503 | } |
| 1506 | 1504 | |
| 1507 | 1505 | return 0; |
| @@ -179,13 +179,6 @@ void tegra_output_remove(struct tegra_output *output) · 178 unmodified lines | ||
| 179 | 179 | int tegra_output_init(struct drm_device *drm, struct tegra_output *output) |
| 180 | 180 | { |
| 181 | 181 | int connector_type; |
| 182 | − int err; | |
| 183 | − | |
| 184 | − if (output->panel) { | |
| 185 | − err = drm_panel_attach(output->panel, &output->connector); | |
| 186 | − if (err < 0) | |
| 187 | − return err; | |
| 188 | − } | |
| 189 | 182 | |
| 190 | 183 | /* |
| 191 | 184 | * The connector is now registered and ready to receive hotplug events |
| @@ -220,9 +213,6 @@ void tegra_output_exit(struct tegra_output *output) · 28 unmodified lines | ||
| 220 | 213 | */ |
| 221 | 214 | if (output->hpd_gpio) |
| 222 | 215 | disable_irq(output->hpd_irq); |
| 223 | − | |
| 224 | − if (output->panel) | |
| 225 | − drm_panel_detach(output->panel); | |
| 226 | 216 | } |
| 227 | 217 | |
| 228 | 218 | void tegra_output_find_possible_crtcs(struct tegra_output *output, |
| @@ -19,6 +19,7 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <linux/platform_device.h> |
| 20 | 20 | #include <linux/pm_runtime.h> |
| 21 | 21 | #include <linux/regmap.h> |
| 22 | +#include <linux/sys_soc.h> | |
| 22 | 23 | |
| 23 | 24 | #include <drm/drm_fourcc.h> |
| 24 | 25 | #include <drm/drm_fb_cma_helper.h> |
| @@ -302,6 +303,8 @@ struct dispc_device { · 277 unmodified lines | ||
| 302 | 303 | u32 num_fourccs; |
| 303 | 304 | |
| 304 | 305 | u32 memory_bandwidth_limit; |
| 306 | + | |
| 307 | + struct dispc_errata errata; | |
| 305 | 308 | }; |
| 306 | 309 | |
| 307 | 310 | static void dispc_write(struct dispc_device *dispc, u16 reg, u32 val) |
| @@ -2641,6 +2644,19 @@ static int dispc_init_am65x_oldi_io_ctrl(struct device *dev, · 2333 unmodified lines | ||
| 2641 | 2644 | return 0; |
| 2642 | 2645 | } |
| 2643 | 2646 | |
| 2647 | +static void dispc_init_errata(struct dispc_device *dispc) | |
| 2648 | +{ | |
| 2649 | + static const struct soc_device_attribute am65x_sr10_soc_devices[] = { | |
| 2650 | + { .family = "AM65X", .revision = "SR1.0" }, | |
| 2651 | + { /* sentinel */ } | |
| 2652 | + }; | |
| 2653 | + | |
| 2654 | + if (soc_device_match(am65x_sr10_soc_devices)) { | |
| 2655 | + dispc->errata.i2000 = true; | |
| 2656 | + dev_info(dispc->dev, "WA for erratum i2000: YUV formats disabled\n"); | |
| 2657 | + } | |
| 2658 | +} | |
| 2659 | + | |
| 2644 | 2660 | int dispc_init(struct tidss_device *tidss) |
| 2645 | 2661 | { |
| 2646 | 2662 | struct device *dev = tidss->dev; |
| @@ -2664,19 +2680,27 @@ int dispc_init(struct tidss_device *tidss) · 17 unmodified lines | ||
| 2664 | 2680 | if (!dispc) |
| 2665 | 2681 | return -ENOMEM; |
| 2666 | 2682 | |
| 2683 | + dispc->tidss = tidss; | |
| 2684 | + dispc->dev = dev; | |
| 2685 | + dispc->feat = feat; | |
| 2686 | + | |
| 2687 | + dispc_init_errata(dispc); | |
| 2688 | + | |
| 2667 | 2689 | dispc->fourccs = devm_kcalloc(dev, ARRAY_SIZE(dispc_color_formats), |
| 2668 | 2690 | sizeof(*dispc->fourccs), GFP_KERNEL); |
| 2669 | 2691 | if (!dispc->fourccs) |
| 2670 | 2692 | return -ENOMEM; |
| 2671 | 2693 | |
| 2672 | 2694 | num_fourccs = 0; |
| 2673 | − for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i) | |
| 2695 | + for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i) { | |
| 2696 | + if (dispc->errata.i2000 && | |
| 2697 | + dispc_fourcc_is_yuv(dispc_color_formats[i].fourcc)) { | |
| 2698 | + continue; | |
| 2699 | + } | |
| 2674 | 2700 | dispc->fourccs[num_fourccs++] = dispc_color_formats[i].fourcc; |
| 2701 | + } | |
| 2675 | 2702 | |
| 2676 | 2703 | dispc->num_fourccs = num_fourccs; |
| 2677 | − dispc->tidss = tidss; | |
| 2678 | − dispc->dev = dev; | |
| 2679 | − dispc->feat = feat; | |
| 2680 | 2704 | |
| 2681 | 2705 | dispc_common_regmap = dispc->feat->common_regs; |
| 2682 | 2706 | |
| @@ -46,6 +46,10 @@ struct dispc_features_scaling { · 45 unmodified lines | ||
| 46 | 46 | u32 xinc_max; |
| 47 | 47 | }; |
| 48 | 48 | |
| 49 | +struct dispc_errata { | |
| 50 | + bool i2000; /* DSS Does Not Support YUV Pixel Data Formats */ | |
| 51 | +}; | |
| 52 | + | |
| 49 | 53 | enum dispc_vp_bus_type { |
| 50 | 54 | DISPC_VP_DPI, /* DPI output */ |
| 51 | 55 | DISPC_VP_OLDI, /* OLDI (LVDS) output */ |
| @@ -4,7 +4,8 @@ · 3 unmodified lines | ||
| 4 | 4 | |
| 5 | 5 | ttm-y := ttm_memory.o ttm_tt.o ttm_bo.o \ |
| 6 | 6 | ttm_bo_util.o ttm_bo_vm.o ttm_module.o \ |
| 7 | − ttm_execbuf_util.o ttm_page_alloc.o ttm_bo_manager.o | |
| 7 | + ttm_execbuf_util.o ttm_page_alloc.o ttm_range_manager.o \ | |
| 8 | + ttm_resource.o | |
| 8 | 9 | ttm-$(CONFIG_AGP) += ttm_agp_backend.o |
| 9 | 10 | ttm-$(CONFIG_DRM_TTM_DMA_PAGE_POOL) += ttm_page_alloc_dma.o |
| 10 | 11 | |
| @@ -48,7 +48,7 @@ struct ttm_agp_backend { · 47 unmodified lines | ||
| 48 | 48 | struct agp_bridge_data *bridge; |
| 49 | 49 | }; |
| 50 | 50 | |
| 51 | −static int ttm_agp_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) | |
| 51 | +static int ttm_agp_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem) | |
| 52 | 52 | { |
| 53 | 53 | struct ttm_agp_backend *agp_be = container_of(ttm, struct ttm_agp_backend, ttm); |
| 54 | 54 | struct page *dummy_read_page = ttm_bo_glob.dummy_read_page; |
| @@ -77,26 +77,12 @@ static inline int ttm_mem_type_from_place(const struct ttm_place *place, · 76 unmodified lines | ||
| 77 | 77 | return 0; |
| 78 | 78 | } |
| 79 | 79 | |
| 80 | −static void ttm_mem_type_debug(struct ttm_bo_device *bdev, struct drm_printer *p, | |
| 81 | − int mem_type) | |
| 82 | −{ | |
| 83 | − struct ttm_mem_type_manager *man = &bdev->man[mem_type]; | |
| 84 | − | |
| 85 | − drm_printf(p, " has_type: %d\n", man->has_type); | |
| 86 | − drm_printf(p, " use_type: %d\n", man->use_type); | |
| 87 | − drm_printf(p, " flags: 0x%08X\n", man->flags); | |
| 88 | − drm_printf(p, " size: %llu\n", man->size); | |
| 89 | − drm_printf(p, " available_caching: 0x%08X\n", man->available_caching); | |
| 90 | − drm_printf(p, " default_caching: 0x%08X\n", man->default_caching); | |
| 91 | − if (mem_type != TTM_PL_SYSTEM) | |
| 92 | − (*man->func->debug)(man, p); | |
| 93 | −} | |
| 94 | − | |
| 95 | 80 | static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo, |
| 96 | 81 | struct ttm_placement *placement) |
| 97 | 82 | { |
| 98 | 83 | struct drm_printer p = drm_debug_printer(TTM_PFX); |
| 99 | 84 | int i, ret, mem_type; |
| 85 | + struct ttm_resource_manager *man; | |
| 100 | 86 | |
| 101 | 87 | drm_printf(&p, "No space for %p (%lu pages, %luK, %luM)\n", |
| 102 | 88 | bo, bo->mem.num_pages, bo->mem.size >> 10, |
| @@ -108,7 +94,8 @@ static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo, · 5 unmodified lines | ||
| 108 | 94 | return; |
| 109 | 95 | drm_printf(&p, " placement[%d]=0x%08X (%d)\n", |
| 110 | 96 | i, placement->placement[i].flags, mem_type); |
| 111 | − ttm_mem_type_debug(bo->bdev, &p, mem_type); | |
| 97 | + man = ttm_manager_type(bo->bdev, mem_type); | |
| 98 | + ttm_resource_manager_debug(man, &p); | |
| 112 | 99 | } |
| 113 | 100 | } |
| 114 | 101 | |
| @@ -145,10 +132,10 @@ static inline uint32_t ttm_bo_type_flags(unsigned type) · 30 unmodified lines | ||
| 145 | 132 | } |
| 146 | 133 | |
| 147 | 134 | static void ttm_bo_add_mem_to_lru(struct ttm_buffer_object *bo, |
| 148 | − struct ttm_mem_reg *mem) | |
| 135 | + struct ttm_resource *mem) | |
| 149 | 136 | { |
| 150 | 137 | struct ttm_bo_device *bdev = bo->bdev; |
| 151 | − struct ttm_mem_type_manager *man; | |
| 138 | + struct ttm_resource_manager *man; | |
| 152 | 139 | |
| 153 | 140 | if (!list_empty(&bo->lru)) |
| 154 | 141 | return; |
| @@ -156,10 +143,10 @@ static void ttm_bo_add_mem_to_lru(struct ttm_buffer_object *bo, · 1 unmodified line | ||
| 156 | 143 | if (mem->placement & TTM_PL_FLAG_NO_EVICT) |
| 157 | 144 | return; |
| 158 | 145 | |
| 159 | − man = &bdev->man[mem->mem_type]; | |
| 146 | + man = ttm_manager_type(bdev, mem->mem_type); | |
| 160 | 147 | list_add_tail(&bo->lru, &man->lru[bo->priority]); |
| 161 | 148 | |
| 162 | − if (!(man->flags & TTM_MEMTYPE_FLAG_FIXED) && bo->ttm && | |
| 149 | + if (man->use_tt && bo->ttm && | |
| 163 | 150 | !(bo->ttm->page_flags & (TTM_PAGE_FLAG_SG | |
| 164 | 151 | TTM_PAGE_FLAG_SWAPPED))) { |
| 165 | 152 | list_add_tail(&bo->swap, &ttm_bo_glob.swap_lru[bo->priority]); |
| @@ -223,7 +210,7 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk) · 57 unmodified lines | ||
| 223 | 210 | |
| 224 | 211 | for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) { |
| 225 | 212 | struct ttm_lru_bulk_move_pos *pos = &bulk->tt[i]; |
| 226 | − struct ttm_mem_type_manager *man; | |
| 213 | + struct ttm_resource_manager *man; | |
| 227 | 214 | |
| 228 | 215 | if (!pos->first) |
| 229 | 216 | continue; |
| @@ -231,14 +218,14 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk) · 1 unmodified line | ||
| 231 | 218 | dma_resv_assert_held(pos->first->base.resv); |
| 232 | 219 | dma_resv_assert_held(pos->last->base.resv); |
| 233 | 220 | |
| 234 | − man = &pos->first->bdev->man[TTM_PL_TT]; | |
| 221 | + man = ttm_manager_type(pos->first->bdev, TTM_PL_TT); | |
| 235 | 222 | list_bulk_move_tail(&man->lru[i], &pos->first->lru, |
| 236 | 223 | &pos->last->lru); |
| 237 | 224 | } |
| 238 | 225 | |
| 239 | 226 | for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) { |
| 240 | 227 | struct ttm_lru_bulk_move_pos *pos = &bulk->vram[i]; |
| 241 | − struct ttm_mem_type_manager *man; | |
| 228 | + struct ttm_resource_manager *man; | |
| 242 | 229 | |
| 243 | 230 | if (!pos->first) |
| 244 | 231 | continue; |
| @@ -246,7 +233,7 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk) · 1 unmodified line | ||
| 246 | 233 | dma_resv_assert_held(pos->first->base.resv); |
| 247 | 234 | dma_resv_assert_held(pos->last->base.resv); |
| 248 | 235 | |
| 249 | − man = &pos->first->bdev->man[TTM_PL_VRAM]; | |
| 236 | + man = ttm_manager_type(pos->first->bdev, TTM_PL_VRAM); | |
| 250 | 237 | list_bulk_move_tail(&man->lru[i], &pos->first->lru, |
| 251 | 238 | &pos->last->lru); |
| 252 | 239 | } |
| @@ -268,12 +255,12 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk) · 15 unmodified lines | ||
| 268 | 255 | EXPORT_SYMBOL(ttm_bo_bulk_move_lru_tail); |
| 269 | 256 | |
| 270 | 257 | static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, |
| 271 | − struct ttm_mem_reg *mem, bool evict, | |
| 258 | + struct ttm_resource *mem, bool evict, | |
| 272 | 259 | struct ttm_operation_ctx *ctx) |
| 273 | 260 | { |
| 274 | 261 | struct ttm_bo_device *bdev = bo->bdev; |
| 275 | − struct ttm_mem_type_manager *old_man = &bdev->man[bo->mem.mem_type]; | |
| 276 | − struct ttm_mem_type_manager *new_man = &bdev->man[mem->mem_type]; | |
| 262 | + struct ttm_resource_manager *old_man = ttm_manager_type(bdev, bo->mem.mem_type); | |
| 263 | + struct ttm_resource_manager *new_man = ttm_manager_type(bdev, mem->mem_type); | |
| 277 | 264 | int ret; |
| 278 | 265 | |
| 279 | 266 | ret = ttm_mem_io_lock(old_man, true); |
| @@ -286,13 +273,13 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, · 6 unmodified lines | ||
| 286 | 273 | * Create and bind a ttm if required. |
| 287 | 274 | */ |
| 288 | 275 | |
| 289 | − if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) { | |
| 290 | − if (bo->ttm == NULL) { | |
| 291 | − bool zero = !(old_man->flags & TTM_MEMTYPE_FLAG_FIXED); | |
| 292 | − ret = ttm_tt_create(bo, zero); | |
| 293 | − if (ret) | |
| 294 | − goto out_err; | |
| 295 | − } | |
| 276 | + if (new_man->use_tt) { | |
| 277 | + /* Zero init the new TTM structure if the old location should | |
| 278 | + * have used one as well. | |
| 279 | + */ | |
| 280 | + ret = ttm_tt_create(bo, old_man->use_tt); | |
| 281 | + if (ret) | |
| 282 | + goto out_err; | |
| 296 | 283 | |
| 297 | 284 | ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement); |
| 298 | 285 | if (ret) |
| @@ -315,8 +302,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, · 16 unmodified lines | ||
| 315 | 302 | if (bdev->driver->move_notify) |
| 316 | 303 | bdev->driver->move_notify(bo, evict, mem); |
| 317 | 304 | |
| 318 | − if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) && | |
| 319 | − !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) | |
| 305 | + if (old_man->use_tt && new_man->use_tt) | |
| 320 | 306 | ret = ttm_bo_move_ttm(bo, ctx, mem); |
| 321 | 307 | else if (bdev->driver->move) |
| 322 | 308 | ret = bdev->driver->move(bo, evict, ctx, mem); |
| @@ -340,8 +326,8 @@ moved: · 17 unmodified lines | ||
| 340 | 326 | return 0; |
| 341 | 327 | |
| 342 | 328 | out_err: |
| 343 | − new_man = &bdev->man[bo->mem.mem_type]; | |
| 344 | − if (new_man->flags & TTM_MEMTYPE_FLAG_FIXED) { | |
| 329 | + new_man = ttm_manager_type(bdev, bo->mem.mem_type); | |
| 330 | + if (!new_man->use_tt) { | |
| 345 | 331 | ttm_tt_destroy(bo->ttm); |
| 346 | 332 | bo->ttm = NULL; |
| 347 | 333 | } |
| @@ -364,7 +350,7 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo) · 16 unmodified lines | ||
| 364 | 350 | |
| 365 | 351 | ttm_tt_destroy(bo->ttm); |
| 366 | 352 | bo->ttm = NULL; |
| 367 | − ttm_bo_mem_put(bo, &bo->mem); | |
| 353 | + ttm_resource_free(bo, &bo->mem); | |
| 368 | 354 | } |
| 369 | 355 | |
| 370 | 356 | static int ttm_bo_individualize_resv(struct ttm_buffer_object *bo) |
| @@ -552,7 +538,7 @@ static void ttm_bo_release(struct kref *kref) · 181 unmodified lines | ||
| 552 | 538 | struct ttm_buffer_object *bo = |
| 553 | 539 | container_of(kref, struct ttm_buffer_object, kref); |
| 554 | 540 | struct ttm_bo_device *bdev = bo->bdev; |
| 555 | − struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type]; | |
| 541 | + struct ttm_resource_manager *man = ttm_manager_type(bdev, bo->mem.mem_type); | |
| 556 | 542 | size_t acc_size = bo->acc_size; |
| 557 | 543 | int ret; |
| 558 | 544 | |
| @@ -643,7 +629,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, · 84 unmodified lines | ||
| 643 | 629 | struct ttm_operation_ctx *ctx) |
| 644 | 630 | { |
| 645 | 631 | struct ttm_bo_device *bdev = bo->bdev; |
| 646 | − struct ttm_mem_reg evict_mem; | |
| 632 | + struct ttm_resource evict_mem; | |
| 647 | 633 | struct ttm_placement placement; |
| 648 | 634 | int ret = 0; |
| 649 | 635 | |
| @@ -654,10 +640,9 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, · 4 unmodified lines | ||
| 654 | 640 | bdev->driver->evict_flags(bo, &placement); |
| 655 | 641 | |
| 656 | 642 | if (!placement.num_placement && !placement.num_busy_placement) { |
| 657 | − ret = ttm_bo_pipeline_gutting(bo); | |
| 658 | − if (ret) | |
| 659 | − return ret; | |
| 643 | + ttm_bo_wait(bo, false, false); | |
| 660 | 644 | |
| 645 | + ttm_bo_cleanup_memtype_use(bo); | |
| 661 | 646 | return ttm_tt_create(bo, false); |
| 662 | 647 | } |
| 663 | 648 | |
| @@ -680,7 +665,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, · 16 unmodified lines | ||
| 680 | 665 | if (unlikely(ret)) { |
| 681 | 666 | if (ret != -ERESTARTSYS) |
| 682 | 667 | pr_err("Buffer eviction failed\n"); |
| 683 | − ttm_bo_mem_put(bo, &evict_mem); | |
| 668 | + ttm_resource_free(bo, &evict_mem); | |
| 684 | 669 | goto out; |
| 685 | 670 | } |
| 686 | 671 | bo->evicted = true; |
| @@ -769,14 +754,13 @@ static int ttm_mem_evict_wait_busy(struct ttm_buffer_object *busy_bo, · 82 unmodified lines | ||
| 769 | 754 | return r == -EDEADLK ? -EBUSY : r; |
| 770 | 755 | } |
| 771 | 756 | |
| 772 | −static int ttm_mem_evict_first(struct ttm_bo_device *bdev, | |
| 773 | − uint32_t mem_type, | |
| 774 | − const struct ttm_place *place, | |
| 775 | − struct ttm_operation_ctx *ctx, | |
| 776 | − struct ww_acquire_ctx *ticket) | |
| 757 | +int ttm_mem_evict_first(struct ttm_bo_device *bdev, | |
| 758 | + struct ttm_resource_manager *man, | |
| 759 | + const struct ttm_place *place, | |
| 760 | + struct ttm_operation_ctx *ctx, | |
| 761 | + struct ww_acquire_ctx *ticket) | |
| 777 | 762 | { |
| 778 | 763 | struct ttm_buffer_object *bo = NULL, *busy_bo = NULL; |
| 779 | − struct ttm_mem_type_manager *man = &bdev->man[mem_type]; | |
| 780 | 764 | bool locked = false; |
| 781 | 765 | unsigned i; |
| 782 | 766 | int ret; |
| @@ -842,38 +826,12 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev, · 59 unmodified lines | ||
| 842 | 826 | return ret; |
| 843 | 827 | } |
| 844 | 828 | |
| 845 | −static int ttm_bo_mem_get(struct ttm_buffer_object *bo, | |
| 846 | − const struct ttm_place *place, | |
| 847 | − struct ttm_mem_reg *mem) | |
| 848 | −{ | |
| 849 | − struct ttm_mem_type_manager *man = &bo->bdev->man[mem->mem_type]; | |
| 850 | − | |
| 851 | − mem->mm_node = NULL; | |
| 852 | − if (!man->func || !man->func->get_node) | |
| 853 | − return 0; | |
| 854 | − | |
| 855 | − return man->func->get_node(man, bo, place, mem); | |
| 856 | −} | |
| 857 | − | |
| 858 | −void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem) | |
| 859 | −{ | |
| 860 | − struct ttm_mem_type_manager *man = &bo->bdev->man[mem->mem_type]; | |
| 861 | − | |
| 862 | − if (!man->func || !man->func->put_node) | |
| 863 | − return; | |
| 864 | − | |
| 865 | − man->func->put_node(man, mem); | |
| 866 | − mem->mm_node = NULL; | |
| 867 | − mem->mem_type = TTM_PL_SYSTEM; | |
| 868 | −} | |
| 869 | −EXPORT_SYMBOL(ttm_bo_mem_put); | |
| 870 | − | |
| 871 | 829 | /** |
| 872 | 830 | * Add the last move fence to the BO and reserve a new shared slot. |
| 873 | 831 | */ |
| 874 | 832 | static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo, |
| 875 | − struct ttm_mem_type_manager *man, | |
| 876 | − struct ttm_mem_reg *mem, | |
| 833 | + struct ttm_resource_manager *man, | |
| 834 | + struct ttm_resource *mem, | |
| 877 | 835 | bool no_wait_gpu) |
| 878 | 836 | { |
| 879 | 837 | struct dma_fence *fence; |
| @@ -910,22 +868,22 @@ static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo, · 30 unmodified lines | ||
| 910 | 868 | */ |
| 911 | 869 | static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, |
| 912 | 870 | const struct ttm_place *place, |
| 913 | − struct ttm_mem_reg *mem, | |
| 871 | + struct ttm_resource *mem, | |
| 914 | 872 | struct ttm_operation_ctx *ctx) |
| 915 | 873 | { |
| 916 | 874 | struct ttm_bo_device *bdev = bo->bdev; |
| 917 | − struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; | |
| 875 | + struct ttm_resource_manager *man = ttm_manager_type(bdev, mem->mem_type); | |
| 918 | 876 | struct ww_acquire_ctx *ticket; |
| 919 | 877 | int ret; |
| 920 | 878 | |
| 921 | 879 | ticket = dma_resv_locking_ctx(bo->base.resv); |
| 922 | 880 | do { |
| 923 | − ret = ttm_bo_mem_get(bo, place, mem); | |
| 881 | + ret = ttm_resource_alloc(bo, place, mem); | |
| 924 | 882 | if (likely(!ret)) |
| 925 | 883 | break; |
| 926 | 884 | if (unlikely(ret != -ENOSPC)) |
| 927 | 885 | return ret; |
| 928 | − ret = ttm_mem_evict_first(bdev, mem->mem_type, place, ctx, | |
| 886 | + ret = ttm_mem_evict_first(bdev, man, place, ctx, | |
| 929 | 887 | ticket); |
| 930 | 888 | if (unlikely(ret != 0)) |
| 931 | 889 | return ret; |
| @@ -934,7 +892,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, · 2 unmodified lines | ||
| 934 | 892 | return ttm_bo_add_move_fence(bo, man, mem, ctx->no_wait_gpu); |
| 935 | 893 | } |
| 936 | 894 | |
| 937 | −static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man, | |
| 895 | +static uint32_t ttm_bo_select_caching(struct ttm_resource_manager *man, | |
| 938 | 896 | uint32_t cur_placement, |
| 939 | 897 | uint32_t proposed_placement) |
| 940 | 898 | { |
| @@ -959,7 +917,7 @@ static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man, · 18 unmodified lines | ||
| 959 | 917 | return result; |
| 960 | 918 | } |
| 961 | 919 | |
| 962 | −static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man, | |
| 920 | +static bool ttm_bo_mt_compatible(struct ttm_resource_manager *man, | |
| 963 | 921 | uint32_t mem_type, |
| 964 | 922 | const struct ttm_place *place, |
| 965 | 923 | uint32_t *masked_placement) |
| @@ -991,12 +949,12 @@ static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man, · 25 unmodified lines | ||
| 991 | 949 | */ |
| 992 | 950 | static int ttm_bo_mem_placement(struct ttm_buffer_object *bo, |
| 993 | 951 | const struct ttm_place *place, |
| 994 | − struct ttm_mem_reg *mem, | |
| 952 | + struct ttm_resource *mem, | |
| 995 | 953 | struct ttm_operation_ctx *ctx) |
| 996 | 954 | { |
| 997 | 955 | struct ttm_bo_device *bdev = bo->bdev; |
| 998 | 956 | uint32_t mem_type = TTM_PL_SYSTEM; |
| 999 | − struct ttm_mem_type_manager *man; | |
| 957 | + struct ttm_resource_manager *man; | |
| 1000 | 958 | uint32_t cur_flags = 0; |
| 1001 | 959 | int ret; |
| 1002 | 960 | |
| @@ -1004,8 +962,8 @@ static int ttm_bo_mem_placement(struct ttm_buffer_object *bo, · 1 unmodified line | ||
| 1004 | 962 | if (ret) |
| 1005 | 963 | return ret; |
| 1006 | 964 | |
| 1007 | − man = &bdev->man[mem_type]; | |
| 1008 | − if (!man->has_type || !man->use_type) | |
| 965 | + man = ttm_manager_type(bdev, mem_type); | |
| 966 | + if (!man || !ttm_resource_manager_used(man)) | |
| 1009 | 967 | return -EBUSY; |
| 1010 | 968 | |
| 1011 | 969 | if (!ttm_bo_mt_compatible(man, mem_type, place, &cur_flags)) |
| @@ -1039,7 +997,7 @@ static int ttm_bo_mem_placement(struct ttm_buffer_object *bo, · 27 unmodified lines | ||
| 1039 | 997 | */ |
| 1040 | 998 | int ttm_bo_mem_space(struct ttm_buffer_object *bo, |
| 1041 | 999 | struct ttm_placement *placement, |
| 1042 | − struct ttm_mem_reg *mem, | |
| 1000 | + struct ttm_resource *mem, | |
| 1043 | 1001 | struct ttm_operation_ctx *ctx) |
| 1044 | 1002 | { |
| 1045 | 1003 | struct ttm_bo_device *bdev = bo->bdev; |
| @@ -1052,7 +1010,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, · 6 unmodified lines | ||
| 1052 | 1010 | |
| 1053 | 1011 | for (i = 0; i < placement->num_placement; ++i) { |
| 1054 | 1012 | const struct ttm_place *place = &placement->placement[i]; |
| 1055 | − struct ttm_mem_type_manager *man; | |
| 1013 | + struct ttm_resource_manager *man; | |
| 1056 | 1014 | |
| 1057 | 1015 | ret = ttm_bo_mem_placement(bo, place, mem, ctx); |
| 1058 | 1016 | if (ret == -EBUSY) |
| @@ -1061,16 +1019,16 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, · 2 unmodified lines | ||
| 1061 | 1019 | goto error; |
| 1062 | 1020 | |
| 1063 | 1021 | type_found = true; |
| 1064 | − ret = ttm_bo_mem_get(bo, place, mem); | |
| 1022 | + ret = ttm_resource_alloc(bo, place, mem); | |
| 1065 | 1023 | if (ret == -ENOSPC) |
| 1066 | 1024 | continue; |
| 1067 | 1025 | if (unlikely(ret)) |
| 1068 | 1026 | goto error; |
| 1069 | 1027 | |
| 1070 | − man = &bdev->man[mem->mem_type]; | |
| 1028 | + man = ttm_manager_type(bdev, mem->mem_type); | |
| 1071 | 1029 | ret = ttm_bo_add_move_fence(bo, man, mem, ctx->no_wait_gpu); |
| 1072 | 1030 | if (unlikely(ret)) { |
| 1073 | − ttm_bo_mem_put(bo, mem); | |
| 1031 | + ttm_resource_free(bo, mem); | |
| 1074 | 1032 | if (ret == -EBUSY) |
| 1075 | 1033 | continue; |
| 1076 | 1034 | |
| @@ -1105,9 +1063,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, · 28 unmodified lines | ||
| 1105 | 1063 | |
| 1106 | 1064 | error: |
| 1107 | 1065 | if (bo->mem.mem_type == TTM_PL_SYSTEM && !list_empty(&bo->lru)) { |
| 1108 | − spin_lock(&ttm_bo_glob.lru_lock); | |
| 1109 | − ttm_bo_move_to_lru_tail(bo, NULL); | |
| 1110 | − spin_unlock(&ttm_bo_glob.lru_lock); | |
| 1066 | + ttm_bo_move_to_lru_tail_unlocked(bo); | |
| 1111 | 1067 | } |
| 1112 | 1068 | |
| 1113 | 1069 | return ret; |
| @@ -1119,7 +1075,7 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo, · 5 unmodified lines | ||
| 1119 | 1075 | struct ttm_operation_ctx *ctx) |
| 1120 | 1076 | { |
| 1121 | 1077 | int ret = 0; |
| 1122 | − struct ttm_mem_reg mem; | |
| 1078 | + struct ttm_resource mem; | |
| 1123 | 1079 | |
| 1124 | 1080 | dma_resv_assert_held(bo->base.resv); |
| 1125 | 1081 | |
| @@ -1139,13 +1095,13 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo, · 13 unmodified lines | ||
| 1139 | 1095 | ret = ttm_bo_handle_move_mem(bo, &mem, false, ctx); |
| 1140 | 1096 | out_unlock: |
| 1141 | 1097 | if (ret) |
| 1142 | − ttm_bo_mem_put(bo, &mem); | |
| 1098 | + ttm_resource_free(bo, &mem); | |
| 1143 | 1099 | return ret; |
| 1144 | 1100 | } |
| 1145 | 1101 | |
| 1146 | 1102 | static bool ttm_bo_places_compat(const struct ttm_place *places, |
| 1147 | 1103 | unsigned num_placement, |
| 1148 | − struct ttm_mem_reg *mem, | |
| 1104 | + struct ttm_resource *mem, | |
| 1149 | 1105 | uint32_t *new_flags) |
| 1150 | 1106 | { |
| 1151 | 1107 | unsigned i; |
| @@ -1168,7 +1124,7 @@ static bool ttm_bo_places_compat(const struct ttm_place *places, · 16 unmodified lines | ||
| 1168 | 1124 | } |
| 1169 | 1125 | |
| 1170 | 1126 | bool ttm_bo_mem_compat(struct ttm_placement *placement, |
| 1171 | − struct ttm_mem_reg *mem, | |
| 1127 | + struct ttm_resource *mem, | |
| 1172 | 1128 | uint32_t *new_flags) |
| 1173 | 1129 | { |
| 1174 | 1130 | if (ttm_bo_places_compat(placement->placement, placement->num_placement, |
| @@ -1224,7 +1180,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, · 49 unmodified lines | ||
| 1224 | 1180 | /* |
| 1225 | 1181 | * We might need to add a TTM. |
| 1226 | 1182 | */ |
| 1227 | − if (bo->mem.mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { | |
| 1183 | + if (bo->mem.mem_type == TTM_PL_SYSTEM) { | |
| 1228 | 1184 | ret = ttm_tt_create(bo, true); |
| 1229 | 1185 | if (ret) |
| 1230 | 1186 | return ret; |
| @@ -1335,9 +1291,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, · 104 unmodified lines | ||
| 1335 | 1291 | return ret; |
| 1336 | 1292 | } |
| 1337 | 1293 | |
| 1338 | − spin_lock(&ttm_bo_glob.lru_lock); | |
| 1339 | − ttm_bo_move_to_lru_tail(bo, NULL); | |
| 1340 | − spin_unlock(&ttm_bo_glob.lru_lock); | |
| 1294 | + ttm_bo_move_to_lru_tail_unlocked(bo); | |
| 1341 | 1295 | |
| 1342 | 1296 | return ret; |
| 1343 | 1297 | } |
| @@ -1426,144 +1380,24 @@ int ttm_bo_create(struct ttm_bo_device *bdev, · 82 unmodified lines | ||
| 1426 | 1380 | } |
| 1427 | 1381 | EXPORT_SYMBOL(ttm_bo_create); |
| 1428 | 1382 | |
| 1429 | −static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev, | |
| 1430 | − unsigned mem_type) | |
| 1431 | −{ | |
| 1432 | − struct ttm_operation_ctx ctx = { | |
| 1433 | − .interruptible = false, | |
| 1434 | − .no_wait_gpu = false, | |
| 1435 | − .flags = TTM_OPT_FLAG_FORCE_ALLOC | |
| 1436 | − }; | |
| 1437 | − struct ttm_mem_type_manager *man = &bdev->man[mem_type]; | |
| 1438 | − struct ttm_bo_global *glob = &ttm_bo_glob; | |
| 1439 | − struct dma_fence *fence; | |
| 1440 | − int ret; | |
| 1441 | − unsigned i; | |
| 1442 | − | |
| 1443 | − /* | |
| 1444 | − * Can't use standard list traversal since we're unlocking. | |
| 1445 | − */ | |
| 1446 | − | |
| 1447 | − spin_lock(&glob->lru_lock); | |
| 1448 | − for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) { | |
| 1449 | − while (!list_empty(&man->lru[i])) { | |
| 1450 | − spin_unlock(&glob->lru_lock); | |
| 1451 | − ret = ttm_mem_evict_first(bdev, mem_type, NULL, &ctx, | |
| 1452 | − NULL); | |
| 1453 | − if (ret) | |
| 1454 | − return ret; | |
| 1455 | − spin_lock(&glob->lru_lock); | |
| 1456 | − } | |
| 1457 | − } | |
| 1458 | − spin_unlock(&glob->lru_lock); | |
| 1459 | − | |
| 1460 | − spin_lock(&man->move_lock); | |
| 1461 | − fence = dma_fence_get(man->move); | |
| 1462 | − spin_unlock(&man->move_lock); | |
| 1463 | − | |
| 1464 | − if (fence) { | |
| 1465 | − ret = dma_fence_wait(fence, false); | |
| 1466 | − dma_fence_put(fence); | |
| 1467 | − if (ret) | |
| 1468 | − return ret; | |
| 1469 | − } | |
| 1470 | − | |
| 1471 | − return 0; | |
| 1472 | −} | |
| 1473 | − | |
| 1474 | −int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type) | |
| 1475 | −{ | |
| 1476 | − struct ttm_mem_type_manager *man; | |
| 1477 | − int ret = -EINVAL; | |
| 1478 | − | |
| 1479 | − if (mem_type >= TTM_NUM_MEM_TYPES) { | |
| 1480 | − pr_err("Illegal memory type %d\n", mem_type); | |
| 1481 | − return ret; | |
| 1482 | − } | |
| 1483 | − man = &bdev->man[mem_type]; | |
| 1484 | − | |
| 1485 | − if (!man->has_type) { | |
| 1486 | − pr_err("Trying to take down uninitialized memory manager type %u\n", | |
| 1487 | − mem_type); | |
| 1488 | − return ret; | |
| 1489 | − } | |
| 1490 | − | |
| 1491 | − man->use_type = false; | |
| 1492 | − man->has_type = false; | |
| 1493 | − | |
| 1494 | − ret = 0; | |
| 1495 | − if (mem_type > 0) { | |
| 1496 | − ret = ttm_bo_force_list_clean(bdev, mem_type); | |
| 1497 | − if (ret) { | |
| 1498 | − pr_err("Cleanup eviction failed\n"); | |
| 1499 | − return ret; | |
| 1500 | − } | |
| 1501 | − | |
| 1502 | − ret = (*man->func->takedown)(man); | |
| 1503 | − } | |
| 1504 | − | |
| 1505 | − dma_fence_put(man->move); | |
| 1506 | − man->move = NULL; | |
| 1507 | − | |
| 1508 | − return ret; | |
| 1509 | −} | |
| 1510 | −EXPORT_SYMBOL(ttm_bo_clean_mm); | |
| 1511 | − | |
| 1512 | 1383 | int ttm_bo_evict_mm(struct ttm_bo_device *bdev, unsigned mem_type) |
| 1513 | 1384 | { |
| 1514 | − struct ttm_mem_type_manager *man = &bdev->man[mem_type]; | |
| 1385 | + struct ttm_resource_manager *man = ttm_manager_type(bdev, mem_type); | |
| 1515 | 1386 | |
| 1516 | 1387 | if (mem_type == 0 || mem_type >= TTM_NUM_MEM_TYPES) { |
| 1517 | 1388 | pr_err("Illegal memory manager memory type %u\n", mem_type); |
| 1518 | 1389 | return -EINVAL; |
| 1519 | 1390 | } |
| 1520 | 1391 | |
| 1521 | − if (!man->has_type) { | |
| 1392 | + if (!man) { | |
| 1522 | 1393 | pr_err("Memory type %u has not been initialized\n", mem_type); |
| 1523 | 1394 | return 0; |
| 1524 | 1395 | } |
| 1525 | 1396 | |
| 1526 | − return ttm_bo_force_list_clean(bdev, mem_type); | |
| 1397 | + return ttm_resource_manager_force_list_clean(bdev, man); | |
| 1527 | 1398 | } |
| 1528 | 1399 | EXPORT_SYMBOL(ttm_bo_evict_mm); |
| 1529 | 1400 | |
| 1530 | −int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type, | |
| 1531 | − unsigned long p_size) | |
| 1532 | −{ | |
| 1533 | − int ret; | |
| 1534 | − struct ttm_mem_type_manager *man; | |
| 1535 | − unsigned i; | |
| 1536 | − | |
| 1537 | − BUG_ON(type >= TTM_NUM_MEM_TYPES); | |
| 1538 | − man = &bdev->man[type]; | |
| 1539 | − BUG_ON(man->has_type); | |
| 1540 | − man->use_io_reserve_lru = false; | |
| 1541 | − mutex_init(&man->io_reserve_mutex); | |
| 1542 | − spin_lock_init(&man->move_lock); | |
| 1543 | − INIT_LIST_HEAD(&man->io_reserve_lru); | |
| 1544 | − | |
| 1545 | − ret = bdev->driver->init_mem_type(bdev, type, man); | |
| 1546 | − if (ret) | |
| 1547 | − return ret; | |
| 1548 | − man->bdev = bdev; | |
| 1549 | − | |
| 1550 | − if (type != TTM_PL_SYSTEM) { | |
| 1551 | − ret = (*man->func->init)(man, p_size); | |
| 1552 | − if (ret) | |
| 1553 | − return ret; | |
| 1554 | − } | |
| 1555 | − man->has_type = true; | |
| 1556 | − man->use_type = true; | |
| 1557 | − man->size = p_size; | |
| 1558 | − | |
| 1559 | − for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) | |
| 1560 | − INIT_LIST_HEAD(&man->lru[i]); | |
| 1561 | − man->move = NULL; | |
| 1562 | − | |
| 1563 | − return 0; | |
| 1564 | −} | |
| 1565 | −EXPORT_SYMBOL(ttm_bo_init_mm); | |
| 1566 | − | |
| 1567 | 1401 | static void ttm_bo_global_kobj_release(struct kobject *kobj) |
| 1568 | 1402 | { |
| 1569 | 1403 | struct ttm_bo_global *glob = |
| @@ -1628,21 +1462,12 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev) · 58 unmodified lines | ||
| 1628 | 1462 | { |
| 1629 | 1463 | struct ttm_bo_global *glob = &ttm_bo_glob; |
| 1630 | 1464 | int ret = 0; |
| 1631 | − unsigned i = TTM_NUM_MEM_TYPES; | |
| 1632 | − struct ttm_mem_type_manager *man; | |
| 1633 | − | |
| 1634 | − while (i--) { | |
| 1635 | − man = &bdev->man[i]; | |
| 1636 | − if (man->has_type) { | |
| 1637 | − man->use_type = false; | |
| 1638 | − if ((i != TTM_PL_SYSTEM) && ttm_bo_clean_mm(bdev, i)) { | |
| 1639 | − ret = -EBUSY; | |
| 1640 | − pr_err("DRM memory manager type %d is not clean\n", | |
| 1641 | − i); | |
| 1642 | − } | |
| 1643 | − man->has_type = false; | |
| 1644 | − } | |
| 1645 | − } | |
| 1465 | + unsigned i; | |
| 1466 | + struct ttm_resource_manager *man; | |
| 1467 | + | |
| 1468 | + man = ttm_manager_type(bdev, TTM_PL_SYSTEM); | |
| 1469 | + ttm_resource_manager_set_used(man, false); | |
| 1470 | + ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, NULL); | |
| 1646 | 1471 | |
| 1647 | 1472 | mutex_lock(&ttm_global_mutex); |
| 1648 | 1473 | list_del(&bdev->device_list); |
| @@ -1655,7 +1480,7 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev) · 6 unmodified lines | ||
| 1655 | 1480 | |
| 1656 | 1481 | spin_lock(&glob->lru_lock); |
| 1657 | 1482 | for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) |
| 1658 | − if (list_empty(&bdev->man[0].lru[0])) | |
| 1483 | + if (list_empty(&man->lru[0])) | |
| 1659 | 1484 | pr_debug("Swap list %d was clean\n", i); |
| 1660 | 1485 | spin_unlock(&glob->lru_lock); |
| 1661 | 1486 | |
| @@ -1666,6 +1491,23 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev) · 4 unmodified lines | ||
| 1666 | 1491 | } |
| 1667 | 1492 | EXPORT_SYMBOL(ttm_bo_device_release); |
| 1668 | 1493 | |
| 1494 | +static void ttm_bo_init_sysman(struct ttm_bo_device *bdev) | |
| 1495 | +{ | |
| 1496 | + struct ttm_resource_manager *man = &bdev->sysman; | |
| 1497 | + | |
| 1498 | + /* | |
| 1499 | + * Initialize the system memory buffer type. | |
| 1500 | + * Other types need to be driver / IOCTL initialized. | |
| 1501 | + */ | |
| 1502 | + man->use_tt = true; | |
| 1503 | + man->available_caching = TTM_PL_MASK_CACHING; | |
| 1504 | + man->default_caching = TTM_PL_FLAG_CACHED; | |
| 1505 | + | |
| 1506 | + ttm_resource_manager_init(man, 0); | |
| 1507 | + ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, man); | |
| 1508 | + ttm_resource_manager_set_used(man, true); | |
| 1509 | +} | |
| 1510 | + | |
| 1669 | 1511 | int ttm_bo_device_init(struct ttm_bo_device *bdev, |
| 1670 | 1512 | struct ttm_bo_driver *driver, |
| 1671 | 1513 | struct address_space *mapping, |
| @@ -1684,15 +1526,7 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev, · 12 unmodified lines | ||
| 1684 | 1526 | |
| 1685 | 1527 | bdev->driver = driver; |
| 1686 | 1528 | |
| 1687 | − memset(bdev->man, 0, sizeof(bdev->man)); | |
| 1688 | − | |
| 1689 | − /* | |
| 1690 | − * Initialize the system memory buffer type. | |
| 1691 | − * Other types need to be driver / IOCTL initialized. | |
| 1692 | − */ | |
| 1693 | − ret = ttm_bo_init_mm(bdev, TTM_PL_SYSTEM, 0); | |
| 1694 | − if (unlikely(ret != 0)) | |
| 1695 | − goto out_no_sys; | |
| 1529 | + ttm_bo_init_sysman(bdev); | |
| 1696 | 1530 | |
| 1697 | 1531 | bdev->vma_manager = vma_manager; |
| 1698 | 1532 | INIT_DELAYED_WORK(&bdev->wq, ttm_bo_delayed_workqueue); |
| @@ -1704,9 +1538,6 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev, · 5 unmodified lines | ||
| 1704 | 1538 | mutex_unlock(&ttm_global_mutex); |
| 1705 | 1539 | |
| 1706 | 1540 | return 0; |
| 1707 | −out_no_sys: | |
| 1708 | − ttm_bo_global_release(); | |
| 1709 | − return ret; | |
| 1710 | 1541 | } |
| 1711 | 1542 | EXPORT_SYMBOL(ttm_bo_device_init); |
| 1712 | 1543 | |
| @@ -1725,7 +1556,7 @@ void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo) · 12 unmodified lines | ||
| 1725 | 1556 | void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo) |
| 1726 | 1557 | { |
| 1727 | 1558 | struct ttm_bo_device *bdev = bo->bdev; |
| 1728 | − struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type]; | |
| 1559 | + struct ttm_resource_manager *man = ttm_manager_type(bdev, bo->mem.mem_type); | |
| 1729 | 1560 | |
| 1730 | 1561 | ttm_mem_io_lock(man, false); |
| 1731 | 1562 | ttm_bo_unmap_virtual_locked(bo); |
| @@ -1812,7 +1643,7 @@ int ttm_bo_swapout(struct ttm_bo_global *glob, struct ttm_operation_ctx *ctx) · 80 unmodified lines | ||
| 1812 | 1643 | if (bo->mem.mem_type != TTM_PL_SYSTEM || |
| 1813 | 1644 | bo->ttm->caching_state != tt_cached) { |
| 1814 | 1645 | struct ttm_operation_ctx ctx = { false, false }; |
| 1815 | − struct ttm_mem_reg evict_mem; | |
| 1646 | + struct ttm_resource evict_mem; | |
| 1816 | 1647 | |
| 1817 | 1648 | evict_mem = bo->mem; |
| 1818 | 1649 | evict_mem.mm_node = NULL; |
| @@ -47,15 +47,15 @@ struct ttm_transfer_obj { · 46 unmodified lines | ||
| 47 | 47 | |
| 48 | 48 | void ttm_bo_free_old_node(struct ttm_buffer_object *bo) |
| 49 | 49 | { |
| 50 | − ttm_bo_mem_put(bo, &bo->mem); | |
| 50 | + ttm_resource_free(bo, &bo->mem); | |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | 53 | int ttm_bo_move_ttm(struct ttm_buffer_object *bo, |
| 54 | 54 | struct ttm_operation_ctx *ctx, |
| 55 | − struct ttm_mem_reg *new_mem) | |
| 55 | + struct ttm_resource *new_mem) | |
| 56 | 56 | { |
| 57 | 57 | struct ttm_tt *ttm = bo->ttm; |
| 58 | − struct ttm_mem_reg *old_mem = &bo->mem; | |
| 58 | + struct ttm_resource *old_mem = &bo->mem; | |
| 59 | 59 | int ret; |
| 60 | 60 | |
| 61 | 61 | if (old_mem->mem_type != TTM_PL_SYSTEM) { |
| @@ -91,7 +91,7 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo, · 29 unmodified lines | ||
| 91 | 91 | } |
| 92 | 92 | EXPORT_SYMBOL(ttm_bo_move_ttm); |
| 93 | 93 | |
| 94 | −int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible) | |
| 94 | +int ttm_mem_io_lock(struct ttm_resource_manager *man, bool interruptible) | |
| 95 | 95 | { |
| 96 | 96 | if (likely(!man->use_io_reserve_lru)) |
| 97 | 97 | return 0; |
| @@ -103,7 +103,7 @@ int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible) · 5 unmodified lines | ||
| 103 | 103 | return 0; |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | −void ttm_mem_io_unlock(struct ttm_mem_type_manager *man) | |
| 106 | +void ttm_mem_io_unlock(struct ttm_resource_manager *man) | |
| 107 | 107 | { |
| 108 | 108 | if (likely(!man->use_io_reserve_lru)) |
| 109 | 109 | return; |
| @@ -111,7 +111,7 @@ void ttm_mem_io_unlock(struct ttm_mem_type_manager *man) · 1 unmodified line | ||
| 111 | 111 | mutex_unlock(&man->io_reserve_mutex); |
| 112 | 112 | } |
| 113 | 113 | |
| 114 | −static int ttm_mem_io_evict(struct ttm_mem_type_manager *man) | |
| 114 | +static int ttm_mem_io_evict(struct ttm_resource_manager *man) | |
| 115 | 115 | { |
| 116 | 116 | struct ttm_buffer_object *bo; |
| 117 | 117 | |
| @@ -127,9 +127,9 @@ static int ttm_mem_io_evict(struct ttm_mem_type_manager *man) · 9 unmodified lines | ||
| 127 | 127 | } |
| 128 | 128 | |
| 129 | 129 | int ttm_mem_io_reserve(struct ttm_bo_device *bdev, |
| 130 | − struct ttm_mem_reg *mem) | |
| 130 | + struct ttm_resource *mem) | |
| 131 | 131 | { |
| 132 | − struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; | |
| 132 | + struct ttm_resource_manager *man = ttm_manager_type(bdev, mem->mem_type); | |
| 133 | 133 | int ret; |
| 134 | 134 | |
| 135 | 135 | if (mem->bus.io_reserved_count++) |
| @@ -138,6 +138,10 @@ int ttm_mem_io_reserve(struct ttm_bo_device *bdev, · 2 unmodified lines | ||
| 138 | 138 | if (!bdev->driver->io_mem_reserve) |
| 139 | 139 | return 0; |
| 140 | 140 | |
| 141 | + mem->bus.addr = NULL; | |
| 142 | + mem->bus.offset = 0; | |
| 143 | + mem->bus.base = 0; | |
| 144 | + mem->bus.is_iomem = false; | |
| 141 | 145 | retry: |
| 142 | 146 | ret = bdev->driver->io_mem_reserve(bdev, mem); |
| 143 | 147 | if (ret == -ENOSPC) { |
| @@ -149,7 +153,7 @@ retry: · 5 unmodified lines | ||
| 149 | 153 | } |
| 150 | 154 | |
| 151 | 155 | void ttm_mem_io_free(struct ttm_bo_device *bdev, |
| 152 | − struct ttm_mem_reg *mem) | |
| 156 | + struct ttm_resource *mem) | |
| 153 | 157 | { |
| 154 | 158 | if (--mem->bus.io_reserved_count) |
| 155 | 159 | return; |
| @@ -162,8 +166,8 @@ void ttm_mem_io_free(struct ttm_bo_device *bdev, · 6 unmodified lines | ||
| 162 | 166 | |
| 163 | 167 | int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo) |
| 164 | 168 | { |
| 165 | − struct ttm_mem_type_manager *man = &bo->bdev->man[bo->mem.mem_type]; | |
| 166 | − struct ttm_mem_reg *mem = &bo->mem; | |
| 169 | + struct ttm_resource_manager *man = ttm_manager_type(bo->bdev, bo->mem.mem_type); | |
| 170 | + struct ttm_resource *mem = &bo->mem; | |
| 167 | 171 | int ret; |
| 168 | 172 | |
| 169 | 173 | if (mem->bus.io_reserved_vm) |
| @@ -181,7 +185,7 @@ int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo) · 11 unmodified lines | ||
| 181 | 185 | |
| 182 | 186 | void ttm_mem_io_free_vm(struct ttm_buffer_object *bo) |
| 183 | 187 | { |
| 184 | − struct ttm_mem_reg *mem = &bo->mem; | |
| 188 | + struct ttm_resource *mem = &bo->mem; | |
| 185 | 189 | |
| 186 | 190 | if (!mem->bus.io_reserved_vm) |
| 187 | 191 | return; |
| @@ -191,11 +195,11 @@ void ttm_mem_io_free_vm(struct ttm_buffer_object *bo) · 3 unmodified lines | ||
| 191 | 195 | ttm_mem_io_free(bo->bdev, mem); |
| 192 | 196 | } |
| 193 | 197 | |
| 194 | −static int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, | |
| 195 | − struct ttm_mem_reg *mem, | |
| 198 | +static int ttm_resource_ioremap(struct ttm_bo_device *bdev, | |
| 199 | + struct ttm_resource *mem, | |
| 196 | 200 | void **virtual) |
| 197 | 201 | { |
| 198 | − struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; | |
| 202 | + struct ttm_resource_manager *man = ttm_manager_type(bdev, mem->mem_type); | |
| 199 | 203 | int ret; |
| 200 | 204 | void *addr; |
| 201 | 205 | |
| @@ -209,12 +213,14 @@ static int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, · 7 unmodified lines | ||
| 209 | 213 | if (mem->bus.addr) { |
| 210 | 214 | addr = mem->bus.addr; |
| 211 | 215 | } else { |
| 216 | + size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT; | |
| 217 | + | |
| 212 | 218 | if (mem->placement & TTM_PL_FLAG_WC) |
| 213 | 219 | addr = ioremap_wc(mem->bus.base + mem->bus.offset, |
| 214 | − mem->bus.size); | |
| 220 | + bus_size); | |
| 215 | 221 | else |
| 216 | 222 | addr = ioremap(mem->bus.base + mem->bus.offset, |
| 217 | − mem->bus.size); | |
| 223 | + bus_size); | |
| 218 | 224 | if (!addr) { |
| 219 | 225 | (void) ttm_mem_io_lock(man, false); |
| 220 | 226 | ttm_mem_io_free(bdev, mem); |
| @@ -226,13 +232,13 @@ static int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, · 5 unmodified lines | ||
| 226 | 232 | return 0; |
| 227 | 233 | } |
| 228 | 234 | |
| 229 | −static void ttm_mem_reg_iounmap(struct ttm_bo_device *bdev, | |
| 230 | − struct ttm_mem_reg *mem, | |
| 235 | +static void ttm_resource_iounmap(struct ttm_bo_device *bdev, | |
| 236 | + struct ttm_resource *mem, | |
| 231 | 237 | void *virtual) |
| 232 | 238 | { |
| 233 | − struct ttm_mem_type_manager *man; | |
| 239 | + struct ttm_resource_manager *man; | |
| 234 | 240 | |
| 235 | − man = &bdev->man[mem->mem_type]; | |
| 241 | + man = ttm_manager_type(bdev, mem->mem_type); | |
| 236 | 242 | |
| 237 | 243 | if (virtual && mem->bus.addr == NULL) |
| 238 | 244 | iounmap(virtual); |
| @@ -300,13 +306,13 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst, · 61 unmodified lines | ||
| 300 | 306 | |
| 301 | 307 | int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, |
| 302 | 308 | struct ttm_operation_ctx *ctx, |
| 303 | − struct ttm_mem_reg *new_mem) | |
| 309 | + struct ttm_resource *new_mem) | |
| 304 | 310 | { |
| 305 | 311 | struct ttm_bo_device *bdev = bo->bdev; |
| 306 | − struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type]; | |
| 312 | + struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type); | |
| 307 | 313 | struct ttm_tt *ttm = bo->ttm; |
| 308 | − struct ttm_mem_reg *old_mem = &bo->mem; | |
| 309 | − struct ttm_mem_reg old_copy = *old_mem; | |
| 314 | + struct ttm_resource *old_mem = &bo->mem; | |
| 315 | + struct ttm_resource old_copy = *old_mem; | |
| 310 | 316 | void *old_iomap; |
| 311 | 317 | void *new_iomap; |
| 312 | 318 | int ret; |
| @@ -319,10 +325,10 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, · 6 unmodified lines | ||
| 319 | 325 | if (ret) |
| 320 | 326 | return ret; |
| 321 | 327 | |
| 322 | − ret = ttm_mem_reg_ioremap(bdev, old_mem, &old_iomap); | |
| 328 | + ret = ttm_resource_ioremap(bdev, old_mem, &old_iomap); | |
| 323 | 329 | if (ret) |
| 324 | 330 | return ret; |
| 325 | − ret = ttm_mem_reg_ioremap(bdev, new_mem, &new_iomap); | |
| 331 | + ret = ttm_resource_ioremap(bdev, new_mem, &new_iomap); | |
| 326 | 332 | if (ret) |
| 327 | 333 | goto out; |
| 328 | 334 | |
| @@ -384,21 +390,21 @@ out2: · 55 unmodified lines | ||
| 384 | 390 | *old_mem = *new_mem; |
| 385 | 391 | new_mem->mm_node = NULL; |
| 386 | 392 | |
| 387 | − if (man->flags & TTM_MEMTYPE_FLAG_FIXED) { | |
| 393 | + if (!man->use_tt) { | |
| 388 | 394 | ttm_tt_destroy(ttm); |
| 389 | 395 | bo->ttm = NULL; |
| 390 | 396 | } |
| 391 | 397 | |
| 392 | 398 | out1: |
| 393 | − ttm_mem_reg_iounmap(bdev, old_mem, new_iomap); | |
| 399 | + ttm_resource_iounmap(bdev, old_mem, new_iomap); | |
| 394 | 400 | out: |
| 395 | − ttm_mem_reg_iounmap(bdev, &old_copy, old_iomap); | |
| 401 | + ttm_resource_iounmap(bdev, &old_copy, old_iomap); | |
| 396 | 402 | |
| 397 | 403 | /* |
| 398 | 404 | * On error, keep the mm node! |
| 399 | 405 | */ |
| 400 | 406 | if (!ret) |
| 401 | − ttm_bo_mem_put(bo, &old_copy); | |
| 407 | + ttm_resource_free(bo, &old_copy); | |
| 402 | 408 | return ret; |
| 403 | 409 | } |
| 404 | 410 | EXPORT_SYMBOL(ttm_bo_move_memcpy); |
| @@ -502,7 +508,7 @@ static int ttm_bo_ioremap(struct ttm_buffer_object *bo, · 97 unmodified lines | ||
| 502 | 508 | unsigned long size, |
| 503 | 509 | struct ttm_bo_kmap_obj *map) |
| 504 | 510 | { |
| 505 | − struct ttm_mem_reg *mem = &bo->mem; | |
| 511 | + struct ttm_resource *mem = &bo->mem; | |
| 506 | 512 | |
| 507 | 513 | if (bo->mem.bus.addr) { |
| 508 | 514 | map->bo_kmap_type = ttm_bo_map_premapped; |
| @@ -526,7 +532,7 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo, · 17 unmodified lines | ||
| 526 | 532 | unsigned long num_pages, |
| 527 | 533 | struct ttm_bo_kmap_obj *map) |
| 528 | 534 | { |
| 529 | − struct ttm_mem_reg *mem = &bo->mem; | |
| 535 | + struct ttm_resource *mem = &bo->mem; | |
| 530 | 536 | struct ttm_operation_ctx ctx = { |
| 531 | 537 | .interruptible = false, |
| 532 | 538 | .no_wait_gpu = false |
| @@ -567,8 +573,8 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo, · 34 unmodified lines | ||
| 567 | 573 | unsigned long start_page, unsigned long num_pages, |
| 568 | 574 | struct ttm_bo_kmap_obj *map) |
| 569 | 575 | { |
| 570 | − struct ttm_mem_type_manager *man = | |
| 571 | − &bo->bdev->man[bo->mem.mem_type]; | |
| 576 | + struct ttm_resource_manager *man = | |
| 577 | + ttm_manager_type(bo->bdev, bo->mem.mem_type); | |
| 572 | 578 | unsigned long offset, size; |
| 573 | 579 | int ret; |
| 574 | 580 | |
| @@ -597,8 +603,8 @@ EXPORT_SYMBOL(ttm_bo_kmap); · 22 unmodified lines | ||
| 597 | 603 | void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map) |
| 598 | 604 | { |
| 599 | 605 | struct ttm_buffer_object *bo = map->bo; |
| 600 | − struct ttm_mem_type_manager *man = | |
| 601 | − &bo->bdev->man[bo->mem.mem_type]; | |
| 606 | + struct ttm_resource_manager *man = | |
| 607 | + ttm_manager_type(bo->bdev, bo->mem.mem_type); | |
| 602 | 608 | |
| 603 | 609 | if (!map->virtual) |
| 604 | 610 | return; |
| @@ -628,11 +634,11 @@ EXPORT_SYMBOL(ttm_bo_kunmap); · 23 unmodified lines | ||
| 628 | 634 | int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, |
| 629 | 635 | struct dma_fence *fence, |
| 630 | 636 | bool evict, |
| 631 | − struct ttm_mem_reg *new_mem) | |
| 637 | + struct ttm_resource *new_mem) | |
| 632 | 638 | { |
| 633 | 639 | struct ttm_bo_device *bdev = bo->bdev; |
| 634 | − struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type]; | |
| 635 | − struct ttm_mem_reg *old_mem = &bo->mem; | |
| 640 | + struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type); | |
| 641 | + struct ttm_resource *old_mem = &bo->mem; | |
| 636 | 642 | int ret; |
| 637 | 643 | struct ttm_buffer_object *ghost_obj; |
| 638 | 644 | |
| @@ -642,7 +648,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, · 3 unmodified lines | ||
| 642 | 648 | if (ret) |
| 643 | 649 | return ret; |
| 644 | 650 | |
| 645 | − if (man->flags & TTM_MEMTYPE_FLAG_FIXED) { | |
| 651 | + if (!man->use_tt) { | |
| 646 | 652 | ttm_tt_destroy(bo->ttm); |
| 647 | 653 | bo->ttm = NULL; |
| 648 | 654 | } |
| @@ -671,7 +677,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, · 22 unmodified lines | ||
| 671 | 677 | * bo to be unbound and destroyed. |
| 672 | 678 | */ |
| 673 | 679 | |
| 674 | − if (!(man->flags & TTM_MEMTYPE_FLAG_FIXED)) | |
| 680 | + if (man->use_tt) | |
| 675 | 681 | ghost_obj->ttm = NULL; |
| 676 | 682 | else |
| 677 | 683 | bo->ttm = NULL; |
| @@ -689,13 +695,13 @@ EXPORT_SYMBOL(ttm_bo_move_accel_cleanup); · 11 unmodified lines | ||
| 689 | 695 | |
| 690 | 696 | int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, |
| 691 | 697 | struct dma_fence *fence, bool evict, |
| 692 | − struct ttm_mem_reg *new_mem) | |
| 698 | + struct ttm_resource *new_mem) | |
| 693 | 699 | { |
| 694 | 700 | struct ttm_bo_device *bdev = bo->bdev; |
| 695 | − struct ttm_mem_reg *old_mem = &bo->mem; | |
| 701 | + struct ttm_resource *old_mem = &bo->mem; | |
| 696 | 702 | |
| 697 | − struct ttm_mem_type_manager *from = &bdev->man[old_mem->mem_type]; | |
| 698 | − struct ttm_mem_type_manager *to = &bdev->man[new_mem->mem_type]; | |
| 703 | + struct ttm_resource_manager *from = ttm_manager_type(bdev, old_mem->mem_type); | |
| 704 | + struct ttm_resource_manager *to = ttm_manager_type(bdev, new_mem->mem_type); | |
| 699 | 705 | |
| 700 | 706 | int ret; |
| 701 | 707 | |
| @@ -727,7 +733,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, · 25 unmodified lines | ||
| 727 | 733 | * bo to be unbound and destroyed. |
| 728 | 734 | */ |
| 729 | 735 | |
| 730 | − if (!(to->flags & TTM_MEMTYPE_FLAG_FIXED)) | |
| 736 | + if (to->use_tt) | |
| 731 | 737 | ghost_obj->ttm = NULL; |
| 732 | 738 | else |
| 733 | 739 | bo->ttm = NULL; |
| @@ -735,7 +741,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, · 1 unmodified line | ||
| 735 | 741 | dma_resv_unlock(&ghost_obj->base._resv); |
| 736 | 742 | ttm_bo_put(ghost_obj); |
| 737 | 743 | |
| 738 | − } else if (from->flags & TTM_MEMTYPE_FLAG_FIXED) { | |
| 744 | + } else if (!from->use_tt) { | |
| 739 | 745 | |
| 740 | 746 | /** |
| 741 | 747 | * BO doesn't have a TTM we need to bind/unbind. Just remember |
| @@ -765,7 +771,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, · 23 unmodified lines | ||
| 765 | 771 | if (ret) |
| 766 | 772 | return ret; |
| 767 | 773 | |
| 768 | − if (to->flags & TTM_MEMTYPE_FLAG_FIXED) { | |
| 774 | + if (!to->use_tt) { | |
| 769 | 775 | ttm_tt_destroy(bo->ttm); |
| 770 | 776 | bo->ttm = NULL; |
| 771 | 777 | } |
| @@ -281,8 +281,8 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, · 280 unmodified lines | ||
| 281 | 281 | pgoff_t i; |
| 282 | 282 | vm_fault_t ret = VM_FAULT_NOPAGE; |
| 283 | 283 | unsigned long address = vmf->address; |
| 284 | − struct ttm_mem_type_manager *man = | |
| 285 | − &bdev->man[bo->mem.mem_type]; | |
| 284 | + struct ttm_resource_manager *man = | |
| 285 | + ttm_manager_type(bdev, bo->mem.mem_type); | |
| 286 | 286 | |
| 287 | 287 | /* |
| 288 | 288 | * Refuse to fault imported pages. This should be handled |
| @@ -308,9 +308,7 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf, · 19 unmodified lines | ||
| 308 | 308 | } |
| 309 | 309 | |
| 310 | 310 | if (bo->moving != moving) { |
| 311 | − spin_lock(&ttm_bo_glob.lru_lock); | |
| 312 | − ttm_bo_move_to_lru_tail(bo, NULL); | |
| 313 | − spin_unlock(&ttm_bo_glob.lru_lock); | |
| 311 | + ttm_bo_move_to_lru_tail_unlocked(bo); | |
| 314 | 312 | } |
| 315 | 313 | dma_fence_put(moving); |
| 316 | 314 | } |
| @@ -93,7 +93,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, · 92 unmodified lines | ||
| 93 | 93 | list_for_each_entry(entry, list, head) { |
| 94 | 94 | struct ttm_buffer_object *bo = entry->bo; |
| 95 | 95 | |
| 96 | − ret = __ttm_bo_reserve(bo, intr, (ticket == NULL), ticket); | |
| 96 | + ret = ttm_bo_reserve(bo, intr, (ticket == NULL), ticket); | |
| 97 | 97 | if (ret == -EALREADY && dups) { |
| 98 | 98 | struct ttm_validate_buffer *safe = entry; |
| 99 | 99 | entry = list_prev_entry(entry, head); |
| @@ -119,13 +119,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, · 19 unmodified lines | ||
| 119 | 119 | ttm_eu_backoff_reservation_reverse(list, entry); |
| 120 | 120 | |
| 121 | 121 | if (ret == -EDEADLK) { |
| 122 | − if (intr) { | |
| 123 | − ret = dma_resv_lock_slow_interruptible(bo->base.resv, | |
| 124 | − ticket); | |
| 125 | − } else { | |
| 126 | − dma_resv_lock_slow(bo->base.resv, ticket); | |
| 127 | − ret = 0; | |
| 128 | − } | |
| 122 | + ret = ttm_bo_reserve_slowpath(bo, intr, ticket); | |
| 129 | 123 | } |
| 130 | 124 | |
| 131 | 125 | if (!ret && entry->num_shared) |
| @@ -133,8 +127,6 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, · 1 unmodified line | ||
| 133 | 127 | entry->num_shared); |
| 134 | 128 | |
| 135 | 129 | if (unlikely(ret != 0)) { |
| 136 | − if (ret == -EINTR) | |
| 137 | − ret = -ERESTARTSYS; | |
| 138 | 130 | if (ticket) { |
| 139 | 131 | ww_acquire_done(ticket); |
| 140 | 132 | ww_acquire_fini(ticket); |
| @@ -44,16 +44,22 @@ · 43 unmodified lines | ||
| 44 | 44 | */ |
| 45 | 45 | |
| 46 | 46 | struct ttm_range_manager { |
| 47 | + struct ttm_resource_manager manager; | |
| 47 | 48 | struct drm_mm mm; |
| 48 | 49 | spinlock_t lock; |
| 49 | 50 | }; |
| 50 | 51 | |
| 51 | −static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man, | |
| 52 | +static inline struct ttm_range_manager *to_range_manager(struct ttm_resource_manager *man) | |
| 53 | +{ | |
| 54 | + return container_of(man, struct ttm_range_manager, manager); | |
| 55 | +} | |
| 56 | + | |
| 57 | +static int ttm_range_man_alloc(struct ttm_resource_manager *man, | |
| 52 | 58 | struct ttm_buffer_object *bo, |
| 53 | 59 | const struct ttm_place *place, |
| 54 | − struct ttm_mem_reg *mem) | |
| 60 | + struct ttm_resource *mem) | |
| 55 | 61 | { |
| 56 | − struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; | |
| 62 | + struct ttm_range_manager *rman = to_range_manager(man); | |
| 57 | 63 | struct drm_mm *mm = &rman->mm; |
| 58 | 64 | struct drm_mm_node *node; |
| 59 | 65 | enum drm_mm_insert_mode mode; |
| @@ -89,10 +95,10 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man, · 29 unmodified lines | ||
| 89 | 95 | return ret; |
| 90 | 96 | } |
| 91 | 97 | |
| 92 | −static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man, | |
| 93 | − struct ttm_mem_reg *mem) | |
| 98 | +static void ttm_range_man_free(struct ttm_resource_manager *man, | |
| 99 | + struct ttm_resource *mem) | |
| 94 | 100 | { |
| 95 | − struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; | |
| 101 | + struct ttm_range_manager *rman = to_range_manager(man); | |
| 96 | 102 | |
| 97 | 103 | if (mem->mm_node) { |
| 98 | 104 | spin_lock(&rman->lock); |
| @@ -104,53 +110,78 @@ static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man, · 5 unmodified lines | ||
| 104 | 110 | } |
| 105 | 111 | } |
| 106 | 112 | |
| 107 | −static int ttm_bo_man_init(struct ttm_mem_type_manager *man, | |
| 108 | − unsigned long p_size) | |
| 113 | +static const struct ttm_resource_manager_func ttm_range_manager_func; | |
| 114 | + | |
| 115 | +int ttm_range_man_init(struct ttm_bo_device *bdev, | |
| 116 | + unsigned type, | |
| 117 | + uint32_t available_caching, | |
| 118 | + uint32_t default_caching, | |
| 119 | + bool use_tt, | |
| 120 | + unsigned long p_size) | |
| 109 | 121 | { |
| 122 | + struct ttm_resource_manager *man; | |
| 110 | 123 | struct ttm_range_manager *rman; |
| 111 | 124 | |
| 112 | 125 | rman = kzalloc(sizeof(*rman), GFP_KERNEL); |
| 113 | 126 | if (!rman) |
| 114 | 127 | return -ENOMEM; |
| 115 | 128 | |
| 129 | + man = &rman->manager; | |
| 130 | + man->available_caching = available_caching; | |
| 131 | + man->default_caching = default_caching; | |
| 132 | + man->use_tt = use_tt; | |
| 133 | + | |
| 134 | + man->func = &ttm_range_manager_func; | |
| 135 | + | |
| 136 | + ttm_resource_manager_init(man, p_size); | |
| 137 | + | |
| 116 | 138 | drm_mm_init(&rman->mm, 0, p_size); |
| 117 | 139 | spin_lock_init(&rman->lock); |
| 118 | − man->priv = rman; | |
| 140 | + | |
| 141 | + ttm_set_driver_manager(bdev, type, &rman->manager); | |
| 142 | + ttm_resource_manager_set_used(man, true); | |
| 119 | 143 | return 0; |
| 120 | 144 | } |
| 145 | +EXPORT_SYMBOL(ttm_range_man_init); | |
| 121 | 146 | |
| 122 | −static int ttm_bo_man_takedown(struct ttm_mem_type_manager *man) | |
| 147 | +int ttm_range_man_fini(struct ttm_bo_device *bdev, | |
| 148 | + unsigned type) | |
| 123 | 149 | { |
| 124 | − struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; | |
| 150 | + struct ttm_resource_manager *man = ttm_manager_type(bdev, type); | |
| 151 | + struct ttm_range_manager *rman = to_range_manager(man); | |
| 125 | 152 | struct drm_mm *mm = &rman->mm; |
| 153 | + int ret; | |
| 154 | + | |
| 155 | + ttm_resource_manager_set_used(man, false); | |
| 156 | + | |
| 157 | + ret = ttm_resource_manager_force_list_clean(bdev, man); | |
| 158 | + if (ret) | |
| 159 | + return ret; | |
| 126 | 160 | |
| 127 | 161 | spin_lock(&rman->lock); |
| 128 | − if (drm_mm_clean(mm)) { | |
| 129 | − drm_mm_takedown(mm); | |
| 130 | − spin_unlock(&rman->lock); | |
| 131 | − kfree(rman); | |
| 132 | − man->priv = NULL; | |
| 133 | − return 0; | |
| 134 | − } | |
| 162 | + drm_mm_clean(mm); | |
| 163 | + drm_mm_takedown(mm); | |
| 135 | 164 | spin_unlock(&rman->lock); |
| 136 | − return -EBUSY; | |
| 165 | + | |
| 166 | + ttm_resource_manager_cleanup(man); | |
| 167 | + ttm_set_driver_manager(bdev, type, NULL); | |
| 168 | + kfree(rman); | |
| 169 | + return 0; | |
| 137 | 170 | } |
| 171 | +EXPORT_SYMBOL(ttm_range_man_fini); | |
| 138 | 172 | |
| 139 | −static void ttm_bo_man_debug(struct ttm_mem_type_manager *man, | |
| 140 | − struct drm_printer *printer) | |
| 173 | +static void ttm_range_man_debug(struct ttm_resource_manager *man, | |
| 174 | + struct drm_printer *printer) | |
| 141 | 175 | { |
| 142 | − struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; | |
| 176 | + struct ttm_range_manager *rman = to_range_manager(man); | |
| 143 | 177 | |
| 144 | 178 | spin_lock(&rman->lock); |
| 145 | 179 | drm_mm_print(&rman->mm, printer); |
| 146 | 180 | spin_unlock(&rman->lock); |
| 147 | 181 | } |
| 148 | 182 | |
| 149 | −const struct ttm_mem_type_manager_func ttm_bo_manager_func = { | |
| 150 | − .init = ttm_bo_man_init, | |
| 151 | − .takedown = ttm_bo_man_takedown, | |
| 152 | − .get_node = ttm_bo_man_get_node, | |
| 153 | − .put_node = ttm_bo_man_put_node, | |
| 154 | − .debug = ttm_bo_man_debug | |
| 183 | +static const struct ttm_resource_manager_func ttm_range_manager_func = { | |
| 184 | + .alloc = ttm_range_man_alloc, | |
| 185 | + .free = ttm_range_man_free, | |
| 186 | + .debug = ttm_range_man_debug | |
| 155 | 187 | }; |
| 156 | −EXPORT_SYMBOL(ttm_bo_manager_func); | |
| @@ -0,0 +1,151 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright 2020 Advanced Micro Devices, Inc. | |
| 3 | + * | |
| 4 | + * Permission is hereby granted, free of charge, to any person obtaining a | |
| 5 | + * copy of this software and associated documentation files (the "Software"), | |
| 6 | + * to deal in the Software without restriction, including without limitation | |
| 7 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 8 | + * and/or sell copies of the Software, and to permit persons to whom the | |
| 9 | + * Software is furnished to do so, subject to the following conditions: | |
| 10 | + * | |
| 11 | + * The above copyright notice and this permission notice shall be included in | |
| 12 | + * all copies or substantial portions of the Software. | |
| 13 | + * | |
| 14 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 17 | + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
| 18 | + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
| 19 | + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
| 20 | + * OTHER DEALINGS IN THE SOFTWARE. | |
| 21 | + * | |
| 22 | + * Authors: Christian König | |
| 23 | + */ | |
| 24 | + | |
| 25 | +#include <drm/ttm/ttm_resource.h> | |
| 26 | +#include <drm/ttm/ttm_bo_driver.h> | |
| 27 | + | |
| 28 | +int ttm_resource_alloc(struct ttm_buffer_object *bo, | |
| 29 | + const struct ttm_place *place, | |
| 30 | + struct ttm_resource *res) | |
| 31 | +{ | |
| 32 | + struct ttm_resource_manager *man = | |
| 33 | + ttm_manager_type(bo->bdev, res->mem_type); | |
| 34 | + | |
| 35 | + res->mm_node = NULL; | |
| 36 | + if (!man->func || !man->func->alloc) | |
| 37 | + return 0; | |
| 38 | + | |
| 39 | + return man->func->alloc(man, bo, place, res); | |
| 40 | +} | |
| 41 | + | |
| 42 | +void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource *res) | |
| 43 | +{ | |
| 44 | + struct ttm_resource_manager *man = | |
| 45 | + ttm_manager_type(bo->bdev, res->mem_type); | |
| 46 | + | |
| 47 | + if (man->func && man->func->free) | |
| 48 | + man->func->free(man, res); | |
| 49 | + | |
| 50 | + res->mm_node = NULL; | |
| 51 | + res->mem_type = TTM_PL_SYSTEM; | |
| 52 | +} | |
| 53 | +EXPORT_SYMBOL(ttm_resource_free); | |
| 54 | + | |
| 55 | +/** | |
| 56 | + * ttm_resource_manager_init | |
| 57 | + * | |
| 58 | + * @man: memory manager object to init | |
| 59 | + * @p_size: size managed area in pages. | |
| 60 | + * | |
| 61 | + * Initialise core parts of a manager object. | |
| 62 | + */ | |
| 63 | +void ttm_resource_manager_init(struct ttm_resource_manager *man, | |
| 64 | + unsigned long p_size) | |
| 65 | +{ | |
| 66 | + unsigned i; | |
| 67 | + | |
| 68 | + man->use_io_reserve_lru = false; | |
| 69 | + mutex_init(&man->io_reserve_mutex); | |
| 70 | + spin_lock_init(&man->move_lock); | |
| 71 | + INIT_LIST_HEAD(&man->io_reserve_lru); | |
| 72 | + man->size = p_size; | |
| 73 | + | |
| 74 | + for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) | |
| 75 | + INIT_LIST_HEAD(&man->lru[i]); | |
| 76 | + man->move = NULL; | |
| 77 | +} | |
| 78 | +EXPORT_SYMBOL(ttm_resource_manager_init); | |
| 79 | + | |
| 80 | +/* | |
| 81 | + * ttm_resource_manager_force_list_clean | |
| 82 | + * | |
| 83 | + * @bdev - device to use | |
| 84 | + * @man - manager to use | |
| 85 | + * | |
| 86 | + * Force all the objects out of a memory manager until clean. | |
| 87 | + * Part of memory manager cleanup sequence. | |
| 88 | + */ | |
| 89 | +int ttm_resource_manager_force_list_clean(struct ttm_bo_device *bdev, | |
| 90 | + struct ttm_resource_manager *man) | |
| 91 | +{ | |
| 92 | + struct ttm_operation_ctx ctx = { | |
| 93 | + .interruptible = false, | |
| 94 | + .no_wait_gpu = false, | |
| 95 | + .flags = TTM_OPT_FLAG_FORCE_ALLOC | |
| 96 | + }; | |
| 97 | + struct ttm_bo_global *glob = &ttm_bo_glob; | |
| 98 | + struct dma_fence *fence; | |
| 99 | + int ret; | |
| 100 | + unsigned i; | |
| 101 | + | |
| 102 | + /* | |
| 103 | + * Can't use standard list traversal since we're unlocking. | |
| 104 | + */ | |
| 105 | + | |
| 106 | + spin_lock(&glob->lru_lock); | |
| 107 | + for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) { | |
| 108 | + while (!list_empty(&man->lru[i])) { | |
| 109 | + spin_unlock(&glob->lru_lock); | |
| 110 | + ret = ttm_mem_evict_first(bdev, man, NULL, &ctx, | |
| 111 | + NULL); | |
| 112 | + if (ret) | |
| 113 | + return ret; | |
| 114 | + spin_lock(&glob->lru_lock); | |
| 115 | + } | |
| 116 | + } | |
| 117 | + spin_unlock(&glob->lru_lock); | |
| 118 | + | |
| 119 | + spin_lock(&man->move_lock); | |
| 120 | + fence = dma_fence_get(man->move); | |
| 121 | + spin_unlock(&man->move_lock); | |
| 122 | + | |
| 123 | + if (fence) { | |
| 124 | + ret = dma_fence_wait(fence, false); | |
| 125 | + dma_fence_put(fence); | |
| 126 | + if (ret) | |
| 127 | + return ret; | |
| 128 | + } | |
| 129 | + | |
| 130 | + return 0; | |
| 131 | +} | |
| 132 | +EXPORT_SYMBOL(ttm_resource_manager_force_list_clean); | |
| 133 | + | |
| 134 | +/** | |
| 135 | + * ttm_resource_manager_debug | |
| 136 | + * | |
| 137 | + * @man: manager type to dump. | |
| 138 | + * @p: printer to use for debug. | |
| 139 | + */ | |
| 140 | +void ttm_resource_manager_debug(struct ttm_resource_manager *man, | |
| 141 | + struct drm_printer *p) | |
| 142 | +{ | |
| 143 | + drm_printf(p, " use_type: %d\n", man->use_type); | |
| 144 | + drm_printf(p, " use_tt: %d\n", man->use_tt); | |
| 145 | + drm_printf(p, " size: %llu\n", man->size); | |
| 146 | + drm_printf(p, " available_caching: 0x%08X\n", man->available_caching); | |
| 147 | + drm_printf(p, " default_caching: 0x%08X\n", man->default_caching); | |
| 148 | + if (man->func && man->func->debug) | |
| 149 | + (*man->func->debug)(man, p); | |
| 150 | +} | |
| 151 | +EXPORT_SYMBOL(ttm_resource_manager_debug); | |
| @@ -50,6 +50,9 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc) · 49 unmodified lines | ||
| 50 | 50 | |
| 51 | 51 | dma_resv_assert_held(bo->base.resv); |
| 52 | 52 | |
| 53 | + if (bo->ttm) | |
| 54 | + return 0; | |
| 55 | + | |
| 53 | 56 | if (bdev->need_dma32) |
| 54 | 57 | page_flags |= TTM_PAGE_FLAG_DMA32; |
| 55 | 58 | |
| @@ -67,7 +70,6 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc) · 11 unmodified lines | ||
| 67 | 70 | page_flags |= TTM_PAGE_FLAG_SG; |
| 68 | 71 | break; |
| 69 | 72 | default: |
| 70 | − bo->ttm = NULL; | |
| 71 | 73 | pr_err("Illegal buffer object type\n"); |
| 72 | 74 | return -EINVAL; |
| 73 | 75 | } |
| @@ -314,7 +316,7 @@ void ttm_tt_unbind(struct ttm_tt *ttm) · 240 unmodified lines | ||
| 314 | 316 | } |
| 315 | 317 | } |
| 316 | 318 | |
| 317 | −int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem, | |
| 319 | +int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_resource *bo_mem, | |
| 318 | 320 | struct ttm_operation_ctx *ctx) |
| 319 | 321 | { |
| 320 | 322 | int ret = 0; |
| @@ -358,18 +358,7 @@ static struct platform_driver v3d_platform_driver = { · 357 unmodified lines | ||
| 358 | 358 | }, |
| 359 | 359 | }; |
| 360 | 360 | |
| 361 | −static int __init v3d_drm_register(void) | |
| 362 | −{ | |
| 363 | − return platform_driver_register(&v3d_platform_driver); | |
| 364 | −} | |
| 365 | − | |
| 366 | −static void __exit v3d_drm_unregister(void) | |
| 367 | −{ | |
| 368 | − platform_driver_unregister(&v3d_platform_driver); | |
| 369 | −} | |
| 370 | − | |
| 371 | −module_init(v3d_drm_register); | |
| 372 | −module_exit(v3d_drm_unregister); | |
| 361 | +module_platform_driver(v3d_platform_driver); | |
| 373 | 362 | |
| 374 | 363 | MODULE_ALIAS("platform:v3d-drm"); |
| 375 | 364 | MODULE_DESCRIPTION("Broadcom V3D DRM Driver"); |
| @@ -471,8 +471,8 @@ static int __init vgem_init(void) · 470 unmodified lines | ||
| 471 | 471 | |
| 472 | 472 | out_put: |
| 473 | 473 | drm_dev_put(&vgem_device->drm); |
| 474 | + platform_device_unregister(vgem_device->platform); | |
| 474 | 475 | return ret; |
| 475 | − | |
| 476 | 476 | out_unregister: |
| 477 | 477 | platform_device_unregister(vgem_device->platform); |
| 478 | 478 | out_free: |
| @@ -4,6 +4,7 @@ config DRM_VIRTIO_GPU · 3 unmodified lines | ||
| 4 | 4 | depends on DRM && VIRTIO && MMU |
| 5 | 5 | select DRM_KMS_HELPER |
| 6 | 6 | select DRM_GEM_SHMEM_HELPER |
| 7 | + select VIRTIO_DMA_SHARED_BUFFER | |
| 7 | 8 | help |
| 8 | 9 | This is the virtual GPU driver for virtio. It can be used with |
| 9 | 10 | QEMU based VMMs (like KVM or Xen). |
| @@ -165,8 +165,6 @@ static int virtio_gpu_conn_get_modes(struct drm_connector *connector) · 164 unmodified lines | ||
| 165 | 165 | count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX); |
| 166 | 166 | |
| 167 | 167 | if (width == 0 || height == 0) { |
| 168 | − width = XRES_DEF; | |
| 169 | − height = YRES_DEF; | |
| 170 | 168 | drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF); |
| 171 | 169 | } else { |
| 172 | 170 | DRM_DEBUG("add mode: %dx%d\n", width, height); |
| @@ -165,6 +165,7 @@ static unsigned int features[] = { · 164 unmodified lines | ||
| 165 | 165 | VIRTIO_GPU_F_VIRGL, |
| 166 | 166 | #endif |
| 167 | 167 | VIRTIO_GPU_F_EDID, |
| 168 | + VIRTIO_GPU_F_RESOURCE_UUID, | |
| 168 | 169 | }; |
| 169 | 170 | static struct virtio_driver virtio_gpu_driver = { |
| 170 | 171 | .feature_table = features, |
| @@ -202,6 +203,8 @@ static struct drm_driver driver = { · 31 unmodified lines | ||
| 202 | 203 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, |
| 203 | 204 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, |
| 204 | 205 | .gem_prime_mmap = drm_gem_prime_mmap, |
| 206 | + .gem_prime_export = virtgpu_gem_prime_export, | |
| 207 | + .gem_prime_import = virtgpu_gem_prime_import, | |
| 205 | 208 | .gem_prime_import_sg_table = virtgpu_gem_prime_import_sg_table, |
| 206 | 209 | |
| 207 | 210 | .gem_create_object = virtio_gpu_create_object, |
| @@ -49,6 +49,10 @@ · 48 unmodified lines | ||
| 49 | 49 | #define DRIVER_MINOR 1 |
| 50 | 50 | #define DRIVER_PATCHLEVEL 0 |
| 51 | 51 | |
| 52 | +#define UUID_INITIALIZING 0 | |
| 53 | +#define UUID_INITIALIZED 1 | |
| 54 | +#define UUID_INITIALIZATION_FAILED 2 | |
| 55 | + | |
| 52 | 56 | struct virtio_gpu_object_params { |
| 53 | 57 | uint32_t format; |
| 54 | 58 | uint32_t width; |
| @@ -71,6 +75,9 @@ struct virtio_gpu_object { · 16 unmodified lines | ||
| 71 | 75 | uint32_t hw_res_handle; |
| 72 | 76 | bool dumb; |
| 73 | 77 | bool created; |
| 78 | + | |
| 79 | + int uuid_state; | |
| 80 | + uuid_t uuid; | |
| 74 | 81 | }; |
| 75 | 82 | #define gem_to_virtio_gpu_obj(gobj) \ |
| 76 | 83 | container_of((gobj), struct virtio_gpu_object, base.base) |
| @@ -200,6 +207,7 @@ struct virtio_gpu_device { · 123 unmodified lines | ||
| 200 | 207 | bool has_virgl_3d; |
| 201 | 208 | bool has_edid; |
| 202 | 209 | bool has_indirect; |
| 210 | + bool has_resource_assign_uuid; | |
| 203 | 211 | |
| 204 | 212 | struct work_struct config_changed_work; |
| 205 | 213 | |
| @@ -210,6 +218,9 @@ struct virtio_gpu_device { · 4 unmodified lines | ||
| 210 | 218 | struct virtio_gpu_drv_capset *capsets; |
| 211 | 219 | uint32_t num_capsets; |
| 212 | 220 | struct list_head cap_cache; |
| 221 | + | |
| 222 | + /* protects resource state when exporting */ | |
| 223 | + spinlock_t resource_export_lock; | |
| 213 | 224 | }; |
| 214 | 225 | |
| 215 | 226 | struct virtio_gpu_fpriv { |
| @@ -336,6 +347,10 @@ void virtio_gpu_dequeue_fence_func(struct work_struct *work); · 120 unmodified lines | ||
| 336 | 347 | |
| 337 | 348 | void virtio_gpu_notify(struct virtio_gpu_device *vgdev); |
| 338 | 349 | |
| 350 | +int | |
| 351 | +virtio_gpu_cmd_resource_assign_uuid(struct virtio_gpu_device *vgdev, | |
| 352 | + struct virtio_gpu_object_array *objs); | |
| 353 | + | |
| 339 | 354 | /* virtgpu_display.c */ |
| 340 | 355 | void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev); |
| 341 | 356 | void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev); |
| @@ -367,6 +382,12 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, · 25 unmodified lines | ||
| 367 | 382 | bool virtio_gpu_is_shmem(struct virtio_gpu_object *bo); |
| 368 | 383 | |
| 369 | 384 | /* virtgpu_prime.c */ |
| 385 | +struct dma_buf *virtgpu_gem_prime_export(struct drm_gem_object *obj, | |
| 386 | + int flags); | |
| 387 | +struct drm_gem_object *virtgpu_gem_prime_import(struct drm_device *dev, | |
| 388 | + struct dma_buf *buf); | |
| 389 | +int virtgpu_gem_prime_get_uuid(struct drm_gem_object *obj, | |
| 390 | + uuid_t *uuid); | |
| 370 | 391 | struct drm_gem_object *virtgpu_gem_prime_import_sg_table( |
| 371 | 392 | struct drm_device *dev, struct dma_buf_attachment *attach, |
| 372 | 393 | struct sg_table *sgt); |
| @@ -154,9 +154,8 @@ void virtio_gpu_gem_object_close(struct drm_gem_object *obj, · 153 unmodified lines | ||
| 154 | 154 | struct virtio_gpu_object_array *virtio_gpu_array_alloc(u32 nents) |
| 155 | 155 | { |
| 156 | 156 | struct virtio_gpu_object_array *objs; |
| 157 | − size_t size = sizeof(*objs) + sizeof(objs->objs[0]) * nents; | |
| 158 | 157 | |
| 159 | − objs = kmalloc(size, GFP_KERNEL); | |
| 158 | + objs = kmalloc(struct_size(objs, objs, nents), GFP_KERNEL); | |
| 160 | 159 | if (!objs) |
| 161 | 160 | return NULL; |
| 162 | 161 | |
| @@ -118,6 +118,7 @@ int virtio_gpu_init(struct drm_device *dev) · 117 unmodified lines | ||
| 118 | 118 | vgdev->dev = dev->dev; |
| 119 | 119 | |
| 120 | 120 | spin_lock_init(&vgdev->display_info_lock); |
| 121 | + spin_lock_init(&vgdev->resource_export_lock); | |
| 121 | 122 | ida_init(&vgdev->ctx_id_ida); |
| 122 | 123 | ida_init(&vgdev->resource_ida); |
| 123 | 124 | init_waitqueue_head(&vgdev->resp_wq); |
| @@ -146,6 +147,9 @@ int virtio_gpu_init(struct drm_device *dev) · 22 unmodified lines | ||
| 146 | 147 | if (virtio_has_feature(vgdev->vdev, VIRTIO_RING_F_INDIRECT_DESC)) { |
| 147 | 148 | vgdev->has_indirect = true; |
| 148 | 149 | } |
| 150 | + if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_RESOURCE_UUID)) { | |
| 151 | + vgdev->has_resource_assign_uuid = true; | |
| 152 | + } | |
| 149 | 153 | |
| 150 | 154 | DRM_INFO("features: %cvirgl %cedid\n", |
| 151 | 155 | vgdev->has_virgl_3d ? '+' : '-', |
| @@ -151,7 +151,13 @@ static int virtio_gpu_object_shmem_init(struct virtio_gpu_device *vgdev, · 150 unmodified lines | ||
| 151 | 151 | if (ret < 0) |
| 152 | 152 | return -EINVAL; |
| 153 | 153 | |
| 154 | − shmem->pages = drm_gem_shmem_get_pages_sgt(&bo->base.base); | |
| 154 | + /* | |
| 155 | + * virtio_gpu uses drm_gem_shmem_get_sg_table instead of | |
| 156 | + * drm_gem_shmem_get_pages_sgt because virtio has it's own set of | |
| 157 | + * dma-ops. This is discouraged for other drivers, but should be fine | |
| 158 | + * since virtio_gpu doesn't support dma-buf import from other devices. | |
| 159 | + */ | |
| 160 | + shmem->pages = drm_gem_shmem_get_sg_table(&bo->base.base); | |
| 155 | 161 | if (!shmem->pages) { |
| 156 | 162 | drm_gem_shmem_unpin(&bo->base.base); |
| 157 | 163 | return -EINVAL; |
| @@ -23,12 +23,102 @@ · 22 unmodified lines | ||
| 23 | 23 | */ |
| 24 | 24 | |
| 25 | 25 | #include <drm/drm_prime.h> |
| 26 | +#include <linux/virtio_dma_buf.h> | |
| 26 | 27 | |
| 27 | 28 | #include "virtgpu_drv.h" |
| 28 | 29 | |
| 29 | −/* Empty Implementations as there should not be any other driver for a virtual | |
| 30 | − * device that might share buffers with virtgpu | |
| 31 | − */ | |
| 30 | +static int virtgpu_virtio_get_uuid(struct dma_buf *buf, | |
| 31 | + uuid_t *uuid) | |
| 32 | +{ | |
| 33 | + struct drm_gem_object *obj = buf->priv; | |
| 34 | + struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj); | |
| 35 | + struct virtio_gpu_device *vgdev = obj->dev->dev_private; | |
| 36 | + | |
| 37 | + wait_event(vgdev->resp_wq, bo->uuid_state != UUID_INITIALIZING); | |
| 38 | + if (bo->uuid_state != UUID_INITIALIZED) | |
| 39 | + return -ENODEV; | |
| 40 | + | |
| 41 | + uuid_copy(uuid, &bo->uuid); | |
| 42 | + | |
| 43 | + return 0; | |
| 44 | +} | |
| 45 | + | |
| 46 | +const struct virtio_dma_buf_ops virtgpu_dmabuf_ops = { | |
| 47 | + .ops = { | |
| 48 | + .cache_sgt_mapping = true, | |
| 49 | + .attach = virtio_dma_buf_attach, | |
| 50 | + .detach = drm_gem_map_detach, | |
| 51 | + .map_dma_buf = drm_gem_map_dma_buf, | |
| 52 | + .unmap_dma_buf = drm_gem_unmap_dma_buf, | |
| 53 | + .release = drm_gem_dmabuf_release, | |
| 54 | + .mmap = drm_gem_dmabuf_mmap, | |
| 55 | + .vmap = drm_gem_dmabuf_vmap, | |
| 56 | + .vunmap = drm_gem_dmabuf_vunmap, | |
| 57 | + }, | |
| 58 | + .device_attach = drm_gem_map_attach, | |
| 59 | + .get_uuid = virtgpu_virtio_get_uuid, | |
| 60 | +}; | |
| 61 | + | |
| 62 | +struct dma_buf *virtgpu_gem_prime_export(struct drm_gem_object *obj, | |
| 63 | + int flags) | |
| 64 | +{ | |
| 65 | + struct dma_buf *buf; | |
| 66 | + struct drm_device *dev = obj->dev; | |
| 67 | + struct virtio_gpu_device *vgdev = dev->dev_private; | |
| 68 | + struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj); | |
| 69 | + struct virtio_gpu_object_array *objs; | |
| 70 | + int ret = 0; | |
| 71 | + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); | |
| 72 | + | |
| 73 | + if (vgdev->has_resource_assign_uuid) { | |
| 74 | + objs = virtio_gpu_array_alloc(1); | |
| 75 | + if (!objs) | |
| 76 | + return ERR_PTR(-ENOMEM); | |
| 77 | + virtio_gpu_array_add_obj(objs, &bo->base.base); | |
| 78 | + | |
| 79 | + ret = virtio_gpu_cmd_resource_assign_uuid(vgdev, objs); | |
| 80 | + if (ret) | |
| 81 | + return ERR_PTR(ret); | |
| 82 | + virtio_gpu_notify(vgdev); | |
| 83 | + } else { | |
| 84 | + bo->uuid_state = UUID_INITIALIZATION_FAILED; | |
| 85 | + } | |
| 86 | + | |
| 87 | + exp_info.ops = &virtgpu_dmabuf_ops.ops; | |
| 88 | + exp_info.size = obj->size; | |
| 89 | + exp_info.flags = flags; | |
| 90 | + exp_info.priv = obj; | |
| 91 | + exp_info.resv = obj->resv; | |
| 92 | + | |
| 93 | + buf = virtio_dma_buf_export(&exp_info); | |
| 94 | + if (IS_ERR(buf)) | |
| 95 | + return buf; | |
| 96 | + | |
| 97 | + drm_dev_get(dev); | |
| 98 | + drm_gem_object_get(obj); | |
| 99 | + | |
| 100 | + return buf; | |
| 101 | +} | |
| 102 | + | |
| 103 | +struct drm_gem_object *virtgpu_gem_prime_import(struct drm_device *dev, | |
| 104 | + struct dma_buf *buf) | |
| 105 | +{ | |
| 106 | + struct drm_gem_object *obj; | |
| 107 | + | |
| 108 | + if (buf->ops == &virtgpu_dmabuf_ops.ops) { | |
| 109 | + obj = buf->priv; | |
| 110 | + if (obj->dev == dev) { | |
| 111 | + /* | |
| 112 | + * Importing dmabuf exported from our own gem increases | |
| 113 | + * refcount on gem itself instead of f_count of dmabuf. | |
| 114 | + */ | |
| 115 | + drm_gem_object_get(obj); | |
| 116 | + return obj; | |
| 117 | + } | |
| 118 | + } | |
| 119 | + | |
| 120 | + return drm_gem_prime_import(dev, buf); | |
| 121 | +} | |
| 32 | 122 | |
| 33 | 123 | struct drm_gem_object *virtgpu_gem_prime_import_sg_table( |
| 34 | 124 | struct drm_device *dev, struct dma_buf_attachment *attach, |
| @@ -1107,3 +1107,58 @@ void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev, · 1106 unmodified lines | ||
| 1107 | 1107 | memcpy(cur_p, &output->cursor, sizeof(output->cursor)); |
| 1108 | 1108 | virtio_gpu_queue_cursor(vgdev, vbuf); |
| 1109 | 1109 | } |
| 1110 | + | |
| 1111 | +static void virtio_gpu_cmd_resource_uuid_cb(struct virtio_gpu_device *vgdev, | |
| 1112 | + struct virtio_gpu_vbuffer *vbuf) | |
| 1113 | +{ | |
| 1114 | + struct virtio_gpu_object *obj = | |
| 1115 | + gem_to_virtio_gpu_obj(vbuf->objs->objs[0]); | |
| 1116 | + struct virtio_gpu_resp_resource_uuid *resp = | |
| 1117 | + (struct virtio_gpu_resp_resource_uuid *)vbuf->resp_buf; | |
| 1118 | + uint32_t resp_type = le32_to_cpu(resp->hdr.type); | |
| 1119 | + | |
| 1120 | + spin_lock(&vgdev->resource_export_lock); | |
| 1121 | + WARN_ON(obj->uuid_state != UUID_INITIALIZING); | |
| 1122 | + | |
| 1123 | + if (resp_type == VIRTIO_GPU_RESP_OK_RESOURCE_UUID && | |
| 1124 | + obj->uuid_state == UUID_INITIALIZING) { | |
| 1125 | + memcpy(&obj->uuid.b, resp->uuid, sizeof(obj->uuid.b)); | |
| 1126 | + obj->uuid_state = UUID_INITIALIZED; | |
| 1127 | + } else { | |
| 1128 | + obj->uuid_state = UUID_INITIALIZATION_FAILED; | |
| 1129 | + } | |
| 1130 | + spin_unlock(&vgdev->resource_export_lock); | |
| 1131 | + | |
| 1132 | + wake_up_all(&vgdev->resp_wq); | |
| 1133 | +} | |
| 1134 | + | |
| 1135 | +int | |
| 1136 | +virtio_gpu_cmd_resource_assign_uuid(struct virtio_gpu_device *vgdev, | |
| 1137 | + struct virtio_gpu_object_array *objs) | |
| 1138 | +{ | |
| 1139 | + struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(objs->objs[0]); | |
| 1140 | + struct virtio_gpu_resource_assign_uuid *cmd_p; | |
| 1141 | + struct virtio_gpu_vbuffer *vbuf; | |
| 1142 | + struct virtio_gpu_resp_resource_uuid *resp_buf; | |
| 1143 | + | |
| 1144 | + resp_buf = kzalloc(sizeof(*resp_buf), GFP_KERNEL); | |
| 1145 | + if (!resp_buf) { | |
| 1146 | + spin_lock(&vgdev->resource_export_lock); | |
| 1147 | + bo->uuid_state = UUID_INITIALIZATION_FAILED; | |
| 1148 | + spin_unlock(&vgdev->resource_export_lock); | |
| 1149 | + virtio_gpu_array_put_free(objs); | |
| 1150 | + return -ENOMEM; | |
| 1151 | + } | |
| 1152 | + | |
| 1153 | + cmd_p = virtio_gpu_alloc_cmd_resp | |
| 1154 | + (vgdev, virtio_gpu_cmd_resource_uuid_cb, &vbuf, sizeof(*cmd_p), | |
| 1155 | + sizeof(struct virtio_gpu_resp_resource_uuid), resp_buf); | |
| 1156 | + memset(cmd_p, 0, sizeof(*cmd_p)); | |
| 1157 | + | |
| 1158 | + cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID); | |
| 1159 | + cmd_p->resource_id = cpu_to_le32(bo->hw_res_handle); | |
| 1160 | + | |
| 1161 | + vbuf->objs = objs; | |
| 1162 | + virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); | |
| 1163 | + return 0; | |
| 1164 | +} | |
| @@ -33,7 +33,7 @@ static uint32_t compute_crc(void *vaddr_out, struct vkms_composer *composer) · 32 unmodified lines | ||
| 33 | 33 | + (i * composer->pitch) |
| 34 | 34 | + (j * composer->cpp); |
| 35 | 35 | /* XRGB format ignores Alpha channel */ |
| 36 | − memset(vaddr_out + src_offset + 24, 0, 8); | |
| 36 | + bitmap_clear(vaddr_out + src_offset, 24, 8); | |
| 37 | 37 | crc = crc32_le(crc, vaddr_out + src_offset, |
| 38 | 38 | sizeof(u32)); |
| 39 | 39 | } |
| @@ -233,6 +233,22 @@ int vkms_verify_crc_source(struct drm_crtc *crtc, const char *src_name, · 193 unmodified lines | ||
| 233 | 233 | return 0; |
| 234 | 234 | } |
| 235 | 235 | |
| 236 | +static void vkms_set_composer(struct vkms_output *out, bool enabled) | |
| 237 | +{ | |
| 238 | + bool old_enabled; | |
| 239 | + | |
| 240 | + if (enabled) | |
| 241 | + drm_crtc_vblank_get(&out->crtc); | |
| 242 | + | |
| 243 | + spin_lock_irq(&out->lock); | |
| 244 | + old_enabled = out->composer_enabled; | |
| 245 | + out->composer_enabled = enabled; | |
| 246 | + spin_unlock_irq(&out->lock); | |
| 247 | + | |
| 248 | + if (old_enabled) | |
| 249 | + drm_crtc_vblank_put(&out->crtc); | |
| 250 | +} | |
| 251 | + | |
| 236 | 252 | int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name) |
| 237 | 253 | { |
| 238 | 254 | struct vkms_output *out = drm_crtc_to_vkms_output(crtc); |
| @@ -241,9 +257,7 @@ int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name) · 2 unmodified lines | ||
| 241 | 257 | |
| 242 | 258 | ret = vkms_crc_parse_source(src_name, &enabled); |
| 243 | 259 | |
| 244 | − spin_lock_irq(&out->lock); | |
| 245 | − out->composer_enabled = enabled; | |
| 246 | − spin_unlock_irq(&out->lock); | |
| 260 | + vkms_set_composer(out, enabled); | |
| 247 | 261 | |
| 248 | 262 | return ret; |
| 249 | 263 | } |
| @@ -190,8 +190,8 @@ static int __init vkms_init(void) · 189 unmodified lines | ||
| 190 | 190 | |
| 191 | 191 | out_put: |
| 192 | 192 | drm_dev_put(&vkms_device->drm); |
| 193 | + platform_device_unregister(vkms_device->platform); | |
| 193 | 194 | return ret; |
| 194 | − | |
| 195 | 195 | out_unregister: |
| 196 | 196 | platform_device_unregister(vkms_device->platform); |
| 197 | 197 | out_free: |
| @@ -1135,14 +1135,14 @@ void vmw_bo_swap_notify(struct ttm_buffer_object *bo) · 1134 unmodified lines | ||
| 1135 | 1135 | * vmw_bo_move_notify - TTM move_notify_callback |
| 1136 | 1136 | * |
| 1137 | 1137 | * @bo: The TTM buffer object about to move. |
| 1138 | − * @mem: The struct ttm_mem_reg indicating to what memory | |
| 1138 | + * @mem: The struct ttm_resource indicating to what memory | |
| 1139 | 1139 | * region the move is taking place. |
| 1140 | 1140 | * |
| 1141 | 1141 | * Detaches cached maps and device bindings that require that the |
| 1142 | 1142 | * buffer doesn't move. |
| 1143 | 1143 | */ |
| 1144 | 1144 | void vmw_bo_move_notify(struct ttm_buffer_object *bo, |
| 1145 | − struct ttm_mem_reg *mem) | |
| 1145 | + struct ttm_resource *mem) | |
| 1146 | 1146 | { |
| 1147 | 1147 | struct vmw_buffer_object *vbo; |
| 1148 | 1148 | |
| @@ -620,6 +620,29 @@ static int vmw_dma_masks(struct vmw_private *dev_priv) · 619 unmodified lines | ||
| 620 | 620 | return ret; |
| 621 | 621 | } |
| 622 | 622 | |
| 623 | +static int vmw_vram_manager_init(struct vmw_private *dev_priv) | |
| 624 | +{ | |
| 625 | + int ret; | |
| 626 | +#ifdef CONFIG_TRANSPARENT_HUGEPAGE | |
| 627 | + ret = vmw_thp_init(dev_priv); | |
| 628 | +#else | |
| 629 | + ret = ttm_range_man_init(&dev_priv->bdev, TTM_PL_VRAM, | |
| 630 | + TTM_PL_FLAG_CACHED, TTM_PL_FLAG_CACHED, | |
| 631 | + false, dev_priv->vram_size >> PAGE_SHIFT); | |
| 632 | +#endif | |
| 633 | + ttm_resource_manager_set_used(ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM), false); | |
| 634 | + return ret; | |
| 635 | +} | |
| 636 | + | |
| 637 | +static void vmw_vram_manager_fini(struct vmw_private *dev_priv) | |
| 638 | +{ | |
| 639 | +#ifdef CONFIG_TRANSPARENT_HUGEPAGE | |
| 640 | + vmw_thp_fini(dev_priv); | |
| 641 | +#else | |
| 642 | + ttm_range_man_fini(&dev_priv->bdev, TTM_PL_VRAM); | |
| 643 | +#endif | |
| 644 | +} | |
| 645 | + | |
| 623 | 646 | static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) |
| 624 | 647 | { |
| 625 | 648 | struct vmw_private *dev_priv; |
| @@ -859,23 +882,30 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) · 233 unmodified lines | ||
| 859 | 882 | DRM_ERROR("Failed initializing TTM buffer object driver.\n"); |
| 860 | 883 | goto out_no_bdev; |
| 861 | 884 | } |
| 885 | + ttm_manager_type(&dev_priv->bdev, TTM_PL_SYSTEM)->available_caching = | |
| 886 | + TTM_PL_FLAG_CACHED; | |
| 862 | 887 | |
| 863 | 888 | /* |
| 864 | 889 | * Enable VRAM, but initially don't use it until SVGA is enabled and |
| 865 | 890 | * unhidden. |
| 866 | 891 | */ |
| 867 | − ret = ttm_bo_init_mm(&dev_priv->bdev, TTM_PL_VRAM, | |
| 868 | − (dev_priv->vram_size >> PAGE_SHIFT)); | |
| 892 | + | |
| 893 | + ret = vmw_vram_manager_init(dev_priv); | |
| 869 | 894 | if (unlikely(ret != 0)) { |
| 870 | 895 | DRM_ERROR("Failed initializing memory manager for VRAM.\n"); |
| 871 | 896 | goto out_no_vram; |
| 872 | 897 | } |
| 873 | − dev_priv->bdev.man[TTM_PL_VRAM].use_type = false; | |
| 874 | 898 | |
| 899 | + /* | |
| 900 | + * "Guest Memory Regions" is an aperture like feature with | |
| 901 | + * one slot per bo. There is an upper limit of the number of | |
| 902 | + * slots as well as the bo size. | |
| 903 | + */ | |
| 875 | 904 | dev_priv->has_gmr = true; |
| 905 | + /* TODO: This is most likely not correct */ | |
| 876 | 906 | if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) || |
| 877 | − refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR, | |
| 878 | − VMW_PL_GMR) != 0) { | |
| 907 | + refuse_dma || | |
| 908 | + vmw_gmrid_man_init(dev_priv, VMW_PL_GMR) != 0) { | |
| 879 | 909 | DRM_INFO("No GMR memory available. " |
| 880 | 910 | "Graphics memory resources are very limited.\n"); |
| 881 | 911 | dev_priv->has_gmr = false; |
| @@ -883,8 +913,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) · 1 unmodified line | ||
| 883 | 913 | |
| 884 | 914 | if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS && !refuse_dma) { |
| 885 | 915 | dev_priv->has_mob = true; |
| 886 | − if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_MOB, | |
| 887 | − VMW_PL_MOB) != 0) { | |
| 916 | + | |
| 917 | + if (vmw_gmrid_man_init(dev_priv, VMW_PL_MOB) != 0) { | |
| 888 | 918 | DRM_INFO("No MOB memory available. " |
| 889 | 919 | "3D will be disabled.\n"); |
| 890 | 920 | dev_priv->has_mob = false; |
| @@ -961,10 +991,10 @@ out_no_fifo: · 70 unmodified lines | ||
| 961 | 991 | vmw_kms_close(dev_priv); |
| 962 | 992 | out_no_kms: |
| 963 | 993 | if (dev_priv->has_mob) |
| 964 | − (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB); | |
| 994 | + vmw_gmrid_man_fini(dev_priv, VMW_PL_MOB); | |
| 965 | 995 | if (dev_priv->has_gmr) |
| 966 | − (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); | |
| 967 | − (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); | |
| 996 | + vmw_gmrid_man_fini(dev_priv, VMW_PL_GMR); | |
| 997 | + vmw_vram_manager_fini(dev_priv); | |
| 968 | 998 | out_no_vram: |
| 969 | 999 | (void)ttm_bo_device_release(&dev_priv->bdev); |
| 970 | 1000 | out_no_bdev: |
| @@ -1012,12 +1042,12 @@ static void vmw_driver_unload(struct drm_device *dev) · 41 unmodified lines | ||
| 1012 | 1042 | vmw_overlay_close(dev_priv); |
| 1013 | 1043 | |
| 1014 | 1044 | if (dev_priv->has_gmr) |
| 1015 | − (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); | |
| 1016 | − (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); | |
| 1045 | + vmw_gmrid_man_fini(dev_priv, VMW_PL_GMR); | |
| 1017 | 1046 | |
| 1018 | 1047 | vmw_release_device_early(dev_priv); |
| 1019 | 1048 | if (dev_priv->has_mob) |
| 1020 | − (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB); | |
| 1049 | + vmw_gmrid_man_fini(dev_priv, VMW_PL_MOB); | |
| 1050 | + vmw_vram_manager_fini(dev_priv); | |
| 1021 | 1051 | (void) ttm_bo_device_release(&dev_priv->bdev); |
| 1022 | 1052 | drm_vma_offset_manager_destroy(&dev_priv->vma_manager); |
| 1023 | 1053 | vmw_release_device_late(dev_priv); |
| @@ -1159,10 +1189,12 @@ static void vmw_master_drop(struct drm_device *dev, · 135 unmodified lines | ||
| 1159 | 1189 | */ |
| 1160 | 1190 | static void __vmw_svga_enable(struct vmw_private *dev_priv) |
| 1161 | 1191 | { |
| 1192 | + struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM); | |
| 1193 | + | |
| 1162 | 1194 | spin_lock(&dev_priv->svga_lock); |
| 1163 | − if (!dev_priv->bdev.man[TTM_PL_VRAM].use_type) { | |
| 1195 | + if (!ttm_resource_manager_used(man)) { | |
| 1164 | 1196 | vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE); |
| 1165 | − dev_priv->bdev.man[TTM_PL_VRAM].use_type = true; | |
| 1197 | + ttm_resource_manager_set_used(man, true); | |
| 1166 | 1198 | } |
| 1167 | 1199 | spin_unlock(&dev_priv->svga_lock); |
| 1168 | 1200 | } |
| @@ -1188,9 +1220,11 @@ void vmw_svga_enable(struct vmw_private *dev_priv) · 19 unmodified lines | ||
| 1188 | 1220 | */ |
| 1189 | 1221 | static void __vmw_svga_disable(struct vmw_private *dev_priv) |
| 1190 | 1222 | { |
| 1223 | + struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM); | |
| 1224 | + | |
| 1191 | 1225 | spin_lock(&dev_priv->svga_lock); |
| 1192 | − if (dev_priv->bdev.man[TTM_PL_VRAM].use_type) { | |
| 1193 | − dev_priv->bdev.man[TTM_PL_VRAM].use_type = false; | |
| 1226 | + if (ttm_resource_manager_used(man)) { | |
| 1227 | + ttm_resource_manager_set_used(man, false); | |
| 1194 | 1228 | vmw_write(dev_priv, SVGA_REG_ENABLE, |
| 1195 | 1229 | SVGA_REG_ENABLE_HIDE | |
| 1196 | 1230 | SVGA_REG_ENABLE_ENABLE); |
| @@ -1207,6 +1241,7 @@ static void __vmw_svga_disable(struct vmw_private *dev_priv) · 10 unmodified lines | ||
| 1207 | 1241 | */ |
| 1208 | 1242 | void vmw_svga_disable(struct vmw_private *dev_priv) |
| 1209 | 1243 | { |
| 1244 | + struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM); | |
| 1210 | 1245 | /* |
| 1211 | 1246 | * Disabling SVGA will turn off device modesetting capabilities, so |
| 1212 | 1247 | * notify KMS about that so that it doesn't cache atomic state that |
| @@ -1222,8 +1257,8 @@ void vmw_svga_disable(struct vmw_private *dev_priv) · 9 unmodified lines | ||
| 1222 | 1257 | vmw_kms_lost_device(dev_priv->dev); |
| 1223 | 1258 | ttm_write_lock(&dev_priv->reservation_sem, false); |
| 1224 | 1259 | spin_lock(&dev_priv->svga_lock); |
| 1225 | − if (dev_priv->bdev.man[TTM_PL_VRAM].use_type) { | |
| 1226 | − dev_priv->bdev.man[TTM_PL_VRAM].use_type = false; | |
| 1260 | + if (ttm_resource_manager_used(man)) { | |
| 1261 | + ttm_resource_manager_set_used(man, false); | |
| 1227 | 1262 | spin_unlock(&dev_priv->svga_lock); |
| 1228 | 1263 | if (ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM)) |
| 1229 | 1264 | DRM_ERROR("Failed evicting VRAM buffers.\n"); |
| @@ -793,7 +793,7 @@ extern void vmw_resource_unreserve(struct vmw_resource *res, · 792 unmodified lines | ||
| 793 | 793 | struct vmw_buffer_object *new_backup, |
| 794 | 794 | unsigned long new_backup_offset); |
| 795 | 795 | extern void vmw_query_move_notify(struct ttm_buffer_object *bo, |
| 796 | − struct ttm_mem_reg *mem); | |
| 796 | + struct ttm_resource *mem); | |
| 797 | 797 | extern int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob); |
| 798 | 798 | extern void vmw_resource_evict_all(struct vmw_private *dev_priv); |
| 799 | 799 | extern void vmw_resource_unbind_list(struct vmw_buffer_object *vbo); |
| @@ -878,7 +878,7 @@ extern void vmw_bo_fence_single(struct ttm_buffer_object *bo, · 78 unmodified lines | ||
| 878 | 878 | extern void *vmw_bo_map_and_cache(struct vmw_buffer_object *vbo); |
| 879 | 879 | extern void vmw_bo_unmap(struct vmw_buffer_object *vbo); |
| 880 | 880 | extern void vmw_bo_move_notify(struct ttm_buffer_object *bo, |
| 881 | − struct ttm_mem_reg *mem); | |
| 881 | + struct ttm_resource *mem); | |
| 882 | 882 | extern void vmw_bo_swap_notify(struct ttm_buffer_object *bo); |
| 883 | 883 | extern struct vmw_buffer_object * |
| 884 | 884 | vmw_user_bo_noref_lookup(struct ttm_object_file *tfile, u32 handle); |
| @@ -1019,10 +1019,12 @@ extern struct ttm_placement vmw_mob_placement; · 134 unmodified lines | ||
| 1019 | 1019 | extern struct ttm_placement vmw_mob_ne_placement; |
| 1020 | 1020 | extern struct ttm_placement vmw_nonfixed_placement; |
| 1021 | 1021 | extern struct ttm_bo_driver vmw_bo_driver; |
| 1022 | −extern int vmw_bo_map_dma(struct ttm_buffer_object *bo); | |
| 1023 | −extern void vmw_bo_unmap_dma(struct ttm_buffer_object *bo); | |
| 1024 | 1022 | extern const struct vmw_sg_table * |
| 1025 | 1023 | vmw_bo_sg_table(struct ttm_buffer_object *bo); |
| 1024 | +extern int vmw_bo_create_and_populate(struct vmw_private *dev_priv, | |
| 1025 | + unsigned long bo_size, | |
| 1026 | + struct ttm_buffer_object **bo_p); | |
| 1027 | + | |
| 1026 | 1028 | extern void vmw_piter_start(struct vmw_piter *viter, |
| 1027 | 1029 | const struct vmw_sg_table *vsgt, |
| 1028 | 1030 | unsigned long p_offs); |
| @@ -1219,7 +1221,8 @@ int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv); · 190 unmodified lines | ||
| 1219 | 1221 | * GMR Id manager |
| 1220 | 1222 | */ |
| 1221 | 1223 | |
| 1222 | −extern const struct ttm_mem_type_manager_func vmw_gmrid_manager_func; | |
| 1224 | +int vmw_gmrid_man_init(struct vmw_private *dev_priv, int type); | |
| 1225 | +void vmw_gmrid_man_fini(struct vmw_private *dev_priv, int type); | |
| 1223 | 1226 | |
| 1224 | 1227 | /** |
| 1225 | 1228 | * Prime - vmwgfx_prime.c |
| @@ -1518,9 +1521,8 @@ vm_fault_t vmw_bo_vm_huge_fault(struct vm_fault *vmf, · 292 unmodified lines | ||
| 1518 | 1521 | |
| 1519 | 1522 | /* Transparent hugepage support - vmwgfx_thp.c */ |
| 1520 | 1523 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
| 1521 | −extern const struct ttm_mem_type_manager_func vmw_thp_func; | |
| 1522 | −#else | |
| 1523 | −#define vmw_thp_func ttm_bo_manager_func | |
| 1524 | +extern int vmw_thp_init(struct vmw_private *dev_priv); | |
| 1525 | +void vmw_thp_fini(struct vmw_private *dev_priv); | |
| 1524 | 1526 | #endif |
| 1525 | 1527 | |
| 1526 | 1528 | /** |
| @@ -37,6 +37,7 @@ · 36 unmodified lines | ||
| 37 | 37 | #include <linux/kernel.h> |
| 38 | 38 | |
| 39 | 39 | struct vmwgfx_gmrid_man { |
| 40 | + struct ttm_resource_manager manager; | |
| 40 | 41 | spinlock_t lock; |
| 41 | 42 | struct ida gmr_ida; |
| 42 | 43 | uint32_t max_gmr_ids; |
| @@ -44,13 +45,17 @@ struct vmwgfx_gmrid_man { · 1 unmodified line | ||
| 44 | 45 | uint32_t used_gmr_pages; |
| 45 | 46 | }; |
| 46 | 47 | |
| 47 | −static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man, | |
| 48 | +static struct vmwgfx_gmrid_man *to_gmrid_manager(struct ttm_resource_manager *man) | |
| 49 | +{ | |
| 50 | + return container_of(man, struct vmwgfx_gmrid_man, manager); | |
| 51 | +} | |
| 52 | + | |
| 53 | +static int vmw_gmrid_man_get_node(struct ttm_resource_manager *man, | |
| 48 | 54 | struct ttm_buffer_object *bo, |
| 49 | 55 | const struct ttm_place *place, |
| 50 | − struct ttm_mem_reg *mem) | |
| 56 | + struct ttm_resource *mem) | |
| 51 | 57 | { |
| 52 | − struct vmwgfx_gmrid_man *gman = | |
| 53 | − (struct vmwgfx_gmrid_man *)man->priv; | |
| 58 | + struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man); | |
| 54 | 59 | int id; |
| 55 | 60 | |
| 56 | 61 | id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL); |
| @@ -79,11 +84,10 @@ nospace: · 22 unmodified lines | ||
| 79 | 84 | return -ENOSPC; |
| 80 | 85 | } |
| 81 | 86 | |
| 82 | −static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man, | |
| 83 | − struct ttm_mem_reg *mem) | |
| 87 | +static void vmw_gmrid_man_put_node(struct ttm_resource_manager *man, | |
| 88 | + struct ttm_resource *mem) | |
| 84 | 89 | { |
| 85 | − struct vmwgfx_gmrid_man *gman = | |
| 86 | − (struct vmwgfx_gmrid_man *)man->priv; | |
| 90 | + struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man); | |
| 87 | 91 | |
| 88 | 92 | if (mem->mm_node) { |
| 89 | 93 | ida_free(&gman->gmr_ida, mem->start); |
| @@ -94,22 +98,30 @@ static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man, · 4 unmodified lines | ||
| 94 | 98 | } |
| 95 | 99 | } |
| 96 | 100 | |
| 97 | −static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man, | |
| 98 | − unsigned long p_size) | |
| 101 | +static const struct ttm_resource_manager_func vmw_gmrid_manager_func; | |
| 102 | + | |
| 103 | +int vmw_gmrid_man_init(struct vmw_private *dev_priv, int type) | |
| 99 | 104 | { |
| 100 | − struct vmw_private *dev_priv = | |
| 101 | − container_of(man->bdev, struct vmw_private, bdev); | |
| 105 | + struct ttm_resource_manager *man; | |
| 102 | 106 | struct vmwgfx_gmrid_man *gman = |
| 103 | 107 | kzalloc(sizeof(*gman), GFP_KERNEL); |
| 104 | 108 | |
| 105 | 109 | if (unlikely(!gman)) |
| 106 | 110 | return -ENOMEM; |
| 107 | 111 | |
| 112 | + man = &gman->manager; | |
| 113 | + | |
| 114 | + man->func = &vmw_gmrid_manager_func; | |
| 115 | + man->available_caching = TTM_PL_FLAG_CACHED; | |
| 116 | + man->default_caching = TTM_PL_FLAG_CACHED; | |
| 117 | + /* TODO: This is most likely not correct */ | |
| 118 | + man->use_tt = true; | |
| 119 | + ttm_resource_manager_init(man, 0); | |
| 108 | 120 | spin_lock_init(&gman->lock); |
| 109 | 121 | gman->used_gmr_pages = 0; |
| 110 | 122 | ida_init(&gman->gmr_ida); |
| 111 | 123 | |
| 112 | − switch (p_size) { | |
| 124 | + switch (type) { | |
| 113 | 125 | case VMW_PL_GMR: |
| 114 | 126 | gman->max_gmr_ids = dev_priv->max_gmr_ids; |
| 115 | 127 | gman->max_gmr_pages = dev_priv->max_gmr_pages; |
| @@ -121,32 +133,29 @@ static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man, · 5 unmodified lines | ||
| 121 | 133 | default: |
| 122 | 134 | BUG(); |
| 123 | 135 | } |
| 124 | − man->priv = (void *) gman; | |
| 136 | + ttm_set_driver_manager(&dev_priv->bdev, type, &gman->manager); | |
| 137 | + ttm_resource_manager_set_used(man, true); | |
| 125 | 138 | return 0; |
| 126 | 139 | } |
| 127 | 140 | |
| 128 | −static int vmw_gmrid_man_takedown(struct ttm_mem_type_manager *man) | |
| 141 | +void vmw_gmrid_man_fini(struct vmw_private *dev_priv, int type) | |
| 129 | 142 | { |
| 130 | − struct vmwgfx_gmrid_man *gman = | |
| 131 | − (struct vmwgfx_gmrid_man *)man->priv; | |
| 143 | + struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, type); | |
| 144 | + struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man); | |
| 132 | 145 | |
| 133 | − if (gman) { | |
| 134 | − ida_destroy(&gman->gmr_ida); | |
| 135 | − kfree(gman); | |
| 136 | − } | |
| 137 | − return 0; | |
| 138 | −} | |
| 146 | + ttm_resource_manager_set_used(man, false); | |
| 147 | + | |
| 148 | + ttm_resource_manager_force_list_clean(&dev_priv->bdev, man); | |
| 149 | + | |
| 150 | + ttm_resource_manager_cleanup(man); | |
| 151 | + | |
| 152 | + ttm_set_driver_manager(&dev_priv->bdev, type, NULL); | |
| 153 | + ida_destroy(&gman->gmr_ida); | |
| 154 | + kfree(gman); | |
| 139 | 155 | |
| 140 | −static void vmw_gmrid_man_debug(struct ttm_mem_type_manager *man, | |
| 141 | − struct drm_printer *printer) | |
| 142 | −{ | |
| 143 | − drm_printf(printer, "No debug info available for the GMR id manager\n"); | |
| 144 | 156 | } |
| 145 | 157 | |
| 146 | −const struct ttm_mem_type_manager_func vmw_gmrid_manager_func = { | |
| 147 | − .init = vmw_gmrid_man_init, | |
| 148 | − .takedown = vmw_gmrid_man_takedown, | |
| 149 | − .get_node = vmw_gmrid_man_get_node, | |
| 150 | − .put_node = vmw_gmrid_man_put_node, | |
| 151 | − .debug = vmw_gmrid_man_debug | |
| 158 | +static const struct ttm_resource_manager_func vmw_gmrid_manager_func = { | |
| 159 | + .alloc = vmw_gmrid_man_get_node, | |
| 160 | + .free = vmw_gmrid_man_put_node, | |
| 152 | 161 | }; |
| @@ -238,10 +238,6 @@ static int vmw_otable_batch_setup(struct vmw_private *dev_priv, · 237 unmodified lines | ||
| 238 | 238 | unsigned long offset; |
| 239 | 239 | unsigned long bo_size; |
| 240 | 240 | struct vmw_otable *otables = batch->otables; |
| 241 | − struct ttm_operation_ctx ctx = { | |
| 242 | − .interruptible = false, | |
| 243 | − .no_wait_gpu = false | |
| 244 | − }; | |
| 245 | 241 | SVGAOTableType i; |
| 246 | 242 | int ret; |
| 247 | 243 | |
| @@ -255,24 +251,9 @@ static int vmw_otable_batch_setup(struct vmw_private *dev_priv, · 7 unmodified lines | ||
| 255 | 251 | bo_size += otables[i].size; |
| 256 | 252 | } |
| 257 | 253 | |
| 258 | − ret = ttm_bo_create(&dev_priv->bdev, bo_size, | |
| 259 | − ttm_bo_type_device, | |
| 260 | − &vmw_sys_ne_placement, | |
| 261 | − 0, false, &batch->otable_bo); | |
| 262 | − | |
| 263 | − if (unlikely(ret != 0)) | |
| 264 | − goto out_no_bo; | |
| 265 | − | |
75 more lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 177 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 89 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 155 lines aren’t shown here.
This diff is large: its 547 lines aren’t shown here.
This diff is large: its 262 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.