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 | compatible: | 13 | compatible: |
| 14 | items: | 14 | items: |
| 15 | - enum: | 15 | - enum: |
| 16 | - bananapi,lhr050h41 | 16 | - bananapi,lhr050h41 |
| 17 | - feixin,k101-im2byl02 | ||
| 18 | |||
| 17 | - const: ilitek,ili9881c | 19 | - const: ilitek,ili9881c |
| 18 | 20 | ||
| 19 | backlight: true | 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 | - cdtech,s070swv29hg-dc44 | 87 | - cdtech,s070swv29hg-dc44 |
| 88 | # CDTech(H.K.) Electronics Limited 7" 800x480 color TFT-LCD panel | 88 | # CDTech(H.K.) Electronics Limited 7" 800x480 color TFT-LCD panel |
| 89 | - cdtech,s070wv95-ct16 | 89 | - cdtech,s070wv95-ct16 |
| 90 | # Chefree CH101OLHLWH-002 10.1" (1280x800) color TFT LCD panel | ||
| 91 | - chefree,ch101olhlwh-002 | ||
| 90 | # Chunghwa Picture Tubes Ltd. 7" WXGA TFT LCD panel | 92 | # Chunghwa Picture Tubes Ltd. 7" WXGA TFT LCD panel |
| 91 | - chunghwa,claa070wp03xg | 93 | - chunghwa,claa070wp03xg |
| 92 | # Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel | 94 | # Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel |
| @@ -159,6 +161,8 @@ properties: · 66 unmodified lines | |||
| 159 | - innolux,n156bge-l21 | 161 | - innolux,n156bge-l21 |
| 160 | # Innolux Corporation 7.0" WSVGA (1024x600) TFT LCD panel | 162 | # Innolux Corporation 7.0" WSVGA (1024x600) TFT LCD panel |
| 161 | - innolux,zj070na-01p | 163 | - innolux,zj070na-01p |
| 164 | # King & Display KD116N21-30NV-A010 eDP TFT LCD panel | ||
| 165 | - kingdisplay,kd116n21-30nv-a010 | ||
| 162 | # Kaohsiung Opto-Electronics Inc. 5.7" QVGA (320 x 240) TFT LCD panel | 166 | # Kaohsiung Opto-Electronics Inc. 5.7" QVGA (320 x 240) TFT LCD panel |
| 163 | - koe,tx14d24vm1bpa | 167 | - koe,tx14d24vm1bpa |
| 164 | # Kaohsiung Opto-Electronics Inc. 10.1" WUXGA (1920 x 1200) LVDS TFT LCD panel | 168 | # Kaohsiung Opto-Electronics Inc. 10.1" WUXGA (1920 x 1200) LVDS TFT LCD panel |
| @@ -219,6 +223,8 @@ properties: · 54 unmodified lines | |||
| 219 | - osddisplays,osd070t1718-19ts | 223 | - osddisplays,osd070t1718-19ts |
| 220 | # One Stop Displays OSD101T2045-53TS 10.1" 1920x1200 panel | 224 | # One Stop Displays OSD101T2045-53TS 10.1" 1920x1200 panel |
| 221 | - osddisplays,osd101t2045-53ts | 225 | - osddisplays,osd101t2045-53ts |
| 226 | # POWERTIP PH800480T013-IDF2 7.0" WVGA TFT LCD panel | ||
| 227 | - powertip,ph800480t013-idf02 | ||
| 222 | # QiaoDian XianShi Corporation 4"3 TFT LCD panel | 228 | # QiaoDian XianShi Corporation 4"3 TFT LCD panel |
| 223 | - qiaodian,qd43003c0-40 | 229 | - qiaodian,qd43003c0-40 |
| 224 | # Rocktech Displays Ltd. RK101II01D-CT 10.1" TFT 1280x800 | 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 | maintainers: | 9 | maintainers: |
| 10 | - Ondrej Jirman <megi@xff.cz> | 10 | - Ondrej Jirman <megi@xff.cz> |
| 11 | - Guido Gŭnther <agx@sigxcpu.org> | ||
| 11 | 12 | ||
| 12 | description: | | 13 | description: |
| 13 | Rocktech JH057N00900 is a 720x1440 TFT LCD panel | 14 | Rocktech JH057N00900 is a 720x1440 TFT LCD panel |
| 14 | connected using a MIPI-DSI video interface. | 15 | connected using a MIPI-DSI video interface. |
| 15 | 16 | ||
| 16 | allOf: | 17 | allOf: |
| 17 | - $ref: panel-common.yaml# | 18 | - $ref: panel-common.yaml# |
| @@ -19,9 +20,9 @@ allOf: · 1 unmodified line | |||
| 19 | properties: | 20 | properties: |
| 20 | compatible: | 21 | compatible: |
| 21 | enum: | 22 | enum: |
| 22 | # Rocktech JH057N00900 5.5" 720x1440 TFT LCD panel | 23 | # Rocktech JH057N00900 5.5" 720x1440 TFT LCD panel |
| 23 | - rocktech,jh057n00900 | 24 | - rocktech,jh057n00900 |
| 24 | # Xingbangda XBD599 5.99" 720x1440 TFT LCD panel | 25 | # Xingbangda XBD599 5.99" 720x1440 TFT LCD panel |
| 25 | - xingbangda,xbd599 | 26 | - xingbangda,xbd599 |
| 26 | 27 | ||
| 27 | port: true | 28 | port: true |
| @@ -35,13 +36,9 @@ properties: · 7 unmodified lines | |||
| 35 | iovcc-supply: | 36 | iovcc-supply: |
| 36 | description: I/O voltage supply | 37 | description: I/O voltage supply |
| 37 | 38 | ||
| 38 | reset-gpios: | 39 | reset-gpios: true |
| 39 | description: GPIO used for the reset pin | ||
| 40 | maxItems: 1 | ||
| 41 | 40 | ||
| 42 | backlight: | 41 | backlight: true |
| 43 | description: Backlight used by the panel | ||
| 44 | $ref: "/schemas/types.yaml#/definitions/phandle" | ||
| 45 | 42 | ||
| 46 | required: | 43 | required: |
| 47 | - compatible | 44 | - compatible |
| @@ -57,15 +54,16 @@ examples: · 9 unmodified lines | |||
| 57 | #include <dt-bindings/gpio/gpio.h> | 54 | #include <dt-bindings/gpio/gpio.h> |
| 58 | 55 | ||
| 59 | dsi { | 56 | dsi { |
| 60 | #address-cells = <1>; | 57 | #address-cells = <1>; |
| 61 | #size-cells = <0>; | 58 | #size-cells = <0>; |
| 62 | panel@0 { | 59 | panel@0 { |
| 63 | compatible = "rocktech,jh057n00900"; | 60 | compatible = "rocktech,jh057n00900"; |
| 64 | reg = <0>; | 61 | reg = <0>; |
| 65 | vcc-supply = <®_2v8_p>; | 62 | vcc-supply = <®_2v8_p>; |
| 66 | iovcc-supply = <®_1v8_p>; | 63 | iovcc-supply = <®_1v8_p>; |
| 67 | reset-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>; | 64 | reset-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>; |
| 68 | backlight = <&backlight>; | 65 | backlight = <&backlight>; |
| 69 | }; | 66 | }; |
| 70 | }; | 67 | }; |
| 68 | |||
| 71 | ... | 69 | ... |
| @@ -197,6 +197,8 @@ patternProperties: · 196 unmodified lines | |||
| 197 | description: Ceva, Inc. | 197 | description: Ceva, Inc. |
| 198 | "^checkpoint,.*": | 198 | "^checkpoint,.*": |
| 199 | description: Check Point Software Technologies Ltd. | 199 | description: Check Point Software Technologies Ltd. |
| 200 | "^chefree,.*": | ||
| 201 | description: Chefree Technology Corp. | ||
| 200 | "^chipidea,.*": | 202 | "^chipidea,.*": |
| 201 | description: Chipidea, Inc | 203 | description: Chipidea, Inc |
| 202 | "^chipone,.*": | 204 | "^chipone,.*": |
| @@ -601,6 +603,8 @@ patternProperties: · 398 unmodified lines | |||
| 601 | description: Logic Technologies Limited | 603 | description: Logic Technologies Limited |
| 602 | "^longcheer,.*": | 604 | "^longcheer,.*": |
| 603 | description: Longcheer Technology (Shanghai) Co., Ltd. | 605 | description: Longcheer Technology (Shanghai) Co., Ltd. |
| 606 | "^lontium,.*": | ||
| 607 | description: Lontium Semiconductor Corporation | ||
| 604 | "^loongson,.*": | 608 | "^loongson,.*": |
| 605 | description: Loongson Technology Corporation Limited | 609 | description: Loongson Technology Corporation Limited |
| 606 | "^lsi,.*": | 610 | "^lsi,.*": |
| @@ -611,6 +615,8 @@ patternProperties: · 4 unmodified lines | |||
| 611 | description: Linux Automation GmbH | 615 | description: Linux Automation GmbH |
| 612 | "^macnica,.*": | 616 | "^macnica,.*": |
| 613 | description: Macnica Americas | 617 | description: Macnica Americas |
| 618 | "^mantix,.*": | ||
| 619 | description: Mantix Display Technology Co.,Ltd. | ||
| 614 | "^mapleboard,.*": | 620 | "^mapleboard,.*": |
| 615 | description: Mapleboard.org | 621 | description: Mapleboard.org |
| 616 | "^marvell,.*": | 622 | "^marvell,.*": |
| @@ -830,6 +836,8 @@ patternProperties: · 213 unmodified lines | |||
| 830 | description: Poslab Technology Co., Ltd. | 836 | description: Poslab Technology Co., Ltd. |
| 831 | "^pov,.*": | 837 | "^pov,.*": |
| 832 | description: Point of View International B.V. | 838 | description: Point of View International B.V. |
| 839 | "^powertip,.*": | ||
| 840 | description: Powertip Tech. Corp. | ||
| 833 | "^powervr,.*": | 841 | "^powervr,.*": |
| 834 | description: PowerVR (deprecated, use img) | 842 | description: PowerVR (deprecated, use img) |
| 835 | "^primux,.*": | 843 | "^primux,.*": |
| @@ -1,3 +1,5 @@ | |||
| 1 | .. Copyright 2020 DisplayLink (UK) Ltd. | ||
| 2 | |||
| 1 | =================== | 3 | =================== |
| 2 | Userland interfaces | 4 | Userland interfaces |
| 3 | =================== | 5 | =================== |
| @@ -162,6 +164,116 @@ other hand, a driver requires shared state between clients which is · 158 unmodified lines | |||
| 162 | visible to user-space and accessible beyond open-file boundaries, they | 164 | visible to user-space and accessible beyond open-file boundaries, they |
| 163 | cannot support render nodes. | 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 | .. _drm_driver_ioctl: | 277 | .. _drm_driver_ioctl: |
| 166 | 278 | ||
| 167 | IOCTL Support on Device Nodes | 279 | IOCTL Support on Device Nodes |
| @@ -199,7 +311,7 @@ EPERM/EACCES: · 31 unmodified lines | |||
| 199 | difference between EACCES and EPERM. | 311 | difference between EACCES and EPERM. |
| 200 | 312 | ||
| 201 | ENODEV: | 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 | EOPNOTSUPP: | 316 | EOPNOTSUPP: |
| 205 | Feature (like PRIME, modesetting, GEM) is not supported by the driver. | 317 | Feature (like PRIME, modesetting, GEM) is not supported by the driver. |
| @@ -1,6 +1,6 @@ | |||
| 1 | ========================================== | 1 | ==================================================== |
| 2 | drm/pl111 ARM PrimeCell PL111 CLCD Driver | 2 | drm/pl111 ARM PrimeCell PL110 and PL111 CLCD Driver |
| 3 | ========================================== | 3 | ==================================================== |
| 4 | 4 | ||
| 5 | .. kernel-doc:: drivers/gpu/drm/pl111/pl111_drv.c | 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 | Level: Intermediate | 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 | Core refactorings | 453 | Core refactorings |
| 408 | ================= | 454 | ================= |
| @@ -5474,12 +5474,19 @@ S: Maintained · 5473 unmodified lines | |||
| 5474 | F: drivers/gpu/drm/panel/panel-lvds.c | 5474 | F: drivers/gpu/drm/panel/panel-lvds.c |
| 5475 | F: Documentation/devicetree/bindings/display/panel/lvds.yaml | 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 | DRM DRIVER FOR MATROX G200/G400 GRAPHICS CARDS | 5484 | DRM DRIVER FOR MATROX G200/G400 GRAPHICS CARDS |
| 5478 | S: Orphan / Obsolete | 5485 | S: Orphan / Obsolete |
| 5479 | F: drivers/gpu/drm/mga/ | 5486 | F: drivers/gpu/drm/mga/ |
| 5480 | F: include/uapi/drm/mga_drm.h | 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 | M: Dave Airlie <airlied@redhat.com> | 5490 | M: Dave Airlie <airlied@redhat.com> |
| 5484 | S: Odd Fixes | 5491 | S: Odd Fixes |
| 5485 | F: drivers/gpu/drm/mgag200/ | 5492 | F: drivers/gpu/drm/mgag200/ |
| @@ -5767,7 +5774,7 @@ F: drivers/gpu/drm/gma500/ · 281 unmodified lines | |||
| 5767 | 5774 | ||
| 5768 | DRM DRIVERS FOR HISILICON | 5775 | DRM DRIVERS FOR HISILICON |
| 5769 | M: Xinliang Liu <xinliang.liu@linaro.org> | 5776 | M: Xinliang Liu <xinliang.liu@linaro.org> |
| 5770 | M: Rongrong Zou <zourongrong@gmail.com> | 5777 | M: Tian Tao <tiantao6@hisilicon.com> |
| 5771 | R: John Stultz <john.stultz@linaro.org> | 5778 | R: John Stultz <john.stultz@linaro.org> |
| 5772 | R: Xinwei Kong <kong.kongxinwei@hisilicon.com> | 5779 | R: Xinwei Kong <kong.kongxinwei@hisilicon.com> |
| 5773 | R: Chen Feng <puck.chen@hisilicon.com> | 5780 | R: Chen Feng <puck.chen@hisilicon.com> |
| @@ -517,8 +517,9 @@ out_put: · 516 unmodified lines | |||
| 517 | uint64_t amdgpu_amdkfd_get_vram_usage(struct kgd_dev *kgd) | 517 | uint64_t amdgpu_amdkfd_get_vram_usage(struct kgd_dev *kgd) |
| 518 | { | 518 | { |
| 519 | struct amdgpu_device *adev = (struct amdgpu_device *)kgd; | 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 | uint64_t amdgpu_amdkfd_get_hive_id(struct kgd_dev *kgd) | 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 | mutex_lock(&process_info->lock); | 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 | if (ret) { | 566 | if (ret) { |
| 567 | pr_err("%s: Failed to set userptr: %d\n", __func__, ret); | 567 | pr_err("%s: Failed to set userptr: %d\n", __func__, ret); |
| 568 | goto out; | 568 | goto out; |
| @@ -26,6 +26,7 @@ · 25 unmodified lines | |||
| 26 | 26 | ||
| 27 | #include <drm/drm_edid.h> | 27 | #include <drm/drm_edid.h> |
| 28 | #include <drm/drm_fb_helper.h> | 28 | #include <drm/drm_fb_helper.h> |
| 29 | #include <drm/drm_dp_helper.h> | ||
| 29 | #include <drm/drm_probe_helper.h> | 30 | #include <drm/drm_probe_helper.h> |
| 30 | #include <drm/amdgpu_drm.h> | 31 | #include <drm/amdgpu_drm.h> |
| 31 | #include "amdgpu.h" | 32 | #include "amdgpu.h" |
| @@ -1413,6 +1414,10 @@ out: · 1381 unmodified lines | |||
| 1413 | pm_runtime_put_autosuspend(connector->dev->dev); | 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 | return ret; | 1421 | return ret; |
| 1417 | } | 1422 | } |
| 1418 | 1423 | ||
| @@ -1959,6 +1964,11 @@ amdgpu_connector_add(struct amdgpu_device *adev, · 540 unmodified lines | |||
| 1959 | if (has_aux) | 1964 | if (has_aux) |
| 1960 | amdgpu_atombios_dp_aux_init(amdgpu_connector); | 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 | return; | 1972 | return; |
| 1963 | 1973 | ||
| 1964 | failed: | 1974 | failed: |
| @@ -299,7 +299,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev, · 298 unmodified lines | |||
| 299 | { | 299 | { |
| 300 | s64 time_us, increment_us; | 300 | s64 time_us, increment_us; |
| 301 | u64 free_vram, total_vram, used_vram; | 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 | /* Allow a maximum of 200 accumulated ms. This is basically per-IB | 303 | /* Allow a maximum of 200 accumulated ms. This is basically per-IB |
| 304 | * throttling. | 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 | total_vram = adev->gmc.real_vram_size - atomic64_read(&adev->vram_pin_size); | 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 | free_vram = used_vram >= total_vram ? 0 : total_vram - used_vram; | 320 | free_vram = used_vram >= total_vram ? 0 : total_vram - used_vram; |
| 321 | 321 | ||
| 322 | spin_lock(&adev->mm_stats.lock); | 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 | if (!amdgpu_gmc_vram_full_visible(&adev->gmc)) { | 363 | if (!amdgpu_gmc_vram_full_visible(&adev->gmc)) { |
| 364 | u64 total_vis_vram = adev->gmc.visible_vram_size; | 364 | u64 total_vis_vram = adev->gmc.visible_vram_size; |
| 365 | u64 used_vis_vram = | 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 | if (used_vis_vram < total_vis_vram) { | 368 | if (used_vis_vram < total_vis_vram) { |
| 369 | u64 free_vis_vram = total_vis_vram - used_vis_vram; | 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 | amdgpu_virt_init_data_exchange(adev); | 3883 | amdgpu_virt_init_data_exchange(adev); |
| 3884 | /* we need recover gart prior to run SMC/CP/SDMA resume */ | 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 | r = amdgpu_device_fw_loading(adev); | 3887 | r = amdgpu_device_fw_loading(adev); |
| 3888 | if (r) | 3888 | if (r) |
| @@ -4081,8 +4081,7 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, · 192 unmodified lines | |||
| 4081 | amdgpu_inc_vram_lost(tmp_adev); | 4081 | amdgpu_inc_vram_lost(tmp_adev); |
| 4082 | } | 4082 | } |
| 4083 | 4083 | ||
| 4084 | r = amdgpu_gtt_mgr_recover( | 4084 | r = amdgpu_gtt_mgr_recover(ttm_manager_type(&tmp_adev->mman.bdev, TTM_PL_TT)); |
| 4085 | &tmp_adev->mman.bdev.man[TTM_PL_TT]); | ||
| 4086 | if (r) | 4085 | if (r) |
| 4087 | goto out; | 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 | module_param_named(sched_hw_submission, amdgpu_sched_hw_submission, int, 0444); | 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 | * Override power features enabled. See enum PP_FEATURE_MASK in drivers/gpu/drm/amd/include/amd_shared.h. | 397 | * Override power features enabled. See enum PP_FEATURE_MASK in drivers/gpu/drm/amd/include/amd_shared.h. |
| 398 | * The default is the current set of stable power features. | 398 | * The default is the current set of stable power features. |
| 399 | */ | 399 | */ |
| 400 | MODULE_PARM_DESC(ppfeaturemask, "all power features enabled (default))"); | 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 | * DOC: forcelongtraining (uint) | 404 | * DOC: forcelongtraining (uint) |
| @@ -332,7 +332,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data, · 331 unmodified lines | |||
| 332 | bo = gem_to_amdgpu_bo(gobj); | 332 | bo = gem_to_amdgpu_bo(gobj); |
| 333 | bo->preferred_domains = AMDGPU_GEM_DOMAIN_GTT; | 333 | bo->preferred_domains = AMDGPU_GEM_DOMAIN_GTT; |
| 334 | bo->allowed_domains = AMDGPU_GEM_DOMAIN_GTT; | 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 | if (r) | 336 | if (r) |
| 337 | goto release_object; | 337 | goto release_object; |
| 338 | 338 | ||
| @@ -24,11 +24,10 @@ · 23 unmodified lines | |||
| 24 | 24 | ||
| 25 | #include "amdgpu.h" | 25 | #include "amdgpu.h" |
| 26 | 26 | ||
| 27 | struct amdgpu_gtt_mgr { | 27 | static inline struct amdgpu_gtt_mgr *to_gtt_mgr(struct ttm_resource_manager *man) |
| 28 | struct drm_mm mm; | 28 | { |
| 29 | spinlock_t lock; | 29 | return container_of(man, struct amdgpu_gtt_mgr, manager); |
| 30 | atomic64_t available; | 30 | } |
| 31 | }; | ||
| 32 | 31 | ||
| 33 | struct amdgpu_gtt_node { | 32 | struct amdgpu_gtt_node { |
| 34 | struct drm_mm_node node; | 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 | struct drm_device *ddev = dev_get_drvdata(dev); | 48 | struct drm_device *ddev = dev_get_drvdata(dev); |
| 50 | struct amdgpu_device *adev = ddev->dev_private; | 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 | return snprintf(buf, PAGE_SIZE, "%llu\n", | 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 | struct drm_device *ddev = dev_get_drvdata(dev); | 66 | struct drm_device *ddev = dev_get_drvdata(dev); |
| 68 | struct amdgpu_device *adev = ddev->dev_private; | 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 | return snprintf(buf, PAGE_SIZE, "%llu\n", | 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 | static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO, | 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 | static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO, | 75 | static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO, |
| 77 | amdgpu_mem_info_gtt_used_show, NULL); | 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 | * amdgpu_gtt_mgr_init - init GTT manager and DRM MM | 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 | * Allocate and initialize the GTT manager. | 85 | * Allocate and initialize the GTT manager. |
| 86 | */ | 86 | */ |
| 87 | static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man, | 87 | int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size) |
| 88 | unsigned long p_size) | ||
| 89 | { | 88 | { |
| 90 | struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); | 89 | struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr; |
| 91 | struct amdgpu_gtt_mgr *mgr; | 90 | struct ttm_resource_manager *man = &mgr->manager; |
| 92 | uint64_t start, size; | 91 | uint64_t start, size; |
| 93 | int ret; | 92 | int ret; |
| 94 | 93 | ||
| 95 | mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); | 94 | man->use_tt = true; |
| 96 | if (!mgr) | 95 | man->func = &amdgpu_gtt_mgr_func; |
| 97 | return -ENOMEM; | 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 | start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS; | 101 | start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS; |
| 100 | size = (adev->gmc.gart_size >> PAGE_SHIFT) - start; | 102 | size = (adev->gmc.gart_size >> PAGE_SHIFT) - start; |
| 101 | drm_mm_init(&mgr->mm, start, size); | 103 | drm_mm_init(&mgr->mm, start, size); |
| 102 | spin_lock_init(&mgr->lock); | 104 | spin_lock_init(&mgr->lock); |
| 103 | atomic64_set(&mgr->available, p_size); | 105 | atomic64_set(&mgr->available, gtt_size >> PAGE_SHIFT); |
| 104 | man->priv = mgr; | ||
| 105 | 106 | ||
| 106 | ret = device_create_file(adev->dev, &dev_attr_mem_info_gtt_total); | 107 | ret = device_create_file(adev->dev, &dev_attr_mem_info_gtt_total); |
| 107 | if (ret) { | 108 | if (ret) { |
| @@ -114,6 +115,8 @@ static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man, · 6 unmodified lines | |||
| 114 | return ret; | 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 | return 0; | 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 | * Destroy and free the GTT manager, returns -EBUSY if ranges are still | 128 | * Destroy and free the GTT manager, returns -EBUSY if ranges are still |
| 126 | * allocated inside it. | 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); | 133 | struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr; |
| 131 | struct amdgpu_gtt_mgr *mgr = man->priv; | 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 | spin_lock(&mgr->lock); | 143 | spin_lock(&mgr->lock); |
| 133 | drm_mm_takedown(&mgr->mm); | 144 | drm_mm_takedown(&mgr->mm); |
| 134 | spin_unlock(&mgr->lock); | 145 | spin_unlock(&mgr->lock); |
| 135 | kfree(mgr); | ||
| 136 | man->priv = NULL; | ||
| 137 | 146 | ||
| 138 | device_remove_file(adev->dev, &dev_attr_mem_info_gtt_total); | 147 | device_remove_file(adev->dev, &dev_attr_mem_info_gtt_total); |
| 139 | device_remove_file(adev->dev, &dev_attr_mem_info_gtt_used); | 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 | * Check if a mem object has already address space allocated. | 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 | return mem->mm_node != NULL; | 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 | * Dummy, allocate the node but no space for it yet. | 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 | struct ttm_buffer_object *tbo, | 177 | struct ttm_buffer_object *tbo, |
| 168 | const struct ttm_place *place, | 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 | struct amdgpu_gtt_node *node; | 182 | struct amdgpu_gtt_node *node; |
| 173 | int r; | 183 | int r; |
| 174 | 184 | ||
| @@ -226,10 +236,10 @@ err_out: · 51 unmodified lines | |||
| 226 | * | 236 | * |
| 227 | * Free the allocated GTT again. | 237 | * Free the allocated GTT again. |
| 228 | */ | 238 | */ |
| 229 | static void amdgpu_gtt_mgr_del(struct ttm_mem_type_manager *man, | 239 | static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man, |
| 230 | struct ttm_mem_reg *mem) | 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 | struct amdgpu_gtt_node *node = mem->mm_node; | 243 | struct amdgpu_gtt_node *node = mem->mm_node; |
| 234 | 244 | ||
| 235 | if (node) { | 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 | * Return how many bytes are used in the GTT domain | 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 | s64 result = man->size - atomic64_read(&mgr->available); | 265 | s64 result = man->size - atomic64_read(&mgr->available); |
| 256 | 266 | ||
| 257 | return (result > 0 ? result : 0) * PAGE_SIZE; | 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 | struct amdgpu_gtt_node *node; | 273 | struct amdgpu_gtt_node *node; |
| 264 | struct drm_mm_node *mm_node; | 274 | struct drm_mm_node *mm_node; |
| 265 | int r = 0; | 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 | * Dump the table content using printk. | 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 | struct drm_printer *printer) | 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 | spin_lock(&mgr->lock); | 302 | spin_lock(&mgr->lock); |
| 293 | drm_mm_print(&mgr->mm, printer); | 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 | amdgpu_gtt_mgr_usage(man) >> 20); | 308 | amdgpu_gtt_mgr_usage(man) >> 20); |
| 299 | } | 309 | } |
| 300 | 310 | ||
| 301 | const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func = { | 311 | static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func = { |
| 302 | .init = amdgpu_gtt_mgr_init, | 312 | .alloc = amdgpu_gtt_mgr_new, |
| 303 | .takedown = amdgpu_gtt_mgr_fini, | 313 | .free = amdgpu_gtt_mgr_del, |
| 304 | .get_node = amdgpu_gtt_mgr_new, | ||
| 305 | .put_node = amdgpu_gtt_mgr_del, | ||
| 306 | .debug = amdgpu_gtt_mgr_debug | 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 | ui64 = atomic64_read(&adev->num_vram_cpu_page_faults); | 594 | ui64 = atomic64_read(&adev->num_vram_cpu_page_faults); |
| 595 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; | 595 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; |
| 596 | case AMDGPU_INFO_VRAM_USAGE: | 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 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; | 598 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; |
| 599 | case AMDGPU_INFO_VIS_VRAM_USAGE: | 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 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; | 601 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; |
| 602 | case AMDGPU_INFO_GTT_USAGE: | 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 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; | 604 | return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; |
| 605 | case AMDGPU_INFO_GDS_CONFIG: { | 605 | case AMDGPU_INFO_GDS_CONFIG: { |
| 606 | struct drm_amdgpu_info_gds gds_info; | 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 | min(adev->gmc.visible_vram_size - | 623 | min(adev->gmc.visible_vram_size - |
| 624 | atomic64_read(&adev->visible_pin_size), | 624 | atomic64_read(&adev->visible_pin_size), |
| 625 | vram_gtt.vram_size); | 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 | vram_gtt.gtt_size *= PAGE_SIZE; | 627 | vram_gtt.gtt_size *= PAGE_SIZE; |
| 628 | vram_gtt.gtt_size -= atomic64_read(&adev->gart_pin_size); | 628 | vram_gtt.gtt_size -= atomic64_read(&adev->gart_pin_size); |
| 629 | return copy_to_user(out, &vram_gtt, | 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 | case AMDGPU_INFO_MEMORY: { | 632 | case AMDGPU_INFO_MEMORY: { |
| 633 | struct drm_amdgpu_memory_info mem; | 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 | memset(&mem, 0, sizeof(mem)); | 638 | memset(&mem, 0, sizeof(mem)); |
| 636 | mem.vram.total_heap_size = adev->gmc.real_vram_size; | 639 | mem.vram.total_heap_size = adev->gmc.real_vram_size; |
| 637 | mem.vram.usable_heap_size = adev->gmc.real_vram_size - | 640 | mem.vram.usable_heap_size = adev->gmc.real_vram_size - |
| 638 | atomic64_read(&adev->vram_pin_size) - | 641 | atomic64_read(&adev->vram_pin_size) - |
| 639 | AMDGPU_VM_RESERVED_VRAM; | 642 | AMDGPU_VM_RESERVED_VRAM; |
| 640 | mem.vram.heap_usage = | 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 | mem.vram.max_allocation = mem.vram.usable_heap_size * 3 / 4; | 645 | mem.vram.max_allocation = mem.vram.usable_heap_size * 3 / 4; |
| 643 | 646 | ||
| 644 | mem.cpu_accessible_vram.total_heap_size = | 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 | atomic64_read(&adev->visible_pin_size), | 651 | atomic64_read(&adev->visible_pin_size), |
| 649 | mem.vram.usable_heap_size); | 652 | mem.vram.usable_heap_size); |
| 650 | mem.cpu_accessible_vram.heap_usage = | 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 | mem.cpu_accessible_vram.max_allocation = | 655 | mem.cpu_accessible_vram.max_allocation = |
| 653 | mem.cpu_accessible_vram.usable_heap_size * 3 / 4; | 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 | mem.gtt.total_heap_size *= PAGE_SIZE; | 659 | mem.gtt.total_heap_size *= PAGE_SIZE; |
| 657 | mem.gtt.usable_heap_size = mem.gtt.total_heap_size - | 660 | mem.gtt.usable_heap_size = mem.gtt.total_heap_size - |
| 658 | atomic64_read(&adev->gart_pin_size); | 661 | atomic64_read(&adev->gart_pin_size); |
| 659 | mem.gtt.heap_usage = | 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 | mem.gtt.max_allocation = mem.gtt.usable_heap_size * 3 / 4; | 664 | mem.gtt.max_allocation = mem.gtt.usable_heap_size * 3 / 4; |
| 662 | 665 | ||
| 663 | return copy_to_user(out, &mem, | 666 | return copy_to_user(out, &mem, |
| @@ -469,6 +469,7 @@ struct amdgpu_encoder { · 468 unmodified lines | |||
| 469 | struct amdgpu_connector_atom_dig { | 469 | struct amdgpu_connector_atom_dig { |
| 470 | /* displayport */ | 470 | /* displayport */ |
| 471 | u8 dpcd[DP_RECEIVER_CAP_SIZE]; | 471 | u8 dpcd[DP_RECEIVER_CAP_SIZE]; |
| 472 | u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; | ||
| 472 | u8 dp_sink_type; | 473 | u8 dp_sink_type; |
| 473 | int dp_clock; | 474 | int dp_clock; |
| 474 | int dp_lane_count; | 475 | int dp_lane_count; |
| @@ -381,7 +381,7 @@ int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev, · 380 unmodified lines | |||
| 381 | if (cpu_addr) | 381 | if (cpu_addr) |
| 382 | amdgpu_bo_kunmap(*bo_ptr); | 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 | for (i = 0; i < (*bo_ptr)->placement.num_placement; ++i) { | 386 | for (i = 0; i < (*bo_ptr)->placement.num_placement; ++i) { |
| 387 | (*bo_ptr)->placements[i].fpfn = offset >> PAGE_SHIFT; | 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 | static bool amdgpu_bo_validate_size(struct amdgpu_device *adev, | 442 | static bool amdgpu_bo_validate_size(struct amdgpu_device *adev, |
| 443 | unsigned long size, u32 domain) | 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 | * If GTT is part of requested domains the check must succeed to | 448 | * If GTT is part of requested domains the check must succeed to |
| 449 | * allow fall back to GTT | 449 | * allow fall back to GTT |
| 450 | */ | 450 | */ |
| 451 | if (domain & AMDGPU_GEM_DOMAIN_GTT) { | 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 | if (size < (man->size << PAGE_SHIFT)) | 454 | if (size < (man->size << PAGE_SHIFT)) |
| 455 | return true; | 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 | if (domain & AMDGPU_GEM_DOMAIN_VRAM) { | 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 | if (size < (man->size << PAGE_SHIFT)) | 463 | if (size < (man->size << PAGE_SHIFT)) |
| 464 | return true; | 464 | return true; |
| @@ -1268,11 +1268,11 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, · 803 unmodified lines | |||
| 1268 | */ | 1268 | */ |
| 1269 | void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, | 1269 | void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, |
| 1270 | bool evict, | 1270 | bool evict, |
| 1271 | struct ttm_mem_reg *new_mem) | 1271 | struct ttm_resource *new_mem) |
| 1272 | { | 1272 | { |
| 1273 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); | 1273 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); |
| 1274 | struct amdgpu_bo *abo; | 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 | if (!amdgpu_bo_is_amdgpu_bo(bo)) | 1277 | if (!amdgpu_bo_is_amdgpu_bo(bo)) |
| 1278 | return; | 1278 | return; |
| @@ -160,7 +160,7 @@ static inline int amdgpu_bo_reserve(struct amdgpu_bo *bo, bool no_intr) · 159 unmodified lines | |||
| 160 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); | 160 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); |
| 161 | int r; | 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 | if (unlikely(r != 0)) { | 164 | if (unlikely(r != 0)) { |
| 165 | if (r != -ERESTARTSYS) | 165 | if (r != -ERESTARTSYS) |
| 166 | dev_err(adev->dev, "%p reserve failed\n", bo); | 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 | uint64_t *flags); | 283 | uint64_t *flags); |
| 284 | void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, | 284 | void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, |
| 285 | bool evict, | 285 | bool evict, |
| 286 | struct ttm_mem_reg *new_mem); | 286 | struct ttm_resource *new_mem); |
| 287 | void amdgpu_bo_release_notify(struct ttm_buffer_object *bo); | 287 | void amdgpu_bo_release_notify(struct ttm_buffer_object *bo); |
| 288 | int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo); | 288 | int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo); |
| 289 | void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence, | 289 | void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence, |
| @@ -63,61 +63,13 @@ · 62 unmodified lines | |||
| 63 | 63 | ||
| 64 | #define AMDGPU_TTM_VRAM_MAX_DW_READ (size_t)128 | 64 | #define AMDGPU_TTM_VRAM_MAX_DW_READ (size_t)128 |
| 65 | 65 | ||
| 66 | 66 | static int amdgpu_ttm_init_on_chip(struct amdgpu_device *adev, | |
| 67 | /** | 67 | unsigned int type, |
| 68 | * amdgpu_init_mem_type - Initialize a memory manager for a specific type of | 68 | uint64_t size) |
| 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) | ||
| 80 | { | 69 | { |
| 81 | struct amdgpu_device *adev; | 70 | return ttm_range_man_init(&adev->mman.bdev, type, |
| 82 | 71 | TTM_PL_FLAG_UNCACHED, TTM_PL_FLAG_UNCACHED, | |
| 83 | adev = amdgpu_ttm_adev(bdev); | 72 | false, size >> PAGE_SHIFT); |
| 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; | ||
| 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 | * Assign the memory from new_mem to the memory of the buffer object bo. | 183 | * Assign the memory from new_mem to the memory of the buffer object bo. |
| 232 | */ | 184 | */ |
| 233 | static void amdgpu_move_null(struct ttm_buffer_object *bo, | 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 | BUG_ON(old_mem->mm_node != NULL); | 190 | BUG_ON(old_mem->mm_node != NULL); |
| 239 | *old_mem = *new_mem; | 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 | static uint64_t amdgpu_mm_node_addr(struct ttm_buffer_object *bo, | 203 | static uint64_t amdgpu_mm_node_addr(struct ttm_buffer_object *bo, |
| 252 | struct drm_mm_node *mm_node, | 204 | struct drm_mm_node *mm_node, |
| 253 | struct ttm_mem_reg *mem) | 205 | struct ttm_resource *mem) |
| 254 | { | 206 | { |
| 255 | uint64_t addr = 0; | 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 | * @offset: The offset that drm_mm_node is used for finding. | 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 | uint64_t *offset) | 226 | uint64_t *offset) |
| 275 | { | 227 | { |
| 276 | struct drm_mm_node *mm_node = mem->mm_node; | 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 | * the physical address for local memory. | 250 | * the physical address for local memory. |
| 299 | */ | 251 | */ |
| 300 | static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo, | 252 | static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo, |
| 301 | struct ttm_mem_reg *mem, | 253 | struct ttm_resource *mem, |
| 302 | struct drm_mm_node *mm_node, | 254 | struct drm_mm_node *mm_node, |
| 303 | unsigned num_pages, uint64_t offset, | 255 | unsigned num_pages, uint64_t offset, |
| 304 | unsigned window, struct amdgpu_ring *ring, | 256 | unsigned window, struct amdgpu_ring *ring, |
| @@ -522,8 +474,8 @@ error: · 217 unmodified lines | |||
| 522 | */ | 474 | */ |
| 523 | static int amdgpu_move_blit(struct ttm_buffer_object *bo, | 475 | static int amdgpu_move_blit(struct ttm_buffer_object *bo, |
| 524 | bool evict, bool no_wait_gpu, | 476 | bool evict, bool no_wait_gpu, |
| 525 | struct ttm_mem_reg *new_mem, | 477 | struct ttm_resource *new_mem, |
| 526 | struct ttm_mem_reg *old_mem) | 478 | struct ttm_resource *old_mem) |
| 527 | { | 479 | { |
| 528 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); | 480 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); |
| 529 | struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo); | 481 | struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo); |
| @@ -582,10 +534,10 @@ error: · 52 unmodified lines | |||
| 582 | */ | 534 | */ |
| 583 | static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict, | 535 | static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict, |
| 584 | struct ttm_operation_ctx *ctx, | 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; | 539 | struct ttm_resource *old_mem = &bo->mem; |
| 588 | struct ttm_mem_reg tmp_mem; | 540 | struct ttm_resource tmp_mem; |
| 589 | struct ttm_place placements; | 541 | struct ttm_place placements; |
| 590 | struct ttm_placement placement; | 542 | struct ttm_placement placement; |
| 591 | int r; | 543 | int r; |
| @@ -627,7 +579,7 @@ static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict, · 35 unmodified lines | |||
| 627 | /* move BO (in tmp_mem) to new_mem */ | 579 | /* move BO (in tmp_mem) to new_mem */ |
| 628 | r = ttm_bo_move_ttm(bo, ctx, new_mem); | 580 | r = ttm_bo_move_ttm(bo, ctx, new_mem); |
| 629 | out_cleanup: | 581 | out_cleanup: |
| 630 | ttm_bo_mem_put(bo, &tmp_mem); | 582 | ttm_resource_free(bo, &tmp_mem); |
| 631 | return r; | 583 | return r; |
| 632 | } | 584 | } |
| 633 | 585 | ||
| @@ -638,10 +590,10 @@ out_cleanup: · 4 unmodified lines | |||
| 638 | */ | 590 | */ |
| 639 | static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, bool evict, | 591 | static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, bool evict, |
| 640 | struct ttm_operation_ctx *ctx, | 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; | 595 | struct ttm_resource *old_mem = &bo->mem; |
| 644 | struct ttm_mem_reg tmp_mem; | 596 | struct ttm_resource tmp_mem; |
| 645 | struct ttm_placement placement; | 597 | struct ttm_placement placement; |
| 646 | struct ttm_place placements; | 598 | struct ttm_place placements; |
| 647 | int r; | 599 | int r; |
| @@ -674,7 +626,7 @@ static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, bool evict, · 26 unmodified lines | |||
| 674 | goto out_cleanup; | 626 | goto out_cleanup; |
| 675 | } | 627 | } |
| 676 | out_cleanup: | 628 | out_cleanup: |
| 677 | ttm_bo_mem_put(bo, &tmp_mem); | 629 | ttm_resource_free(bo, &tmp_mem); |
| 678 | return r; | 630 | return r; |
| 679 | } | 631 | } |
| 680 | 632 | ||
| @@ -684,7 +636,7 @@ out_cleanup: · 3 unmodified lines | |||
| 684 | * Called by amdgpu_bo_move() | 636 | * Called by amdgpu_bo_move() |
| 685 | */ | 637 | */ |
| 686 | static bool amdgpu_mem_visible(struct amdgpu_device *adev, | 638 | static bool amdgpu_mem_visible(struct amdgpu_device *adev, |
| 687 | struct ttm_mem_reg *mem) | 639 | struct ttm_resource *mem) |
| 688 | { | 640 | { |
| 689 | struct drm_mm_node *nodes = mem->mm_node; | 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 | if (mem->mem_type != TTM_PL_VRAM) | 646 | if (mem->mem_type != TTM_PL_VRAM) |
| 695 | return false; | 647 | return false; |
| 696 | 648 | ||
| 697 | /* ttm_mem_reg_ioremap only supports contiguous memory */ | 649 | /* ttm_resource_ioremap only supports contiguous memory */ |
| 698 | if (nodes->size != mem->num_pages) | 650 | if (nodes->size != mem->num_pages) |
| 699 | return false; | 651 | return false; |
| 700 | 652 | ||
| @@ -709,11 +661,11 @@ static bool amdgpu_mem_visible(struct amdgpu_device *adev, · 8 unmodified lines | |||
| 709 | */ | 661 | */ |
| 710 | static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict, | 662 | static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict, |
| 711 | struct ttm_operation_ctx *ctx, | 663 | struct ttm_operation_ctx *ctx, |
| 712 | struct ttm_mem_reg *new_mem) | 664 | struct ttm_resource *new_mem) |
| 713 | { | 665 | { |
| 714 | struct amdgpu_device *adev; | 666 | struct amdgpu_device *adev; |
| 715 | struct amdgpu_bo *abo; | 667 | struct amdgpu_bo *abo; |
| 716 | struct ttm_mem_reg *old_mem = &bo->mem; | 668 | struct ttm_resource *old_mem = &bo->mem; |
| 717 | int r; | 669 | int r; |
| 718 | 670 | ||
| 719 | /* Can't move a pinned BO */ | 671 | /* Can't move a pinned BO */ |
| @@ -795,19 +747,12 @@ memcpy: · 75 unmodified lines | |||
| 795 | * | 747 | * |
| 796 | * Called by ttm_mem_io_reserve() ultimately via ttm_bo_vm_fault() | 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 | struct amdgpu_device *adev = amdgpu_ttm_adev(bdev); | 752 | struct amdgpu_device *adev = amdgpu_ttm_adev(bdev); |
| 802 | struct drm_mm_node *mm_node = mem->mm_node; | 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 | switch (mem->mem_type) { | 756 | switch (mem->mem_type) { |
| 812 | case TTM_PL_SYSTEM: | 757 | case TTM_PL_SYSTEM: |
| 813 | /* system memory */ | 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 | case TTM_PL_VRAM: | 762 | case TTM_PL_VRAM: |
| 818 | mem->bus.offset = mem->start << PAGE_SHIFT; | 763 | mem->bus.offset = mem->start << PAGE_SHIFT; |
| 819 | /* check if it's visible */ | 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 | return -EINVAL; | 766 | return -EINVAL; |
| 822 | /* Only physically contiguous buffers apply. In a contiguous | 767 | /* Only physically contiguous buffers apply. In a contiguous |
| 823 | * buffer, size of the first mm_node would match the number of | 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 | if (adev->mman.aper_base_kaddr && | 771 | if (adev->mman.aper_base_kaddr && |
| 827 | (mm_node->size == mem->num_pages)) | 772 | (mm_node->size == mem->num_pages)) |
| @@ -1166,7 +1111,7 @@ gart_bind_fail: · 338 unmodified lines | |||
| 1166 | * This handles binding GTT memory to the device address space. | 1111 | * This handles binding GTT memory to the device address space. |
| 1167 | */ | 1112 | */ |
| 1168 | static int amdgpu_ttm_backend_bind(struct ttm_tt *ttm, | 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 | struct amdgpu_device *adev = amdgpu_ttm_adev(ttm->bdev); | 1116 | struct amdgpu_device *adev = amdgpu_ttm_adev(ttm->bdev); |
| 1172 | struct amdgpu_ttm_tt *gtt = (void*)ttm; | 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 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); | 1162 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); |
| 1218 | struct ttm_operation_ctx ctx = { false, false }; | 1163 | struct ttm_operation_ctx ctx = { false, false }; |
| 1219 | struct amdgpu_ttm_tt *gtt = (void*)bo->ttm; | 1164 | struct amdgpu_ttm_tt *gtt = (void*)bo->ttm; |
| 1220 | struct ttm_mem_reg tmp; | 1165 | struct ttm_resource tmp; |
| 1221 | struct ttm_placement placement; | 1166 | struct ttm_placement placement; |
| 1222 | struct ttm_place placements; | 1167 | struct ttm_place placements; |
| 1223 | uint64_t addr, flags; | 1168 | uint64_t addr, flags; |
| @@ -1254,11 +1199,11 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo) · 30 unmodified lines | |||
| 1254 | gtt->offset = (u64)tmp.start << PAGE_SHIFT; | 1199 | gtt->offset = (u64)tmp.start << PAGE_SHIFT; |
| 1255 | r = amdgpu_ttm_gart_bind(adev, bo, flags); | 1200 | r = amdgpu_ttm_gart_bind(adev, bo, flags); |
| 1256 | if (unlikely(r)) { | 1201 | if (unlikely(r)) { |
| 1257 | ttm_bo_mem_put(bo, &tmp); | 1202 | ttm_resource_free(bo, &tmp); |
| 1258 | return r; | 1203 | return r; |
| 1259 | } | 1204 | } |
| 1260 | 1205 | ||
| 1261 | ttm_bo_mem_put(bo, &bo->mem); | 1206 | ttm_resource_free(bo, &bo->mem); |
| 1262 | bo->mem = tmp; | 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 | * amdgpu_ttm_tt_set_userptr - Initialize userptr GTT ttm_tt for the current | 1402 | * amdgpu_ttm_tt_set_userptr - Initialize userptr GTT ttm_tt for the current |
| 1458 | * task | 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 | * @addr: The address in the current tasks VM space to use | 1406 | * @addr: The address in the current tasks VM space to use |
| 1462 | * @flags: Requirements of userptr object. | 1407 | * @flags: Requirements of userptr object. |
| 1463 | * | 1408 | * |
| 1464 | * Called by amdgpu_gem_userptr_ioctl() to bind userptr pages | 1409 | * Called by amdgpu_gem_userptr_ioctl() to bind userptr pages |
| 1465 | * to current task | 1410 | * to current task |
| 1466 | */ | 1411 | */ |
| 1467 | int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr, | 1412 | int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo, |
| 1468 | uint32_t flags) | 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) | 1417 | if (!bo->ttm) { |
| 1473 | return -EINVAL; | 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 | gtt->userptr = addr; | 1425 | gtt->userptr = addr; |
| 1476 | gtt->userflags = flags; | 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 | * Figure out the flags to use for a VM PDE (Page Directory Entry). | 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 | uint64_t flags = 0; | 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 | * Figure out the flags to use for a VM PTE (Page Table Entry). | 1533 | * Figure out the flags to use for a VM PTE (Page Table Entry). |
| 1584 | */ | 1534 | */ |
| 1585 | uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm, | 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 | uint64_t flags = amdgpu_ttm_tt_pde_flags(ttm, mem); | 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 | .ttm_tt_create = &amdgpu_ttm_tt_create, | 1691 | .ttm_tt_create = &amdgpu_ttm_tt_create, |
| 1742 | .ttm_tt_populate = &amdgpu_ttm_tt_populate, | 1692 | .ttm_tt_populate = &amdgpu_ttm_tt_populate, |
| 1743 | .ttm_tt_unpopulate = &amdgpu_ttm_tt_unpopulate, | 1693 | .ttm_tt_unpopulate = &amdgpu_ttm_tt_unpopulate, |
| 1744 | .init_mem_type = &amdgpu_init_mem_type, | ||
| 1745 | .eviction_valuable = amdgpu_ttm_bo_eviction_valuable, | 1694 | .eviction_valuable = amdgpu_ttm_bo_eviction_valuable, |
| 1746 | .evict_flags = &amdgpu_evict_flags, | 1695 | .evict_flags = &amdgpu_evict_flags, |
| 1747 | .move = &amdgpu_bo_move, | 1696 | .move = &amdgpu_bo_move, |
| @@ -1936,8 +1885,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) · 188 unmodified lines | |||
| 1936 | adev->mman.bdev.no_retry = true; | 1885 | adev->mman.bdev.no_retry = true; |
| 1937 | 1886 | ||
| 1938 | /* Initialize VRAM pool with all of VRAM divided into pages */ | 1887 | /* Initialize VRAM pool with all of VRAM divided into pages */ |
| 1939 | r = ttm_bo_init_mm(&adev->mman.bdev, TTM_PL_VRAM, | 1888 | r = amdgpu_vram_mgr_init(adev); |
| 1940 | adev->gmc.real_vram_size >> PAGE_SHIFT); | ||
| 1941 | if (r) { | 1889 | if (r) { |
| 1942 | DRM_ERROR("Failed initializing VRAM heap.\n"); | 1890 | DRM_ERROR("Failed initializing VRAM heap.\n"); |
| 1943 | return r; | 1891 | return r; |
| @@ -2004,7 +1952,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) · 60 unmodified lines | |||
| 2004 | gtt_size = (uint64_t)amdgpu_gtt_size << 20; | 1952 | gtt_size = (uint64_t)amdgpu_gtt_size << 20; |
| 2005 | 1953 | ||
| 2006 | /* Initialize GTT memory pool */ | 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 | if (r) { | 1956 | if (r) { |
| 2009 | DRM_ERROR("Failed initializing GTT heap.\n"); | 1957 | DRM_ERROR("Failed initializing GTT heap.\n"); |
| 2010 | return r; | 1958 | return r; |
| @@ -2013,22 +1961,19 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) · 2 unmodified lines | |||
| 2013 | (unsigned)(gtt_size / (1024 * 1024))); | 1961 | (unsigned)(gtt_size / (1024 * 1024))); |
| 2014 | 1962 | ||
| 2015 | /* Initialize various on-chip memory pools */ | 1963 | /* Initialize various on-chip memory pools */ |
| 2016 | r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GDS, | 1964 | r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GDS, adev->gds.gds_size); |
| 2017 | adev->gds.gds_size); | ||
| 2018 | if (r) { | 1965 | if (r) { |
| 2019 | DRM_ERROR("Failed initializing GDS heap.\n"); | 1966 | DRM_ERROR("Failed initializing GDS heap.\n"); |
| 2020 | return r; | 1967 | return r; |
| 2021 | } | 1968 | } |
| 2022 | 1969 | ||
| 2023 | r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GWS, | 1970 | r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GWS, adev->gds.gws_size); |
| 2024 | adev->gds.gws_size); | ||
| 2025 | if (r) { | 1971 | if (r) { |
| 2026 | DRM_ERROR("Failed initializing gws heap.\n"); | 1972 | DRM_ERROR("Failed initializing gws heap.\n"); |
| 2027 | return r; | 1973 | return r; |
| 2028 | } | 1974 | } |
| 2029 | 1975 | ||
| 2030 | r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_OA, | 1976 | r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_OA, adev->gds.oa_size); |
| 2031 | adev->gds.oa_size); | ||
| 2032 | if (r) { | 1977 | if (r) { |
| 2033 | DRM_ERROR("Failed initializing oa heap.\n"); | 1978 | DRM_ERROR("Failed initializing oa heap.\n"); |
| 2034 | return r; | 1979 | return r; |
| @@ -2064,11 +2009,11 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) · 29 unmodified lines | |||
| 2064 | iounmap(adev->mman.aper_base_kaddr); | 2009 | iounmap(adev->mman.aper_base_kaddr); |
| 2065 | adev->mman.aper_base_kaddr = NULL; | 2010 | adev->mman.aper_base_kaddr = NULL; |
| 2066 | 2011 | ||
| 2067 | ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_VRAM); | 2012 | amdgpu_vram_mgr_fini(adev); |
| 2068 | ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_TT); | 2013 | amdgpu_gtt_mgr_fini(adev); |
| 2069 | ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GDS); | 2014 | ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GDS); |
| 2070 | ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GWS); | 2015 | ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GWS); |
| 2071 | ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_OA); | 2016 | ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_OA); |
| 2072 | ttm_bo_device_release(&adev->mman.bdev); | 2017 | ttm_bo_device_release(&adev->mman.bdev); |
| 2073 | adev->mman.initialized = false; | 2018 | adev->mman.initialized = false; |
| 2074 | DRM_INFO("amdgpu: ttm finalized\n"); | 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 | void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable) | 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 | uint64_t size; | 2034 | uint64_t size; |
| 2090 | int r; | 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 | unsigned ttm_pl = (uintptr_t)node->info_ent->data; | 2252 | unsigned ttm_pl = (uintptr_t)node->info_ent->data; |
| 2308 | struct drm_device *dev = node->minor->dev; | 2253 | struct drm_device *dev = node->minor->dev; |
| 2309 | struct amdgpu_device *adev = dev->dev_private; | 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 | struct drm_printer p = drm_seq_file_printer(m); | 2256 | struct drm_printer p = drm_seq_file_printer(m); |
| 2312 | 2257 | ||
| 2313 | man->func->debug(man, &p); | 2258 | man->func->debug(man, &p); |
| @@ -41,6 +41,21 @@ · 40 unmodified lines | |||
| 41 | 41 | ||
| 42 | #define AMDGPU_POISON 0xd0bed0be | 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 | struct amdgpu_mman { | 59 | struct amdgpu_mman { |
| 45 | struct ttm_bo_device bdev; | 60 | struct ttm_bo_device bdev; |
| 46 | bool mem_global_referenced; | 61 | bool mem_global_referenced; |
| @@ -59,24 +74,29 @@ struct amdgpu_mman { · 12 unmodified lines | |||
| 59 | struct mutex gtt_window_lock; | 74 | struct mutex gtt_window_lock; |
| 60 | /* Scheduler entity for buffer moves */ | 75 | /* Scheduler entity for buffer moves */ |
| 61 | struct drm_sched_entity entity; | 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 | struct amdgpu_copy_mem { | 82 | struct amdgpu_copy_mem { |
| 65 | struct ttm_buffer_object *bo; | 83 | struct ttm_buffer_object *bo; |
| 66 | struct ttm_mem_reg *mem; | 84 | struct ttm_resource *mem; |
| 67 | unsigned long offset; | 85 | unsigned long offset; |
| 68 | }; | 86 | }; |
| 69 | 87 | ||
| 70 | extern const struct ttm_mem_type_manager_func amdgpu_gtt_mgr_func; | 88 | int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size); |
| 71 | extern const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func; | 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); | 93 | bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem); |
| 74 | uint64_t amdgpu_gtt_mgr_usage(struct ttm_mem_type_manager *man); | 94 | uint64_t amdgpu_gtt_mgr_usage(struct ttm_resource_manager *man); |
| 75 | int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man); | 95 | int amdgpu_gtt_mgr_recover(struct ttm_resource_manager *man); |
| 76 | 96 | ||
| 77 | u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo); | 97 | u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo); |
| 78 | int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev, | 98 | int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev, |
| 79 | struct ttm_mem_reg *mem, | 99 | struct ttm_resource *mem, |
| 80 | struct device *dev, | 100 | struct device *dev, |
| 81 | enum dma_data_direction dir, | 101 | enum dma_data_direction dir, |
| 82 | struct sg_table **sgt); | 102 | struct sg_table **sgt); |
| @@ -84,8 +104,8 @@ void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev, · 1 unmodified line | |||
| 84 | struct device *dev, | 104 | struct device *dev, |
| 85 | enum dma_data_direction dir, | 105 | enum dma_data_direction dir, |
| 86 | struct sg_table *sgt); | 106 | struct sg_table *sgt); |
| 87 | uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man); | 107 | uint64_t amdgpu_vram_mgr_usage(struct ttm_resource_manager *man); |
| 88 | uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man); | 108 | uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_resource_manager *man); |
| 89 | 109 | ||
| 90 | int amdgpu_ttm_init(struct amdgpu_device *adev); | 110 | int amdgpu_ttm_init(struct amdgpu_device *adev); |
| 91 | void amdgpu_ttm_late_init(struct amdgpu_device *adev); | 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 | #endif | 150 | #endif |
| 131 | 151 | ||
| 132 | void amdgpu_ttm_tt_set_user_pages(struct ttm_tt *ttm, struct page **pages); | 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, | 153 | int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo, |
| 134 | uint32_t flags); | 154 | uint64_t addr, uint32_t flags); |
| 135 | bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm); | 155 | bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm); |
| 136 | struct mm_struct *amdgpu_ttm_tt_get_usermm(struct ttm_tt *ttm); | 156 | struct mm_struct *amdgpu_ttm_tt_get_usermm(struct ttm_tt *ttm); |
| 137 | bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start, | 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 | int *last_invalidated); | 160 | int *last_invalidated); |
| 141 | bool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm); | 161 | bool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm); |
| 142 | bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm); | 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 | uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm, | 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 | int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev); | 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 | struct amdgpu_vm *vm = bo_va->base.vm; | 1765 | struct amdgpu_vm *vm = bo_va->base.vm; |
| 1766 | struct amdgpu_bo_va_mapping *mapping; | 1766 | struct amdgpu_bo_va_mapping *mapping; |
| 1767 | dma_addr_t *pages_addr = NULL; | 1767 | dma_addr_t *pages_addr = NULL; |
| 1768 | struct ttm_mem_reg *mem; | 1768 | struct ttm_resource *mem; |
| 1769 | struct drm_mm_node *nodes; | 1769 | struct drm_mm_node *nodes; |
| 1770 | struct dma_fence **last_update; | 1770 | struct dma_fence **last_update; |
| 1771 | struct dma_resv *resv; | 1771 | struct dma_resv *resv; |
| @@ -28,12 +28,15 @@ · 27 unmodified lines | |||
| 28 | #include "amdgpu_atomfirmware.h" | 28 | #include "amdgpu_atomfirmware.h" |
| 29 | #include "atom.h" | 29 | #include "atom.h" |
| 30 | 30 | ||
| 31 | struct amdgpu_vram_mgr { | 31 | static inline struct amdgpu_vram_mgr *to_vram_mgr(struct ttm_resource_manager *man) |
| 32 | struct drm_mm mm; | 32 | { |
| 33 | spinlock_t lock; | 33 | return container_of(man, struct amdgpu_vram_mgr, manager); |
| 34 | atomic64_t usage; | 34 | } |
| 35 | atomic64_t vis_usage; | 35 | |
| 36 | }; | 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 | * DOC: mem_info_vram_total | 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 | struct drm_device *ddev = dev_get_drvdata(dev); | 86 | struct drm_device *ddev = dev_get_drvdata(dev); |
| 84 | struct amdgpu_device *adev = ddev->dev_private; | 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 | return snprintf(buf, PAGE_SIZE, "%llu\n", | 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 | struct drm_device *ddev = dev_get_drvdata(dev); | 104 | struct drm_device *ddev = dev_get_drvdata(dev); |
| 102 | struct amdgpu_device *adev = ddev->dev_private; | 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 | return snprintf(buf, PAGE_SIZE, "%llu\n", | 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 | static ssize_t amdgpu_mem_info_vram_vendor(struct device *dev, | 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 | NULL | 161 | NULL |
| 159 | }; | 162 | }; |
| 160 | 163 | ||
| 164 | static const struct ttm_resource_manager_func amdgpu_vram_mgr_func; | ||
| 165 | |||
| 161 | /** | 166 | /** |
| 162 | * amdgpu_vram_mgr_init - init VRAM manager and DRM MM | 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 | * Allocate and initialize the VRAM manager. | 172 | * Allocate and initialize the VRAM manager. |
| 168 | */ | 173 | */ |
| 169 | static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man, | 174 | int amdgpu_vram_mgr_init(struct amdgpu_device *adev) |
| 170 | unsigned long p_size) | ||
| 171 | { | 175 | { |
| 172 | struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); | 176 | struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr; |
| 173 | struct amdgpu_vram_mgr *mgr; | 177 | struct ttm_resource_manager *man = &mgr->manager; |
| 174 | int ret; | 178 | int ret; |
| 175 | 179 | ||
| 176 | mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); | 180 | man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; |
| 177 | if (!mgr) | 181 | man->default_caching = TTM_PL_FLAG_WC; |
| 178 | return -ENOMEM; | ||
| 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 | spin_lock_init(&mgr->lock); | 188 | spin_lock_init(&mgr->lock); |
| 182 | man->priv = mgr; | ||
| 183 | 189 | ||
| 184 | /* Add the two VRAM-related sysfs files */ | 190 | /* Add the two VRAM-related sysfs files */ |
| 185 | ret = sysfs_create_files(&adev->dev->kobj, amdgpu_vram_mgr_attributes); | 191 | ret = sysfs_create_files(&adev->dev->kobj, amdgpu_vram_mgr_attributes); |
| 186 | if (ret) | 192 | if (ret) |
| 187 | DRM_ERROR("Failed to register sysfs\n"); | 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 | return 0; | 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 | * Destroy and free the VRAM manager, returns -EBUSY if ranges are still | 205 | * Destroy and free the VRAM manager, returns -EBUSY if ranges are still |
| 198 | * allocated inside it. | 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); | 210 | struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr; |
| 203 | struct amdgpu_vram_mgr *mgr = man->priv; | 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 | spin_lock(&mgr->lock); | 220 | spin_lock(&mgr->lock); |
| 206 | drm_mm_takedown(&mgr->mm); | 221 | drm_mm_takedown(&mgr->mm); |
| 207 | spin_unlock(&mgr->lock); | 222 | spin_unlock(&mgr->lock); |
| 208 | kfree(mgr); | 223 | |
| 209 | man->priv = NULL; | ||
| 210 | sysfs_remove_files(&adev->dev->kobj, amdgpu_vram_mgr_attributes); | 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 | u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo) | 259 | u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo) |
| 244 | { | 260 | { |
| 245 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); | 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 | struct drm_mm_node *nodes = mem->mm_node; | 263 | struct drm_mm_node *nodes = mem->mm_node; |
| 248 | unsigned pages = mem->num_pages; | 264 | unsigned pages = mem->num_pages; |
| 249 | u64 usage; | 265 | u64 usage; |
| @@ -263,13 +279,13 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo) · 13 unmodified lines | |||
| 263 | /** | 279 | /** |
| 264 | * amdgpu_vram_mgr_virt_start - update virtual start address | 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 | * @node: just allocated node | 283 | * @node: just allocated node |
| 268 | * | 284 | * |
| 269 | * Calculate a virtual BO start address to easily check if everything is CPU | 285 | * Calculate a virtual BO start address to easily check if everything is CPU |
| 270 | * accessible. | 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 | struct drm_mm_node *node) | 289 | struct drm_mm_node *node) |
| 274 | { | 290 | { |
| 275 | unsigned long start; | 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 | * Allocate VRAM for the given BO. | 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 | struct ttm_buffer_object *tbo, | 312 | struct ttm_buffer_object *tbo, |
| 297 | const struct ttm_place *place, | 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); | 316 | struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); |
| 301 | struct amdgpu_vram_mgr *mgr = man->priv; | 317 | struct amdgpu_device *adev = to_amdgpu_device(mgr); |
| 302 | struct drm_mm *mm = &mgr->mm; | 318 | struct drm_mm *mm = &mgr->mm; |
| 303 | struct drm_mm_node *nodes; | 319 | struct drm_mm_node *nodes; |
| 304 | enum drm_mm_insert_mode mode; | 320 | enum drm_mm_insert_mode mode; |
| @@ -410,11 +426,11 @@ error: · 105 unmodified lines | |||
| 410 | * | 426 | * |
| 411 | * Free the allocated VRAM again. | 427 | * Free the allocated VRAM again. |
| 412 | */ | 428 | */ |
| 413 | static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man, | 429 | static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man, |
| 414 | struct ttm_mem_reg *mem) | 430 | struct ttm_resource *mem) |
| 415 | { | 431 | { |
| 416 | struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev); | 432 | struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); |
| 417 | struct amdgpu_vram_mgr *mgr = man->priv; | 433 | struct amdgpu_device *adev = to_amdgpu_device(mgr); |
| 418 | struct drm_mm_node *nodes = mem->mm_node; | 434 | struct drm_mm_node *nodes = mem->mm_node; |
| 419 | uint64_t usage = 0, vis_usage = 0; | 435 | uint64_t usage = 0, vis_usage = 0; |
| 420 | unsigned pages = mem->num_pages; | 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 | * Allocate and fill a sg table from a VRAM allocation. | 467 | * Allocate and fill a sg table from a VRAM allocation. |
| 452 | */ | 468 | */ |
| 453 | int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev, | 469 | int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev, |
| 454 | struct ttm_mem_reg *mem, | 470 | struct ttm_resource *mem, |
| 455 | struct device *dev, | 471 | struct device *dev, |
| 456 | enum dma_data_direction dir, | 472 | enum dma_data_direction dir, |
| 457 | struct sg_table **sgt) | 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 | * Returns how many bytes are used in this domain. | 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 | return atomic64_read(&mgr->usage); | 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 | * Returns how many bytes are used in the visible part of VRAM | 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 | return atomic64_read(&mgr->vis_usage); | 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 | * Dump the table content using printk. | 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 | struct drm_printer *printer) | 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 | spin_lock(&mgr->lock); | 597 | spin_lock(&mgr->lock); |
| 582 | drm_mm_print(&mgr->mm, printer); | 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 | amdgpu_vram_mgr_vis_usage(man) >> 20); | 603 | amdgpu_vram_mgr_vis_usage(man) >> 20); |
| 588 | } | 604 | } |
| 589 | 605 | ||
| 590 | const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func = { | 606 | static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = { |
| 591 | .init = amdgpu_vram_mgr_init, | 607 | .alloc = amdgpu_vram_mgr_new, |
| 592 | .takedown = amdgpu_vram_mgr_fini, | 608 | .free = amdgpu_vram_mgr_del, |
| 593 | .get_node = amdgpu_vram_mgr_new, | 609 | .debug = amdgpu_vram_mgr_debug |
| 594 | .put_node = amdgpu_vram_mgr_del, | ||
| 595 | .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 | buf[0], buf[1], buf[2]); | 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 | int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector) | 347 | int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector) |
| 332 | { | 348 | { |
| 333 | struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv; | 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 | dig_connector->dpcd); | 359 | dig_connector->dpcd); |
| 344 | 360 | ||
| 345 | amdgpu_atombios_dp_probe_oui(amdgpu_connector); | 361 | amdgpu_atombios_dp_probe_oui(amdgpu_connector); |
| 346 | 362 | amdgpu_atombios_dp_ds_ports(amdgpu_connector); | |
| 347 | return 0; | 363 | return 0; |
| 348 | } | 364 | } |
| 349 | 365 | ||
| @@ -127,6 +127,42 @@ MODULE_FIRMWARE(FIRMWARE_NAVI12_DMCU); · 126 unmodified lines | |||
| 127 | static int amdgpu_dm_init(struct amdgpu_device *adev); | 127 | static int amdgpu_dm_init(struct amdgpu_device *adev); |
| 128 | static void amdgpu_dm_fini(struct amdgpu_device *adev); | 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 | * initializes drm_device display related structures, based on the information | 167 | * initializes drm_device display related structures, based on the information |
| 132 | * provided by DAL. The drm strcutures are: drm_crtc, drm_connector, | 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 | if (aconnector->mst_mgr.mst_state == true) | 2131 | if (aconnector->mst_mgr.mst_state == true) |
| 2096 | return; | 2132 | return; |
| 2097 | 2133 | ||
| 2098 | |||
| 2099 | sink = aconnector->dc_link->local_sink; | 2134 | sink = aconnector->dc_link->local_sink; |
| 2100 | if (sink) | 2135 | if (sink) |
| 2101 | dc_sink_retain(sink); | 2136 | dc_sink_retain(sink); |
| @@ -2222,6 +2257,8 @@ void amdgpu_dm_update_connector_after_detect( · 120 unmodified lines | |||
| 2222 | 2257 | ||
| 2223 | mutex_unlock(&dev->mode_config.mutex); | 2258 | mutex_unlock(&dev->mode_config.mutex); |
| 2224 | 2259 | ||
| 2260 | update_subconnector_property(aconnector); | ||
| 2261 | |||
| 2225 | if (sink) | 2262 | if (sink) |
| 2226 | dc_sink_release(sink); | 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 | else | 4794 | else |
| 4758 | connected = (aconnector->base.force == DRM_FORCE_ON); | 4795 | connected = (aconnector->base.force == DRM_FORCE_ON); |
| 4759 | 4796 | ||
| 4797 | update_subconnector_property(aconnector); | ||
| 4798 | |||
| 4760 | return (connected ? connector_status_connected : | 4799 | return (connected ? connector_status_connected : |
| 4761 | connector_status_disconnected); | 4800 | connector_status_disconnected); |
| 4762 | } | 4801 | } |
| @@ -26,6 +26,7 @@ · 25 unmodified lines | |||
| 26 | #include <linux/version.h> | 26 | #include <linux/version.h> |
| 27 | #include <drm/drm_atomic_helper.h> | 27 | #include <drm/drm_atomic_helper.h> |
| 28 | #include <drm/drm_dp_mst_helper.h> | 28 | #include <drm/drm_dp_mst_helper.h> |
| 29 | #include <drm/drm_dp_helper.h> | ||
| 29 | #include "dm_services.h" | 30 | #include "dm_services.h" |
| 30 | #include "amdgpu.h" | 31 | #include "amdgpu.h" |
| 31 | #include "amdgpu_dm.h" | 32 | #include "amdgpu_dm.h" |
| @@ -431,6 +432,8 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, · 399 unmodified lines | |||
| 431 | 16, | 432 | 16, |
| 432 | 4, | 433 | 4, |
| 433 | aconnector->connector_id); | 434 | aconnector->connector_id); |
| 435 | |||
| 436 | drm_connector_attach_dp_subconnector_property(&aconnector->base); | ||
| 434 | } | 437 | } |
| 435 | 438 | ||
| 436 | int dm_mst_get_pbn_divider(struct dc_link *link) | 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 | if (cma_obj->sgt) | 346 | if (cma_obj->sgt) |
| 347 | sgt = cma_obj->sgt; | 347 | sgt = cma_obj->sgt; |
| 348 | else | 348 | else |
| 349 | sgt = obj->dev->driver->gem_prime_get_sg_table(obj); | 349 | sgt = obj->funcs->get_sg_table(obj); |
| 350 | 350 | ||
| 351 | if (!sgt) | 351 | if (!sgt) |
| 352 | return false; | 352 | return false; |
| @@ -47,7 +47,7 @@ static void ast_cursor_fini(struct ast_private *ast) · 46 unmodified lines | |||
| 47 | 47 | ||
| 48 | static void ast_cursor_release(struct drm_device *dev, void *ptr) | 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 | ast_cursor_fini(ast); | 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 | int ast_cursor_init(struct ast_private *ast) | 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 | size_t size, i; | 61 | size_t size, i; |
| 62 | struct drm_gem_vram_object *gbo; | 62 | struct drm_gem_vram_object *gbo; |
| 63 | void __iomem *vaddr; | 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 | int ast_cursor_blit(struct ast_private *ast, struct drm_framebuffer *fb) | 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 | struct drm_gem_vram_object *gbo; | 172 | struct drm_gem_vram_object *gbo; |
| 173 | int ret; | 173 | int ret; |
| 174 | void *src; | 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 | void ast_cursor_page_flip(struct ast_private *ast) | 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 | struct drm_gem_vram_object *gbo; | 221 | struct drm_gem_vram_object *gbo; |
| 222 | s64 off; | 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 | unsigned int offset_x, unsigned int offset_y) | 253 | unsigned int offset_x, unsigned int offset_y) |
| 254 | { | 254 | { |
| 255 | u8 x_offset, y_offset; | 255 | u8 x_offset, y_offset; |
| 256 | u8 __iomem *dst, __iomem *sig; | 256 | u8 __iomem *dst; |
| 257 | u8 __iomem *sig; | ||
| 257 | u8 jreg; | 258 | u8 jreg; |
| 258 | 259 | ||
| 259 | dst = ast->cursor.vaddr[ast->cursor.next_index]; | 260 | dst = ast->cursor.vaddr[ast->cursor.next_index]; |
| @@ -8,11 +8,24 @@ · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | MODULE_FIRMWARE("ast_dp501_fw.bin"); | 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 | static int ast_load_dp501_microcode(struct drm_device *dev) | 19 | static int ast_load_dp501_microcode(struct drm_device *dev) |
| 12 | { | 20 | { |
| 13 | struct ast_private *ast = to_ast_private(dev); | 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 | static void send_ack(struct ast_private *ast) | 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 | MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); | 43 | MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); |
| 44 | module_param_named(modeset, ast_modeset, int, 0400); | 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 | #define AST_VGA_DEVICE(id, info) { \ | 74 | #define AST_VGA_DEVICE(id, info) { \ |
| 51 | .class = PCI_BASE_CLASS_DISPLAY << 16, \ | 75 | .class = PCI_BASE_CLASS_DISPLAY << 16, \ |
| @@ -56,13 +80,13 @@ static struct drm_driver driver; · 4 unmodified lines | |||
| 56 | .subdevice = PCI_ANY_ID, \ | 80 | .subdevice = PCI_ANY_ID, \ |
| 57 | .driver_data = (unsigned long) info } | 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 | AST_VGA_DEVICE(PCI_CHIP_AST2000, NULL), | 84 | AST_VGA_DEVICE(PCI_CHIP_AST2000, NULL), |
| 61 | AST_VGA_DEVICE(PCI_CHIP_AST2100, NULL), | 85 | AST_VGA_DEVICE(PCI_CHIP_AST2100, NULL), |
| 62 | {0, 0, 0}, | 86 | {0, 0, 0}, |
| 63 | }; | 87 | }; |
| 64 | 88 | ||
| 65 | MODULE_DEVICE_TABLE(pci, pciidlist); | 89 | MODULE_DEVICE_TABLE(pci, ast_pciidlist); |
| 66 | 90 | ||
| 67 | static void ast_kick_out_firmware_fb(struct pci_dev *pdev) | 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 | static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 110 | static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
| 87 | { | 111 | { |
| 112 | struct ast_private *ast; | ||
| 88 | struct drm_device *dev; | 113 | struct drm_device *dev; |
| 89 | int ret; | 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 | if (ret) | 119 | if (ret) |
| 95 | return ret; | 120 | return ret; |
| 96 | 121 | ||
| 97 | dev = drm_dev_alloc(&driver, &pdev->dev); | 122 | ast = ast_device_create(&ast_driver, pdev, ent->driver_data); |
| 98 | if (IS_ERR(dev)) | 123 | if (IS_ERR(ast)) |
| 99 | return PTR_ERR(dev); | 124 | return PTR_ERR(ast); |
| 100 | 125 | dev = &ast->base; | |
| 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; | ||
| 107 | 126 | ||
| 108 | ret = drm_dev_register(dev, ent->driver_data); | 127 | ret = drm_dev_register(dev, ent->driver_data); |
| 109 | if (ret) | 128 | if (ret) |
| 110 | goto err_ast_driver_unload; | 129 | return ret; |
| 111 | 130 | ||
| 112 | drm_fbdev_generic_setup(dev, 32); | 131 | drm_fbdev_generic_setup(dev, 32); |
| 113 | 132 | ||
| 114 | return 0; | 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 | 136 | static void ast_pci_remove(struct pci_dev *pdev) |
| 125 | ast_pci_remove(struct pci_dev *pdev) | ||
| 126 | { | 137 | { |
| 127 | struct drm_device *dev = pci_get_drvdata(pdev); | 138 | struct drm_device *dev = pci_get_drvdata(pdev); |
| 128 | 139 | ||
| 129 | drm_dev_unregister(dev); | 140 | drm_dev_unregister(dev); |
| 130 | ast_driver_unload(dev); | ||
| 131 | drm_dev_put(dev); | ||
| 132 | } | 141 | } |
| 133 | 142 | ||
| 134 | static int ast_drm_freeze(struct drm_device *dev) | 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 | static struct pci_driver ast_pci_driver = { | 227 | static struct pci_driver ast_pci_driver = { |
| 219 | .name = DRIVER_NAME, | 228 | .name = DRIVER_NAME, |
| 220 | .id_table = pciidlist, | 229 | .id_table = ast_pciidlist, |
| 221 | .probe = ast_pci_probe, | 230 | .probe = ast_pci_probe, |
| 222 | .remove = ast_pci_remove, | 231 | .remove = ast_pci_remove, |
| 223 | .driver.pm = &ast_pm_ops, | 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 | static int __init ast_init(void) | 235 | static int __init ast_init(void) |
| 245 | { | 236 | { |
| 246 | if (vgacon_text_force() && ast_modeset == -1) | 237 | if (vgacon_text_force() && ast_modeset == -1) |
| @@ -261,4 +252,3 @@ module_exit(ast_exit); · 14 unmodified lines | |||
| 261 | MODULE_AUTHOR(DRIVER_AUTHOR); | 252 | MODULE_AUTHOR(DRIVER_AUTHOR); |
| 262 | MODULE_DESCRIPTION(DRIVER_DESC); | 253 | MODULE_DESCRIPTION(DRIVER_DESC); |
| 263 | MODULE_LICENSE("GPL and additional rights"); | 254 | MODULE_LICENSE("GPL and additional rights"); |
| 264 | |||
| @@ -98,9 +98,25 @@ enum ast_tx_chip { · 97 unmodified lines | |||
| 98 | #define AST_HWC_SIGNATURE_HOTSPOTX 0x14 | 98 | #define AST_HWC_SIGNATURE_HOTSPOTX 0x14 |
| 99 | #define AST_HWC_SIGNATURE_HOTSPOTY 0x18 | 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 | struct ast_private { | 118 | struct ast_private { |
| 103 | struct drm_device *dev; | 119 | struct drm_device base; |
| 104 | 120 | ||
| 105 | void __iomem *regs; | 121 | void __iomem *regs; |
| 106 | void __iomem *ioregs; | 122 | void __iomem *ioregs; |
| @@ -119,9 +135,11 @@ struct ast_private { · 12 unmodified lines | |||
| 119 | unsigned int next_index; | 135 | unsigned int next_index; |
| 120 | } cursor; | 136 | } cursor; |
| 121 | 137 | ||
| 122 | struct drm_encoder encoder; | ||
| 123 | struct drm_plane primary_plane; | 138 | struct drm_plane primary_plane; |
| 124 | struct drm_plane cursor_plane; | 139 | struct drm_plane cursor_plane; |
| 140 | struct drm_crtc crtc; | ||
| 141 | struct drm_encoder encoder; | ||
| 142 | struct ast_connector connector; | ||
| 125 | 143 | ||
| 126 | bool support_wide_screen; | 144 | bool support_wide_screen; |
| 127 | enum { | 145 | enum { |
| @@ -138,11 +156,12 @@ struct ast_private { · 10 unmodified lines | |||
| 138 | 156 | ||
| 139 | static inline struct ast_private *to_ast_private(struct drm_device *dev) | 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); | 162 | struct ast_private *ast_device_create(struct drm_driver *drv, |
| 145 | void ast_driver_unload(struct drm_device *dev); | 163 | struct pci_dev *pdev, |
| 164 | unsigned long flags); | ||
| 146 | 165 | ||
| 147 | #define AST_IO_AR_PORT_WRITE (0x40) | 166 | #define AST_IO_AR_PORT_WRITE (0x40) |
| 148 | #define AST_IO_MISC_PORT_WRITE (0x42) | 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 | #define AST_VIDMEM_DEFAULT_SIZE AST_VIDMEM_SIZE_8M | 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 | struct ast_vbios_stdtable { | 248 | struct ast_vbios_stdtable { |
| 243 | u8 misc; | 249 | u8 misc; |
| 244 | u8 seq[4]; | 250 | u8 seq[4]; |
| @@ -305,7 +311,6 @@ bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size); · 60 unmodified lines | |||
| 305 | bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata); | 311 | bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata); |
| 306 | u8 ast_get_dp501_max_clk(struct drm_device *dev); | 312 | u8 ast_get_dp501_max_clk(struct drm_device *dev); |
| 307 | void ast_init_3rdtx(struct drm_device *dev); | 313 | void ast_init_3rdtx(struct drm_device *dev); |
| 308 | void ast_release_firmware(struct drm_device *dev); | ||
| 309 | 314 | ||
| 310 | /* ast_cursor.c */ | 315 | /* ast_cursor.c */ |
| 311 | int ast_cursor_init(struct ast_private *ast); | 316 | int ast_cursor_init(struct ast_private *ast); |
| @@ -30,8 +30,10 @@ · 29 unmodified lines | |||
| 30 | 30 | ||
| 31 | #include <drm/drm_atomic_helper.h> | 31 | #include <drm/drm_atomic_helper.h> |
| 32 | #include <drm/drm_crtc_helper.h> | 32 | #include <drm/drm_crtc_helper.h> |
| 33 | #include <drm/drm_drv.h> | ||
| 33 | #include <drm/drm_gem.h> | 34 | #include <drm/drm_gem.h> |
| 34 | #include <drm/drm_gem_vram_helper.h> | 35 | #include <drm/drm_gem_vram_helper.h> |
| 36 | #include <drm/drm_managed.h> | ||
| 35 | 37 | ||
| 36 | #include "ast_drv.h" | 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 | ast->tx_chip_type = AST_TX_SIL164; | 232 | ast->tx_chip_type = AST_TX_SIL164; |
| 231 | break; | 233 | break; |
| 232 | case 0x08: | 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 | if (ast->dp501_fw_addr) { | 236 | if (ast->dp501_fw_addr) { |
| 235 | /* backup firmware */ | 237 | /* backup firmware */ |
| 236 | if (ast_backup_fw(dev, ast->dp501_fw_addr, 32*1024)) { | 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 | ast->dp501_fw_addr = NULL; | 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 | return 0; | 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 | struct ast_private *ast; | 400 | struct ast_private *ast; |
| 384 | bool need_post; | 401 | bool need_post; |
| 385 | int ret = 0; | 402 | int ret = 0; |
| 386 | 403 | ||
| 387 | ast = kzalloc(sizeof(struct ast_private), GFP_KERNEL); | 404 | ast = devm_drm_dev_alloc(&pdev->dev, drv, struct ast_private, base); |
| 388 | if (!ast) | 405 | if (IS_ERR(ast)) |
| 389 | return -ENOMEM; | 406 | return ast; |
| 407 | dev = &ast->base; | ||
| 390 | 408 | ||
| 391 | dev->dev_private = ast; | 409 | dev->pdev = pdev; |
| 392 | ast->dev = dev; | 410 | pci_set_drvdata(pdev, dev); |
| 393 | 411 | ||
| 394 | ast->regs = pci_iomap(dev->pdev, 1, 0); | 412 | ast->regs = pci_iomap(dev->pdev, 1, 0); |
| 395 | if (!ast->regs) { | 413 | if (!ast->regs) |
| 396 | ret = -EIO; | 414 | return ERR_PTR(-EIO); |
| 397 | goto out_free; | ||
| 398 | } | ||
| 399 | 415 | ||
| 400 | /* | 416 | /* |
| 401 | * If we don't have IO space at all, use MMIO now and | 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 | /* "map" IO regs if the above hasn't done so already */ | 426 | /* "map" IO regs if the above hasn't done so already */ |
| 411 | if (!ast->ioregs) { | 427 | if (!ast->ioregs) { |
| 412 | ast->ioregs = pci_iomap(dev->pdev, 2, 0); | 428 | ast->ioregs = pci_iomap(dev->pdev, 2, 0); |
| 413 | if (!ast->ioregs) { | 429 | if (!ast->ioregs) |
| 414 | ret = -EIO; | 430 | return ERR_PTR(-EIO); |
| 415 | goto out_free; | ||
| 416 | } | ||
| 417 | } | 431 | } |
| 418 | 432 | ||
| 419 | ast_detect_chip(dev, &need_post); | 433 | ast_detect_chip(dev, &need_post); |
| 420 | 434 | ||
| 421 | ret = ast_get_dram_info(dev); | 435 | ret = ast_get_dram_info(dev); |
| 422 | if (ret) | 436 | if (ret) |
| 423 | goto out_free; | 437 | return ERR_PTR(ret); |
| 438 | |||
| 424 | drm_info(dev, "dram MCLK=%u Mhz type=%d bus_width=%d\n", | 439 | drm_info(dev, "dram MCLK=%u Mhz type=%d bus_width=%d\n", |
| 425 | ast->mclk, ast->dram_type, ast->dram_bus_width); | 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 | ret = ast_mm_init(ast); | 445 | ret = ast_mm_init(ast); |
| 431 | if (ret) | 446 | if (ret) |
| 432 | goto out_free; | 447 | return ERR_PTR(ret); |
| 433 | 448 | ||
| 434 | ret = ast_mode_config_init(ast); | 449 | ret = ast_mode_config_init(ast); |
| 435 | if (ret) | 450 | if (ret) |
| 436 | goto out_free; | 451 | return ERR_PTR(ret); |
| 437 | 452 | ||
| 438 | return 0; | 453 | ret = devm_add_action_or_reset(dev->dev, ast_device_release, ast); |
| 439 | out_free: | 454 | if (ret) |
| 440 | kfree(ast); | 455 | return ERR_PTR(ret); |
| 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); | ||
| 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 | int ast_mm_init(struct ast_private *ast) | 86 | int ast_mm_init(struct ast_private *ast) |
| 87 | { | 87 | { |
| 88 | struct drm_device *dev = &ast->base; | ||
| 88 | u32 vram_size; | 89 | u32 vram_size; |
| 89 | int ret; | 90 | int ret; |
| 90 | struct drm_device *dev = ast->dev; | ||
| 91 | 91 | ||
| 92 | vram_size = ast_get_vram_size(ast); | 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 | struct drm_plane_state *state = plane->state; | 664 | struct drm_plane_state *state = plane->state; |
| 665 | struct drm_framebuffer *fb = state->fb; | 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 | unsigned int offset_x, offset_y; | 667 | unsigned int offset_x, offset_y; |
| 668 | 668 | ||
| 669 | offset_x = AST_MAX_HWC_WIDTH - fb->width; | 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 | __drm_atomic_helper_crtc_reset(crtc, &ast_state->base); | 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 | static struct drm_crtc_state * | 834 | static struct drm_crtc_state * |
| 841 | ast_crtc_atomic_duplicate_state(struct drm_crtc *crtc) | 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 | static const struct drm_crtc_funcs ast_crtc_funcs = { | 866 | static const struct drm_crtc_funcs ast_crtc_funcs = { |
| 873 | .reset = ast_crtc_reset, | 867 | .reset = ast_crtc_reset, |
| 874 | .gamma_set = drm_atomic_helper_legacy_gamma_set, | 868 | .gamma_set = drm_atomic_helper_legacy_gamma_set, |
| 875 | .destroy = ast_crtc_destroy, | 869 | .destroy = drm_crtc_cleanup, |
| 876 | .set_config = drm_atomic_helper_set_config, | 870 | .set_config = drm_atomic_helper_set_config, |
| 877 | .page_flip = drm_atomic_helper_page_flip, | 871 | .page_flip = drm_atomic_helper_page_flip, |
| 878 | .atomic_duplicate_state = ast_crtc_atomic_duplicate_state, | 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 | static int ast_crtc_init(struct drm_device *dev) | 876 | static int ast_crtc_init(struct drm_device *dev) |
| 883 | { | 877 | { |
| 884 | struct ast_private *ast = to_ast_private(dev); | 878 | struct ast_private *ast = to_ast_private(dev); |
| 885 | struct drm_crtc *crtc; | 879 | struct drm_crtc *crtc = &ast->crtc; |
| 886 | int ret; | 880 | int ret; |
| 887 | 881 | ||
| 888 | crtc = kzalloc(sizeof(*crtc), GFP_KERNEL); | ||
| 889 | if (!crtc) | ||
| 890 | return -ENOMEM; | ||
| 891 | |||
| 892 | ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane, | 882 | ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane, |
| 893 | &ast->cursor_plane, &ast_crtc_funcs, | 883 | &ast->cursor_plane, &ast_crtc_funcs, |
| 894 | NULL); | 884 | NULL); |
| 895 | if (ret) | 885 | if (ret) |
| 896 | goto err_kfree; | 886 | return ret; |
| 897 | 887 | ||
| 898 | drm_mode_crtc_set_gamma_size(crtc, 256); | 888 | drm_mode_crtc_set_gamma_size(crtc, 256); |
| 899 | drm_crtc_helper_add(crtc, &ast_crtc_helper_funcs); | 889 | drm_crtc_helper_add(crtc, &ast_crtc_helper_funcs); |
| 900 | 890 | ||
| 901 | return 0; | 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 | struct ast_connector *ast_connector = to_ast_connector(connector); | 1007 | struct ast_connector *ast_connector = to_ast_connector(connector); |
| 1022 | ast_i2c_destroy(ast_connector->i2c); | 1008 | ast_i2c_destroy(ast_connector->i2c); |
| 1023 | drm_connector_cleanup(connector); | 1009 | drm_connector_cleanup(connector); |
| 1024 | kfree(connector); | ||
| 1025 | } | 1010 | } |
| 1026 | 1011 | ||
| 1027 | static const struct drm_connector_helper_funcs ast_connector_helper_funcs = { | 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 | static int ast_connector_init(struct drm_device *dev) | 1025 | static int ast_connector_init(struct drm_device *dev) |
| 1041 | { | 1026 | { |
| 1042 | struct ast_connector *ast_connector; | 1027 | struct ast_private *ast = to_ast_private(dev); |
| 1043 | struct drm_connector *connector; | 1028 | struct ast_connector *ast_connector = &ast->connector; |
| 1044 | struct drm_encoder *encoder; | 1029 | struct drm_connector *connector = &ast_connector->base; |
| 1045 | 1030 | struct drm_encoder *encoder = &ast->encoder; | |
| 1046 | ast_connector = kzalloc(sizeof(struct ast_connector), GFP_KERNEL); | ||
| 1047 | if (!ast_connector) | ||
| 1048 | return -ENOMEM; | ||
| 1049 | 1031 | ||
| 1050 | connector = &ast_connector->base; | ||
| 1051 | ast_connector->i2c = ast_i2c_create(dev); | 1032 | ast_connector->i2c = ast_i2c_create(dev); |
| 1052 | if (!ast_connector->i2c) | 1033 | if (!ast_connector->i2c) |
| 1053 | drm_err(dev, "failed to add ddc bus for connector\n"); | 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 | connector->polled = DRM_CONNECTOR_POLL_CONNECT; | 1046 | connector->polled = DRM_CONNECTOR_POLL_CONNECT; |
| 1066 | 1047 | ||
| 1067 | encoder = list_first_entry(&dev->mode_config.encoder_list, struct drm_encoder, head); | ||
| 1068 | drm_connector_attach_encoder(connector, encoder); | 1048 | drm_connector_attach_encoder(connector, encoder); |
| 1069 | 1049 | ||
| 1070 | return 0; | 1050 | return 0; |
| @@ -1083,7 +1063,7 @@ static const struct drm_mode_config_funcs ast_mode_config_funcs = { · 12 unmodified lines | |||
| 1083 | 1063 | ||
| 1084 | int ast_mode_config_init(struct ast_private *ast) | 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 | int ret; | 1067 | int ret; |
| 1088 | 1068 | ||
| 1089 | ret = ast_cursor_init(ast); | 1069 | ret = ast_cursor_init(ast); |
| @@ -1099,7 +1079,7 @@ int ast_mode_config_init(struct ast_private *ast) · 9 unmodified lines | |||
| 1099 | dev->mode_config.min_height = 0; | 1079 | dev->mode_config.min_height = 0; |
| 1100 | dev->mode_config.preferred_depth = 24; | 1080 | dev->mode_config.preferred_depth = 24; |
| 1101 | dev->mode_config.prefer_shadow = 1; | 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 | if (ast->chip == AST2100 || | 1084 | if (ast->chip == AST2100 || |
| 1105 | ast->chip == AST2200 || | 1085 | ast->chip == AST2200 || |
| @@ -365,12 +365,12 @@ static void ast_init_dram_reg(struct drm_device *dev) · 364 unmodified lines | |||
| 365 | 365 | ||
| 366 | void ast_post_gpu(struct drm_device *dev) | 366 | void ast_post_gpu(struct drm_device *dev) |
| 367 | { | 367 | { |
| 368 | u32 reg; | ||
| 369 | struct ast_private *ast = to_ast_private(dev); | 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 | reg |= 0x3; | 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 | ast_enable_vga(dev); | 375 | ast_enable_vga(dev); |
| 376 | ast_open_key(ast); | 376 | ast_open_key(ast); |
| @@ -48,6 +48,19 @@ config DRM_DISPLAY_CONNECTOR · 47 unmodified lines | |||
| 48 | on ARM-based platforms. Saying Y here when this driver is not needed | 48 | on ARM-based platforms. Saying Y here when this driver is not needed |
| 49 | will not cause any issue. | 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 | config DRM_LVDS_CODEC | 64 | config DRM_LVDS_CODEC |
| 52 | tristate "Transparent LVDS encoders and decoders support" | 65 | tristate "Transparent LVDS encoders and decoders support" |
| 53 | depends on OF | 66 | depends on OF |
| @@ -153,6 +166,14 @@ config DRM_THINE_THC63LVD1024 · 99 unmodified lines | |||
| 153 | help | 166 | help |
| 154 | Thine THC63LVD1024 LVDS/parallel converter driver. | 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 | config DRM_TOSHIBA_TC358764 | 177 | config DRM_TOSHIBA_TC358764 |
| 157 | tristate "TC358764 DSI/LVDS bridge" | 178 | tristate "TC358764 DSI/LVDS bridge" |
| 158 | depends on OF | 179 | depends on OF |
| @@ -181,6 +202,16 @@ config DRM_TOSHIBA_TC358768 · 22 unmodified lines | |||
| 181 | help | 202 | help |
| 182 | Toshiba TC358768AXBG/TC358778XBG DSI bridge chip driver. | 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 | config DRM_TI_TFP410 | 215 | config DRM_TI_TFP410 |
| 185 | tristate "TI TFP410 DVI/HDMI bridge" | 216 | tristate "TI TFP410 DVI/HDMI bridge" |
| 186 | depends on OF | 217 | depends on OF |
| @@ -2,6 +2,7 @@ · 1 unmodified line | |||
| 2 | obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o | 2 | obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o |
| 3 | obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o | 3 | obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o |
| 4 | obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o | 4 | obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o |
| 5 | obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o | ||
| 5 | obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o | 6 | obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o |
| 6 | obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o | 7 | obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o |
| 7 | obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o | 8 | obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o |
| @@ -12,9 +13,11 @@ obj-$(CONFIG_DRM_SII902X) += sii902x.o · 4 unmodified lines | |||
| 12 | obj-$(CONFIG_DRM_SII9234) += sii9234.o | 13 | obj-$(CONFIG_DRM_SII9234) += sii9234.o |
| 13 | obj-$(CONFIG_DRM_SIMPLE_BRIDGE) += simple-bridge.o | 14 | obj-$(CONFIG_DRM_SIMPLE_BRIDGE) += simple-bridge.o |
| 14 | obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o | 15 | obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o |
| 16 | obj-$(CONFIG_DRM_TOSHIBA_TC358762) += tc358762.o | ||
| 15 | obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o | 17 | obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o |
| 16 | obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o | 18 | obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o |
| 17 | obj-$(CONFIG_DRM_TOSHIBA_TC358768) += tc358768.o | 19 | obj-$(CONFIG_DRM_TOSHIBA_TC358768) += tc358768.o |
| 20 | obj-$(CONFIG_DRM_TOSHIBA_TC358775) += tc358775.o | ||
| 18 | obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/ | 21 | obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/ |
| 19 | obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o | 22 | obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o |
| 20 | obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o | 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 | static void | 507 | static void |
| 508 | anx6345_connector_destroy(struct drm_connector *connector) | 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 | drm_connector_cleanup(connector); | 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 | return err; | 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 | return 0; | 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 | return 0; | 1268 | return 0; |
| 1277 | } | 1269 | } |
| 1278 | 1270 | ||
| @@ -1803,7 +1795,6 @@ void analogix_dp_unbind(struct analogix_dp_device *dp) · 524 unmodified lines | |||
| 1803 | if (dp->plat_data->panel) { | 1795 | if (dp->plat_data->panel) { |
| 1804 | if (drm_panel_unprepare(dp->plat_data->panel)) | 1796 | if (drm_panel_unprepare(dp->plat_data->panel)) |
| 1805 | DRM_ERROR("failed to turnoff the panel\n"); | 1797 | DRM_ERROR("failed to turnoff the panel\n"); |
| 1806 | drm_panel_detach(dp->plat_data->panel); | ||
| 1807 | } | 1798 | } |
| 1808 | 1799 | ||
| 1809 | drm_dp_aux_unregister(&dp->aux); | 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 | struct drm_bridge bridge; | 61 | struct drm_bridge bridge; |
| 62 | struct i2c_client *stdp4028_i2c; | 62 | struct i2c_client *stdp4028_i2c; |
| 63 | struct i2c_client *stdp2690_i2c; | 63 | struct i2c_client *stdp2690_i2c; |
| 64 | struct edid *edid; | ||
| 65 | }; | 64 | }; |
| 66 | 65 | ||
| 67 | static struct ge_b850v3_lvds *ge_b850v3_lvds_ptr; | 66 | static struct ge_b850v3_lvds *ge_b850v3_lvds_ptr; |
| @@ -131,22 +130,26 @@ err: · 63 unmodified lines | |||
| 131 | return NULL; | 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 | struct i2c_client *client; | 136 | struct i2c_client *client; |
| 137 | int num_modes = 0; | ||
| 138 | 137 | ||
| 139 | client = ge_b850v3_lvds_ptr->stdp2690_i2c; | 138 | client = ge_b850v3_lvds_ptr->stdp2690_i2c; |
| 140 | 139 | ||
| 141 | kfree(ge_b850v3_lvds_ptr->edid); | 140 | return (struct edid *)stdp2690_get_edid(client); |
| 142 | ge_b850v3_lvds_ptr->edid = (struct edid *)stdp2690_get_edid(client); | 141 | } |
| 143 | 142 | ||
| 144 | if (ge_b850v3_lvds_ptr->edid) { | 143 | static int ge_b850v3_lvds_get_modes(struct drm_connector *connector) |
| 145 | drm_connector_update_edid_property(connector, | 144 | { |
| 146 | ge_b850v3_lvds_ptr->edid); | 145 | struct edid *edid; |
| 147 | num_modes = drm_add_edid_modes(connector, | 146 | int num_modes; |
| 148 | ge_b850v3_lvds_ptr->edid); | 147 | |
| 149 | } | 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 | return num_modes; | 154 | return num_modes; |
| 152 | } | 155 | } |
| @@ -163,8 +166,7 @@ drm_connector_helper_funcs ge_b850v3_lvds_connector_helper_funcs = { · 10 unmodified lines | |||
| 163 | .mode_valid = ge_b850v3_lvds_mode_valid, | 166 | .mode_valid = ge_b850v3_lvds_mode_valid, |
| 164 | }; | 167 | }; |
| 165 | 168 | ||
| 166 | static enum drm_connector_status ge_b850v3_lvds_detect( | 169 | static enum drm_connector_status ge_b850v3_lvds_bridge_detect(struct drm_bridge *bridge) |
| 167 | struct drm_connector *connector, bool force) | ||
| 168 | { | 170 | { |
| 169 | struct i2c_client *stdp4028_i2c = | 171 | struct i2c_client *stdp4028_i2c = |
| 170 | ge_b850v3_lvds_ptr->stdp4028_i2c; | 172 | ge_b850v3_lvds_ptr->stdp4028_i2c; |
| @@ -182,6 +184,12 @@ static enum drm_connector_status ge_b850v3_lvds_detect( · 11 unmodified lines | |||
| 182 | return connector_status_unknown; | 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 | static const struct drm_connector_funcs ge_b850v3_lvds_connector_funcs = { | 193 | static const struct drm_connector_funcs ge_b850v3_lvds_connector_funcs = { |
| 186 | .fill_modes = drm_helper_probe_single_connector_modes, | 194 | .fill_modes = drm_helper_probe_single_connector_modes, |
| 187 | .detect = ge_b850v3_lvds_detect, | 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 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | 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) | 202 | static int ge_b850v3_lvds_create_connector(struct drm_bridge *bridge) |
| 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) | ||
| 211 | { | 203 | { |
| 212 | struct drm_connector *connector = &ge_b850v3_lvds_ptr->connector; | 204 | struct drm_connector *connector = &ge_b850v3_lvds_ptr->connector; |
| 213 | struct i2c_client *stdp4028_i2c | ||
| 214 | = ge_b850v3_lvds_ptr->stdp4028_i2c; | ||
| 215 | int ret; | 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 | if (!bridge->encoder) { | 207 | if (!bridge->encoder) { |
| 223 | DRM_ERROR("Parent encoder object not found"); | 208 | DRM_ERROR("Parent encoder object not found"); |
| 224 | return -ENODEV; | 209 | return -ENODEV; |
| @@ -237,9 +222,29 @@ static int ge_b850v3_lvds_attach(struct drm_bridge *bridge, · 12 unmodified lines | |||
| 237 | return ret; | 222 | return ret; |
| 238 | } | 223 | } |
| 239 | 224 | ||
| 240 | ret = drm_connector_attach_encoder(connector, bridge->encoder); | 225 | return drm_connector_attach_encoder(connector, bridge->encoder); |
| 241 | if (ret) | 226 | } |
| 242 | return ret; | 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 | /* Configures the bridge to re-enable interrupts after each ack. */ | 249 | /* Configures the bridge to re-enable interrupts after each ack. */ |
| 245 | i2c_smbus_write_word_data(stdp4028_i2c, | 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 | STDP4028_DPTX_IRQ_EN_REG, | 256 | STDP4028_DPTX_IRQ_EN_REG, |
| 252 | STDP4028_DPTX_IRQ_CONFIG); | 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 | static const struct drm_bridge_funcs ge_b850v3_lvds_funcs = { | 265 | static const struct drm_bridge_funcs ge_b850v3_lvds_funcs = { |
| 258 | .attach = ge_b850v3_lvds_attach, | 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 | static int ge_b850v3_lvds_init(struct device *dev) | 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 | drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge); | 302 | drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge); |
| 293 | 303 | ||
| 294 | kfree(ge_b850v3_lvds_ptr->edid); | ||
| 295 | |||
| 296 | ge_b850v3_lvds_ptr = NULL; | 304 | ge_b850v3_lvds_ptr = NULL; |
| 297 | out: | 305 | out: |
| 298 | mutex_unlock(&ge_b850v3_lvds_dev_mutex); | 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 | const struct i2c_device_id *id) | 310 | const struct i2c_device_id *id) |
| 303 | { | 311 | { |
| 304 | struct device *dev = &stdp4028_i2c->dev; | 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 | ge_b850v3_lvds_ptr->stdp4028_i2c = stdp4028_i2c; | 320 | ge_b850v3_lvds_ptr->stdp4028_i2c = stdp4028_i2c; |
| 309 | i2c_set_clientdata(stdp4028_i2c, ge_b850v3_lvds_ptr); | 321 | i2c_set_clientdata(stdp4028_i2c, ge_b850v3_lvds_ptr); |
| 310 | 322 | ||
| 311 | /* drm bridge initialization */ | 323 | /* drm bridge initialization */ |
| 312 | ge_b850v3_lvds_ptr->bridge.funcs = &ge_b850v3_lvds_funcs; | 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 | ge_b850v3_lvds_ptr->bridge.of_node = dev->of_node; | 328 | ge_b850v3_lvds_ptr->bridge.of_node = dev->of_node; |
| 314 | drm_bridge_add(&ge_b850v3_lvds_ptr->bridge); | 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 | const struct i2c_device_id *id) | 376 | const struct i2c_device_id *id) |
| 362 | { | 377 | { |
| 363 | struct device *dev = &stdp2690_i2c->dev; | 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 | ge_b850v3_lvds_ptr->stdp2690_i2c = stdp2690_i2c; | 386 | ge_b850v3_lvds_ptr->stdp2690_i2c = stdp2690_i2c; |
| 368 | i2c_set_clientdata(stdp2690_i2c, ge_b850v3_lvds_ptr); | 387 | i2c_set_clientdata(stdp2690_i2c, ge_b850v3_lvds_ptr); |
| @@ -29,8 +29,7 @@ struct ptn3460_bridge { · 28 unmodified lines | |||
| 29 | struct drm_connector connector; | 29 | struct drm_connector connector; |
| 30 | struct i2c_client *client; | 30 | struct i2c_client *client; |
| 31 | struct drm_bridge bridge; | 31 | struct drm_bridge bridge; |
| 32 | struct edid *edid; | 32 | struct drm_bridge *panel_bridge; |
| 33 | struct drm_panel *panel; | ||
| 34 | struct gpio_desc *gpio_pd_n; | 33 | struct gpio_desc *gpio_pd_n; |
| 35 | struct gpio_desc *gpio_rst_n; | 34 | struct gpio_desc *gpio_rst_n; |
| 36 | u32 edid_emulation; | 35 | u32 edid_emulation; |
| @@ -127,11 +126,6 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge) · 90 unmodified lines | |||
| 127 | usleep_range(10, 20); | 126 | usleep_range(10, 20); |
| 128 | gpiod_set_value(ptn_bridge->gpio_rst_n, 1); | 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 | * There's a bug in the PTN chip where it falsely asserts hotplug before | 130 | * There's a bug in the PTN chip where it falsely asserts hotplug before |
| 137 | * it is fully functional. We're forced to wait for the maximum start up | 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 | ptn_bridge->enabled = true; | 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 | static void ptn3460_disable(struct drm_bridge *bridge) | 143 | static void ptn3460_disable(struct drm_bridge *bridge) |
| 160 | { | 144 | { |
| 161 | struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); | 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 | ptn_bridge->enabled = false; | 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 | gpiod_set_value(ptn_bridge->gpio_rst_n, 1); | 152 | gpiod_set_value(ptn_bridge->gpio_rst_n, 1); |
| 174 | gpiod_set_value(ptn_bridge->gpio_pd_n, 0); | 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)) { | 157 | static struct edid *ptn3460_get_edid(struct drm_bridge *bridge, |
| 182 | DRM_ERROR("failed to unprepare panel\n"); | 158 | struct drm_connector *connector) |
| 183 | return; | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 187 | static int ptn3460_get_modes(struct drm_connector *connector) | ||
| 188 | { | 159 | { |
| 189 | struct ptn3460_bridge *ptn_bridge; | 160 | struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); |
| 190 | u8 *edid; | ||
| 191 | int ret, num_modes = 0; | ||
| 192 | bool power_off; | 161 | bool power_off; |
| 193 | 162 | u8 *edid; | |
| 194 | ptn_bridge = connector_to_ptn3460(connector); | 163 | int ret; |
| 195 | |||
| 196 | if (ptn_bridge->edid) | ||
| 197 | return drm_add_edid_modes(connector, ptn_bridge->edid); | ||
| 198 | 164 | ||
| 199 | power_off = !ptn_bridge->enabled; | 165 | power_off = !ptn_bridge->enabled; |
| 200 | ptn3460_pre_enable(&ptn_bridge->bridge); | 166 | ptn3460_pre_enable(&ptn_bridge->bridge); |
| @@ -202,30 +168,40 @@ static int ptn3460_get_modes(struct drm_connector *connector) · 1 unmodified line | |||
| 202 | edid = kmalloc(EDID_LENGTH, GFP_KERNEL); | 168 | edid = kmalloc(EDID_LENGTH, GFP_KERNEL); |
| 203 | if (!edid) { | 169 | if (!edid) { |
| 204 | DRM_ERROR("Failed to allocate EDID\n"); | 170 | DRM_ERROR("Failed to allocate EDID\n"); |
| 205 | return 0; | 171 | goto out; |
| 206 | } | 172 | } |
| 207 | 173 | ||
| 208 | ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid, | 174 | ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid, |
| 209 | EDID_LENGTH); | 175 | EDID_LENGTH); |
| 210 | if (ret) { | 176 | if (ret) { |
| 211 | kfree(edid); | 177 | kfree(edid); |
| 178 | edid = NULL; | ||
| 212 | goto out; | 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 | out: | 182 | out: |
| 221 | if (power_off) | 183 | if (power_off) |
| 222 | ptn3460_disable(&ptn_bridge->bridge); | 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 | return num_modes; | 200 | return num_modes; |
| 225 | } | 201 | } |
| 226 | 202 | ||
| 227 | static const struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { | 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 | static const struct drm_connector_funcs ptn3460_connector_funcs = { | 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 | struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); | 218 | struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); |
| 243 | int ret; | 219 | int ret; |
| 244 | 220 | ||
| 245 | if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { | 221 | /* Let this driver create connector if requested */ |
| 246 | DRM_ERROR("Fix bridge driver to make connector optional!"); | 222 | ret = drm_bridge_attach(bridge->encoder, ptn_bridge->panel_bridge, |
| 247 | return -EINVAL; | 223 | bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR); |
| 248 | } | 224 | if (ret < 0) |
| 225 | return ret; | ||
| 226 | |||
| 227 | if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) | ||
| 228 | return 0; | ||
| 249 | 229 | ||
| 250 | if (!bridge->encoder) { | 230 | if (!bridge->encoder) { |
| 251 | DRM_ERROR("Parent encoder object not found"); | 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 | drm_connector_attach_encoder(&ptn_bridge->connector, | 245 | drm_connector_attach_encoder(&ptn_bridge->connector, |
| 266 | bridge->encoder); | 246 | bridge->encoder); |
| 267 | 247 | ||
| 268 | if (ptn_bridge->panel) | ||
| 269 | drm_panel_attach(ptn_bridge->panel, &ptn_bridge->connector); | ||
| 270 | |||
| 271 | drm_helper_hpd_irq_event(ptn_bridge->connector.dev); | 248 | drm_helper_hpd_irq_event(ptn_bridge->connector.dev); |
| 272 | 249 | ||
| 273 | return ret; | 250 | return ret; |
| @@ -275,10 +252,9 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge, · 1 unmodified line | |||
| 275 | 252 | ||
| 276 | static const struct drm_bridge_funcs ptn3460_bridge_funcs = { | 253 | static const struct drm_bridge_funcs ptn3460_bridge_funcs = { |
| 277 | .pre_enable = ptn3460_pre_enable, | 254 | .pre_enable = ptn3460_pre_enable, |
| 278 | .enable = ptn3460_enable, | ||
| 279 | .disable = ptn3460_disable, | 255 | .disable = ptn3460_disable, |
| 280 | .post_disable = ptn3460_post_disable, | ||
| 281 | .attach = ptn3460_bridge_attach, | 256 | .attach = ptn3460_bridge_attach, |
| 257 | .get_edid = ptn3460_get_edid, | ||
| 282 | }; | 258 | }; |
| 283 | 259 | ||
| 284 | static int ptn3460_probe(struct i2c_client *client, | 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 | struct device *dev = &client->dev; | 263 | struct device *dev = &client->dev; |
| 288 | struct ptn3460_bridge *ptn_bridge; | 264 | struct ptn3460_bridge *ptn_bridge; |
| 265 | struct drm_bridge *panel_bridge; | ||
| 266 | struct drm_panel *panel; | ||
| 289 | int ret; | 267 | int ret; |
| 290 | 268 | ||
| 291 | ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL); | 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 | return -ENOMEM; | 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 | if (ret) | 275 | if (ret) |
| 298 | return ret; | 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 | ptn_bridge->client = client; | 283 | ptn_bridge->client = client; |
| 301 | 284 | ||
| 302 | ptn_bridge->gpio_pd_n = devm_gpiod_get(&client->dev, "powerdown", | 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 | ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs; | 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 | ptn_bridge->bridge.of_node = dev->of_node; | 315 | ptn_bridge->bridge.of_node = dev->of_node; |
| 331 | drm_bridge_add(&ptn_bridge->bridge); | 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 | drm_connector_attach_encoder(&panel_bridge->connector, | 82 | drm_connector_attach_encoder(&panel_bridge->connector, |
| 83 | bridge->encoder); | 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 | return 0; | 85 | return 0; |
| 90 | } | 86 | } |
| 91 | 87 | ||
| 92 | static void panel_bridge_detach(struct drm_bridge *bridge) | 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 | static void panel_bridge_pre_enable(struct drm_bridge *bridge) | 92 | static void panel_bridge_pre_enable(struct drm_bridge *bridge) |
| @@ -42,10 +42,9 @@ · 41 unmodified lines | |||
| 42 | #endif | 42 | #endif |
| 43 | 43 | ||
| 44 | struct ps8622_bridge { | 44 | struct ps8622_bridge { |
| 45 | struct drm_connector connector; | ||
| 46 | struct i2c_client *client; | 45 | struct i2c_client *client; |
| 47 | struct drm_bridge bridge; | 46 | struct drm_bridge bridge; |
| 48 | struct drm_panel *panel; | 47 | struct drm_bridge *panel_bridge; |
| 49 | struct regulator *v12; | 48 | struct regulator *v12; |
| 50 | struct backlight_device *bl; | 49 | struct backlight_device *bl; |
| 51 | 50 | ||
| @@ -64,12 +63,6 @@ static inline struct ps8622_bridge * · 12 unmodified lines | |||
| 64 | return container_of(bridge, struct ps8622_bridge, bridge); | 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 | static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val) | 66 | static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val) |
| 74 | { | 67 | { |
| 75 | int ret; | 68 | int ret; |
| @@ -365,11 +358,6 @@ static void ps8622_pre_enable(struct drm_bridge *bridge) · 289 unmodified lines | |||
| 365 | DRM_ERROR("fails to enable ps8622->v12"); | 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 | gpiod_set_value(ps8622->gpio_slp, 1); | 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 | ps8622->enabled = true; | 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 | static void ps8622_disable(struct drm_bridge *bridge) | 390 | static void ps8622_disable(struct drm_bridge *bridge) |
| 413 | { | 391 | { |
| 414 | struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); | 392 | /* Delay after panel is disabled */ |
| 415 | |||
| 416 | if (drm_panel_disable(ps8622->panel)) { | ||
| 417 | DRM_ERROR("failed to disable panel\n"); | ||
| 418 | return; | ||
| 419 | } | ||
| 420 | msleep(PS8622_PWMO_END_T12_MS); | 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 | gpiod_set_value(ps8622->gpio_slp, 0); | 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 | if (ps8622->v12) | 412 | if (ps8622->v12) |
| 445 | regulator_disable(ps8622->v12); | 413 | regulator_disable(ps8622->v12); |
| 446 | 414 | ||
| @@ -455,67 +423,17 @@ static void ps8622_post_disable(struct drm_bridge *bridge) · 8 unmodified lines | |||
| 455 | msleep(PS8622_POWER_OFF_T17_MS); | 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 | static int ps8622_attach(struct drm_bridge *bridge, | 426 | static int ps8622_attach(struct drm_bridge *bridge, |
| 480 | enum drm_bridge_attach_flags flags) | 427 | enum drm_bridge_attach_flags flags) |
| 481 | { | 428 | { |
| 482 | struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); | 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) { | 431 | return drm_bridge_attach(ps8622->bridge.encoder, ps8622->panel_bridge, |
| 491 | DRM_ERROR("Parent encoder object not found"); | 432 | &ps8622->bridge, flags); |
| 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; | ||
| 514 | } | 433 | } |
| 515 | 434 | ||
| 516 | static const struct drm_bridge_funcs ps8622_bridge_funcs = { | 435 | static const struct drm_bridge_funcs ps8622_bridge_funcs = { |
| 517 | .pre_enable = ps8622_pre_enable, | 436 | .pre_enable = ps8622_pre_enable, |
| 518 | .enable = ps8622_enable, | ||
| 519 | .disable = ps8622_disable, | 437 | .disable = ps8622_disable, |
| 520 | .post_disable = ps8622_post_disable, | 438 | .post_disable = ps8622_post_disable, |
| 521 | .attach = ps8622_attach, | 439 | .attach = ps8622_attach, |
| @@ -533,16 +451,23 @@ static int ps8622_probe(struct i2c_client *client, · 11 unmodified lines | |||
| 533 | { | 451 | { |
| 534 | struct device *dev = &client->dev; | 452 | struct device *dev = &client->dev; |
| 535 | struct ps8622_bridge *ps8622; | 453 | struct ps8622_bridge *ps8622; |
| 454 | struct drm_bridge *panel_bridge; | ||
| 455 | struct drm_panel *panel; | ||
| 536 | int ret; | 456 | int ret; |
| 537 | 457 | ||
| 538 | ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL); | 458 | ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL); |
| 539 | if (!ps8622) | 459 | if (!ps8622) |
| 540 | return -ENOMEM; | 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 | if (ret) | 463 | if (ret) |
| 544 | return ret; | 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 | ps8622->client = client; | 471 | ps8622->client = client; |
| 547 | 472 | ||
| 548 | ps8622->v12 = devm_regulator_get(dev, "vdd12"); | 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 | ps8622->bridge.funcs = &ps8622_bridge_funcs; | 522 | ps8622->bridge.funcs = &ps8622_bridge_funcs; |
| 523 | ps8622->bridge.type = DRM_MODE_CONNECTOR_LVDS; | ||
| 598 | ps8622->bridge.of_node = dev->of_node; | 524 | ps8622->bridge.of_node = dev->of_node; |
| 599 | drm_bridge_add(&ps8622->bridge); | 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 | ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD, | 82 | ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD, |
| 83 | sizeof(vdo_ctrl_buf), | 83 | sizeof(vdo_ctrl_buf), |
| 84 | vdo_ctrl_buf); | 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 | return ret; | 88 | return ret; |
| 89 | } | ||
| 87 | 90 | ||
| 88 | return 0; | 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 | ret = ps8640_bridge_vdo_control(ps_bridge, ENABLE); | 155 | ret = ps8640_bridge_vdo_control(ps_bridge, ENABLE); |
| 153 | if (ret) { | 156 | if (ret) |
| 154 | DRM_ERROR("failed to enable VDO: %d\n", ret); | ||
| 155 | goto err_regulators_disable; | 157 | goto err_regulators_disable; |
| 156 | } | ||
| 157 | 158 | ||
| 158 | /* Switch access edp panel's edid through i2c */ | 159 | /* Switch access edp panel's edid through i2c */ |
| 159 | ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS, | 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 | struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); | 176 | struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); |
| 176 | int ret; | 177 | int ret; |
| 177 | 178 | ||
| 178 | ret = ps8640_bridge_vdo_control(ps_bridge, DISABLE); | 179 | ps8640_bridge_vdo_control(ps_bridge, DISABLE); |
| 179 | if (ret < 0) | ||
| 180 | DRM_ERROR("failed to disable VDO: %d\n", ret); | ||
| 181 | 180 | ||
| 182 | gpiod_set_value(ps_bridge->gpio_reset, 1); | 181 | gpiod_set_value(ps_bridge->gpio_reset, 1); |
| 183 | gpiod_set_value(ps_bridge->gpio_powerdown, 1); | 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 | .channel = 0, | 199 | .channel = 0, |
| 201 | .node = NULL, | 200 | .node = NULL, |
| 202 | }; | 201 | }; |
| 202 | |||
| 203 | if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) | ||
| 204 | return -EINVAL; | ||
| 205 | |||
| 203 | /* port@0 is ps8640 dsi input port */ | 206 | /* port@0 is ps8640 dsi input port */ |
| 204 | in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1); | 207 | in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1); |
| 205 | if (!in_ep) | 208 | if (!in_ep) |
| @@ -242,8 +245,18 @@ err_dsi_attach: · 36 unmodified lines | |||
| 242 | return ret; | 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 | static const struct drm_bridge_funcs ps8640_bridge_funcs = { | 257 | static const struct drm_bridge_funcs ps8640_bridge_funcs = { |
| 246 | .attach = ps8640_bridge_attach, | 258 | .attach = ps8640_bridge_attach, |
| 259 | .get_edid = ps8640_bridge_get_edid, | ||
| 247 | .post_disable = ps8640_post_disable, | 260 | .post_disable = ps8640_post_disable, |
| 248 | .pre_enable = ps8640_pre_enable, | 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 | ps_bridge->bridge.funcs = &ps8640_bridge_funcs; | 308 | ps_bridge->bridge.funcs = &ps8640_bridge_funcs; |
| 296 | ps_bridge->bridge.of_node = dev->of_node; | 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 | ps_bridge->page[PAGE0_DP_CNTL] = client; | 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 | struct tc358764 { | 153 | struct tc358764 { |
| 154 | struct device *dev; | 154 | struct device *dev; |
| 155 | struct drm_bridge bridge; | 155 | struct drm_bridge bridge; |
| 156 | struct drm_connector connector; | ||
| 157 | struct regulator_bulk_data supplies[ARRAY_SIZE(tc358764_supplies)]; | 156 | struct regulator_bulk_data supplies[ARRAY_SIZE(tc358764_supplies)]; |
| 158 | struct gpio_desc *gpio_reset; | 157 | struct gpio_desc *gpio_reset; |
| 159 | struct drm_panel *panel; | 158 | struct drm_bridge *panel_bridge; |
| 160 | int error; | 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 | return container_of(bridge, struct tc358764, bridge); | 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 | static int tc358764_init(struct tc358764 *ctx) | 212 | static int tc358764_init(struct tc358764 *ctx) |
| 220 | { | 213 | { |
| 221 | u32 v = 0; | 214 | u32 v = 0; |
| @@ -278,43 +271,11 @@ static void tc358764_reset(struct tc358764 *ctx) · 56 unmodified lines | |||
| 278 | usleep_range(1000, 2000); | 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 | static void tc358764_post_disable(struct drm_bridge *bridge) | 274 | static void tc358764_post_disable(struct drm_bridge *bridge) |
| 311 | { | 275 | { |
| 312 | struct tc358764 *ctx = bridge_to_tc358764(bridge); | 276 | struct tc358764 *ctx = bridge_to_tc358764(bridge); |
| 313 | int ret; | 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 | tc358764_reset(ctx); | 279 | tc358764_reset(ctx); |
| 319 | usleep_range(10000, 15000); | 280 | usleep_range(10000, 15000); |
| 320 | ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); | 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 | ret = tc358764_init(ctx); | 296 | ret = tc358764_init(ctx); |
| 336 | if (ret < 0) | 297 | if (ret < 0) |
| 337 | dev_err(ctx->dev, "error initializing bridge (%d)\n", ret); | 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 | static int tc358764_attach(struct drm_bridge *bridge, | 301 | static int tc358764_attach(struct drm_bridge *bridge, |
| 353 | enum drm_bridge_attach_flags flags) | 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 | struct tc358764 *ctx = bridge_to_tc358764(bridge); | 304 | struct tc358764 *ctx = bridge_to_tc358764(bridge); |
| 386 | 305 | ||
| 387 | drm_connector_unregister(&ctx->connector); | 306 | return drm_bridge_attach(bridge->encoder, ctx->panel_bridge, |
| 388 | drm_panel_detach(ctx->panel); | 307 | bridge, flags); |
| 389 | ctx->panel = NULL; | ||
| 390 | drm_connector_put(&ctx->connector); | ||
| 391 | } | 308 | } |
| 392 | 309 | ||
| 393 | static const struct drm_bridge_funcs tc358764_bridge_funcs = { | 310 | static const struct drm_bridge_funcs tc358764_bridge_funcs = { |
| 394 | .disable = tc358764_disable, | ||
| 395 | .post_disable = tc358764_post_disable, | 311 | .post_disable = tc358764_post_disable, |
| 396 | .enable = tc358764_enable, | ||
| 397 | .pre_enable = tc358764_pre_enable, | 312 | .pre_enable = tc358764_pre_enable, |
| 398 | .attach = tc358764_attach, | 313 | .attach = tc358764_attach, |
| 399 | .detach = tc358764_detach, | ||
| 400 | }; | 314 | }; |
| 401 | 315 | ||
| 402 | static int tc358764_parse_dt(struct tc358764 *ctx) | 316 | static int tc358764_parse_dt(struct tc358764 *ctx) |
| 403 | { | 317 | { |
| 318 | struct drm_bridge *panel_bridge; | ||
| 404 | struct device *dev = ctx->dev; | 319 | struct device *dev = ctx->dev; |
| 320 | struct drm_panel *panel; | ||
| 405 | int ret; | 321 | int ret; |
| 406 | 322 | ||
| 407 | ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); | 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 | return PTR_ERR(ctx->gpio_reset); | 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, | 329 | ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL); |
| 414 | NULL); | 330 | if (ret) |
| 415 | if (ret && ret != -EPROBE_DEFER) | 331 | return ret; |
| 416 | dev_err(dev, "cannot find panel (%d)\n", 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 | static int tc358764_configure_regulators(struct tc358764 *ctx) | 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 | return ret; | 381 | return ret; |
| 462 | 382 | ||
| 463 | ctx->bridge.funcs = &tc358764_bridge_funcs; | 383 | ctx->bridge.funcs = &tc358764_bridge_funcs; |
| 384 | ctx->bridge.type = DRM_MODE_CONNECTOR_LVDS; | ||
| 464 | ctx->bridge.of_node = dev->of_node; | 385 | ctx->bridge.of_node = dev->of_node; |
| 465 | 386 | ||
| 466 | drm_bridge_add(&ctx->bridge); | 387 | drm_bridge_add(&ctx->bridge); |
| @@ -244,14 +244,12 @@ struct tc_data { · 243 unmodified lines | |||
| 244 | struct drm_dp_aux aux; | 244 | struct drm_dp_aux aux; |
| 245 | 245 | ||
| 246 | struct drm_bridge bridge; | 246 | struct drm_bridge bridge; |
| 247 | struct drm_bridge *panel_bridge; | ||
| 247 | struct drm_connector connector; | 248 | struct drm_connector connector; |
| 248 | struct drm_panel *panel; | ||
| 249 | 249 | ||
| 250 | /* link settings */ | 250 | /* link settings */ |
| 251 | struct tc_edp_link link; | 251 | struct tc_edp_link link; |
| 252 | 252 | ||
| 253 | /* display edid */ | ||
| 254 | struct edid *edid; | ||
| 255 | /* current mode */ | 253 | /* current mode */ |
| 256 | struct drm_display_mode mode; | 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 | return 0; | 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 | static void tc_bridge_enable(struct drm_bridge *bridge) | 1237 | static void tc_bridge_enable(struct drm_bridge *bridge) |
| 1247 | { | 1238 | { |
| 1248 | struct tc_data *tc = bridge_to_tc(bridge); | 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 | tc_main_link_disable(tc); | 1257 | tc_main_link_disable(tc); |
| 1267 | return; | 1258 | return; |
| 1268 | } | 1259 | } |
| 1269 | |||
| 1270 | drm_panel_enable(tc->panel); | ||
| 1271 | } | 1260 | } |
| 1272 | 1261 | ||
| 1273 | static void tc_bridge_disable(struct drm_bridge *bridge) | 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 | struct tc_data *tc = bridge_to_tc(bridge); | 1264 | struct tc_data *tc = bridge_to_tc(bridge); |
| 1276 | int ret; | 1265 | int ret; |
| 1277 | 1266 | ||
| 1278 | drm_panel_disable(tc->panel); | ||
| 1279 | |||
| 1280 | ret = tc_stream_disable(tc); | 1267 | ret = tc_stream_disable(tc); |
| 1281 | if (ret < 0) | 1268 | if (ret < 0) |
| 1282 | dev_err(tc->dev, "main link stream stop error: %d\n", ret); | 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 | dev_err(tc->dev, "main link disable error: %d\n", ret); | 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 | static bool tc_bridge_mode_fixup(struct drm_bridge *bridge, | 1276 | static bool tc_bridge_mode_fixup(struct drm_bridge *bridge, |
| 1297 | const struct drm_display_mode *mode, | 1277 | const struct drm_display_mode *mode, |
| 1298 | struct drm_display_mode *adj) | 1278 | struct drm_display_mode *adj) |
| @@ -1335,11 +1315,19 @@ static void tc_bridge_mode_set(struct drm_bridge *bridge, · 36 unmodified lines | |||
| 1335 | tc->mode = *mode; | 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 | static int tc_connector_get_modes(struct drm_connector *connector) | 1326 | static int tc_connector_get_modes(struct drm_connector *connector) |
| 1339 | { | 1327 | { |
| 1340 | struct tc_data *tc = connector_to_tc(connector); | 1328 | struct tc_data *tc = connector_to_tc(connector); |
| 1329 | int num_modes; | ||
| 1341 | struct edid *edid; | 1330 | struct edid *edid; |
| 1342 | int count; | ||
| 1343 | int ret; | 1331 | int ret; |
| 1344 | 1332 | ||
| 1345 | ret = tc_get_display_props(tc); | 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 | return 0; | 1336 | return 0; |
| 1349 | } | 1337 | } |
| 1350 | 1338 | ||
| 1351 | count = drm_panel_get_modes(tc->panel, connector); | 1339 | if (tc->panel_bridge) { |
| 1352 | if (count > 0) | 1340 | num_modes = drm_bridge_get_modes(tc->panel_bridge, connector); |
| 1353 | return count; | 1341 | if (num_modes > 0) |
| 1354 | 1342 | return num_modes; | |
| 1355 | edid = drm_get_edid(connector, &tc->aux.ddc); | 1343 | } |
| 1356 | |||
| 1357 | kfree(tc->edid); | ||
| 1358 | tc->edid = edid; | ||
| 1359 | if (!edid) | ||
| 1360 | return 0; | ||
| 1361 | 1344 | ||
| 1362 | drm_connector_update_edid_property(connector, edid); | 1345 | edid = tc_get_edid(&tc->bridge, connector); |
| 1363 | count = drm_add_edid_modes(connector, edid); | 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 | static const struct drm_connector_helper_funcs tc_connector_helper_funcs = { | 1352 | static const struct drm_connector_helper_funcs tc_connector_helper_funcs = { |
| 1369 | .get_modes = tc_connector_get_modes, | 1353 | .get_modes = tc_connector_get_modes, |
| 1370 | }; | 1354 | }; |
| 1371 | 1355 | ||
| 1372 | static enum drm_connector_status tc_connector_detect(struct drm_connector *connector, | 1356 | static enum drm_connector_status tc_bridge_detect(struct drm_bridge *bridge) |
| 1373 | bool force) | ||
| 1374 | { | 1357 | { |
| 1375 | struct tc_data *tc = connector_to_tc(connector); | 1358 | struct tc_data *tc = bridge_to_tc(bridge); |
| 1376 | bool conn; | 1359 | bool conn; |
| 1377 | u32 val; | 1360 | u32 val; |
| 1378 | int ret; | 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 | ret = regmap_read(tc->regmap, GPIOI, &val); | 1363 | ret = regmap_read(tc->regmap, GPIOI, &val); |
| 1388 | if (ret) | 1364 | if (ret) |
| 1389 | return connector_status_unknown; | 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 | return connector_status_disconnected; | 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 | static const struct drm_connector_funcs tc_connector_funcs = { | 1389 | static const struct drm_connector_funcs tc_connector_funcs = { |
| 1400 | .detect = tc_connector_detect, | 1390 | .detect = tc_connector_detect, |
| 1401 | .fill_modes = drm_helper_probe_single_connector_modes, | 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 | struct drm_device *drm = bridge->dev; | 1403 | struct drm_device *drm = bridge->dev; |
| 1414 | int ret; | 1404 | int ret; |
| 1415 | 1405 | ||
| 1416 | if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { | 1406 | if (tc->panel_bridge) { |
| 1417 | DRM_ERROR("Fix bridge driver to make connector optional!"); | 1407 | /* If a connector is required then this driver shall create it */ |
| 1418 | return -EINVAL; | 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 | /* Create DP/eDP connector */ | 1417 | /* Create DP/eDP connector */ |
| 1422 | drm_connector_helper_add(&tc->connector, &tc_connector_helper_funcs); | 1418 | drm_connector_helper_add(&tc->connector, &tc_connector_helper_funcs); |
| 1423 | ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs, | 1419 | ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs, tc->bridge.type); |
| 1424 | tc->panel ? DRM_MODE_CONNECTOR_eDP : | ||
| 1425 | DRM_MODE_CONNECTOR_DisplayPort); | ||
| 1426 | if (ret) | 1420 | if (ret) |
| 1427 | return ret; | 1421 | return ret; |
| 1428 | 1422 | ||
| @@ -1435,9 +1429,6 @@ static int tc_bridge_attach(struct drm_bridge *bridge, · 6 unmodified lines | |||
| 1435 | DRM_CONNECTOR_POLL_DISCONNECT; | 1429 | DRM_CONNECTOR_POLL_DISCONNECT; |
| 1436 | } | 1430 | } |
| 1437 | 1431 | ||
| 1438 | if (tc->panel) | ||
| 1439 | drm_panel_attach(tc->panel, &tc->connector); | ||
| 1440 | |||
| 1441 | drm_display_info_set_bus_formats(&tc->connector.display_info, | 1432 | drm_display_info_set_bus_formats(&tc->connector.display_info, |
| 1442 | &bus_format, 1); | 1433 | &bus_format, 1); |
| 1443 | tc->connector.display_info.bus_flags = | 1434 | tc->connector.display_info.bus_flags = |
| @@ -1453,11 +1444,11 @@ static const struct drm_bridge_funcs tc_bridge_funcs = { · 9 unmodified lines | |||
| 1453 | .attach = tc_bridge_attach, | 1444 | .attach = tc_bridge_attach, |
| 1454 | .mode_valid = tc_mode_valid, | 1445 | .mode_valid = tc_mode_valid, |
| 1455 | .mode_set = tc_bridge_mode_set, | 1446 | .mode_set = tc_bridge_mode_set, |
| 1456 | .pre_enable = tc_bridge_pre_enable, | ||
| 1457 | .enable = tc_bridge_enable, | 1447 | .enable = tc_bridge_enable, |
| 1458 | .disable = tc_bridge_disable, | 1448 | .disable = tc_bridge_disable, |
| 1459 | .post_disable = tc_bridge_post_disable, | ||
| 1460 | .mode_fixup = tc_bridge_mode_fixup, | 1449 | .mode_fixup = tc_bridge_mode_fixup, |
| 1450 | .detect = tc_bridge_detect, | ||
| 1451 | .get_edid = tc_get_edid, | ||
| 1461 | }; | 1452 | }; |
| 1462 | 1453 | ||
| 1463 | static bool tc_readable_reg(struct device *dev, unsigned int reg) | 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 | static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) | 1538 | static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) |
| 1548 | { | 1539 | { |
| 1549 | struct device *dev = &client->dev; | 1540 | struct device *dev = &client->dev; |
| 1541 | struct drm_panel *panel; | ||
| 1550 | struct tc_data *tc; | 1542 | struct tc_data *tc; |
| 1551 | int ret; | 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 | tc->dev = dev; | 1549 | tc->dev = dev; |
| 1558 | 1550 | ||
| 1559 | /* port@2 is the output port */ | 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 | if (ret && ret != -ENODEV) | 1553 | if (ret && ret != -ENODEV) |
| 1562 | return ret; | 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 | /* Shut down GPIO is optional */ | 1569 | /* Shut down GPIO is optional */ |
| 1565 | tc->sd_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH); | 1570 | tc->sd_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH); |
| 1566 | if (IS_ERR(tc->sd_gpio)) | 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 | return ret; | 1685 | return ret; |
| 1681 | 1686 | ||
| 1682 | tc->bridge.funcs = &tc_bridge_funcs; | 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 | tc->bridge.of_node = dev->of_node; | 1692 | tc->bridge.of_node = dev->of_node; |
| 1684 | drm_bridge_add(&tc->bridge); | 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 | pdata->dsi = dsi; | 395 | pdata->dsi = dsi; |
| 396 | 396 | ||
| 397 | /* attach panel to bridge */ | ||
| 398 | drm_panel_attach(pdata->panel, &pdata->connector); | ||
| 399 | |||
| 400 | return 0; | 397 | return 0; |
| 401 | 398 | ||
| 402 | err_dsi_attach: | 399 | err_dsi_attach: |
| @@ -187,6 +187,7 @@ drm_bridge_connector_detect(struct drm_connector *connector, bool force) · 186 unmodified lines | |||
| 187 | case DRM_MODE_CONNECTOR_DPI: | 187 | case DRM_MODE_CONNECTOR_DPI: |
| 188 | case DRM_MODE_CONNECTOR_LVDS: | 188 | case DRM_MODE_CONNECTOR_LVDS: |
| 189 | case DRM_MODE_CONNECTOR_DSI: | 189 | case DRM_MODE_CONNECTOR_DSI: |
| 190 | case DRM_MODE_CONNECTOR_eDP: | ||
| 190 | status = connector_status_connected; | 191 | status = connector_status_connected; |
| 191 | break; | 192 | break; |
| 192 | default: | 193 | default: |
| @@ -850,7 +850,7 @@ static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { · 849 unmodified lines | |||
| 850 | DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) | 850 | DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) |
| 851 | 851 | ||
| 852 | static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { | 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 | { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ | 854 | { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ |
| 855 | { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ | 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 | DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) | 867 | DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) |
| 868 | 868 | ||
| 869 | static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { | 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 | { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ | 871 | { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ |
| 872 | { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ | 872 | { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ |
| 873 | { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ | 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 | DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, | 876 | DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, |
| 877 | drm_tv_subconnector_enum_list) | 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 | static const struct drm_prop_enum_list hdmi_colorspaces[] = { | 892 | static const struct drm_prop_enum_list hdmi_colorspaces[] = { |
| 880 | /* For Default case, driver will set the colorspace */ | 893 | /* For Default case, driver will set the colorspace */ |
| 881 | { DRM_MODE_COLORIMETRY_DEFAULT, "Default" }, | 894 | { DRM_MODE_COLORIMETRY_DEFAULT, "Default" }, |
| @@ -1217,6 +1230,14 @@ static const struct drm_prop_enum_list dp_colorspaces[] = { · 335 unmodified lines | |||
| 1217 | * can also expose this property to external outputs, in which case they | 1230 | * can also expose this property to external outputs, in which case they |
| 1218 | * must support "None", which should be the default (since external screens | 1231 | * must support "None", which should be the default (since external screens |
| 1219 | * have a built-in scaler). | 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 | int drm_connector_create_standard_properties(struct drm_device *dev) | 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 | EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); | 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 | * DOC: HDMI connector properties | 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 | EXPORT_SYMBOL(drm_dp_downstream_debug); | 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 | * I2C-over-AUX implementation | 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 | static void drm_gem_vram_bo_driver_move_notify(struct drm_gem_vram_object *gbo, | 654 | static void drm_gem_vram_bo_driver_move_notify(struct drm_gem_vram_object *gbo, |
| 655 | bool evict, | 655 | bool evict, |
| 656 | struct ttm_mem_reg *new_mem) | 656 | struct ttm_resource *new_mem) |
| 657 | { | 657 | { |
| 658 | struct ttm_bo_kmap_obj *kmap = &gbo->kmap; | 658 | struct ttm_bo_kmap_obj *kmap = &gbo->kmap; |
| 659 | 659 | ||
| @@ -1004,28 +1004,6 @@ err_ttm_tt_init: · 344 unmodified lines | |||
| 1004 | return NULL; | 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 | static void bo_driver_evict_flags(struct ttm_buffer_object *bo, | 1007 | static void bo_driver_evict_flags(struct ttm_buffer_object *bo, |
| 1030 | struct ttm_placement *placement) | 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 | static void bo_driver_move_notify(struct ttm_buffer_object *bo, | 1021 | static void bo_driver_move_notify(struct ttm_buffer_object *bo, |
| 1044 | bool evict, | 1022 | bool evict, |
| 1045 | struct ttm_mem_reg *new_mem) | 1023 | struct ttm_resource *new_mem) |
| 1046 | { | 1024 | { |
| 1047 | struct drm_gem_vram_object *gbo; | 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 | static int bo_driver_io_mem_reserve(struct ttm_bo_device *bdev, | 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 | struct drm_vram_mm *vmm = drm_vram_mm_of_bdev(bdev); | 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 | switch (mem->mem_type) { | 1041 | switch (mem->mem_type) { |
| 1067 | case TTM_PL_SYSTEM: /* nothing to do */ | 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 | break; | 1043 | break; |
| 1072 | case TTM_PL_VRAM: | 1044 | case TTM_PL_VRAM: |
| 1073 | mem->bus.offset = mem->start << PAGE_SHIFT; | 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 | static struct ttm_bo_driver bo_driver = { | 1056 | static struct ttm_bo_driver bo_driver = { |
| 1085 | .ttm_tt_create = bo_driver_ttm_tt_create, | 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 | .eviction_valuable = ttm_bo_eviction_valuable, | 1058 | .eviction_valuable = ttm_bo_eviction_valuable, |
| 1090 | .evict_flags = bo_driver_evict_flags, | 1059 | .evict_flags = bo_driver_evict_flags, |
| 1091 | .move_notify = bo_driver_move_notify, | 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 | struct drm_info_node *node = (struct drm_info_node *) m->private; | 1070 | struct drm_info_node *node = (struct drm_info_node *) m->private; |
| 1102 | struct drm_vram_mm *vmm = node->minor->dev->vram_mm; | 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 | struct drm_printer p = drm_seq_file_printer(m); | 1073 | struct drm_printer p = drm_seq_file_printer(m); |
| 1105 | 1074 | ||
| 1106 | spin_lock(&ttm_bo_glob.lru_lock); | 1075 | ttm_resource_manager_debug(man, &p); |
| 1107 | drm_mm_print(mm, &p); | ||
| 1108 | spin_unlock(&ttm_bo_glob.lru_lock); | ||
| 1109 | return 0; | 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 | if (ret) | 1109 | if (ret) |
| 1143 | return ret; | 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 | if (ret) | 1116 | if (ret) |
| 1147 | return ret; | 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 | static void drm_vram_mm_cleanup(struct drm_vram_mm *vmm) | 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 | ttm_bo_device_release(&vmm->bdev); | 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 | * Add a panel to the global registry so that it can be looked up by display | 71 | * Add a panel to the global registry so that it can be looked up by display |
| 72 | * drivers. | 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 | mutex_lock(&panel_lock); | 76 | mutex_lock(&panel_lock); |
| 79 | list_add_tail(&panel->list, &panel_list); | 77 | list_add_tail(&panel->list, &panel_list); |
| 80 | mutex_unlock(&panel_lock); | 78 | mutex_unlock(&panel_lock); |
| 81 | |||
| 82 | return 0; | ||
| 83 | } | 79 | } |
| 84 | EXPORT_SYMBOL(drm_panel_add); | 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 | EXPORT_SYMBOL(drm_panel_remove); | 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 | * drm_panel_prepare - power on a panel | 97 | * drm_panel_prepare - power on a panel |
| 138 | * @panel: DRM panel | 98 | * @panel: DRM panel |
| @@ -300,6 +260,49 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np) · 161 unmodified lines | |||
| 300 | return ERR_PTR(-EPROBE_DEFER); | 260 | return ERR_PTR(-EPROBE_DEFER); |
| 301 | } | 261 | } |
| 302 | EXPORT_SYMBOL(of_drm_find_panel); | 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 | #endif | 306 | #endif |
| 304 | 307 | ||
| 305 | #if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE) | 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 | prev = drm_syncobj_fence_get(syncobj); | 297 | prev = drm_syncobj_fence_get(syncobj); |
| 298 | /* You are adding an unorder point to timeline, which could cause payload returned from query_ioctl is 0! */ | 298 | /* You are adding an unorder point to timeline, which could cause payload returned from query_ioctl is 0! */ |
| 299 | if (prev && prev->seqno >= point) | 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 | dma_fence_chain_init(chain, prev, fence, point); | 301 | dma_fence_chain_init(chain, prev, fence, point); |
| 302 | rcu_assign_pointer(syncobj->fence, &chain->base); | 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 | static enum drm_connector_status | 42 | static enum drm_connector_status |
| 43 | exynos_dpi_detect(struct drm_connector *connector, bool force) | 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 | return connector_status_connected; | 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 | exynos_dpi_disable(&ctx->encoder); | 245 | exynos_dpi_disable(&ctx->encoder); |
| 251 | 246 | ||
| 252 | if (ctx->panel) | ||
| 253 | drm_panel_detach(ctx->panel); | ||
| 254 | |||
| 255 | return 0; | 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 | dsi->panel = of_drm_find_panel(device->dev.of_node); | 1553 | dsi->panel = of_drm_find_panel(device->dev.of_node); |
| 1554 | if (IS_ERR(dsi->panel)) { | 1554 | if (IS_ERR(dsi->panel)) |
| 1555 | dsi->panel = NULL; | 1555 | dsi->panel = NULL; |
| 1556 | } else { | 1556 | else |
| 1557 | drm_panel_attach(dsi->panel, &dsi->connector); | ||
| 1558 | dsi->connector.status = connector_status_connected; | 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 | if (dsi->panel) { | 1594 | if (dsi->panel) { |
| 1597 | mutex_lock(&drm->mode_config.mutex); | 1595 | mutex_lock(&drm->mode_config.mutex); |
| 1598 | exynos_dsi_disable(&dsi->encoder); | 1596 | exynos_dsi_disable(&dsi->encoder); |
| 1599 | drm_panel_detach(dsi->panel); | ||
| 1600 | dsi->panel = NULL; | 1597 | dsi->panel = NULL; |
| 1601 | dsi->connector.status = connector_status_disconnected; | 1598 | dsi->connector.status = connector_status_disconnected; |
| 1602 | mutex_unlock(&drm->mode_config.mutex); | 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 | static void fsl_dcu_drm_connector_destroy(struct drm_connector *connector) | 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 | drm_connector_unregister(connector); | 43 | drm_connector_unregister(connector); |
| 46 | drm_panel_detach(fsl_con->panel); | ||
| 47 | drm_connector_cleanup(connector); | 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 | if (ret < 0) | 98 | if (ret < 0) |
| 102 | goto err_sysfs; | 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 | return 0; | 101 | return 0; |
| 111 | 102 | ||
| 112 | err_sysfs: | 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 | intel_dp->dpcd, | 2078 | intel_dp->dpcd, |
| 2079 | sizeof(intel_dp->dpcd)); | 2079 | sizeof(intel_dp->dpcd)); |
| 2080 | cdv_intel_edp_panel_vdd_off(gma_encoder); | 2080 | cdv_intel_edp_panel_vdd_off(gma_encoder); |
| 2081 | if (ret == 0) { | 2081 | if (ret <= 0) { |
| 2082 | /* if this fails, presume the device is a ghost */ | 2082 | /* if this fails, presume the device is a ghost */ |
| 2083 | DRM_INFO("failed to retrieve link info, disabling eDP\n"); | 2083 | DRM_INFO("failed to retrieve link info, disabling eDP\n"); |
| 2084 | drm_encoder_cleanup(encoder); | 2084 | drm_encoder_cleanup(encoder); |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | |||
| 6 | **************************************************************************/ | 6 | **************************************************************************/ |
| 7 | 7 | ||
| 8 | #include <linux/delay.h> | 8 | #include <linux/delay.h> |
| 9 | #include <linux/gpio/machine.h> | ||
| 9 | 10 | ||
| 10 | #include <asm/intel_scu_ipc.h> | 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 | static int mdfld_chip_setup(struct drm_device *dev) | 523 | static int mdfld_chip_setup(struct drm_device *dev) |
| 509 | { | 524 | { |
| 510 | struct drm_psb_private *dev_priv = dev->dev_private; | 525 | struct drm_psb_private *dev_priv = dev->dev_private; |
| 511 | if (pci_enable_msi(dev->pdev)) | 526 | if (pci_enable_msi(dev->pdev)) |
| 512 | dev_warn(dev->dev, "Enabling MSI failed!\n"); | 527 | dev_warn(dev->dev, "Enabling MSI failed!\n"); |
| 513 | dev_priv->regmap = mdfld_regmap; | 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 | return mid_chip_setup(dev); | 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 | /* panel hard-reset */ | 956 | /* panel hard-reset */ |
| 957 | if (p_funcs->reset) { | 957 | if (p_funcs->reset) { |
| 958 | ret = p_funcs->reset(pipe); | 958 | ret = p_funcs->reset(dev, pipe); |
| 959 | if (ret) { | 959 | if (ret) { |
| 960 | DRM_ERROR("Panel %d hard-reset failed\n", pipe); | 960 | DRM_ERROR("Panel %d hard-reset failed\n", pipe); |
| 961 | return NULL; | 961 | return NULL; |
| @@ -28,6 +28,7 @@ · 27 unmodified lines | |||
| 28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
| 29 | #include <linux/moduleparam.h> | 29 | #include <linux/moduleparam.h> |
| 30 | #include <linux/pm_runtime.h> | 30 | #include <linux/pm_runtime.h> |
| 31 | #include <linux/gpio/consumer.h> | ||
| 31 | 32 | ||
| 32 | #include <asm/intel_scu_ipc.h> | 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 | * FIXME: current DC has no fitting unit, reject any mode setting | 368 | * FIXME: current DC has no fitting unit, reject any mode setting |
| 368 | * request | 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 | if (fixed_mode) { | 372 | if (fixed_mode) { |
| 372 | if (mode->hdisplay != fixed_mode->hdisplay) | 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 | return 0; | 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 | struct device *dev = ddev->dev; |
| 438 | int ret = 0; | 439 | struct gpio_desc *gpiod; |
| 439 | 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 | switch (pipe) { | 447 | switch (pipe) { |
| 441 | case 0: | 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 | break; | 452 | break; |
| 444 | case 2: | 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 | break; | 457 | break; |
| 447 | default: | 458 | default: |
| 448 | DRM_ERROR("Invalid output\n"); | 459 | DRM_DEV_ERROR(dev, "Invalid output pipe\n"); |
| 449 | return -EINVAL; | 460 | return -EINVAL; |
| 450 | } | 461 | } |
| 462 | gpiod_put(gpiod); | ||
| 451 | 463 | ||
| 452 | ret = gpio_request(gpio, "gfx"); | 464 | /* Flush posted writes on the device */ |
| 453 | if (ret) { | 465 | gpiod = gpiod_get(dev, "dsi-pipe0-reset", GPIOD_ASIS); |
| 454 | DRM_ERROR("gpio_rqueset failed\n"); | 466 | if (IS_ERR(gpiod)) |
| 455 | return ret; | 467 | return PTR_ERR(gpiod); |
| 456 | } | 468 | gpiod_get_value(gpiod); |
| 457 | 469 | gpiod_put(gpiod); | |
| 458 | ret = gpio_direction_output(gpio, 1); | ||
| 459 | if (ret) { | ||
| 460 | DRM_ERROR("gpio_direction_output failed\n"); | ||
| 461 | goto gpio_error; | ||
| 462 | } | ||
| 463 | 470 | ||
| 464 | gpio_get_value(128); | 471 | return 0; |
| 465 | |||
| 466 | gpio_error: | ||
| 467 | if (gpio_is_valid(gpio)) | ||
| 468 | gpio_free(gpio); | ||
| 469 | |||
| 470 | return ret; | ||
| 471 | } | 472 | } |
| 472 | 473 | ||
| 473 | /* | 474 | /* |
| @@ -531,7 +532,7 @@ void mdfld_dsi_output_init(struct drm_device *dev, · 57 unmodified lines | |||
| 531 | dsi_config->connector = dsi_connector; | 532 | dsi_config->connector = dsi_connector; |
| 532 | 533 | ||
| 533 | if (!dsi_config->fixed_mode) { | 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 | goto dsi_init_err0; | 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 | extern int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, | 373 | extern int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, |
| 374 | u32 *mode, bool hs); | 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 | #endif /*__MDFLD_DSI_OUTPUT_H__*/ | 377 | #endif /*__MDFLD_DSI_OUTPUT_H__*/ |
| @@ -54,7 +54,7 @@ struct panel_funcs { · 53 unmodified lines | |||
| 54 | const struct drm_encoder_helper_funcs *encoder_helper_funcs; | 54 | const struct drm_encoder_helper_funcs *encoder_helper_funcs; |
| 55 | struct drm_display_mode * (*get_config_mode)(struct drm_device *); | 55 | struct drm_display_mode * (*get_config_mode)(struct drm_device *); |
| 56 | int (*get_panel_info)(struct drm_device *, int, struct panel_info *); | 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 | void (*drv_ic_init)(struct mdfld_dsi_config *dsi_config, int pipe); | 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 | #include <drm/drm_encoder.h> | 13 | #include <drm/drm_encoder.h> |
| 14 | #include <drm/drm_probe_helper.h> | 14 | #include <drm/drm_probe_helper.h> |
| 15 | #include <drm/drm_vblank.h> | 15 | #include <drm/drm_vblank.h> |
| 16 | #include <linux/gpio.h> | ||
| 17 | #include "gma_display.h" | 16 | #include "gma_display.h" |
| 18 | 17 | ||
| 19 | /* | 18 | /* |
| @@ -125,7 +125,7 @@ struct psb_intel_sdvo { · 124 unmodified lines | |||
| 125 | bool is_lvds; | 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 | struct drm_display_mode *sdvo_lvds_fixed_mode; | 130 | struct drm_display_mode *sdvo_lvds_fixed_mode; |
| 131 | 131 | ||
| @@ -17,9 +17,6 @@ · 16 unmodified lines | |||
| 17 | #include <drm/drm_atomic_helper.h> | 17 | #include <drm/drm_atomic_helper.h> |
| 18 | #include <drm/drm_fourcc.h> | 18 | #include <drm/drm_fourcc.h> |
| 19 | #include <drm/drm_gem_vram_helper.h> | 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 | #include <drm/drm_vblank.h> | 20 | #include <drm/drm_vblank.h> |
| 24 | 21 | ||
| 25 | #include "hibmc_drm_drv.h" | 22 | #include "hibmc_drm_drv.h" |
| @@ -74,12 +71,12 @@ static int hibmc_plane_atomic_check(struct drm_plane *plane, · 48 unmodified lines | |||
| 74 | return PTR_ERR(crtc_state); | 71 | return PTR_ERR(crtc_state); |
| 75 | 72 | ||
| 76 | if (src_w != state->crtc_w || src_h != state->crtc_h) { | 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 | return -EINVAL; | 75 | return -EINVAL; |
| 79 | } | 76 | } |
| 80 | 77 | ||
| 81 | if (state->crtc_x < 0 || state->crtc_y < 0) { | 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 | return -EINVAL; | 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 | crtc_state->adjusted_mode.hdisplay || | 87 | crtc_state->adjusted_mode.hdisplay || |
| 91 | state->crtc_y + state->crtc_h > | 88 | state->crtc_y + state->crtc_h > |
| 92 | crtc_state->adjusted_mode.vdisplay) { | 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 | return -EINVAL; | 91 | return -EINVAL; |
| 95 | } | 92 | } |
| 96 | 93 | ||
| 97 | if (state->fb->pitches[0] % 128 != 0) { | 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 | return -EINVAL; | 96 | return -EINVAL; |
| 100 | } | 97 | } |
| 101 | return 0; | 98 | return 0; |
| @@ -160,37 +157,6 @@ static const struct drm_plane_helper_funcs hibmc_plane_helper_funcs = { · 58 unmodified lines | |||
| 160 | .atomic_update = hibmc_plane_atomic_update, | 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 | static void hibmc_crtc_dpms(struct drm_crtc *crtc, int dpms) | 160 | static void hibmc_crtc_dpms(struct drm_crtc *crtc, int dpms) |
| 195 | { | 161 | { |
| 196 | struct hibmc_drm_private *priv = crtc->dev->dev_private; | 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 | int hibmc_de_init(struct hibmc_drm_private *priv) | 503 | int hibmc_de_init(struct hibmc_drm_private *priv) |
| 538 | { | 504 | { |
| 539 | struct drm_device *dev = priv->dev; | 505 | struct drm_device *dev = priv->dev; |
| 540 | struct drm_crtc *crtc; | 506 | struct drm_crtc *crtc = &priv->crtc; |
| 541 | struct drm_plane *plane; | 507 | struct drm_plane *plane = &priv->primary_plane; |
| 542 | int ret; | 508 | int ret; |
| 543 | 509 | ||
| 544 | plane = hibmc_plane_init(priv); | 510 | ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs, |
| 545 | if (IS_ERR(plane)) { | 511 | channel_formats1, |
| 546 | DRM_ERROR("failed to create plane: %ld\n", PTR_ERR(plane)); | 512 | ARRAY_SIZE(channel_formats1), |
| 547 | return PTR_ERR(plane); | 513 | NULL, |
| 548 | } | 514 | DRM_PLANE_TYPE_PRIMARY, |
| 515 | NULL); | ||
| 549 | 516 | ||
| 550 | crtc = devm_kzalloc(dev->dev, sizeof(*crtc), GFP_KERNEL); | 517 | if (ret) { |
| 551 | if (!crtc) { | 518 | drm_err(dev, "failed to init plane: %d\n", ret); |
| 552 | DRM_ERROR("failed to alloc memory when init crtc\n"); | 519 | return ret; |
| 553 | return -ENOMEM; | ||
| 554 | } | 520 | } |
| 555 | 521 | ||
| 522 | drm_plane_helper_add(plane, &hibmc_plane_helper_funcs); | ||
| 523 | |||
| 556 | ret = drm_crtc_init_with_planes(dev, crtc, plane, | 524 | ret = drm_crtc_init_with_planes(dev, crtc, plane, |
| 557 | NULL, &hibmc_crtc_funcs, NULL); | 525 | NULL, &hibmc_crtc_funcs, NULL); |
| 558 | if (ret) { | 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 | return ret; | 528 | return ret; |
| 561 | } | 529 | } |
| 562 | 530 | ||
| 563 | ret = drm_mode_crtc_set_gamma_size(crtc, 256); | 531 | ret = drm_mode_crtc_set_gamma_size(crtc, 256); |
| 564 | if (ret) { | 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 | return ret; | 534 | return ret; |
| 567 | } | 535 | } |
| 568 | drm_crtc_helper_add(crtc, &hibmc_crtc_helper_funcs); | 536 | drm_crtc_helper_add(crtc, &hibmc_crtc_helper_funcs); |
| @@ -11,18 +11,14 @@ · 10 unmodified lines | |||
| 11 | * Jianhua Li <lijianhua@huawei.com> | 11 | * Jianhua Li <lijianhua@huawei.com> |
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #include <linux/console.h> | ||
| 15 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 16 | #include <linux/pci.h> | 15 | #include <linux/pci.h> |
| 17 | 16 | ||
| 18 | #include <drm/drm_atomic_helper.h> | 17 | #include <drm/drm_atomic_helper.h> |
| 19 | #include <drm/drm_drv.h> | 18 | #include <drm/drm_drv.h> |
| 20 | #include <drm/drm_fb_helper.h> | ||
| 21 | #include <drm/drm_gem_vram_helper.h> | 19 | #include <drm/drm_gem_vram_helper.h> |
| 22 | #include <drm/drm_irq.h> | 20 | #include <drm/drm_irq.h> |
| 23 | #include <drm/drm_managed.h> | 21 | #include <drm/drm_managed.h> |
| 24 | #include <drm/drm_print.h> | ||
| 25 | #include <drm/drm_probe_helper.h> | ||
| 26 | #include <drm/drm_vblank.h> | 22 | #include <drm/drm_vblank.h> |
| 27 | 23 | ||
| 28 | #include "hibmc_drm_drv.h" | 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 | ret = hibmc_de_init(priv); | 99 | ret = hibmc_de_init(priv); |
| 104 | if (ret) { | 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 | return ret; | 102 | return ret; |
| 107 | } | 103 | } |
| 108 | 104 | ||
| 109 | ret = hibmc_vdac_init(priv); | 105 | ret = hibmc_vdac_init(priv); |
| 110 | if (ret) { | 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 | return ret; | 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 | iosize = pci_resource_len(pdev, 1); | 212 | iosize = pci_resource_len(pdev, 1); |
| 217 | priv->mmio = devm_ioremap(dev->dev, ioaddr, iosize); | 213 | priv->mmio = devm_ioremap(dev->dev, ioaddr, iosize); |
| 218 | if (!priv->mmio) { | 214 | if (!priv->mmio) { |
| 219 | DRM_ERROR("Cannot map mmio region\n"); | 215 | drm_err(dev, "Cannot map mmio region\n"); |
| 220 | return -ENOMEM; | 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 | size = pci_resource_len(pdev, 0); | 220 | size = pci_resource_len(pdev, 0); |
| 225 | priv->fb_map = devm_ioremap(dev->dev, addr, size); | 221 | priv->fb_map = devm_ioremap(dev->dev, addr, size); |
| 226 | if (!priv->fb_map) { | 222 | if (!priv->fb_map) { |
| 227 | DRM_ERROR("Cannot map framebuffer\n"); | 223 | drm_err(dev, "Cannot map framebuffer\n"); |
| 228 | return -ENOMEM; | 224 | return -ENOMEM; |
| 229 | } | 225 | } |
| 230 | priv->fb_base = addr; | 226 | priv->fb_base = addr; |
| @@ -254,9 +250,8 @@ static int hibmc_unload(struct drm_device *dev) · 23 unmodified lines | |||
| 254 | 250 | ||
| 255 | if (dev->irq_enabled) | 251 | if (dev->irq_enabled) |
| 256 | drm_irq_uninstall(dev); | 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 | hibmc_kms_fini(priv); | 255 | hibmc_kms_fini(priv); |
| 261 | hibmc_mm_fini(priv); | 256 | hibmc_mm_fini(priv); |
| 262 | dev->dev_private = NULL; | 257 | dev->dev_private = NULL; |
| @@ -270,7 +265,7 @@ static int hibmc_load(struct drm_device *dev) · 7 unmodified lines | |||
| 270 | 265 | ||
| 271 | priv = drmm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | 266 | priv = drmm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
| 272 | if (!priv) { | 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 | return -ENOMEM; | 269 | return -ENOMEM; |
| 275 | } | 270 | } |
| 276 | dev->dev_private = priv; | 271 | dev->dev_private = priv; |
| @@ -290,19 +285,17 @@ static int hibmc_load(struct drm_device *dev) · 13 unmodified lines | |||
| 290 | 285 | ||
| 291 | ret = drm_vblank_init(dev, dev->mode_config.num_crtc); | 286 | ret = drm_vblank_init(dev, dev->mode_config.num_crtc); |
| 292 | if (ret) { | 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 | goto err; | 289 | goto err; |
| 295 | } | 290 | } |
| 296 | 291 | ||
| 297 | priv->msi_enabled = 0; | ||
| 298 | ret = pci_enable_msi(dev->pdev); | 292 | ret = pci_enable_msi(dev->pdev); |
| 299 | if (ret) { | 293 | if (ret) { |
| 300 | DRM_WARN("enabling MSI failed: %d\n", ret); | 294 | drm_warn(dev, "enabling MSI failed: %d\n", ret); |
| 301 | } else { | 295 | } else { |
| 302 | priv->msi_enabled = 1; | ||
| 303 | ret = drm_irq_install(dev, dev->pdev->irq); | 296 | ret = drm_irq_install(dev, dev->pdev->irq); |
| 304 | if (ret) | 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 | /* reset all the states of crtc/plane/encoder/connector */ | 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 | err: | 306 | err: |
| 314 | hibmc_unload(dev); | 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 | return ret; | 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 | ret = pci_enable_device(pdev); | 332 | ret = pci_enable_device(pdev); |
| 340 | if (ret) { | 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 | goto err_free; | 335 | goto err_free; |
| 343 | } | 336 | } |
| 344 | 337 | ||
| 345 | ret = hibmc_load(dev); | 338 | ret = hibmc_load(dev); |
| 346 | if (ret) { | 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 | goto err_disable; | 341 | goto err_disable; |
| 349 | } | 342 | } |
| 350 | 343 | ||
| 351 | ret = drm_dev_register(dev, 0); | 344 | ret = drm_dev_register(dev, 0); |
| 352 | if (ret) { | 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 | ret); | 347 | ret); |
| 355 | goto err_unload; | 348 | goto err_unload; |
| 356 | } | 349 | } |
| @@ -25,10 +25,11 @@ struct hibmc_drm_private { · 24 unmodified lines | |||
| 25 | void __iomem *fb_map; | 25 | void __iomem *fb_map; |
| 26 | unsigned long fb_base; | 26 | unsigned long fb_base; |
| 27 | unsigned long fb_size; | 27 | unsigned long fb_size; |
| 28 | bool msi_enabled; | ||
| 29 | 28 | ||
| 30 | /* drm */ | 29 | /* drm */ |
| 31 | struct drm_device *dev; | 30 | struct drm_device *dev; |
| 31 | struct drm_plane primary_plane; | ||
| 32 | struct drm_crtc crtc; | ||
| 32 | struct drm_encoder encoder; | 33 | struct drm_encoder encoder; |
| 33 | struct drm_connector connector; | 34 | struct drm_connector connector; |
| 34 | bool mode_config_initialized; | 35 | bool mode_config_initialized; |
| @@ -11,10 +11,8 @@ · 10 unmodified lines | |||
| 11 | * Jianhua Li <lijianhua@huawei.com> | 11 | * Jianhua Li <lijianhua@huawei.com> |
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #include <drm/drm_gem_vram_helper.h> | ||
| 15 | #include <drm/drm_atomic_helper.h> | 14 | #include <drm/drm_atomic_helper.h> |
| 16 | #include <drm/drm_probe_helper.h> | 15 | #include <drm/drm_probe_helper.h> |
| 17 | #include <drm/drm_crtc_helper.h> | ||
| 18 | #include <drm/drm_print.h> | 16 | #include <drm/drm_print.h> |
| 19 | 17 | ||
| 20 | #include "hibmc_drm_drv.h" | 18 | #include "hibmc_drm_drv.h" |
| @@ -87,7 +85,7 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv) · 66 unmodified lines | |||
| 87 | ret = drm_encoder_init(dev, encoder, &hibmc_encoder_funcs, | 85 | ret = drm_encoder_init(dev, encoder, &hibmc_encoder_funcs, |
| 88 | DRM_MODE_ENCODER_DAC, NULL); | 86 | DRM_MODE_ENCODER_DAC, NULL); |
| 89 | if (ret) { | 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 | return ret; | 89 | return ret; |
| 92 | } | 90 | } |
| 93 | 91 | ||
| @@ -96,7 +94,7 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv) · 2 unmodified lines | |||
| 96 | ret = drm_connector_init(dev, connector, &hibmc_connector_funcs, | 94 | ret = drm_connector_init(dev, connector, &hibmc_connector_funcs, |
| 97 | DRM_MODE_CONNECTOR_VGA); | 95 | DRM_MODE_CONNECTOR_VGA); |
| 98 | if (ret) { | 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 | return ret; | 98 | return ret; |
| 101 | } | 99 | } |
| 102 | drm_connector_helper_add(connector, &hibmc_connector_helper_funcs); | 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 | hibmc->fb_size); | 32 | hibmc->fb_size); |
| 33 | if (IS_ERR(vmm)) { | 33 | if (IS_ERR(vmm)) { |
| 34 | ret = PTR_ERR(vmm); | 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 | return ret; | 36 | return ret; |
| 37 | } | 37 | } |
| 38 | 38 | ||
| @@ -6243,6 +6243,11 @@ out: · 6242 unmodified lines | |||
| 6243 | */ | 6243 | */ |
| 6244 | intel_display_power_flush_work(dev_priv); | 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 | return status; | 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 | struct drm_i915_private *dev_priv = to_i915(connector->dev); | 7317 | struct drm_i915_private *dev_priv = to_i915(connector->dev); |
| 7313 | enum port port = dp_to_dig_port(intel_dp)->base.port; | 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 | if (!IS_G4X(dev_priv) && port != PORT_A) | 7323 | if (!IS_G4X(dev_priv) && port != PORT_A) |
| 7316 | intel_attach_force_audio_property(connector); | 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 | drm_connector_attach_encoder(&imx_ldb_ch->connector, encoder); | 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 | return 0; | 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 | for (i = 0; i < 2; i++) { | 695 | for (i = 0; i < 2; i++) { |
| 703 | struct imx_ldb_channel *channel = &imx_ldb->channel[i]; | 696 | struct imx_ldb_channel *channel = &imx_ldb->channel[i]; |
| 704 | 697 | ||
| 705 | if (channel->panel) | ||
| 706 | drm_panel_detach(channel->panel); | ||
| 707 | |||
| 708 | kfree(channel->edid); | 698 | kfree(channel->edid); |
| 709 | i2c_put_adapter(channel->ddc); | 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 | DRM_MODE_CONNECTOR_DPI); | 289 | DRM_MODE_CONNECTOR_DPI); |
| 290 | } | 290 | } |
| 291 | 291 | ||
| 292 | if (imxpd->panel) | ||
| 293 | drm_panel_attach(imxpd->panel, &imxpd->connector); | ||
| 294 | |||
| 295 | if (imxpd->next_bridge) { | 292 | if (imxpd->next_bridge) { |
| 296 | ret = drm_bridge_attach(encoder, imxpd->next_bridge, | 293 | ret = drm_bridge_attach(encoder, imxpd->next_bridge, |
| 297 | &imxpd->bridge, 0); | 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 | struct imx_parallel_display *imxpd = dev_get_drvdata(dev); | 355 | struct imx_parallel_display *imxpd = dev_get_drvdata(dev); |
| 359 | 356 | ||
| 360 | if (imxpd->panel) | ||
| 361 | drm_panel_detach(imxpd->panel); | ||
| 362 | |||
| 363 | kfree(imxpd->edid); | 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 | struct ingenic_drm *priv = drm_crtc_get_priv(crtc); | 200 | struct ingenic_drm *priv = drm_crtc_get_priv(crtc); |
| 201 | struct drm_plane_state *f1_state, *f0_state, *ipu_state = NULL; | 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, | 203 | if (drm_atomic_crtc_needs_modeset(state) && priv->soc_info->has_osd) { |
| 212 | state->adjusted_mode.clock * 1000); | ||
| 213 | if (rate < 0) | ||
| 214 | return rate; | ||
| 215 | |||
| 216 | if (priv->soc_info->has_osd) { | ||
| 217 | f1_state = drm_atomic_get_plane_state(state->state, &priv->f1); | 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 | f0_state = drm_atomic_get_plane_state(state->state, &priv->f0); | 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 | if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU) && priv->ipu_plane) { | 212 | if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU) && priv->ipu_plane) { |
| 221 | ipu_state = drm_atomic_get_plane_state(state->state, priv->ipu_plane); | 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 | /* IPU and F1 planes cannot be enabled at the same time. */ | 217 | /* IPU and F1 planes cannot be enabled at the same time. */ |
| 224 | if (f1_state->fb && ipu_state->fb) { | 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 | return 0; | 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 | static void ingenic_drm_crtc_atomic_begin(struct drm_crtc *crtc, | 250 | static void ingenic_drm_crtc_atomic_begin(struct drm_crtc *crtc, |
| 239 | struct drm_crtc_state *oldstate) | 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 | .atomic_begin = ingenic_drm_crtc_atomic_begin, | 660 | .atomic_begin = ingenic_drm_crtc_atomic_begin, |
| 649 | .atomic_flush = ingenic_drm_crtc_atomic_flush, | 661 | .atomic_flush = ingenic_drm_crtc_atomic_flush, |
| 650 | .atomic_check = ingenic_drm_crtc_atomic_check, | 662 | .atomic_check = ingenic_drm_crtc_atomic_check, |
| 663 | .mode_valid = ingenic_drm_crtc_mode_valid, | ||
| 651 | }; | 664 | }; |
| 652 | 665 | ||
| 653 | static const struct drm_encoder_helper_funcs ingenic_drm_encoder_helper_funcs = { | 666 | static const struct drm_encoder_helper_funcs ingenic_drm_encoder_helper_funcs = { |
| @@ -35,6 +35,7 @@ struct soc_info { · 34 unmodified lines | |||
| 35 | const u32 *formats; | 35 | const u32 *formats; |
| 36 | size_t num_formats; | 36 | size_t num_formats; |
| 37 | bool has_bicubic; | 37 | bool has_bicubic; |
| 38 | bool manual_restart; | ||
| 38 | 39 | ||
| 39 | void (*set_coefs)(struct ingenic_ipu *ipu, unsigned int reg, | 40 | void (*set_coefs)(struct ingenic_ipu *ipu, unsigned int reg, |
| 40 | unsigned int sharpness, bool downscale, | 41 | unsigned int sharpness, bool downscale, |
| @@ -48,6 +49,7 @@ struct ingenic_ipu { · 7 unmodified lines | |||
| 48 | struct regmap *map; | 49 | struct regmap *map; |
| 49 | struct clk *clk; | 50 | struct clk *clk; |
| 50 | const struct soc_info *soc_info; | 51 | const struct soc_info *soc_info; |
| 52 | bool clk_enabled; | ||
| 51 | 53 | ||
| 52 | unsigned int num_w, num_h, denom_w, denom_h; | 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 | const struct drm_format_info *finfo; | 289 | const struct drm_format_info *finfo; |
| 288 | u32 ctrl, stride = 0, coef_index = 0, format = 0; | 290 | u32 ctrl, stride = 0, coef_index = 0, format = 0; |
| 289 | bool needs_modeset, upscaling_w, upscaling_h; | 291 | bool needs_modeset, upscaling_w, upscaling_h; |
| 292 | int err; | ||
| 290 | 293 | ||
| 291 | if (!state || !state->fb) | 294 | if (!state || !state->fb) |
| 292 | return; | 295 | return; |
| 293 | 296 | ||
| 294 | finfo = drm_format_info(state->fb->format->format); | 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 | /* Reset all the registers if needed */ | 309 | /* Reset all the registers if needed */ |
| 297 | needs_modeset = drm_atomic_crtc_needs_modeset(state->crtc->state); | 310 | needs_modeset = drm_atomic_crtc_needs_modeset(state->crtc->state); |
| 298 | if (needs_modeset) { | 311 | if (needs_modeset) { |
| @@ -577,6 +590,11 @@ static void ingenic_ipu_plane_atomic_disable(struct drm_plane *plane, · 278 unmodified lines | |||
| 577 | regmap_clear_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_CHIP_EN); | 590 | regmap_clear_bits(ipu->map, JZ_REG_IPU_CTRL, JZ_IPU_CTRL_CHIP_EN); |
| 578 | 591 | ||
| 579 | ingenic_drm_plane_disable(ipu->master, plane); | 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 | static const struct drm_plane_helper_funcs ingenic_ipu_plane_helper_funcs = { | 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 | unsigned int dummy; | 663 | unsigned int dummy; |
| 646 | 664 | ||
| 647 | /* dummy read allows CPU to reconfigure IPU */ | 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 | /* ACK interrupt */ | 669 | /* ACK interrupt */ |
| 651 | regmap_write(ipu->map, JZ_REG_IPU_STATUS, 0); | 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 | regmap_write(ipu->map, JZ_REG_IPU_V_ADDR, ipu->addr_v); | 675 | regmap_write(ipu->map, JZ_REG_IPU_V_ADDR, ipu->addr_v); |
| 657 | 676 | ||
| 658 | /* Run IPU for the new frame */ | 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 | drm_crtc_handle_vblank(crtc); | 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 | drm_object_attach_property(&plane->base, ipu->sharpness_prop, | 778 | drm_object_attach_property(&plane->base, ipu->sharpness_prop, |
| 759 | ipu->sharpness); | 779 | ipu->sharpness); |
| 760 | 780 | ||
| 761 | err = clk_prepare_enable(ipu->clk); | 781 | err = clk_prepare(ipu->clk); |
| 762 | if (err) { | 782 | if (err) { |
| 763 | dev_err(dev, "Unable to enable clock\n"); | 783 | dev_err(dev, "Unable to prepare clock\n"); |
| 764 | return err; | 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 | struct ingenic_ipu *ipu = dev_get_drvdata(dev); | 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 | static const struct component_ops ingenic_ipu_ops = { | 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 | static const u32 jz4725b_ipu_formats[] = { | 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 | DRM_FORMAT_YUYV, | 820 | DRM_FORMAT_YUYV, |
| 796 | DRM_FORMAT_YVYU, | 821 | DRM_FORMAT_YVYU, |
| 797 | DRM_FORMAT_UYVY, | 822 | DRM_FORMAT_UYVY, |
| 798 | DRM_FORMAT_VYUY, | 823 | DRM_FORMAT_VYUY, |
| 824 | */ | ||
| 799 | DRM_FORMAT_YUV411, | 825 | DRM_FORMAT_YUV411, |
| 800 | DRM_FORMAT_YUV420, | 826 | DRM_FORMAT_YUV420, |
| 801 | DRM_FORMAT_YUV422, | 827 | DRM_FORMAT_YUV422, |
| @@ -806,6 +832,7 @@ static const struct soc_info jz4725b_soc_info = { · 4 unmodified lines | |||
| 806 | .formats = jz4725b_ipu_formats, | 832 | .formats = jz4725b_ipu_formats, |
| 807 | .num_formats = ARRAY_SIZE(jz4725b_ipu_formats), | 833 | .num_formats = ARRAY_SIZE(jz4725b_ipu_formats), |
| 808 | .has_bicubic = false, | 834 | .has_bicubic = false, |
| 835 | .manual_restart = true, | ||
| 809 | .set_coefs = jz4725b_set_coefs, | 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 | .formats = jz4760_ipu_formats, | 858 | .formats = jz4760_ipu_formats, |
| 832 | .num_formats = ARRAY_SIZE(jz4760_ipu_formats), | 859 | .num_formats = ARRAY_SIZE(jz4760_ipu_formats), |
| 833 | .has_bicubic = true, | 860 | .has_bicubic = true, |
| 861 | .manual_restart = false, | ||
| 834 | .set_coefs = jz4760_set_coefs, | 862 | .set_coefs = jz4760_set_coefs, |
| 835 | }; | 863 | }; |
| 836 | 864 | ||
| @@ -7,6 +7,7 @@ · 6 unmodified lines | |||
| 7 | #include <linux/clk.h> | 7 | #include <linux/clk.h> |
| 8 | #include <linux/delay.h> | 8 | #include <linux/delay.h> |
| 9 | #include <linux/dma-buf.h> | 9 | #include <linux/dma-buf.h> |
| 10 | #include <linux/regulator/consumer.h> | ||
| 10 | 11 | ||
| 11 | #include <drm/drm_device.h> | 12 | #include <drm/drm_device.h> |
| 12 | #include <drm/drm_fb_cma_helper.h> | 13 | #include <drm/drm_fb_cma_helper.h> |
| @@ -89,7 +90,7 @@ void mcde_display_irq(struct mcde *mcde) · 76 unmodified lines | |||
| 89 | * the update function is called, then we disable the | 90 | * the update function is called, then we disable the |
| 90 | * flow on the channel once we get the TE IRQ. | 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 | spin_lock(&mcde->flow_lock); | 94 | spin_lock(&mcde->flow_lock); |
| 94 | if (--mcde->flow_active == 0) { | 95 | if (--mcde->flow_active == 0) { |
| 95 | dev_dbg(mcde->dev, "TE0 IRQ\n"); | 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 | enum mcde_extsrc src, | 334 | enum mcde_extsrc src, |
| 334 | enum mcde_channel ch, | 335 | enum mcde_channel ch, |
| 335 | const struct drm_display_mode *mode, | 336 | const struct drm_display_mode *mode, |
| 336 | u32 format) | 337 | u32 format, int cpp) |
| 337 | { | 338 | { |
| 338 | u32 val; | 339 | u32 val; |
| 339 | u32 conf1; | 340 | u32 conf1; |
| @@ -342,6 +343,7 @@ static void mcde_configure_overlay(struct mcde *mcde, enum mcde_overlay ovl, · 2 unmodified lines | |||
| 342 | u32 ljinc; | 343 | u32 ljinc; |
| 343 | u32 cr; | 344 | u32 cr; |
| 344 | u32 comp; | 345 | u32 comp; |
| 346 | u32 pixel_fetcher_watermark; | ||
| 345 | 347 | ||
| 346 | switch (ovl) { | 348 | switch (ovl) { |
| 347 | case MCDE_OVERLAY_0: | 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 | format); | 428 | format); |
| 427 | break; | 429 | break; |
| 428 | } | 430 | } |
| 429 | /* The default watermark level for overlay 0 is 48 */ | 431 | |
| 430 | val |= 48 << MCDE_OVLXCONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT; | 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 | writel(val, mcde->regs + conf2); | 458 | writel(val, mcde->regs + conf2); |
| 432 | 459 | ||
| 433 | /* Number of bytes to fetch per line */ | 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 | /* Set up channel 0 sync (based on chnl_update_registers()) */ | 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 | val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE | 535 | val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE |
| 503 | << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; | 536 | << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; |
| 504 | else | 537 | val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0 |
| 505 | val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SOFTWARE | 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 | << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; | 554 | << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; |
| 507 | |||
| 508 | if (mcde->te_sync) | ||
| 509 | val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0 | 555 | val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0 |
| 510 | << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; | 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 | val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_FORMATTER | 561 | val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_FORMATTER |
| 513 | << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; | 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 | writel(val, mcde->regs + sync); | 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 | u32 formatter_frame; | 880 | u32 formatter_frame; |
| 826 | u32 pkt_div; | 881 | u32 pkt_div; |
| 827 | u32 val; | 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 | dev_info(drm->dev, "enable MCDE, %d x %d format %s\n", | 892 | dev_info(drm->dev, "enable MCDE, %d x %d format %s\n", |
| 830 | mode->hdisplay, mode->vdisplay, | 893 | mode->hdisplay, mode->vdisplay, |
| @@ -835,6 +898,26 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, · 4 unmodified lines | |||
| 835 | return; | 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 | dev_info(drm->dev, "output in %s mode, format %dbpp\n", | 921 | dev_info(drm->dev, "output in %s mode, format %dbpp\n", |
| 839 | (mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? | 922 | (mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? |
| 840 | "VIDEO" : "CMD", | 923 | "VIDEO" : "CMD", |
| @@ -904,7 +987,7 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, · 63 unmodified lines | |||
| 904 | * channel 0 | 987 | * channel 0 |
| 905 | */ | 988 | */ |
| 906 | mcde_configure_overlay(mcde, MCDE_OVERLAY_0, MCDE_EXTSRC_0, | 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 | * Configure pixel-per-line and line-per-frame for channel 0 and then | 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 | mcde_configure_fifo(mcde, MCDE_FIFO_A, MCDE_DSI_FORMATTER_0, | 999 | mcde_configure_fifo(mcde, MCDE_FIFO_A, MCDE_DSI_FORMATTER_0, |
| 917 | fifo_wtrmrk); | 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 | /* Configure the DSI formatter 0 for the DSI panel output */ | 1012 | /* Configure the DSI formatter 0 for the DSI panel output */ |
| 920 | mcde_configure_dsi_formatter(mcde, MCDE_DSI_FORMATTER_0, | 1013 | mcde_configure_dsi_formatter(mcde, MCDE_DSI_FORMATTER_0, |
| 921 | formatter_frame, pkt_size); | 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 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | 1021 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) |
| 925 | val = MCDE_VSCRC_VSPOL; | 1022 | val = MCDE_VSCRC_VSPOL; |
| 926 | else | 1023 | else |
| @@ -930,16 +1027,31 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, · 3 unmodified lines | |||
| 930 | val = readl(mcde->regs + MCDE_CRC); | 1027 | val = readl(mcde->regs + MCDE_CRC); |
| 931 | val |= MCDE_CRC_SYCEN0; | 1028 | val |= MCDE_CRC_SYCEN0; |
| 932 | writel(val, mcde->regs + MCDE_CRC); | 1029 | writel(val, mcde->regs + MCDE_CRC); |
| 1030 | break; | ||
| 1031 | default: | ||
| 1032 | /* No TE capture */ | ||
| 1033 | break; | ||
| 933 | } | 1034 | } |
| 934 | 1035 | ||
| 935 | drm_crtc_vblank_on(crtc); | 1036 | drm_crtc_vblank_on(crtc); |
| 936 | 1037 | ||
| 937 | if (mcde->video_mode) | 1038 | /* |
| 938 | /* | 1039 | * If we're using oneshot mode we don't start the flow |
| 939 | * Keep FIFO permanently enabled in video mode, | 1040 | * until each time the display is given an update, and |
| 940 | * otherwise MCDE will stop feeding data to the panel. | 1041 | * then we disable it immediately after. For all other |
| 941 | */ | 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 | mcde_enable_fifo(mcde, MCDE_FIFO_A); | 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 | dev_info(drm->dev, "MCDE display is enabled\n"); | 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 | struct drm_device *drm = crtc->dev; | 1062 | struct drm_device *drm = crtc->dev; |
| 951 | struct mcde *mcde = to_mcde(drm); | 1063 | struct mcde *mcde = to_mcde(drm); |
| 952 | struct drm_pending_vblank_event *event; | 1064 | struct drm_pending_vblank_event *event; |
| 1065 | int ret; | ||
| 953 | 1066 | ||
| 954 | drm_crtc_vblank_off(crtc); | 1067 | drm_crtc_vblank_off(crtc); |
| 955 | 1068 | ||
| 956 | /* Disable FIFO A flow */ | 1069 | /* Disable FIFO A flow */ |
| 957 | mcde_disable_fifo(mcde, MCDE_FIFO_A, true); | 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 | event = crtc->state->event; | 1075 | event = crtc->state->event; |
| 960 | if (event) { | 1076 | if (event) { |
| 961 | crtc->state->event = NULL; | 1077 | crtc->state->event = NULL; |
| @@ -965,43 +1081,47 @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe) · 3 unmodified lines | |||
| 965 | spin_unlock_irq(&crtc->dev->event_lock); | 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 | dev_info(drm->dev, "MCDE display is disabled\n"); | 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 */ | 1095 | /* Request a TE ACK only in TE+BTA mode */ |
| 974 | if (mcde->te_sync) | 1096 | if (mcde->flow_mode == MCDE_COMMAND_BTA_TE_FLOW) |
| 975 | mcde_dsi_te_request(mcde->mdsi); | 1097 | mcde_dsi_te_request(mcde->mdsi); |
| 976 | 1098 | ||
| 977 | /* Enable FIFO A flow */ | 1099 | /* Enable FIFO A flow */ |
| 978 | mcde_enable_fifo(mcde, MCDE_FIFO_A); | 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 | 1115 | * Disable FIFO A flow again: since we are using TE sync we |
| 983 | * when the TE0 IRQ arrives in the interrupt handler. Otherwise | 1116 | * need to wait for the FIFO to drain before we continue |
| 984 | * updates are continuously streamed to the display after this | 1117 | * so repeated calls to this function will not cause a mess |
| 985 | * point. | 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"); | 1121 | mcde_disable_fifo(mcde, MCDE_FIFO_A, true); |
| 988 | return; | ||
| 989 | } | 1122 | } |
| 990 | 1123 | ||
| 991 | /* Trigger a software sync out on channel 0 */ | 1124 | dev_dbg(mcde->dev, "started MCDE FIFO flow\n"); |
| 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"); | ||
| 1005 | } | 1125 | } |
| 1006 | 1126 | ||
| 1007 | static void mcde_set_extsrc(struct mcde *mcde, u32 buffer_address) | 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 | if (fb) { | 1181 | if (fb) { |
| 1062 | mcde_set_extsrc(mcde, drm_fb_cma_get_gem_addr(fb, pstate, 0)); | 1182 | mcde_set_extsrc(mcde, drm_fb_cma_get_gem_addr(fb, pstate, 0)); |
| 1063 | if (!mcde->video_mode) { | 1183 | dev_info_once(mcde->dev, "first update of display contents\n"); |
| 1064 | /* | 1184 | /* |
| 1065 | * Send a single frame using software sync if the flow | 1185 | * Usually the flow is already active, unless we are in |
| 1066 | * is not active yet. | 1186 | * oneshot mode, then we need to kick the flow right here. |
| 1067 | */ | 1187 | */ |
| 1068 | if (mcde->flow_active == 0) | 1188 | if (mcde->flow_active == 0) |
| 1069 | mcde_display_send_one_frame(mcde); | 1189 | mcde_start_flow(mcde); |
| 1070 | } | ||
| 1071 | dev_info_once(mcde->dev, "sent first display update\n"); | ||
| 1072 | } else { | 1190 | } else { |
| 1073 | /* | 1191 | /* |
| 1074 | * If an update is receieved before the MCDE is enabled | 1192 | * If an update is receieved before the MCDE is enabled |
| @@ -9,6 +9,61 @@ · 8 unmodified lines | |||
| 9 | #ifndef _MCDE_DRM_H_ | 9 | #ifndef _MCDE_DRM_H_ |
| 10 | #define _MCDE_DRM_H_ | 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 | struct mcde { | 67 | struct mcde { |
| 13 | struct drm_device drm; | 68 | struct drm_device drm; |
| 14 | struct device *dev; | 69 | struct device *dev; |
| @@ -18,9 +73,7 @@ struct mcde { · 3 unmodified lines | |||
| 18 | struct drm_simple_display_pipe pipe; | 73 | struct drm_simple_display_pipe pipe; |
| 19 | struct mipi_dsi_device *mdsi; | 74 | struct mipi_dsi_device *mdsi; |
| 20 | s16 stride; | 75 | s16 stride; |
| 21 | bool te_sync; | 76 | enum mcde_flow_mode flow_mode; |
| 22 | bool video_mode; | ||
| 23 | bool oneshot_mode; | ||
| 24 | unsigned int flow_active; | 77 | unsigned int flow_active; |
| 25 | spinlock_t flow_lock; /* Locks the channel flow control */ | 78 | spinlock_t flow_lock; /* Locks the channel flow control */ |
| 26 | 79 | ||
| @@ -36,8 +89,16 @@ struct mcde { · 9 unmodified lines | |||
| 36 | 89 | ||
| 37 | #define to_mcde(dev) container_of(dev, struct mcde, drm) | 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 | bool mcde_dsi_irq(struct mipi_dsi_device *mdsi); | 98 | bool mcde_dsi_irq(struct mipi_dsi_device *mdsi); |
| 40 | void mcde_dsi_te_request(struct mipi_dsi_device *mdsi); | 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 | extern struct platform_driver mcde_dsi_driver; | 102 | extern struct platform_driver mcde_dsi_driver; |
| 42 | 103 | ||
| 43 | void mcde_display_irq(struct mcde *mcde); | 104 | void mcde_display_irq(struct mcde *mcde); |
| @@ -63,6 +63,7 @@ · 62 unmodified lines | |||
| 63 | #include <linux/platform_device.h> | 63 | #include <linux/platform_device.h> |
| 64 | #include <linux/regulator/consumer.h> | 64 | #include <linux/regulator/consumer.h> |
| 65 | #include <linux/slab.h> | 65 | #include <linux/slab.h> |
| 66 | #include <linux/delay.h> | ||
| 66 | 67 | ||
| 67 | #include <drm/drm_atomic_helper.h> | 68 | #include <drm/drm_atomic_helper.h> |
| 68 | #include <drm/drm_bridge.h> | 69 | #include <drm/drm_bridge.h> |
| @@ -82,44 +83,6 @@ · 13 unmodified lines | |||
| 82 | 83 | ||
| 83 | #define DRIVER_DESC "DRM module for MCDE" | 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 | #define MCDE_PID 0x000001FC | 86 | #define MCDE_PID 0x000001FC |
| 124 | #define MCDE_PID_METALFIX_VERSION_SHIFT 0 | 87 | #define MCDE_PID_METALFIX_VERSION_SHIFT 0 |
| 125 | #define MCDE_PID_METALFIX_VERSION_MASK 0x000000FF | 88 | #define MCDE_PID_METALFIX_VERSION_MASK 0x000000FF |
| @@ -293,7 +256,6 @@ static int mcde_probe(struct platform_device *pdev) · 167 unmodified lines | |||
| 293 | struct component_match *match = NULL; | 256 | struct component_match *match = NULL; |
| 294 | struct resource *res; | 257 | struct resource *res; |
| 295 | u32 pid; | 258 | u32 pid; |
| 296 | u32 val; | ||
| 297 | int irq; | 259 | int irq; |
| 298 | int ret; | 260 | int ret; |
| 299 | int i; | 261 | int i; |
| @@ -305,9 +267,6 @@ static int mcde_probe(struct platform_device *pdev) · 5 unmodified lines | |||
| 305 | mcde->dev = dev; | 267 | mcde->dev = dev; |
| 306 | platform_set_drvdata(pdev, drm); | 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 | /* First obtain and turn on the main power */ | 270 | /* First obtain and turn on the main power */ |
| 312 | mcde->epod = devm_regulator_get(dev, "epod"); | 271 | mcde->epod = devm_regulator_get(dev, "epod"); |
| 313 | if (IS_ERR(mcde->epod)) { | 272 | if (IS_ERR(mcde->epod)) { |
| @@ -405,27 +364,7 @@ static int mcde_probe(struct platform_device *pdev) · 91 unmodified lines | |||
| 405 | goto clk_disable; | 364 | goto clk_disable; |
| 406 | } | 365 | } |
| 407 | 366 | ||
| 408 | /* Set up the main control, watermark level at 7 */ | 367 | /* Disable and clear any pending interrupts */ |
| 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 */ | ||
| 429 | mcde_display_disable_irqs(mcde); | 368 | mcde_display_disable_irqs(mcde); |
| 430 | writel(0, mcde->regs + MCDE_IMSCERR); | 369 | writel(0, mcde->regs + MCDE_IMSCERR); |
| 431 | writel(0xFFFFFFFF, mcde->regs + MCDE_RISERR); | 370 | writel(0xFFFFFFFF, mcde->regs + MCDE_RISERR); |
| @@ -455,12 +394,28 @@ static int mcde_probe(struct platform_device *pdev) · 23 unmodified lines | |||
| 455 | ret = PTR_ERR(match); | 394 | ret = PTR_ERR(match); |
| 456 | goto clk_disable; | 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 | ret = component_master_add_with_match(&pdev->dev, &mcde_drm_comp_ops, | 412 | ret = component_master_add_with_match(&pdev->dev, &mcde_drm_comp_ops, |
| 459 | match); | 413 | match); |
| 460 | if (ret) { | 414 | if (ret) { |
| 461 | dev_err(dev, "failed to add component master\n"); | 415 | dev_err(dev, "failed to add component master\n"); |
| 462 | goto clk_disable; | 416 | goto clk_disable; |
| 463 | } | 417 | } |
| 418 | |||
| 464 | return 0; | 419 | return 0; |
| 465 | 420 | ||
| 466 | clk_disable: | 421 | clk_disable: |
| @@ -43,6 +43,7 @@ struct mcde_dsi { · 42 unmodified lines | |||
| 43 | struct drm_bridge *bridge_out; | 43 | struct drm_bridge *bridge_out; |
| 44 | struct mipi_dsi_host dsi_host; | 44 | struct mipi_dsi_host dsi_host; |
| 45 | struct mipi_dsi_device *mdsi; | 45 | struct mipi_dsi_device *mdsi; |
| 46 | const struct drm_display_mode *mode; | ||
| 46 | struct clk *hs_clk; | 47 | struct clk *hs_clk; |
| 47 | struct clk *lp_clk; | 48 | struct clk *lp_clk; |
| 48 | unsigned long hs_freq; | 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 | d->mcde->mdsi = d->mdsi; | 150 | d->mcde->mdsi = d->mdsi; |
| 150 | 151 | ||
| 151 | d->mcde->video_mode = !!(d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO); | 152 | /* |
| 152 | /* Enable use of the TE signal for all command mode panels */ | 153 | * Select the way the DSI data flow is pushing to the display: |
| 153 | d->mcde->te_sync = !d->mcde->video_mode; | 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 | static int mcde_dsi_host_attach(struct mipi_dsi_host *host, | 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 | (type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM) || \ | 208 | (type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM) || \ |
| 195 | (type == MIPI_DSI_DCS_READ)) | 209 | (type == MIPI_DSI_DCS_READ)) |
| 196 | 210 | ||
| 197 | static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host, | 211 | static int mcde_dsi_execute_transfer(struct mcde_dsi *d, |
| 198 | const struct mipi_dsi_msg *msg) | 212 | const struct mipi_dsi_msg *msg) |
| 199 | { | 213 | { |
| 200 | struct mcde_dsi *d = host_to_mcde_dsi(host); | ||
| 201 | const u32 loop_delay_us = 10; /* us */ | 214 | const u32 loop_delay_us = 10; /* us */ |
| 202 | const u8 *tx = msg->tx_buf; | ||
| 203 | u32 loop_counter; | 215 | u32 loop_counter; |
| 204 | size_t txlen = msg->tx_len; | 216 | size_t txlen = msg->tx_len; |
| 205 | size_t rxlen = msg->rx_len; | 217 | size_t rxlen = msg->rx_len; |
| 218 | int i; | ||
| 206 | u32 val; | 219 | u32 val; |
| 207 | int ret; | 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 | writel(~0, d->regs + DSI_DIRECT_CMD_STS_CLR); | 222 | writel(~0, d->regs + DSI_DIRECT_CMD_STS_CLR); |
| 272 | writel(~0, d->regs + DSI_CMD_MODE_STS_CLR); | 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 | usleep_range(loop_delay_us, (loop_delay_us * 3) / 2); | 234 | usleep_range(loop_delay_us, (loop_delay_us * 3) / 2); |
| 284 | if (!loop_counter) { | 235 | if (!loop_counter) { |
| 285 | dev_err(d->dev, "DSI read timeout!\n"); | 236 | dev_err(d->dev, "DSI read timeout!\n"); |
| 237 | /* Set exit code and retry */ | ||
| 286 | return -ETIME; | 238 | return -ETIME; |
| 287 | } | 239 | } |
| 288 | } else { | 240 | } else { |
| @@ -293,6 +245,7 @@ static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host, · 4 unmodified lines | |||
| 293 | usleep_range(loop_delay_us, (loop_delay_us * 3) / 2); | 245 | usleep_range(loop_delay_us, (loop_delay_us * 3) / 2); |
| 294 | 246 | ||
| 295 | if (!loop_counter) { | 247 | if (!loop_counter) { |
| 248 | /* Set exit code and retry */ | ||
| 296 | dev_err(d->dev, "DSI write timeout!\n"); | 249 | dev_err(d->dev, "DSI write timeout!\n"); |
| 297 | return -ETIME; | 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 | ret = rdsz; | 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 | writel(~0, d->regs + DSI_DIRECT_CMD_STS_CLR); | 377 | writel(~0, d->regs + DSI_DIRECT_CMD_STS_CLR); |
| 338 | writel(~0, d->regs + DSI_CMD_MODE_STS_CLR); | 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 | /* Command mode, clear IF1 ID */ | 839 | /* Command mode, clear IF1 ID */ |
| 800 | val = readl(d->regs + DSI_CMD_MODE_CTL); | 840 | val = readl(d->regs + DSI_CMD_MODE_CTL); |
| 801 | /* | 841 | /* |
| 802 | * If we enable low-power mode here, with | 842 | * If we enable low-power mode here, |
| 803 | * val |= DSI_CMD_MODE_CTL_IF1_LP_EN | ||
| 804 | * then display updates become really slow. | 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 | val &= ~DSI_CMD_MODE_CTL_IF1_ID_MASK; | 847 | val &= ~DSI_CMD_MODE_CTL_IF1_ID_MASK; |
| 807 | writel(val, d->regs + DSI_CMD_MODE_CTL); | 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 | dev_info(d->dev, "DSI link enabled\n"); | 852 | dev_info(d->dev, "DSI link enabled\n"); |
| 812 | } | 853 | } |
| 813 | 854 | ||
| 814 | 855 | /* | |
| 815 | static void mcde_dsi_bridge_enable(struct drm_bridge *bridge) | 856 | * Notice that this is called from inside the display controller |
| 816 | { | 857 | * and not from the bridge callbacks. |
| 817 | struct mcde_dsi *d = bridge_to_mcde_dsi(bridge); | 858 | */ |
| 818 | u32 val; | 859 | void mcde_dsi_enable(struct drm_bridge *bridge) |
| 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) | ||
| 831 | { | 860 | { |
| 832 | struct mcde_dsi *d = bridge_to_mcde_dsi(bridge); | 861 | struct mcde_dsi *d = bridge_to_mcde_dsi(bridge); |
| 833 | unsigned long hs_freq, lp_freq; | 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 | dev_info(d->dev, "DSI HS clock rate %lu Hz\n", | 900 | dev_info(d->dev, "DSI HS clock rate %lu Hz\n", |
| 872 | d->hs_freq); | 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 | if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) { | 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 | /* Put IF1 into video mode */ | 922 | /* Put IF1 into video mode */ |
| 876 | val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL); | 923 | val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL); |
| 877 | val |= DSI_MCTL_MAIN_DATA_CTL_IF1_MODE; | 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 | val |= DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC; | 934 | val |= DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC; |
| 888 | val |= DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA; | 935 | val |= DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA; |
| 889 | writel(val, d->regs + DSI_VID_MODE_STS_CTL); | 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 | } else { | 942 | } else { |
| 891 | /* Command mode, clear IF1 ID */ | 943 | /* Command mode, clear IF1 ID */ |
| 892 | val = readl(d->regs + DSI_CMD_MODE_CTL); | 944 | val = readl(d->regs + DSI_CMD_MODE_CTL); |
| 893 | /* | 945 | /* |
| 894 | * If we enable low-power mode here with | 946 | * If we enable low-power mode here |
| 895 | * val |= DSI_CMD_MODE_CTL_IF1_LP_EN | ||
| 896 | * the display updates become really slow. | 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 | val &= ~DSI_CMD_MODE_CTL_IF1_ID_MASK; | 951 | val &= ~DSI_CMD_MODE_CTL_IF1_ID_MASK; |
| 899 | writel(val, d->regs + DSI_CMD_MODE_CTL); | 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 | static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge, | 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 | return; | 966 | return; |
| 912 | } | 967 | } |
| 913 | 968 | ||
| 969 | d->mode = mode; | ||
| 970 | |||
| 914 | dev_info(d->dev, "set DSI master to %dx%d %u Hz %s mode\n", | 971 | dev_info(d->dev, "set DSI master to %dx%d %u Hz %s mode\n", |
| 915 | mode->hdisplay, mode->vdisplay, mode->clock * 1000, | 972 | mode->hdisplay, mode->vdisplay, mode->clock * 1000, |
| 916 | (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? "VIDEO" : "CMD" | 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 | static void mcde_dsi_wait_for_command_mode_stop(struct mcde_dsi *d) | 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 | struct mcde_dsi *d = bridge_to_mcde_dsi(bridge); | 1024 | struct mcde_dsi *d = bridge_to_mcde_dsi(bridge); |
| 967 | u32 val; | 1025 | u32 val; |
| 968 | 1026 | ||
| 969 | /* Disable all error interrupts */ | ||
| 970 | writel(0, d->regs + DSI_VID_MODE_STS_CTL); | ||
| 971 | |||
| 972 | if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) { | 1027 | if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) { |
| 973 | /* Stop video mode */ | 1028 | /* Stop video mode */ |
| 974 | val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL); | 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 | mcde_dsi_wait_for_command_mode_stop(d); | 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 | clk_disable_unprepare(d->hs_clk); | 1046 | clk_disable_unprepare(d->hs_clk); |
| 985 | clk_disable_unprepare(d->lp_clk); | 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 | static const struct drm_bridge_funcs mcde_dsi_bridge_funcs = { | 1072 | static const struct drm_bridge_funcs mcde_dsi_bridge_funcs = { |
| 1011 | .attach = mcde_dsi_bridge_attach, | 1073 | .attach = mcde_dsi_bridge_attach, |
| 1012 | .mode_set = mcde_dsi_bridge_mode_set, | 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 | static int mcde_dsi_bind(struct device *dev, struct device *master, | 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 | return PTR_ERR(d->lp_clk); | 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 | /* Look for a panel as a child to this node */ | 1110 | /* Look for a panel as a child to this node */ |
| 1067 | for_each_available_child_of_node(dev->of_node, child) { | 1111 | for_each_available_child_of_node(dev->of_node, child) { |
| 1068 | panel = of_drm_find_panel(child); | 1112 | panel = of_drm_find_panel(child); |
| @@ -1,13 +1,11 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0-only | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | config DRM_MGAG200 | 2 | config DRM_MGAG200 |
| 3 | tristate "Kernel modesetting driver for MGA G200 server engines" | 3 | tristate "Matrox G200" |
| 4 | depends on DRM && PCI && MMU | 4 | depends on DRM && PCI && MMU |
| 5 | select DRM_GEM_SHMEM_HELPER | 5 | select DRM_GEM_SHMEM_HELPER |
| 6 | select DRM_KMS_HELPER | 6 | select DRM_KMS_HELPER |
| 7 | help | 7 | help |
| 8 | This is a KMS driver for the MGA G200 server chips, it | 8 | This is a KMS driver for Matrox G200 chips. It supports the original |
| 9 | does not support the original MGA G200 or any of the desktop | 9 | MGA G200 desktop chips and the server variants. It requires 0.3.0 |
| 10 | chips. It requires 0.3.0 of the modesetting userspace driver, | 10 | of the modesetting userspace driver, and a version of mga driver |
| 11 | and a version of mga driver that will fail on KMS enabled | 11 | that will fail on KMS enabled devices. |
| 12 | devices. | ||
| 13 | |||
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include <linux/console.h> | 9 | #include <linux/console.h> |
| 10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 11 | #include <linux/pci.h> | 11 | #include <linux/pci.h> |
| 12 | #include <linux/vmalloc.h> | ||
| 12 | 13 | ||
| 13 | #include <drm/drm_drv.h> | 14 | #include <drm/drm_drv.h> |
| 14 | #include <drm/drm_file.h> | 15 | #include <drm/drm_file.h> |
| @@ -36,6 +37,7 @@ static struct drm_driver mgag200_driver = { · 21 unmodified lines | |||
| 36 | .major = DRIVER_MAJOR, | 37 | .major = DRIVER_MAJOR, |
| 37 | .minor = DRIVER_MINOR, | 38 | .minor = DRIVER_MINOR, |
| 38 | .patchlevel = DRIVER_PATCHLEVEL, | 39 | .patchlevel = DRIVER_PATCHLEVEL, |
| 40 | .gem_create_object = drm_gem_shmem_create_object_cached, | ||
| 39 | DRM_GEM_SHMEM_DRIVER_OPS, | 41 | DRM_GEM_SHMEM_DRIVER_OPS, |
| 40 | }; | 42 | }; |
| 41 | 43 | ||
| @@ -43,18 +45,66 @@ static struct drm_driver mgag200_driver = { · 1 unmodified line | |||
| 43 | * DRM device | 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 | struct drm_device *dev = &mdev->base; | 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); | 54 | ret = pci_read_config_dword(dev->pdev, PCI_MGA_OPTION, &option); |
| 52 | mdev->type = mgag200_type_from_driver_data(flags); | 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); | 58 | return !!(option & PCI_MGA_OPTION_HARDPWMSK); |
| 55 | mdev->has_sdram = !(option & (1 << 14)); | 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 | mdev->rmmio_base = pci_resource_start(dev->pdev, 1); | 108 | mdev->rmmio_base = pci_resource_start(dev->pdev, 1); |
| 59 | mdev->rmmio_size = pci_resource_len(dev->pdev, 1); | 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 | if (mdev->rmmio == NULL) | 118 | if (mdev->rmmio == NULL) |
| 69 | return -ENOMEM; | 119 | return -ENOMEM; |
| 70 | 120 | ||
| 71 | /* stash G200 SE model number for later use */ | 121 | RREG_ECRT(0x03, crtcext3); |
| 72 | if (IS_G200_SE(mdev)) { | 122 | crtcext3 |= MGAREG_CRTCEXT3_MGAMODE; |
| 73 | mdev->unique_rev_id = RREG32(0x1e24); | 123 | WREG_ECRT(0x03, crtcext3); |
| 74 | drm_dbg(dev, "G200 SE unique revision id is 0x%x\n", | 124 | |
| 75 | mdev->unique_rev_id); | 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 | ret = mgag200_mm_init(mdev); | 279 | ret = mgag200_mm_init(mdev); |
| 79 | if (ret) | 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 | static const struct pci_device_id mgag200_pciidlist[] = { | 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 | { PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 322 | { PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
| 120 | G200_SE_A | MGAG200_FLAG_HW_BUG_NO_STARTADD}, | 323 | G200_SE_A | MGAG200_FLAG_HW_BUG_NO_STARTADD}, |
| 121 | { PCI_VENDOR_ID_MATROX, 0x524, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_B }, | 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 | #define RREG32(reg) ioread32(((void __iomem *)mdev->rmmio) + (reg)) | 38 | #define RREG32(reg) ioread32(((void __iomem *)mdev->rmmio) + (reg)) |
| 39 | #define WREG32(reg, v) iowrite32(v, ((void __iomem *)mdev->rmmio) + (reg)) | 39 | #define WREG32(reg, v) iowrite32(v, ((void __iomem *)mdev->rmmio) + (reg)) |
| 40 | 40 | ||
| 41 | #define MGA_BIOS_OFFSET 0x7ffc | ||
| 42 | |||
| 41 | #define ATTR_INDEX 0x1fc0 | 43 | #define ATTR_INDEX 0x1fc0 |
| 42 | #define ATTR_DATA 0x1fc1 | 44 | #define ATTR_DATA 0x1fc1 |
| 43 | 45 | ||
| @@ -129,6 +131,8 @@ struct mga_mc { · 85 unmodified lines | |||
| 129 | }; | 131 | }; |
| 130 | 132 | ||
| 131 | enum mga_type { | 133 | enum mga_type { |
| 134 | G200_PCI, | ||
| 135 | G200_AGP, | ||
| 132 | G200_SE_A, | 136 | G200_SE_A, |
| 133 | G200_SE_B, | 137 | G200_SE_B, |
| 134 | G200_WB, | 138 | G200_WB, |
| @@ -161,14 +165,23 @@ struct mga_device { · 26 unmodified lines | |||
| 161 | size_t vram_fb_available; | 165 | size_t vram_fb_available; |
| 162 | 166 | ||
| 163 | enum mga_type type; | 167 | enum mga_type type; |
| 164 | int has_sdram; | ||
| 165 | 168 | ||
| 166 | int bpp_shifts[4]; | 169 | int bpp_shifts[4]; |
| 167 | 170 | ||
| 168 | int fb_mtrr; | 171 | int fb_mtrr; |
| 169 | 172 | ||
| 170 | /* SE model number stored in reg 0x1e24 */ | 173 | union { |
| 171 | u32 unique_rev_id; | 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 | struct mga_connector connector; | 186 | struct mga_connector connector; |
| 174 | struct drm_simple_display_pipe display_pipe; | 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 | int mgag200_mm_init(struct mga_device *mdev) | 90 | int mgag200_mm_init(struct mga_device *mdev) |
| 91 | { | 91 | { |
| 92 | struct drm_device *dev = &mdev->base; | 92 | struct drm_device *dev = &mdev->base; |
| 93 | u8 misc; | ||
| 93 | resource_size_t start, len; | 94 | resource_size_t start, len; |
| 94 | int ret; | 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 | /* BAR 0 is VRAM */ | 104 | /* BAR 0 is VRAM */ |
| 97 | start = pci_resource_start(dev->pdev, 0); | 105 | start = pci_resource_start(dev->pdev, 0); |
| 98 | len = pci_resource_len(dev->pdev, 0); | 106 | len = pci_resource_len(dev->pdev, 0); |
| @@ -9,7 +9,6 @@ · 8 unmodified lines | |||
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
| 12 | #include <linux/pci.h> | ||
| 13 | 12 | ||
| 14 | #include <drm/drm_atomic_helper.h> | 13 | #include <drm/drm_atomic_helper.h> |
| 15 | #include <drm/drm_atomic_state_helper.h> | 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 | } while ((status & 0x01) && time_before(jiffies, timeout)); | 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 | #define P_ARRAY_SIZE 9 | 182 | #define P_ARRAY_SIZE 9 |
| 113 | 183 | ||
| 114 | static int mga_g200se_set_plls(struct mga_device *mdev, long clock) | 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 | unsigned int vcomax, vcomin, pllreffreq; | 187 | unsigned int vcomax, vcomin, pllreffreq; |
| 117 | unsigned int delta, tmpdelta, permitteddelta; | 188 | unsigned int delta, tmpdelta, permitteddelta; |
| 118 | unsigned int testp, testm, testn; | 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 | unsigned int fvv; | 193 | unsigned int fvv; |
| 123 | unsigned int i; | 194 | unsigned int i; |
| 124 | 195 | ||
| 125 | if (mdev->unique_rev_id <= 0x03) { | 196 | if (unique_rev_id <= 0x03) { |
| 126 | 197 | ||
| 127 | m = n = p = 0; | 198 | m = n = p = 0; |
| 128 | vcomax = 320000; | 199 | vcomax = 320000; |
| @@ -220,7 +291,7 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock) · 91 unmodified lines | |||
| 220 | WREG_DAC(MGA1064_PIX_PLLC_N, n); | 291 | WREG_DAC(MGA1064_PIX_PLLC_N, n); |
| 221 | WREG_DAC(MGA1064_PIX_PLLC_P, p); | 292 | WREG_DAC(MGA1064_PIX_PLLC_P, p); |
| 222 | 293 | ||
| 223 | if (mdev->unique_rev_id >= 0x04) { | 294 | if (unique_rev_id >= 0x04) { |
| 224 | WREG_DAC(0x1a, 0x09); | 295 | WREG_DAC(0x1a, 0x09); |
| 225 | msleep(20); | 296 | msleep(20); |
| 226 | WREG_DAC(0x1a, 0x01); | 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 | u8 misc; | 788 | u8 misc; |
| 718 | 789 | ||
| 719 | switch(mdev->type) { | 790 | switch(mdev->type) { |
| 791 | case G200_PCI: | ||
| 792 | case G200_AGP: | ||
| 793 | return mgag200_g200_set_plls(mdev, clock); | ||
| 720 | case G200_SE_A: | 794 | case G200_SE_A: |
| 721 | case G200_SE_B: | 795 | case G200_SE_B: |
| 722 | return mga_g200se_set_plls(mdev, clock); | 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 | WREG_ECRT(0x00, crtcext0); | 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 | static void mgag200_set_dac_regs(struct mga_device *mdev) | 954 | static void mgag200_set_dac_regs(struct mga_device *mdev) |
| 920 | { | 955 | { |
| 921 | size_t i; | 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 | switch (mdev->type) { | 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 | case G200_SE_A: | 977 | case G200_SE_A: |
| 937 | case G200_SE_B: | 978 | case G200_SE_B: |
| 938 | dacvalue[MGA1064_VREF_CTL] = 0x03; | 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 | static void mgag200_init_regs(struct mga_device *mdev) | 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 | mgag200_set_dac_regs(mdev); | 1032 | mgag200_set_dac_regs(mdev); |
| 993 | 1033 | ||
| 994 | WREG_SEQ(2, 0x0f); | 1034 | WREG_SEQ(2, 0x0f); |
| @@ -1002,14 +1042,6 @@ static void mgag200_init_regs(struct mga_device *mdev) · 7 unmodified lines | |||
| 1002 | WREG_CRT(14, 0); | 1042 | WREG_CRT(14, 0); |
| 1003 | WREG_CRT(15, 0); | 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 | RREG_CRT(0x11, crtc11); | 1045 | RREG_CRT(0x11, crtc11); |
| 1014 | crtc11 &= ~(MGAREG_CRTC11_CRTCPROTECT | | 1046 | crtc11 &= ~(MGAREG_CRTC11_CRTCPROTECT | |
| 1015 | MGAREG_CRTC11_VINTEN | | 1047 | MGAREG_CRTC11_VINTEN | |
| @@ -1023,9 +1055,7 @@ static void mgag200_init_regs(struct mga_device *mdev) · 7 unmodified lines | |||
| 1023 | WREG_ECRT(0x34, 0x5); | 1055 | WREG_ECRT(0x34, 0x5); |
| 1024 | 1056 | ||
| 1025 | misc = RREG8(MGA_MISC_IN); | 1057 | misc = RREG8(MGA_MISC_IN); |
| 1026 | misc |= MGAREG_MISC_IOADSEL | | 1058 | misc |= MGAREG_MISC_IOADSEL; |
| 1027 | MGAREG_MISC_RAMMAPEN | | ||
| 1028 | MGAREG_MISC_HIGH_PG_SEL; | ||
| 1029 | WREG8(MGA_MISC_OUT, misc); | 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 | const struct drm_display_mode *mode, | 1264 | const struct drm_display_mode *mode, |
| 1235 | const struct drm_framebuffer *fb) | 1265 | const struct drm_framebuffer *fb) |
| 1236 | { | 1266 | { |
| 1267 | u32 unique_rev_id = mdev->model.g200se.unique_rev_id; | ||
| 1237 | unsigned int hiprilvl; | 1268 | unsigned int hiprilvl; |
| 1238 | u8 crtcext6; | 1269 | u8 crtcext6; |
| 1239 | 1270 | ||
| 1240 | if (mdev->unique_rev_id >= 0x04) { | 1271 | if (unique_rev_id >= 0x04) { |
| 1241 | hiprilvl = 0; | 1272 | hiprilvl = 0; |
| 1242 | } else if (mdev->unique_rev_id >= 0x02) { | 1273 | } else if (unique_rev_id >= 0x02) { |
| 1243 | unsigned int bpp; | 1274 | unsigned int bpp; |
| 1244 | unsigned long mb; | 1275 | unsigned long mb; |
| 1245 | 1276 | ||
| @@ -1264,7 +1295,7 @@ static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev, · 18 unmodified lines | |||
| 1264 | else | 1295 | else |
| 1265 | hiprilvl = 5; | 1296 | hiprilvl = 5; |
| 1266 | 1297 | ||
| 1267 | } else if (mdev->unique_rev_id >= 0x01) { | 1298 | } else if (unique_rev_id >= 0x01) { |
| 1268 | hiprilvl = 3; | 1299 | hiprilvl = 3; |
| 1269 | } else { | 1300 | } else { |
| 1270 | hiprilvl = 4; | 1301 | hiprilvl = 4; |
| @@ -1388,7 +1419,9 @@ static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector, · 117 unmodified lines | |||
| 1388 | int bpp = 32; | 1419 | int bpp = 32; |
| 1389 | 1420 | ||
| 1390 | if (IS_G200_SE(mdev)) { | 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 | if (mode->hdisplay > 1600) | 1425 | if (mode->hdisplay > 1600) |
| 1393 | return MODE_VIRTUAL_X; | 1426 | return MODE_VIRTUAL_X; |
| 1394 | if (mode->vdisplay > 1200) | 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 | if (mga_vga_calculate_mode_bandwidth(mode, bpp) | 1429 | if (mga_vga_calculate_mode_bandwidth(mode, bpp) |
| 1397 | > (24400 * 1024)) | 1430 | > (24400 * 1024)) |
| 1398 | return MODE_BANDWIDTH; | 1431 | return MODE_BANDWIDTH; |
| 1399 | } else if (mdev->unique_rev_id == 0x02) { | 1432 | } else if (unique_rev_id == 0x02) { |
| 1400 | if (mode->hdisplay > 1920) | 1433 | if (mode->hdisplay > 1920) |
| 1401 | return MODE_VIRTUAL_X; | 1434 | return MODE_VIRTUAL_X; |
| 1402 | if (mode->vdisplay > 1200) | 1435 | if (mode->vdisplay > 1200) |
| @@ -256,6 +256,8 @@ · 255 unmodified lines | |||
| 256 | #define MGAREG_CRTCEXT1_VSYNCOFF BIT(5) | 256 | #define MGAREG_CRTCEXT1_VSYNCOFF BIT(5) |
| 257 | #define MGAREG_CRTCEXT1_HSYNCOFF BIT(4) | 257 | #define MGAREG_CRTCEXT1_HSYNCOFF BIT(4) |
| 258 | 258 | ||
| 259 | #define MGAREG_CRTCEXT3_MGAMODE BIT(7) | ||
| 260 | |||
| 259 | /* Cursor X and Y position */ | 261 | /* Cursor X and Y position */ |
| 260 | #define MGA_CURPOSXL 0x3c0c | 262 | #define MGA_CURPOSXL 0x3c0c |
| 261 | #define MGA_CURPOSXH 0x3c0d | 263 | #define MGA_CURPOSXH 0x3c0d |
| @@ -282,6 +284,8 @@ · 20 unmodified lines | |||
| 282 | #define PCI_MGA_OPTION2 0x50 | 284 | #define PCI_MGA_OPTION2 0x50 |
| 283 | #define PCI_MGA_OPTION3 0x54 | 285 | #define PCI_MGA_OPTION3 0x54 |
| 284 | 286 | ||
| 287 | #define PCI_MGA_OPTION_HARDPWMSK BIT(14) | ||
| 288 | |||
| 285 | #define RAMDAC_OFFSET 0x3c00 | 289 | #define RAMDAC_OFFSET 0x3c00 |
| 286 | 290 | ||
| 287 | /* TVP3026 direct registers */ | 291 | /* TVP3026 direct registers */ |
| @@ -50,14 +50,9 @@ static int mdp4_lvds_connector_get_modes(struct drm_connector *connector) · 49 unmodified lines | |||
| 50 | struct drm_panel *panel = mdp4_lvds_connector->panel; | 50 | struct drm_panel *panel = mdp4_lvds_connector->panel; |
| 51 | int ret = 0; | 51 | int ret = 0; |
| 52 | 52 | ||
| 53 | if (panel) { | 53 | if (panel) |
| 54 | drm_panel_attach(panel, connector); | ||
| 55 | |||
| 56 | ret = drm_panel_get_modes(panel, connector); | 54 | ret = drm_panel_get_modes(panel, connector); |
| 57 | 55 | ||
| 58 | drm_panel_detach(panel); | ||
| 59 | } | ||
| 60 | |||
| 61 | return ret; | 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 | * In dual DSI mode, we have one connector that can be | 328 | * In dual DSI mode, we have one connector that can be |
| 329 | * attached to the drm_panel. | 329 | * attached to the drm_panel. |
| 330 | */ | 330 | */ |
| 331 | drm_panel_attach(panel, connector); | ||
| 332 | num = drm_panel_get_modes(panel, connector); | 331 | num = drm_panel_get_modes(panel, connector); |
| 333 | if (!num) | 332 | if (!num) |
| 334 | return 0; | 333 | return 0; |
| @@ -5,7 +5,7 @@ config DRM_MXS · 4 unmodified lines | |||
| 5 | Choose this option to select drivers for MXS FB devices | 5 | Choose this option to select drivers for MXS FB devices |
| 6 | 6 | ||
| 7 | config DRM_MXSFB | 7 | config DRM_MXSFB |
| 8 | tristate "i.MX23/i.MX28/i.MX6SX MXSFB LCD controller" | 8 | tristate "i.MX (e)LCDIF LCD controller" |
| 9 | depends on DRM && OF | 9 | depends on DRM && OF |
| 10 | depends on COMMON_CLK | 10 | depends on COMMON_CLK |
| 11 | select DRM_MXS | 11 | select DRM_MXS |
| @@ -13,8 +13,10 @@ config DRM_MXSFB · 1 unmodified line | |||
| 13 | select DRM_KMS_FB_HELPER | 13 | select DRM_KMS_FB_HELPER |
| 14 | select DRM_KMS_CMA_HELPER | 14 | select DRM_KMS_CMA_HELPER |
| 15 | select DRM_PANEL | 15 | select DRM_PANEL |
| 16 | select DRM_PANEL_BRIDGE | ||
| 16 | help | 17 | help |
| 17 | Choose this option if you have an i.MX23/i.MX28/i.MX6SX MXSFB | 18 | Choose this option if you have an LCDIF or eLCDIF LCD controller. |
| 18 | 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 | If M is selected the module will be called mxsfb. | 22 | If M is selected the module will be called mxsfb. |
| @@ -1,3 +1,3 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0-only | 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 | obj-$(CONFIG_DRM_MXSFB) += mxsfb.o | 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 | #include <linux/clk.h> | 11 | #include <linux/clk.h> |
| 12 | #include <linux/component.h> | ||
| 13 | #include <linux/dma-mapping.h> | 12 | #include <linux/dma-mapping.h> |
| 14 | #include <linux/list.h> | 13 | #include <linux/io.h> |
| 15 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 16 | #include <linux/of_device.h> | 15 | #include <linux/of_device.h> |
| 17 | #include <linux/of_graph.h> | 16 | #include <linux/platform_device.h> |
| 18 | #include <linux/of_reserved_mem.h> | ||
| 19 | #include <linux/pm_runtime.h> | 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 | #include <drm/drm_atomic_helper.h> | 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 | #include <drm/drm_drv.h> | 22 | #include <drm/drm_drv.h> |
| 27 | #include <drm/drm_fb_cma_helper.h> | ||
| 28 | #include <drm/drm_fb_helper.h> | 23 | #include <drm/drm_fb_helper.h> |
| 29 | #include <drm/drm_gem_cma_helper.h> | 24 | #include <drm/drm_gem_cma_helper.h> |
| 30 | #include <drm/drm_gem_framebuffer_helper.h> | 25 | #include <drm/drm_gem_framebuffer_helper.h> |
| 31 | #include <drm/drm_irq.h> | 26 | #include <drm/drm_irq.h> |
| 27 | #include <drm/drm_mode_config.h> | ||
| 32 | #include <drm/drm_of.h> | 28 | #include <drm/drm_of.h> |
| 33 | #include <drm/drm_panel.h> | ||
| 34 | #include <drm/drm_probe_helper.h> | 29 | #include <drm/drm_probe_helper.h> |
| 35 | #include <drm/drm_simple_kms_helper.h> | ||
| 36 | #include <drm/drm_vblank.h> | 30 | #include <drm/drm_vblank.h> |
| 37 | 31 | ||
| 38 | #include "mxsfb_drv.h" | 32 | #include "mxsfb_drv.h" |
| @@ -41,6 +35,11 @@ · 2 unmodified lines | |||
| 41 | enum mxsfb_devtype { | 35 | enum mxsfb_devtype { |
| 42 | MXSFB_V3, | 36 | MXSFB_V3, |
| 43 | MXSFB_V4, | 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 | static const struct mxsfb_devdata mxsfb_devdata[] = { | 45 | static const struct mxsfb_devdata mxsfb_devdata[] = { |
| @@ -48,38 +47,28 @@ static const struct mxsfb_devdata mxsfb_devdata[] = { · 1 unmodified line | |||
| 48 | .transfer_count = LCDC_V3_TRANSFER_COUNT, | 47 | .transfer_count = LCDC_V3_TRANSFER_COUNT, |
| 49 | .cur_buf = LCDC_V3_CUR_BUF, | 48 | .cur_buf = LCDC_V3_CUR_BUF, |
| 50 | .next_buf = LCDC_V3_NEXT_BUF, | 49 | .next_buf = LCDC_V3_NEXT_BUF, |
| 51 | .debug0 = LCDC_V3_DEBUG0, | ||
| 52 | .hs_wdth_mask = 0xff, | 50 | .hs_wdth_mask = 0xff, |
| 53 | .hs_wdth_shift = 24, | 51 | .hs_wdth_shift = 24, |
| 54 | .ipversion = 3, | 52 | .has_overlay = false, |
| 55 | }, | 53 | }, |
| 56 | [MXSFB_V4] = { | 54 | [MXSFB_V4] = { |
| 57 | .transfer_count = LCDC_V4_TRANSFER_COUNT, | 55 | .transfer_count = LCDC_V4_TRANSFER_COUNT, |
| 58 | .cur_buf = LCDC_V4_CUR_BUF, | 56 | .cur_buf = LCDC_V4_CUR_BUF, |
| 59 | .next_buf = LCDC_V4_NEXT_BUF, | 57 | .next_buf = LCDC_V4_NEXT_BUF, |
| 60 | .debug0 = LCDC_V4_DEBUG0, | ||
| 61 | .hs_wdth_mask = 0x3fff, | 58 | .hs_wdth_mask = 0x3fff, |
| 62 | .hs_wdth_shift = 18, | 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 | void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb) | 72 | void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb) |
| 84 | { | 73 | { |
| 85 | if (mxsfb->clk_axi) | 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 | .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, | 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, | 94 | static int mxsfb_attach_bridge(struct mxsfb_drm_private *mxsfb) |
| 106 | struct drm_crtc_state *crtc_state, | ||
| 107 | struct drm_plane_state *plane_state) | ||
| 108 | { | 95 | { |
| 109 | struct drm_connector *connector; | 96 | struct drm_device *drm = mxsfb->drm; |
| 110 | struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); | 97 | struct drm_connector_list_iter iter; |
| 111 | struct drm_device *drm = pipe->plane.dev; | 98 | struct drm_panel *panel; |
| 112 | 99 | struct drm_bridge *bridge; | |
| 113 | if (!mxsfb->connector) { | 100 | int ret; |
| 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 | } | ||
| 133 | 101 | ||
| 134 | static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe) | 102 | ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, &panel, |
| 135 | { | 103 | &bridge); |
| 136 | struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); | 104 | if (ret) |
| 137 | struct drm_device *drm = pipe->plane.dev; | 105 | return ret; |
| 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); | ||
| 145 | 106 | ||
| 146 | spin_lock_irq(&drm->event_lock); | 107 | if (panel) { |
| 147 | event = crtc->state->event; | 108 | bridge = devm_drm_panel_bridge_add_typed(drm->dev, panel, |
| 148 | if (event) { | 109 | DRM_MODE_CONNECTOR_DPI); |
| 149 | crtc->state->event = NULL; | 110 | if (IS_ERR(bridge)) |
| 150 | drm_crtc_send_vblank_event(crtc, event); | 111 | return PTR_ERR(bridge); |
| 151 | } | 112 | } |
| 152 | spin_unlock_irq(&drm->event_lock); | ||
| 153 | 113 | ||
| 154 | if (mxsfb->connector != &mxsfb->panel_connector) | 114 | if (!bridge) |
| 155 | mxsfb->connector = NULL; | 115 | return -ENODEV; |
| 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); | ||
| 162 | 116 | ||
| 163 | mxsfb_plane_atomic_update(mxsfb, plane_state); | 117 | ret = drm_bridge_attach(&mxsfb->encoder, bridge, NULL, 0); |
| 164 | } | 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) | 124 | mxsfb->bridge = bridge; |
| 167 | { | ||
| 168 | struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); | ||
| 169 | 125 | ||
| 170 | /* Clear and enable VBLANK IRQ */ | 126 | /* |
| 171 | mxsfb_enable_axi_clk(mxsfb); | 127 | * Get hold of the connector. This is a bit of a hack, until the bridge |
| 172 | writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); | 128 | * API gives us bus flags and formats. |
| 173 | writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET); | 129 | */ |
| 174 | mxsfb_disable_axi_clk(mxsfb); | 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 | return 0; | 134 | return 0; |
| 177 | } | 135 | } |
| 178 | 136 | ||
| 179 | static void mxsfb_pipe_disable_vblank(struct drm_simple_display_pipe *pipe) | 137 | static int mxsfb_load(struct drm_device *drm, |
| 180 | { | 138 | const struct mxsfb_devdata *devdata) |
| 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) | ||
| 200 | { | 139 | { |
| 201 | struct platform_device *pdev = to_platform_device(drm->dev); | 140 | struct platform_device *pdev = to_platform_device(drm->dev); |
| 202 | struct mxsfb_drm_private *mxsfb; | 141 | struct mxsfb_drm_private *mxsfb; |
| @@ -207,8 +146,9 @@ static int mxsfb_load(struct drm_device *drm) · 4 unmodified lines | |||
| 207 | if (!mxsfb) | 146 | if (!mxsfb) |
| 208 | return -ENOMEM; | 147 | return -ENOMEM; |
| 209 | 148 | ||
| 149 | mxsfb->drm = drm; | ||
| 210 | drm->dev_private = mxsfb; | 150 | drm->dev_private = mxsfb; |
| 211 | mxsfb->devdata = &mxsfb_devdata[pdev->id_entry->driver_data]; | 151 | mxsfb->devdata = devdata; |
| 212 | 152 | ||
| 213 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 153 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 214 | mxsfb->base = devm_ioremap_resource(drm->dev, res); | 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 | pm_runtime_enable(drm->dev); | 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 | /* Modeset init */ | 176 | /* Modeset init */ |
| 243 | drm_mode_config_init(drm); | 177 | drm_mode_config_init(drm); |
| 244 | 178 | ||
| 245 | ret = mxsfb_create_output(drm); | 179 | ret = mxsfb_kms_init(mxsfb); |
| 246 | if (ret < 0) { | 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 | goto err_vblank; | 182 | goto err_vblank; |
| 249 | } | 183 | } |
| 250 | 184 | ||
| 251 | ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs, | 185 | ret = drm_vblank_init(drm, drm->mode_config.num_crtc); |
| 252 | mxsfb_formats, ARRAY_SIZE(mxsfb_formats), | ||
| 253 | mxsfb_modifiers, mxsfb->connector); | ||
| 254 | if (ret < 0) { | 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 | goto err_vblank; | 188 | goto err_vblank; |
| 257 | } | 189 | } |
| 258 | 190 | ||
| 259 | /* | 191 | /* Start with vertical blanking interrupt reporting disabled. */ |
| 260 | * Attach panel only if there is one. | 192 | drm_crtc_vblank_off(&mxsfb->crtc); |
| 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 | */ | ||
| 266 | 193 | ||
| 267 | if (mxsfb->panel) { | 194 | ret = mxsfb_attach_bridge(mxsfb); |
| 268 | ret = drm_panel_attach(mxsfb->panel, mxsfb->connector); | 195 | if (ret) { |
| 269 | if (ret) { | 196 | dev_err(drm->dev, "Cannot connect bridge: %d\n", ret); |
| 270 | dev_err(drm->dev, "Cannot connect panel: %d\n", ret); | 197 | goto err_vblank; |
| 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 | } | ||
| 280 | } | 198 | } |
| 281 | 199 | ||
| 282 | drm->mode_config.min_width = MXSFB_MIN_XRES; | 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 | if (ret < 0) { | 213 | if (ret < 0) { |
| 296 | dev_err(drm->dev, "Failed to install IRQ handler\n"); | 214 | dev_err(drm->dev, "Failed to install IRQ handler\n"); |
| 297 | goto err_irq; | 215 | goto err_vblank; |
| 298 | } | 216 | } |
| 299 | 217 | ||
| 300 | drm_kms_helper_poll_init(drm); | 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 | return 0; | 224 | return 0; |
| 307 | 225 | ||
| 308 | err_irq: | ||
| 309 | drm_panel_detach(mxsfb->panel); | ||
| 310 | err_vblank: | 226 | err_vblank: |
| 311 | pm_runtime_disable(drm->dev); | 227 | pm_runtime_disable(drm->dev); |
| 312 | 228 | ||
| @@ -327,11 +243,13 @@ static void mxsfb_unload(struct drm_device *drm) · 14 unmodified lines | |||
| 327 | pm_runtime_disable(drm->dev); | 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 | struct mxsfb_drm_private *mxsfb = drm->dev_private; | 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 | static irqreturn_t mxsfb_irq_handler(int irq, void *data) | 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 | struct mxsfb_drm_private *mxsfb = drm->dev_private; | 258 | struct mxsfb_drm_private *mxsfb = drm->dev_private; |
| 341 | u32 reg; | 259 | u32 reg; |
| 342 | 260 | ||
| 343 | mxsfb_enable_axi_clk(mxsfb); | ||
| 344 | |||
| 345 | reg = readl(mxsfb->base + LCDC_CTRL1); | 261 | reg = readl(mxsfb->base + LCDC_CTRL1); |
| 346 | 262 | ||
| 347 | if (reg & CTRL1_CUR_FRAME_DONE_IRQ) | 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 | writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); | 266 | writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR); |
| 351 | 267 | ||
| 352 | mxsfb_disable_axi_clk(mxsfb); | ||
| 353 | |||
| 354 | return IRQ_HANDLED; | 268 | return IRQ_HANDLED; |
| 355 | } | 269 | } |
| 356 | 270 | ||
| @@ -359,8 +273,8 @@ DEFINE_DRM_GEM_CMA_FOPS(fops); · 2 unmodified lines | |||
| 359 | static struct drm_driver mxsfb_driver = { | 273 | static struct drm_driver mxsfb_driver = { |
| 360 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, | 274 | .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, |
| 361 | .irq_handler = mxsfb_irq_handler, | 275 | .irq_handler = mxsfb_irq_handler, |
| 362 | .irq_preinstall = mxsfb_irq_preinstall, | 276 | .irq_preinstall = mxsfb_irq_disable, |
| 363 | .irq_uninstall = mxsfb_irq_preinstall, | 277 | .irq_uninstall = mxsfb_irq_disable, |
| 364 | DRM_GEM_CMA_DRIVER_OPS, | 278 | DRM_GEM_CMA_DRIVER_OPS, |
| 365 | .fops = &fops, | 279 | .fops = &fops, |
| 366 | .name = "mxsfb-drm", | 280 | .name = "mxsfb-drm", |
| @@ -370,18 +284,10 @@ static struct drm_driver mxsfb_driver = { · 3 unmodified lines | |||
| 370 | .minor = 0, | 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 | static const struct of_device_id mxsfb_dt_ids[] = { | 287 | static const struct of_device_id mxsfb_dt_ids[] = { |
| 382 | { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devtype[0], }, | 288 | { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devdata[MXSFB_V3], }, |
| 383 | { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devtype[1], }, | 289 | { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devdata[MXSFB_V4], }, |
| 384 | { .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devtype[2], }, | 290 | { .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devdata[MXSFB_V6], }, |
| 385 | { /* sentinel */ } | 291 | { /* sentinel */ } |
| 386 | }; | 292 | }; |
| 387 | MODULE_DEVICE_TABLE(of, mxsfb_dt_ids); | 293 | MODULE_DEVICE_TABLE(of, mxsfb_dt_ids); |
| @@ -396,14 +302,11 @@ static int mxsfb_probe(struct platform_device *pdev) · 8 unmodified lines | |||
| 396 | if (!pdev->dev.of_node) | 302 | if (!pdev->dev.of_node) |
| 397 | return -ENODEV; | 303 | return -ENODEV; |
| 398 | 304 | ||
| 399 | if (of_id) | ||
| 400 | pdev->id_entry = of_id->data; | ||
| 401 | |||
| 402 | drm = drm_dev_alloc(&mxsfb_driver, &pdev->dev); | 305 | drm = drm_dev_alloc(&mxsfb_driver, &pdev->dev); |
| 403 | if (IS_ERR(drm)) | 306 | if (IS_ERR(drm)) |
| 404 | return PTR_ERR(drm); | 307 | return PTR_ERR(drm); |
| 405 | 308 | ||
| 406 | ret = mxsfb_load(drm); | 309 | ret = mxsfb_load(drm, of_id->data); |
| 407 | if (ret) | 310 | if (ret) |
| 408 | goto err_free; | 311 | goto err_free; |
| 409 | 312 | ||
| @@ -457,7 +360,6 @@ static const struct dev_pm_ops mxsfb_pm_ops = { · 47 unmodified lines | |||
| 457 | static struct platform_driver mxsfb_platform_driver = { | 360 | static struct platform_driver mxsfb_platform_driver = { |
| 458 | .probe = mxsfb_probe, | 361 | .probe = mxsfb_probe, |
| 459 | .remove = mxsfb_remove, | 362 | .remove = mxsfb_remove, |
| 460 | .id_table = mxsfb_devtype, | ||
| 461 | .driver = { | 363 | .driver = { |
| 462 | .name = "mxsfb", | 364 | .name = "mxsfb", |
| 463 | .of_match_table = mxsfb_dt_ids, | 365 | .of_match_table = mxsfb_dt_ids, |
| @@ -8,14 +8,20 @@ · 7 unmodified lines | |||
| 8 | #ifndef __MXSFB_DRV_H__ | 8 | #ifndef __MXSFB_DRV_H__ |
| 9 | #define __MXSFB_DRV_H__ | 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 | struct mxsfb_devdata { | 18 | struct mxsfb_devdata { |
| 12 | unsigned int transfer_count; | 19 | unsigned int transfer_count; |
| 13 | unsigned int cur_buf; | 20 | unsigned int cur_buf; |
| 14 | unsigned int next_buf; | 21 | unsigned int next_buf; |
| 15 | unsigned int debug0; | 22 | unsigned int hs_wdth_mask; |
| 16 | unsigned int hs_wdth_mask; | 23 | unsigned int hs_wdth_shift; |
| 17 | unsigned int hs_wdth_shift; | 24 | bool has_overlay; |
| 18 | unsigned int ipversion; | ||
| 19 | }; | 25 | }; |
| 20 | 26 | ||
| 21 | struct mxsfb_drm_private { | 27 | struct mxsfb_drm_private { |
| @@ -26,22 +32,26 @@ struct mxsfb_drm_private { · 4 unmodified lines | |||
| 26 | struct clk *clk_axi; | 32 | struct clk *clk_axi; |
| 27 | struct clk *clk_disp_axi; | 33 | struct clk *clk_disp_axi; |
| 28 | 34 | ||
| 29 | struct drm_simple_display_pipe pipe; | 35 | struct drm_device *drm; |
| 30 | struct drm_connector panel_connector; | 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 | struct drm_connector *connector; | 42 | struct drm_connector *connector; |
| 32 | struct drm_panel *panel; | ||
| 33 | struct drm_bridge *bridge; | 43 | struct drm_bridge *bridge; |
| 34 | }; | 44 | }; |
| 35 | 45 | ||
| 36 | int mxsfb_setup_crtc(struct drm_device *dev); | 46 | static inline struct mxsfb_drm_private * |
| 37 | int mxsfb_create_output(struct drm_device *dev); | 47 | to_mxsfb_drm_private(struct drm_device *drm) |
| 48 | { | ||
| 49 | return drm->dev_private; | ||
| 50 | } | ||
| 38 | 51 | ||
| 39 | void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb); | 52 | void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb); |
| 40 | void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb); | 53 | void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb); |
| 41 | 54 | ||
| 42 | void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb); | 55 | int mxsfb_kms_init(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); | ||
| 46 | 56 | ||
| 47 | #endif /* __MXSFB_DRV_H__ */ | 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 | #define LCDC_VDCTRL4 0xb0 | 27 | #define LCDC_VDCTRL4 0xb0 |
| 28 | #define LCDC_V4_DEBUG0 0x1d0 | 28 | #define LCDC_V4_DEBUG0 0x1d0 |
| 29 | #define LCDC_V3_DEBUG0 0x1f0 | 29 | #define LCDC_V3_DEBUG0 0x1f0 |
| 30 | 30 | #define LCDC_AS_CTRL 0x210 | |
| 31 | #define CTRL_SFTRST (1 << 31) | 31 | #define LCDC_AS_BUF 0x220 |
| 32 | #define CTRL_CLKGATE (1 << 30) | 32 | #define LCDC_AS_NEXT_BUF 0x230 |
| 33 | #define CTRL_BYPASS_COUNT (1 << 19) | 33 | #define LCDC_AS_CLRKEYLOW 0x240 |
| 34 | #define CTRL_VSYNC_MODE (1 << 18) | 34 | #define LCDC_AS_CLRKEYHIGH 0x250 |
| 35 | #define CTRL_DOTCLK_MODE (1 << 17) | 35 | |
| 36 | #define CTRL_DATA_SELECT (1 << 16) | 36 | #define CTRL_SFTRST BIT(31) |
| 37 | #define CTRL_SET_BUS_WIDTH(x) (((x) & 0x3) << 10) | 37 | #define CTRL_CLKGATE BIT(30) |
| 38 | #define CTRL_GET_BUS_WIDTH(x) (((x) >> 10) & 0x3) | 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 | #define CTRL_BUS_WIDTH_MASK (0x3 << 10) | 46 | #define CTRL_BUS_WIDTH_MASK (0x3 << 10) |
| 40 | #define CTRL_SET_WORD_LENGTH(x) (((x) & 0x3) << 8) | 47 | #define CTRL_WORD_LENGTH_16 (0 << 8) |
| 41 | #define CTRL_GET_WORD_LENGTH(x) (((x) >> 8) & 0x3) | 48 | #define CTRL_WORD_LENGTH_8 (1 << 8) |
| 42 | #define CTRL_MASTER (1 << 5) | 49 | #define CTRL_WORD_LENGTH_18 (2 << 8) |
| 43 | #define CTRL_DF16 (1 << 3) | 50 | #define CTRL_WORD_LENGTH_24 (3 << 8) |
| 44 | #define CTRL_DF18 (1 << 2) | 51 | #define CTRL_MASTER BIT(5) |
| 45 | #define CTRL_DF24 (1 << 1) | 52 | #define CTRL_DF16 BIT(3) |
| 46 | #define CTRL_RUN (1 << 0) | 53 | #define CTRL_DF18 BIT(2) |
| 47 | 54 | #define CTRL_DF24 BIT(1) | |
| 48 | #define CTRL1_FIFO_CLEAR (1 << 21) | 55 | #define CTRL_RUN BIT(0) |
| 56 | |||
| 57 | #define CTRL1_FIFO_CLEAR BIT(21) | ||
| 49 | #define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16) | 58 | #define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16) |
| 50 | #define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf) | 59 | #define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf) |
| 51 | #define CTRL1_CUR_FRAME_DONE_IRQ_EN (1 << 13) | 60 | #define CTRL1_CUR_FRAME_DONE_IRQ_EN BIT(13) |
| 52 | #define CTRL1_CUR_FRAME_DONE_IRQ (1 << 9) | 61 | #define CTRL1_CUR_FRAME_DONE_IRQ BIT(9) |
| 53 | 62 | ||
| 54 | #define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16) | 63 | #define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16) |
| 55 | #define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff) | 64 | #define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff) |
| 56 | #define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff) | 65 | #define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff) |
| 57 | #define TRANSFER_COUNT_GET_HCOUNT(x) ((x) & 0xffff) | 66 | #define TRANSFER_COUNT_GET_HCOUNT(x) ((x) & 0xffff) |
| 58 | 67 | ||
| 59 | #define VDCTRL0_ENABLE_PRESENT (1 << 28) | 68 | #define VDCTRL0_ENABLE_PRESENT BIT(28) |
| 60 | #define VDCTRL0_VSYNC_ACT_HIGH (1 << 27) | 69 | #define VDCTRL0_VSYNC_ACT_HIGH BIT(27) |
| 61 | #define VDCTRL0_HSYNC_ACT_HIGH (1 << 26) | 70 | #define VDCTRL0_HSYNC_ACT_HIGH BIT(26) |
| 62 | #define VDCTRL0_DOTCLK_ACT_FALLING (1 << 25) | 71 | #define VDCTRL0_DOTCLK_ACT_FALLING BIT(25) |
| 63 | #define VDCTRL0_ENABLE_ACT_HIGH (1 << 24) | 72 | #define VDCTRL0_ENABLE_ACT_HIGH BIT(24) |
| 64 | #define VDCTRL0_VSYNC_PERIOD_UNIT (1 << 21) | 73 | #define VDCTRL0_VSYNC_PERIOD_UNIT BIT(21) |
| 65 | #define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT (1 << 20) | 74 | #define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT BIT(20) |
| 66 | #define VDCTRL0_HALF_LINE (1 << 19) | 75 | #define VDCTRL0_HALF_LINE BIT(19) |
| 67 | #define VDCTRL0_HALF_LINE_MODE (1 << 18) | 76 | #define VDCTRL0_HALF_LINE_MODE BIT(18) |
| 68 | #define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff) | 77 | #define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff) |
| 69 | #define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff) | 78 | #define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff) |
| 70 | 79 | ||
| 71 | #define VDCTRL2_SET_HSYNC_PERIOD(x) ((x) & 0x3ffff) | 80 | #define VDCTRL2_SET_HSYNC_PERIOD(x) ((x) & 0x3ffff) |
| 72 | #define VDCTRL2_GET_HSYNC_PERIOD(x) ((x) & 0x3ffff) | 81 | #define VDCTRL2_GET_HSYNC_PERIOD(x) ((x) & 0x3ffff) |
| 73 | 82 | ||
| 74 | #define VDCTRL3_MUX_SYNC_SIGNALS (1 << 29) | 83 | #define VDCTRL3_MUX_SYNC_SIGNALS BIT(29) |
| 75 | #define VDCTRL3_VSYNC_ONLY (1 << 28) | 84 | #define VDCTRL3_VSYNC_ONLY BIT(28) |
| 76 | #define SET_HOR_WAIT_CNT(x) (((x) & 0xfff) << 16) | 85 | #define SET_HOR_WAIT_CNT(x) (((x) & 0xfff) << 16) |
| 77 | #define GET_HOR_WAIT_CNT(x) (((x) >> 16) & 0xfff) | 86 | #define GET_HOR_WAIT_CNT(x) (((x) >> 16) & 0xfff) |
| 78 | #define SET_VERT_WAIT_CNT(x) ((x) & 0xffff) | 87 | #define SET_VERT_WAIT_CNT(x) ((x) & 0xffff) |
| @@ -80,28 +89,32 @@ · 1 unmodified line | |||
| 80 | 89 | ||
| 81 | #define VDCTRL4_SET_DOTCLK_DLY(x) (((x) & 0x7) << 29) /* v4 only */ | 90 | #define VDCTRL4_SET_DOTCLK_DLY(x) (((x) & 0x7) << 29) /* v4 only */ |
| 82 | #define VDCTRL4_GET_DOTCLK_DLY(x) (((x) >> 29) & 0x7) /* v4 only */ | 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 | #define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff) | 93 | #define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff) |
| 85 | 94 | ||
| 86 | #define DEBUG0_HSYNC (1 < 26) | 95 | #define DEBUG0_HSYNC BIT(26) |
| 87 | #define DEBUG0_VSYNC (1 < 25) | 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 | #define MXSFB_MIN_XRES 120 | 115 | #define MXSFB_MIN_XRES 120 |
| 90 | #define MXSFB_MIN_YRES 120 | 116 | #define MXSFB_MIN_YRES 120 |
| 91 | #define MXSFB_MAX_XRES 0xffff | 117 | #define MXSFB_MAX_XRES 0xffff |
| 92 | #define MXSFB_MAX_YRES 0xffff | 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 | #endif /* __MXSFB_REGS_H__ */ | 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 | return nouveau_sgdma_create_ttm(bo, page_flags); | 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 | static void | 649 | static void |
| 710 | nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) | 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 | static int | 667 | static int |
| 728 | nouveau_bo_move_prep(struct nouveau_drm *drm, struct ttm_buffer_object *bo, | 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 | struct nouveau_mem *old_mem = nouveau_mem(&bo->mem); | 671 | struct nouveau_mem *old_mem = nouveau_mem(&bo->mem); |
| 732 | struct nouveau_mem *new_mem = nouveau_mem(reg); | 672 | struct nouveau_mem *new_mem = nouveau_mem(reg); |
| @@ -758,7 +698,7 @@ done: · 25 unmodified lines | |||
| 758 | 698 | ||
| 759 | static int | 699 | static int |
| 760 | nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, | 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 | struct nouveau_drm *drm = nouveau_bdev(bo->bdev); | 703 | struct nouveau_drm *drm = nouveau_bdev(bo->bdev); |
| 764 | struct nouveau_channel *chan = drm->ttm.chan; | 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 | /* create temporary vmas for the transfer and attach them to the | 709 | /* create temporary vmas for the transfer and attach them to the |
| 770 | * old nvkm_mem node, these will get cleaned up after ttm has | 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 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) { | 713 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) { |
| 774 | ret = nouveau_bo_move_prep(drm, bo, new_reg); | 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 | s32 oclass; | 744 | s32 oclass; |
| 805 | int (*exec)(struct nouveau_channel *, | 745 | int (*exec)(struct nouveau_channel *, |
| 806 | struct ttm_buffer_object *, | 746 | struct ttm_buffer_object *, |
| 807 | struct ttm_mem_reg *, struct ttm_mem_reg *); | 747 | struct ttm_resource *, struct ttm_resource *); |
| 808 | int (*init)(struct nouveau_channel *, u32 handle); | 748 | int (*init)(struct nouveau_channel *, u32 handle); |
| 809 | } _methods[] = { | 749 | } _methods[] = { |
| 810 | { "COPY", 4, 0xc5b5, nve0_bo_move_copy, nve0_bo_move_init }, | 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 | static int | 806 | static int |
| 867 | nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, | 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 | struct ttm_operation_ctx ctx = { intr, no_wait_gpu }; | 810 | struct ttm_operation_ctx ctx = { intr, no_wait_gpu }; |
| 871 | struct ttm_place placement_memtype = { | 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 | .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING | 814 | .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING |
| 875 | }; | 815 | }; |
| 876 | struct ttm_placement placement; | 816 | struct ttm_placement placement; |
| 877 | struct ttm_mem_reg tmp_reg; | 817 | struct ttm_resource tmp_reg; |
| 878 | int ret; | 818 | int ret; |
| 879 | 819 | ||
| 880 | placement.num_placement = placement.num_busy_placement = 1; | 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 | ret = ttm_bo_move_ttm(bo, &ctx, new_reg); | 837 | ret = ttm_bo_move_ttm(bo, &ctx, new_reg); |
| 898 | out: | 838 | out: |
| 899 | ttm_bo_mem_put(bo, &tmp_reg); | 839 | ttm_resource_free(bo, &tmp_reg); |
| 900 | return ret; | 840 | return ret; |
| 901 | } | 841 | } |
| 902 | 842 | ||
| 903 | static int | 843 | static int |
| 904 | nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, | 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 | struct ttm_operation_ctx ctx = { intr, no_wait_gpu }; | 847 | struct ttm_operation_ctx ctx = { intr, no_wait_gpu }; |
| 908 | struct ttm_place placement_memtype = { | 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 | .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING | 851 | .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING |
| 912 | }; | 852 | }; |
| 913 | struct ttm_placement placement; | 853 | struct ttm_placement placement; |
| 914 | struct ttm_mem_reg tmp_reg; | 854 | struct ttm_resource tmp_reg; |
| 915 | int ret; | 855 | int ret; |
| 916 | 856 | ||
| 917 | placement.num_placement = placement.num_busy_placement = 1; | 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 | goto out; | 872 | goto out; |
| 933 | 873 | ||
| 934 | out: | 874 | out: |
| 935 | ttm_bo_mem_put(bo, &tmp_reg); | 875 | ttm_resource_free(bo, &tmp_reg); |
| 936 | return ret; | 876 | return ret; |
| 937 | } | 877 | } |
| 938 | 878 | ||
| 939 | static void | 879 | static void |
| 940 | nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict, | 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 | struct nouveau_mem *mem = new_reg ? nouveau_mem(new_reg) : NULL; | 883 | struct nouveau_mem *mem = new_reg ? nouveau_mem(new_reg) : NULL; |
| 944 | struct nouveau_bo *nvbo = nouveau_bo(bo); | 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 | static int | 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 | struct nouveau_drm_tile **new_tile) | 914 | struct nouveau_drm_tile **new_tile) |
| 975 | { | 915 | { |
| 976 | struct nouveau_drm *drm = nouveau_bdev(bo->bdev); | 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 | static int | 946 | static int |
| 1007 | nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, | 947 | nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, |
| 1008 | struct ttm_operation_ctx *ctx, | 948 | struct ttm_operation_ctx *ctx, |
| 1009 | struct ttm_mem_reg *new_reg) | 949 | struct ttm_resource *new_reg) |
| 1010 | { | 950 | { |
| 1011 | struct nouveau_drm *drm = nouveau_bdev(bo->bdev); | 951 | struct nouveau_drm *drm = nouveau_bdev(bo->bdev); |
| 1012 | struct nouveau_bo *nvbo = nouveau_bo(bo); | 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 | struct nouveau_drm_tile *new_tile = NULL; | 954 | struct nouveau_drm_tile *new_tile = NULL; |
| 1015 | int ret = 0; | 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 | static int | 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 | struct nouveau_drm *drm = nouveau_bdev(bdev); | 1024 | struct nouveau_drm *drm = nouveau_bdev(bdev); |
| 1085 | struct nvkm_device *device = nvxx_device(&drm->client.device); | 1025 | struct nvkm_device *device = nvxx_device(&drm->client.device); |
| 1086 | struct nouveau_mem *mem = nouveau_mem(reg); | 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 | switch (reg->mem_type) { | 1028 | switch (reg->mem_type) { |
| 1095 | case TTM_PL_SYSTEM: | 1029 | case TTM_PL_SYSTEM: |
| 1096 | /* System memory */ | 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 | static void | 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 | struct nouveau_drm *drm = nouveau_bdev(bdev); | 1098 | struct nouveau_drm *drm = nouveau_bdev(bdev); |
| 1165 | struct nouveau_mem *mem = nouveau_mem(reg); | 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 | struct ttm_dma_tt *ttm_dma = (void *)ttm; | 1165 | struct ttm_dma_tt *ttm_dma = (void *)ttm; |
| 1232 | struct nouveau_drm *drm; | 1166 | struct nouveau_drm *drm; |
| 1233 | struct device *dev; | 1167 | struct device *dev; |
| 1234 | unsigned i; | ||
| 1235 | int r; | ||
| 1236 | bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); | 1168 | bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); |
| 1237 | 1169 | ||
| 1238 | if (ttm->state != tt_unpopulated) | 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 | return ttm_dma_populate((void *)ttm, dev, ctx); | 1192 | return ttm_dma_populate((void *)ttm, dev, ctx); |
| 1261 | } | 1193 | } |
| 1262 | #endif | 1194 | #endif |
| 1263 | 1195 | return ttm_populate_and_map_pages(dev, ttm_dma, ctx); | |
| 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; | ||
| 1288 | } | 1196 | } |
| 1289 | 1197 | ||
| 1290 | static void | 1198 | static void |
| @@ -1293,7 +1201,6 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) · 2 unmodified lines | |||
| 1293 | struct ttm_dma_tt *ttm_dma = (void *)ttm; | 1201 | struct ttm_dma_tt *ttm_dma = (void *)ttm; |
| 1294 | struct nouveau_drm *drm; | 1202 | struct nouveau_drm *drm; |
| 1295 | struct device *dev; | 1203 | struct device *dev; |
| 1296 | unsigned i; | ||
| 1297 | bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); | 1204 | bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); |
| 1298 | 1205 | ||
| 1299 | if (slave) | 1206 | if (slave) |
| @@ -1316,14 +1223,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) · 16 unmodified lines | |||
| 1316 | } | 1223 | } |
| 1317 | #endif | 1224 | #endif |
| 1318 | 1225 | ||
| 1319 | for (i = 0; i < ttm->num_pages; i++) { | 1226 | ttm_unmap_and_unpopulate_pages(dev, ttm_dma); |
| 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); | ||
| 1327 | } | 1227 | } |
| 1328 | 1228 | ||
| 1329 | void | 1229 | void |
| @@ -1341,7 +1241,6 @@ struct ttm_bo_driver nouveau_bo_driver = { · 11 unmodified lines | |||
| 1341 | .ttm_tt_create = &nouveau_ttm_tt_create, | 1241 | .ttm_tt_create = &nouveau_ttm_tt_create, |
| 1342 | .ttm_tt_populate = &nouveau_ttm_tt_populate, | 1242 | .ttm_tt_populate = &nouveau_ttm_tt_populate, |
| 1343 | .ttm_tt_unpopulate = &nouveau_ttm_tt_unpopulate, | 1243 | .ttm_tt_unpopulate = &nouveau_ttm_tt_unpopulate, |
| 1344 | .init_mem_type = nouveau_bo_init_mem_type, | ||
| 1345 | .eviction_valuable = ttm_bo_eviction_valuable, | 1244 | .eviction_valuable = ttm_bo_eviction_valuable, |
| 1346 | .evict_flags = nouveau_bo_evict_flags, | 1245 | .evict_flags = nouveau_bo_evict_flags, |
| 1347 | .move_notify = nouveau_bo_move_ntfy, | 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 | int nv04_bo_move_init(struct nouveau_channel *, u32); | 140 | int nv04_bo_move_init(struct nouveau_channel *, u32); |
| 141 | int nv04_bo_move_m2mf(struct nouveau_channel *, struct ttm_buffer_object *, | 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 | int nv50_bo_move_init(struct nouveau_channel *, u32); | 144 | int nv50_bo_move_init(struct nouveau_channel *, u32); |
| 145 | int nv50_bo_move_m2mf(struct nouveau_channel *, struct ttm_buffer_object *, | 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 | int nv84_bo_move_exec(struct nouveau_channel *, struct ttm_buffer_object *, | 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 | int nva3_bo_move_copy(struct nouveau_channel *, struct ttm_buffer_object *, | 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 | int nvc0_bo_move_init(struct nouveau_channel *, u32); | 154 | int nvc0_bo_move_init(struct nouveau_channel *, u32); |
| 155 | int nvc0_bo_move_m2mf(struct nouveau_channel *, struct ttm_buffer_object *, | 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 | int nvc0_bo_move_copy(struct nouveau_channel *, struct ttm_buffer_object *, | 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 | int nve0_bo_move_init(struct nouveau_channel *, u32); | 161 | int nve0_bo_move_init(struct nouveau_channel *, u32); |
| 162 | int nve0_bo_move_copy(struct nouveau_channel *, struct ttm_buffer_object *, | 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 | #define NVBO_WR32_(b,o,dr,f) nouveau_bo_wr32((b), (o)/4 + (dr), (f)) | 165 | #define NVBO_WR32_(b,o,dr,f) nouveau_bo_wr32((b), (o)/4 + (dr), (f)) |
| 166 | #define NVBO_RD32_(b,o,dr) nouveau_bo_rd32((b), (o)/4 + (dr)) | 166 | #define NVBO_RD32_(b,o,dr) nouveau_bo_rd32((b), (o)/4 + (dr)) |
| @@ -36,7 +36,7 @@ · 35 unmodified lines | |||
| 36 | 36 | ||
| 37 | static inline uint32_t | 37 | static inline uint32_t |
| 38 | nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo, | 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 | if (reg->mem_type == TTM_PL_TT) | 41 | if (reg->mem_type == TTM_PL_TT) |
| 42 | return NvDmaTT; | 42 | return NvDmaTT; |
| @@ -45,7 +45,7 @@ nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo, · 2 unmodified lines | |||
| 45 | 45 | ||
| 46 | int | 46 | int |
| 47 | nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | 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 | struct nvif_push *push = chan->chan.push; | 50 | struct nvif_push *push = chan->chan.push; |
| 51 | u32 src_ctxdma = nouveau_bo_mem_ctxdma(bo, chan, old_reg); | 51 | u32 src_ctxdma = nouveau_bo_mem_ctxdma(bo, chan, old_reg); |
| @@ -37,7 +37,7 @@ · 36 unmodified lines | |||
| 37 | 37 | ||
| 38 | int | 38 | int |
| 39 | nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | 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 | struct nouveau_mem *mem = nouveau_mem(old_reg); | 42 | struct nouveau_mem *mem = nouveau_mem(old_reg); |
| 43 | struct nvif_push *push = chan->chan.push; | 43 | struct nvif_push *push = chan->chan.push; |
| @@ -34,7 +34,7 @@ · 33 unmodified lines | |||
| 34 | 34 | ||
| 35 | int | 35 | int |
| 36 | nv84_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | 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 | struct nouveau_mem *mem = nouveau_mem(old_reg); | 39 | struct nouveau_mem *mem = nouveau_mem(old_reg); |
| 40 | struct nvif_push *push = chan->chan.push; | 40 | struct nvif_push *push = chan->chan.push; |
| @@ -38,7 +38,7 @@ · 37 unmodified lines | |||
| 38 | 38 | ||
| 39 | int | 39 | int |
| 40 | nva3_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | 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 | struct nouveau_mem *mem = nouveau_mem(old_reg); | 43 | struct nouveau_mem *mem = nouveau_mem(old_reg); |
| 44 | struct nvif_push *push = chan->chan.push; | 44 | struct nvif_push *push = chan->chan.push; |
| @@ -36,7 +36,7 @@ · 35 unmodified lines | |||
| 36 | 36 | ||
| 37 | int | 37 | int |
| 38 | nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | 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 | struct nvif_push *push = chan->chan.push; | 41 | struct nvif_push *push = chan->chan.push; |
| 42 | struct nouveau_mem *mem = nouveau_mem(old_reg); | 42 | struct nouveau_mem *mem = nouveau_mem(old_reg); |
| @@ -31,7 +31,7 @@ · 30 unmodified lines | |||
| 31 | 31 | ||
| 32 | int | 32 | int |
| 33 | nvc0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | 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 | struct nouveau_mem *mem = nouveau_mem(old_reg); | 36 | struct nouveau_mem *mem = nouveau_mem(old_reg); |
| 37 | struct nvif_push *push = chan->chan.push; | 37 | struct nvif_push *push = chan->chan.push; |
| @@ -36,7 +36,7 @@ · 35 unmodified lines | |||
| 36 | 36 | ||
| 37 | int | 37 | int |
| 38 | nve0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo, | 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 | struct nouveau_mem *mem = nouveau_mem(old_reg); | 41 | struct nouveau_mem *mem = nouveau_mem(old_reg); |
| 42 | struct nvif_push *push = chan->chan.push; | 42 | struct nvif_push *push = chan->chan.push; |
| @@ -157,7 +157,7 @@ struct nouveau_drm { · 156 unmodified lines | |||
| 157 | atomic_t validate_sequence; | 157 | atomic_t validate_sequence; |
| 158 | int (*move)(struct nouveau_channel *, | 158 | int (*move)(struct nouveau_channel *, |
| 159 | struct ttm_buffer_object *, | 159 | struct ttm_buffer_object *, |
| 160 | struct ttm_mem_reg *, struct ttm_mem_reg *); | 160 | struct ttm_resource *, struct ttm_resource *); |
| 161 | struct nouveau_channel *chan; | 161 | struct nouveau_channel *chan; |
| 162 | struct nvif_object copy; | 162 | struct nvif_object copy; |
| 163 | int mtrr; | 163 | int mtrr; |
| @@ -92,7 +92,7 @@ nouveau_mem_fini(struct nouveau_mem *mem) · 91 unmodified lines | |||
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | int | 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 | struct nouveau_mem *mem = nouveau_mem(reg); | 97 | struct nouveau_mem *mem = nouveau_mem(reg); |
| 98 | struct nouveau_cli *cli = mem->cli; | 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 | int | 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 | struct nouveau_mem *mem = nouveau_mem(reg); | 135 | struct nouveau_mem *mem = nouveau_mem(reg); |
| 136 | struct nouveau_cli *cli = mem->cli; | 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 | void | 175 | void |
| 176 | nouveau_mem_del(struct ttm_mem_reg *reg) | 176 | nouveau_mem_del(struct ttm_resource *reg) |
| 177 | { | 177 | { |
| 178 | struct nouveau_mem *mem = nouveau_mem(reg); | 178 | struct nouveau_mem *mem = nouveau_mem(reg); |
| 179 | nouveau_mem_fini(mem); | 179 | nouveau_mem_fini(mem); |
| @@ -183,7 +183,7 @@ nouveau_mem_del(struct ttm_mem_reg *reg) · 3 unmodified lines | |||
| 183 | 183 | ||
| 184 | int | 184 | int |
| 185 | nouveau_mem_new(struct nouveau_cli *cli, u8 kind, u8 comp, | 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 | struct nouveau_mem *mem; | 188 | struct nouveau_mem *mem; |
| 189 | 189 | ||
| @@ -7,7 +7,7 @@ struct ttm_dma_tt; · 6 unmodified lines | |||
| 7 | #include <nvif/vmm.h> | 7 | #include <nvif/vmm.h> |
| 8 | 8 | ||
| 9 | static inline struct nouveau_mem * | 9 | static inline struct nouveau_mem * |
| 10 | nouveau_mem(struct ttm_mem_reg *reg) | 10 | nouveau_mem(struct ttm_resource *reg) |
| 11 | { | 11 | { |
| 12 | return reg->mm_node; | 12 | return reg->mm_node; |
| 13 | } | 13 | } |
| @@ -21,10 +21,10 @@ struct nouveau_mem { · 7 unmodified lines | |||
| 21 | }; | 21 | }; |
| 22 | 22 | ||
| 23 | int nouveau_mem_new(struct nouveau_cli *, u8 kind, u8 comp, | 23 | int nouveau_mem_new(struct nouveau_cli *, u8 kind, u8 comp, |
| 24 | struct ttm_mem_reg *); | 24 | struct ttm_resource *); |
| 25 | void nouveau_mem_del(struct ttm_mem_reg *); | 25 | void nouveau_mem_del(struct ttm_resource *); |
| 26 | int nouveau_mem_vram(struct ttm_mem_reg *, bool contig, u8 page); | 26 | int nouveau_mem_vram(struct ttm_resource *, bool contig, u8 page); |
| 27 | int nouveau_mem_host(struct ttm_mem_reg *, struct ttm_dma_tt *); | 27 | int nouveau_mem_host(struct ttm_resource *, struct ttm_dma_tt *); |
| 28 | void nouveau_mem_fini(struct nouveau_mem *); | 28 | void nouveau_mem_fini(struct nouveau_mem *); |
| 29 | int nouveau_mem_map(struct nouveau_mem *, struct nvif_vmm *, struct nvif_vma *); | 29 | int nouveau_mem_map(struct nouveau_mem *, struct nvif_vmm *, struct nvif_vma *); |
| 30 | #endif | 30 | #endif |
| @@ -26,7 +26,7 @@ nouveau_sgdma_destroy(struct ttm_tt *ttm) · 25 unmodified lines | |||
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | static int | 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 | struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm; | 31 | struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm; |
| 32 | struct nouveau_mem *mem = nouveau_mem(reg); | 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 | static int | 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 | struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm; | 65 | struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm; |
| 66 | struct nouveau_mem *mem = nouveau_mem(reg); | 66 | struct nouveau_mem *mem = nouveau_mem(reg); |
| @@ -31,35 +31,17 @@ · 30 unmodified lines | |||
| 31 | 31 | ||
| 32 | #include <core/tegra.h> | 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 | static void | 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 | nouveau_mem_del(reg); | 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 | static int | 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 | struct ttm_buffer_object *bo, | 42 | struct ttm_buffer_object *bo, |
| 61 | const struct ttm_place *place, | 43 | const struct ttm_place *place, |
| 62 | struct ttm_mem_reg *reg) | 44 | struct ttm_resource *reg) |
| 63 | { | 45 | { |
| 64 | struct nouveau_bo *nvbo = nouveau_bo(bo); | 46 | struct nouveau_bo *nvbo = nouveau_bo(bo); |
| 65 | struct nouveau_drm *drm = nouveau_bdev(bo->bdev); | 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 | return 0; | 63 | return 0; |
| 82 | } | 64 | } |
| 83 | 65 | ||
| 84 | const struct ttm_mem_type_manager_func nouveau_vram_manager = { | 66 | const struct ttm_resource_manager_func nouveau_vram_manager = { |
| 85 | .init = nouveau_manager_init, | 67 | .alloc = nouveau_vram_manager_new, |
| 86 | .takedown = nouveau_manager_fini, | 68 | .free = nouveau_manager_del, |
| 87 | .get_node = nouveau_vram_manager_new, | ||
| 88 | .put_node = nouveau_manager_del, | ||
| 89 | .debug = nouveau_manager_debug, | ||
| 90 | }; | 69 | }; |
| 91 | 70 | ||
| 92 | static int | 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 | struct ttm_buffer_object *bo, | 73 | struct ttm_buffer_object *bo, |
| 95 | const struct ttm_place *place, | 74 | const struct ttm_place *place, |
| 96 | struct ttm_mem_reg *reg) | 75 | struct ttm_resource *reg) |
| 97 | { | 76 | { |
| 98 | struct nouveau_bo *nvbo = nouveau_bo(bo); | 77 | struct nouveau_bo *nvbo = nouveau_bo(bo); |
| 99 | struct nouveau_drm *drm = nouveau_bdev(bo->bdev); | 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 | return 0; | 86 | return 0; |
| 108 | } | 87 | } |
| 109 | 88 | ||
| 110 | const struct ttm_mem_type_manager_func nouveau_gart_manager = { | 89 | const struct ttm_resource_manager_func nouveau_gart_manager = { |
| 111 | .init = nouveau_manager_init, | 90 | .alloc = nouveau_gart_manager_new, |
| 112 | .takedown = nouveau_manager_fini, | 91 | .free = nouveau_manager_del, |
| 113 | .get_node = nouveau_gart_manager_new, | ||
| 114 | .put_node = nouveau_manager_del, | ||
| 115 | .debug = nouveau_manager_debug | ||
| 116 | }; | 92 | }; |
| 117 | 93 | ||
| 118 | static int | 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 | struct ttm_buffer_object *bo, | 96 | struct ttm_buffer_object *bo, |
| 121 | const struct ttm_place *place, | 97 | const struct ttm_place *place, |
| 122 | struct ttm_mem_reg *reg) | 98 | struct ttm_resource *reg) |
| 123 | { | 99 | { |
| 124 | struct nouveau_bo *nvbo = nouveau_bo(bo); | 100 | struct nouveau_bo *nvbo = nouveau_bo(bo); |
| 125 | struct nouveau_drm *drm = nouveau_bdev(bo->bdev); | 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 | return 0; | 118 | return 0; |
| 143 | } | 119 | } |
| 144 | 120 | ||
| 145 | const struct ttm_mem_type_manager_func nv04_gart_manager = { | 121 | const struct ttm_resource_manager_func nv04_gart_manager = { |
| 146 | .init = nouveau_manager_init, | 122 | .alloc = nv04_gart_manager_new, |
| 147 | .takedown = nouveau_manager_fini, | 123 | .free = nouveau_manager_del, |
| 148 | .get_node = nv04_gart_manager_new, | ||
| 149 | .put_node = nouveau_manager_del, | ||
| 150 | .debug = nouveau_manager_debug | ||
| 151 | }; | 124 | }; |
| 152 | 125 | ||
| 153 | int | 126 | int |
| @@ -180,6 +153,113 @@ nouveau_ttm_init_host(struct nouveau_drm *drm, u8 kind) · 26 unmodified lines | |||
| 180 | return 0; | 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 | int | 263 | int |
| 184 | nouveau_ttm_init(struct nouveau_drm *drm) | 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 | arch_io_reserve_memtype_wc(device->func->resource_addr(device, 1), | 317 | arch_io_reserve_memtype_wc(device->func->resource_addr(device, 1), |
| 238 | device->func->resource_size(device, 1)); | 318 | device->func->resource_size(device, 1)); |
| 239 | 319 | ||
| 240 | ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM, | 320 | ret = nouveau_ttm_init_vram(drm); |
| 241 | drm->gem.vram_available >> PAGE_SHIFT); | ||
| 242 | if (ret) { | 321 | if (ret) { |
| 243 | NV_ERROR(drm, "VRAM mm init failed, %d\n", ret); | 322 | NV_ERROR(drm, "VRAM mm init failed, %d\n", ret); |
| 244 | return ret; | 323 | return ret; |
| @@ -254,8 +333,7 @@ nouveau_ttm_init(struct nouveau_drm *drm) · 9 unmodified lines | |||
| 254 | drm->gem.gart_available = drm->agp.size; | 333 | drm->gem.gart_available = drm->agp.size; |
| 255 | } | 334 | } |
| 256 | 335 | ||
| 257 | ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_TT, | 336 | ret = nouveau_ttm_init_gtt(drm); |
| 258 | drm->gem.gart_available >> PAGE_SHIFT); | ||
| 259 | if (ret) { | 337 | if (ret) { |
| 260 | NV_ERROR(drm, "GART mm init failed, %d\n", ret); | 338 | NV_ERROR(drm, "GART mm init failed, %d\n", ret); |
| 261 | return ret; | 339 | return ret; |
| @@ -271,8 +349,8 @@ nouveau_ttm_fini(struct nouveau_drm *drm) · 9 unmodified lines | |||
| 271 | { | 349 | { |
| 272 | struct nvkm_device *device = nvxx_device(&drm->client.device); | 350 | struct nvkm_device *device = nvxx_device(&drm->client.device); |
| 273 | 351 | ||
| 274 | ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_VRAM); | 352 | nouveau_ttm_fini_vram(drm); |
| 275 | ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_TT); | 353 | nouveau_ttm_fini_gtt(drm); |
| 276 | 354 | ||
| 277 | ttm_bo_device_release(&drm->ttm.bdev); | 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 | return container_of(bd, struct nouveau_drm, ttm.bdev); | 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; | 11 | extern const struct ttm_resource_manager_func nouveau_vram_manager; |
| 12 | extern const struct ttm_mem_type_manager_func nouveau_gart_manager; | 12 | extern const struct ttm_resource_manager_func nouveau_gart_manager; |
| 13 | extern const struct ttm_mem_type_manager_func nv04_gart_manager; | 13 | extern const struct ttm_resource_manager_func nv04_gart_manager; |
| 14 | 14 | ||
| 15 | struct ttm_tt *nouveau_sgdma_create_ttm(struct ttm_buffer_object *bo, | 15 | struct ttm_tt *nouveau_sgdma_create_ttm(struct ttm_buffer_object *bo, |
| 16 | u32 page_flags); | 16 | u32 page_flags); |
| @@ -78,7 +78,7 @@ nv17_fence_context_new(struct nouveau_channel *chan) · 77 unmodified lines | |||
| 78 | { | 78 | { |
| 79 | struct nv10_fence_priv *priv = chan->drm->fence; | 79 | struct nv10_fence_priv *priv = chan->drm->fence; |
| 80 | struct nv10_fence_chan *fctx; | 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 | u32 start = reg->start * PAGE_SIZE; | 82 | u32 start = reg->start * PAGE_SIZE; |
| 83 | u32 limit = start + reg->size - 1; | 83 | u32 limit = start + reg->size - 1; |
| 84 | int ret = 0; | 84 | int ret = 0; |
| @@ -37,7 +37,7 @@ nv50_fence_context_new(struct nouveau_channel *chan) · 36 unmodified lines | |||
| 37 | { | 37 | { |
| 38 | struct nv10_fence_priv *priv = chan->drm->fence; | 38 | struct nv10_fence_priv *priv = chan->drm->fence; |
| 39 | struct nv10_fence_chan *fctx; | 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 | u32 start = reg->start * PAGE_SIZE; | 41 | u32 start = reg->start * PAGE_SIZE; |
| 42 | u32 limit = start + reg->size - 1; | 42 | u32 limit = start + reg->size - 1; |
| 43 | int ret; | 43 | int ret; |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | |||
| 20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
| 21 | #include <linux/pm_runtime.h> | 21 | #include <linux/pm_runtime.h> |
| 22 | #include <linux/clk.h> | 22 | #include <linux/clk.h> |
| 23 | #include <linux/gpio.h> | ||
| 24 | #include <linux/regulator/consumer.h> | 23 | #include <linux/regulator/consumer.h> |
| 25 | #include <linux/component.h> | 24 | #include <linux/component.h> |
| 26 | #include <linux/of.h> | 25 | #include <linux/of.h> |
| @@ -24,7 +24,6 @@ · 23 unmodified lines | |||
| 24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
| 25 | #include <linux/pm_runtime.h> | 25 | #include <linux/pm_runtime.h> |
| 26 | #include <linux/clk.h> | 26 | #include <linux/clk.h> |
| 27 | #include <linux/gpio.h> | ||
| 28 | #include <linux/regulator/consumer.h> | 27 | #include <linux/regulator/consumer.h> |
| 29 | #include <linux/component.h> | 28 | #include <linux/component.h> |
| 30 | #include <linux/of.h> | 29 | #include <linux/of.h> |
| @@ -781,7 +781,7 @@ static int venc_probe_of(struct venc_device *venc) · 780 unmodified lines | |||
| 781 | venc->type = OMAP_DSS_VENC_TYPE_SVIDEO; | 781 | venc->type = OMAP_DSS_VENC_TYPE_SVIDEO; |
| 782 | break; | 782 | break; |
| 783 | default: | 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 | channels); | 785 | channels); |
| 786 | r = -EINVAL; | 786 | r = -EINVAL; |
| 787 | goto err; | 787 | goto err; |
| @@ -349,13 +349,6 @@ static int omap_modeset_init(struct drm_device *dev) · 348 unmodified lines | |||
| 349 | 349 | ||
| 350 | drm_connector_attach_encoder(pipe->connector, encoder); | 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 | crtc = omap_crtc_init(dev, pipe, priv->planes[i]); | 352 | crtc = omap_crtc_init(dev, pipe, priv->planes[i]); |
| 360 | if (IS_ERR(crtc)) | 353 | if (IS_ERR(crtc)) |
| 361 | return PTR_ERR(crtc); | 354 | return PTR_ERR(crtc); |
| @@ -394,18 +387,8 @@ static int omap_modeset_init(struct drm_device *dev) · 32 unmodified lines | |||
| 394 | 387 | ||
| 395 | static void omap_modeset_fini(struct drm_device *ddev) | 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 | omap_drm_irq_uninstall(ddev); | 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 | drm_mode_config_cleanup(ddev); | 392 | drm_mode_config_cleanup(ddev); |
| 410 | } | 393 | } |
| 411 | 394 | ||
| @@ -217,6 +217,17 @@ config DRM_PANEL_NOVATEK_NT39016 · 216 unmodified lines | |||
| 217 | Say Y here if you want to enable support for the panels built | 217 | Say Y here if you want to enable support for the panels built |
| 218 | around the Novatek NT39016 display controller. | 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 | config DRM_PANEL_OLIMEX_LCD_OLINUXINO | 231 | config DRM_PANEL_OLIMEX_LCD_OLINUXINO |
| 221 | tristate "Olimex LCD-OLinuXino panel" | 232 | tristate "Olimex LCD-OLinuXino panel" |
| 222 | depends on OF | 233 | depends on OF |
| @@ -20,6 +20,7 @@ obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o · 19 unmodified lines | |||
| 20 | obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o | 20 | obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o |
| 21 | obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35510) += panel-novatek-nt35510.o | 21 | obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35510) += panel-novatek-nt35510.o |
| 22 | obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o | 22 | obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o |
| 23 | obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o | ||
| 23 | obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o | 24 | obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o |
| 24 | obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o | 25 | obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o |
| 25 | obj-$(CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS) += panel-osd-osd101t2587-53ts.o | 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 | drm_panel_init(&vpanel->panel, dev, &versatile_panel_drm_funcs, | 349 | drm_panel_init(&vpanel->panel, dev, &versatile_panel_drm_funcs, |
| 350 | DRM_MODE_CONNECTOR_DPI); | 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 | static const struct of_device_id versatile_panel_match[] = { | 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 | return ret; | 315 | return ret; |
| 316 | } | 316 | } |
| 317 | 317 | ||
| 318 | ret = drm_panel_add(&ctx->panel); | 318 | drm_panel_add(&ctx->panel); |
| 319 | if (ret < 0) { | ||
| 320 | dev_err(dev, "Failed to add panel: %d\n", ret); | ||
| 321 | return ret; | ||
| 322 | } | ||
| 323 | 319 | ||
| 324 | ret = mipi_dsi_attach(dsi); | 320 | ret = mipi_dsi_attach(dsi); |
| 325 | if (ret < 0) { | 321 | if (ret < 0) { |
| @@ -19,7 +19,6 @@ · 18 unmodified lines | |||
| 19 | #include <drm/drm_mipi_dsi.h> | 19 | #include <drm/drm_mipi_dsi.h> |
| 20 | #include <drm/drm_modes.h> | 20 | #include <drm/drm_modes.h> |
| 21 | #include <drm/drm_panel.h> | 21 | #include <drm/drm_panel.h> |
| 22 | #include <drm/drm_print.h> | ||
| 23 | 22 | ||
| 24 | #include <video/mipi_display.h> | 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 | err = mipi_dsi_dcs_set_display_off(pinfo->link); | 93 | err = mipi_dsi_dcs_set_display_off(pinfo->link); |
| 95 | if (err < 0) { | 94 | if (err < 0) { |
| 96 | DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", | 95 | dev_err(panel->dev, "failed to set display off: %d\n", err); |
| 97 | err); | ||
| 98 | return err; | 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 | err = mipi_dsi_dcs_set_display_off(pinfo->link); | 112 | err = mipi_dsi_dcs_set_display_off(pinfo->link); |
| 115 | if (err < 0) | 113 | if (err < 0) |
| 116 | DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", | 114 | dev_err(panel->dev, "failed to set display off: %d\n", err); |
| 117 | err); | ||
| 118 | 115 | ||
| 119 | err = mipi_dsi_dcs_enter_sleep_mode(pinfo->link); | 116 | err = mipi_dsi_dcs_enter_sleep_mode(pinfo->link); |
| 120 | if (err < 0) | 117 | if (err < 0) |
| 121 | DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", | 118 | dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); |
| 122 | err); | ||
| 123 | 119 | ||
| 124 | /* sleep_mode_delay: 1ms - 2ms */ | 120 | /* sleep_mode_delay: 1ms - 2ms */ |
| 125 | usleep_range(1000, 2000); | 121 | usleep_range(1000, 2000); |
| @@ -163,15 +159,13 @@ static int boe_panel_prepare(struct drm_panel *panel) · 37 unmodified lines | |||
| 163 | /* send init code */ | 159 | /* send init code */ |
| 164 | err = send_mipi_cmds(panel, pinfo->desc->on_cmds); | 160 | err = send_mipi_cmds(panel, pinfo->desc->on_cmds); |
| 165 | if (err < 0) { | 161 | if (err < 0) { |
| 166 | DRM_DEV_ERROR(panel->dev, "failed to send DCS Init Code: %d\n", | 162 | dev_err(panel->dev, "failed to send DCS Init Code: %d\n", err); |
| 167 | err); | ||
| 168 | goto poweroff; | 163 | goto poweroff; |
| 169 | } | 164 | } |
| 170 | 165 | ||
| 171 | err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link); | 166 | err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link); |
| 172 | if (err < 0) { | 167 | if (err < 0) { |
| 173 | DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n", | 168 | dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); |
| 174 | err); | ||
| 175 | goto poweroff; | 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 | err = mipi_dsi_dcs_set_display_on(pinfo->link); | 175 | err = mipi_dsi_dcs_set_display_on(pinfo->link); |
| 182 | if (err < 0) { | 176 | if (err < 0) { |
| 183 | DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", | 177 | dev_err(panel->dev, "failed to set display on: %d\n", err); |
| 184 | err); | ||
| 185 | goto poweroff; | 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 | ret = mipi_dsi_dcs_set_display_on(pinfo->link); | 203 | ret = mipi_dsi_dcs_set_display_on(pinfo->link); |
| 211 | if (ret < 0) { | 204 | if (ret < 0) { |
| 212 | DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", | 205 | dev_err(panel->dev, "failed to set display on: %d\n", ret); |
| 213 | ret); | ||
| 214 | return ret; | 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 | mode = drm_mode_duplicate(connector->dev, m); | 221 | mode = drm_mode_duplicate(connector->dev, m); |
| 230 | if (!mode) { | 222 | if (!mode) { |
| 231 | DRM_DEV_ERROR(pinfo->base.dev, "failed to add mode %ux%u@%u\n", | 223 | dev_err(pinfo->base.dev, "failed to add mode %ux%u@%u\n", |
| 232 | m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); | 224 | m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); |
| 233 | return -ENOMEM; | 225 | return -ENOMEM; |
| 234 | } | 226 | } |
| 235 | 227 | ||
| @@ -865,8 +857,7 @@ static int panel_add(struct panel_info *pinfo) · 629 unmodified lines | |||
| 865 | if (IS_ERR(pinfo->pp18_gpio)) { | 857 | if (IS_ERR(pinfo->pp18_gpio)) { |
| 866 | ret = PTR_ERR(pinfo->pp18_gpio); | 858 | ret = PTR_ERR(pinfo->pp18_gpio); |
| 867 | if (ret != -EPROBE_DEFER) | 859 | if (ret != -EPROBE_DEFER) |
| 868 | DRM_DEV_ERROR(dev, "failed to get pp18 gpio: %d\n", | 860 | dev_err(dev, "failed to get pp18 gpio: %d\n", ret); |
| 869 | ret); | ||
| 870 | return ret; | 861 | return ret; |
| 871 | } | 862 | } |
| 872 | 863 | ||
| @@ -874,8 +865,7 @@ static int panel_add(struct panel_info *pinfo) · 1 unmodified line | |||
| 874 | if (IS_ERR(pinfo->pp33_gpio)) { | 865 | if (IS_ERR(pinfo->pp33_gpio)) { |
| 875 | ret = PTR_ERR(pinfo->pp33_gpio); | 866 | ret = PTR_ERR(pinfo->pp33_gpio); |
| 876 | if (ret != -EPROBE_DEFER) | 867 | if (ret != -EPROBE_DEFER) |
| 877 | DRM_DEV_ERROR(dev, "failed to get pp33 gpio: %d\n", | 868 | dev_err(dev, "failed to get pp33 gpio: %d\n", ret); |
| 878 | ret); | ||
| 879 | return ret; | 869 | return ret; |
| 880 | } | 870 | } |
| 881 | 871 | ||
| @@ -883,8 +873,7 @@ static int panel_add(struct panel_info *pinfo) · 1 unmodified line | |||
| 883 | if (IS_ERR(pinfo->enable_gpio)) { | 873 | if (IS_ERR(pinfo->enable_gpio)) { |
| 884 | ret = PTR_ERR(pinfo->enable_gpio); | 874 | ret = PTR_ERR(pinfo->enable_gpio); |
| 885 | if (ret != -EPROBE_DEFER) | 875 | if (ret != -EPROBE_DEFER) |
| 886 | DRM_DEV_ERROR(dev, "failed to get enable gpio: %d\n", | 876 | dev_err(dev, "failed to get enable gpio: %d\n", ret); |
| 887 | ret); | ||
| 888 | return ret; | 877 | return ret; |
| 889 | } | 878 | } |
| 890 | 879 | ||
| @@ -895,7 +884,9 @@ static int panel_add(struct panel_info *pinfo) · 4 unmodified lines | |||
| 895 | if (ret) | 884 | if (ret) |
| 896 | return ret; | 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 | static int panel_probe(struct mipi_dsi_device *dsi) | 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 | err = boe_panel_disable(&pinfo->base); | 927 | err = boe_panel_disable(&pinfo->base); |
| 937 | if (err < 0) | 928 | if (err < 0) |
| 938 | DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", | 929 | dev_err(&dsi->dev, "failed to disable panel: %d\n", err); |
| 939 | err); | ||
| 940 | 930 | ||
| 941 | err = boe_panel_unprepare(&pinfo->base); | 931 | err = boe_panel_unprepare(&pinfo->base); |
| 942 | if (err < 0) | 932 | if (err < 0) |
| 943 | DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n", | 933 | dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err); |
| 944 | err); | ||
| 945 | 934 | ||
| 946 | err = mipi_dsi_detach(dsi); | 935 | err = mipi_dsi_detach(dsi); |
| 947 | if (err < 0) | 936 | if (err < 0) |
| 948 | DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n", | 937 | dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); |
| 949 | err); | ||
| 950 | 938 | ||
| 951 | drm_panel_remove(&pinfo->base); | 939 | drm_panel_remove(&pinfo->base); |
| 952 | 940 | ||
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | #include <linux/of_device.h> | 11 | #include <linux/of_device.h> |
| 12 | #include <linux/regulator/consumer.h> | 12 | #include <linux/regulator/consumer.h> |
| 13 | 13 | ||
| 14 | #include <drm/drm_connector.h> | ||
| 14 | #include <drm/drm_crtc.h> | 15 | #include <drm/drm_crtc.h> |
| 15 | #include <drm/drm_mipi_dsi.h> | 16 | #include <drm/drm_mipi_dsi.h> |
| 16 | #include <drm/drm_panel.h> | 17 | #include <drm/drm_panel.h> |
| @@ -43,6 +44,7 @@ struct boe_panel { · 26 unmodified lines | |||
| 43 | 44 | ||
| 44 | const struct panel_desc *desc; | 45 | const struct panel_desc *desc; |
| 45 | 46 | ||
| 47 | enum drm_panel_orientation orientation; | ||
| 46 | struct regulator *pp1800; | 48 | struct regulator *pp1800; |
| 47 | struct regulator *avee; | 49 | struct regulator *avee; |
| 48 | struct regulator *avdd; | 50 | struct regulator *avdd; |
| @@ -740,6 +742,7 @@ static int boe_panel_get_modes(struct drm_panel *panel, · 691 unmodified lines | |||
| 740 | connector->display_info.width_mm = boe->desc->size.width_mm; | 742 | connector->display_info.width_mm = boe->desc->size.width_mm; |
| 741 | connector->display_info.height_mm = boe->desc->size.height_mm; | 743 | connector->display_info.height_mm = boe->desc->size.height_mm; |
| 742 | connector->display_info.bpc = boe->desc->bpc; | 744 | connector->display_info.bpc = boe->desc->bpc; |
| 745 | drm_connector_set_panel_orientation(connector, boe->orientation); | ||
| 743 | 746 | ||
| 744 | return 1; | 747 | return 1; |
| 745 | } | 748 | } |
| @@ -779,6 +782,11 @@ static int boe_panel_add(struct boe_panel *boe) · 33 unmodified lines | |||
| 779 | 782 | ||
| 780 | drm_panel_init(&boe->base, dev, &boe_panel_funcs, | 783 | drm_panel_init(&boe->base, dev, &boe_panel_funcs, |
| 781 | DRM_MODE_CONNECTOR_DSI); | 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 | err = drm_panel_of_backlight(&boe->base); | 791 | err = drm_panel_of_backlight(&boe->base); |
| 784 | if (err) | 792 | if (err) |
| @@ -787,7 +795,9 @@ static int boe_panel_add(struct boe_panel *boe) · 2 unmodified lines | |||
| 787 | boe->base.funcs = &boe_panel_funcs; | 795 | boe->base.funcs = &boe_panel_funcs; |
| 788 | boe->base.dev = &boe->dsi->dev; | 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 | static int boe_panel_probe(struct mipi_dsi_device *dsi) | 803 | static int boe_panel_probe(struct mipi_dsi_device *dsi) |
| @@ -22,7 +22,6 @@ · 21 unmodified lines | |||
| 22 | #include <drm/drm_mipi_dsi.h> | 22 | #include <drm/drm_mipi_dsi.h> |
| 23 | #include <drm/drm_modes.h> | 23 | #include <drm/drm_modes.h> |
| 24 | #include <drm/drm_panel.h> | 24 | #include <drm/drm_panel.h> |
| 25 | #include <drm/drm_print.h> | ||
| 26 | 25 | ||
| 27 | /* Manufacturer specific Commands send via DSI */ | 26 | /* Manufacturer specific Commands send via DSI */ |
| 28 | #define KD35T133_CMD_INTERFACEMODECTRL 0xb0 | 27 | #define KD35T133_CMD_INTERFACEMODECTRL 0xb0 |
| @@ -89,7 +88,7 @@ static int kd35t133_init_sequence(struct kd35t133 *ctx) · 60 unmodified lines | |||
| 89 | 0xa9, 0x51, 0x2c, 0x82); | 88 | 0xa9, 0x51, 0x2c, 0x82); |
| 90 | mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_INVERT_MODE, NULL, 0); | 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 | return 0; | 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 | ret = mipi_dsi_dcs_set_display_off(dsi); | 104 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 106 | if (ret < 0) | 105 | if (ret < 0) |
| 107 | DRM_DEV_ERROR(ctx->dev, "failed to set display off: %d\n", | 106 | dev_err(ctx->dev, "failed to set display off: %d\n", ret); |
| 108 | ret); | ||
| 109 | 107 | ||
| 110 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); | 108 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 111 | if (ret < 0) { | 109 | if (ret < 0) { |
| 112 | DRM_DEV_ERROR(ctx->dev, "failed to enter sleep mode: %d\n", | 110 | dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret); |
| 113 | ret); | ||
| 114 | return ret; | 111 | return ret; |
| 115 | } | 112 | } |
| 116 | 113 | ||
| @@ -131,18 +128,16 @@ static int kd35t133_prepare(struct drm_panel *panel) · 14 unmodified lines | |||
| 131 | if (ctx->prepared) | 128 | if (ctx->prepared) |
| 132 | return 0; | 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 | ret = regulator_enable(ctx->vdd); | 132 | ret = regulator_enable(ctx->vdd); |
| 136 | if (ret < 0) { | 133 | if (ret < 0) { |
| 137 | DRM_DEV_ERROR(ctx->dev, | 134 | dev_err(ctx->dev, "Failed to enable vdd supply: %d\n", ret); |
| 138 | "Failed to enable vdd supply: %d\n", ret); | ||
| 139 | return ret; | 135 | return ret; |
| 140 | } | 136 | } |
| 141 | 137 | ||
| 142 | ret = regulator_enable(ctx->iovcc); | 138 | ret = regulator_enable(ctx->iovcc); |
| 143 | if (ret < 0) { | 139 | if (ret < 0) { |
| 144 | DRM_DEV_ERROR(ctx->dev, | 140 | dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); |
| 145 | "Failed to enable iovcc supply: %d\n", ret); | ||
| 146 | goto disable_vdd; | 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 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | 152 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 158 | if (ret < 0) { | 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 | goto disable_iovcc; | 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 | ret = kd35t133_init_sequence(ctx); | 160 | ret = kd35t133_init_sequence(ctx); |
| 166 | if (ret < 0) { | 161 | if (ret < 0) { |
| 167 | DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", | 162 | dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); |
| 168 | ret); | ||
| 169 | goto disable_iovcc; | 163 | goto disable_iovcc; |
| 170 | } | 164 | } |
| 171 | 165 | ||
| 172 | ret = mipi_dsi_dcs_set_display_on(dsi); | 166 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 173 | if (ret < 0) { | 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 | goto disable_iovcc; | 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 | mode = drm_mode_duplicate(connector->dev, &default_mode); | 205 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 212 | if (!mode) { | 206 | if (!mode) { |
| 213 | DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n", | 207 | dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", |
| 214 | default_mode.hdisplay, default_mode.vdisplay, | 208 | default_mode.hdisplay, default_mode.vdisplay, |
| 215 | drm_mode_vrefresh(&default_mode)); | 209 | drm_mode_vrefresh(&default_mode)); |
| 216 | return -ENOMEM; | 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 | ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); | 239 | ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); |
| 246 | if (IS_ERR(ctx->reset_gpio)) { | 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 | return PTR_ERR(ctx->reset_gpio); | 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 | if (IS_ERR(ctx->vdd)) { | 246 | if (IS_ERR(ctx->vdd)) { |
| 253 | ret = PTR_ERR(ctx->vdd); | 247 | ret = PTR_ERR(ctx->vdd); |
| 254 | if (ret != -EPROBE_DEFER) | 248 | if (ret != -EPROBE_DEFER) |
| 255 | DRM_DEV_ERROR(dev, | 249 | dev_err(dev, "Failed to request vdd regulator: %d\n", ret); |
| 256 | "Failed to request vdd regulator: %d\n", | ||
| 257 | ret); | ||
| 258 | return ret; | 250 | return ret; |
| 259 | } | 251 | } |
| 260 | 252 | ||
| @@ -262,9 +254,7 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi) · 1 unmodified line | |||
| 262 | if (IS_ERR(ctx->iovcc)) { | 254 | if (IS_ERR(ctx->iovcc)) { |
| 263 | ret = PTR_ERR(ctx->iovcc); | 255 | ret = PTR_ERR(ctx->iovcc); |
| 264 | if (ret != -EPROBE_DEFER) | 256 | if (ret != -EPROBE_DEFER) |
| 265 | DRM_DEV_ERROR(dev, | 257 | dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); |
| 266 | "Failed to request iovcc regulator: %d\n", | ||
| 267 | ret); | ||
| 268 | return ret; | 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 | ret = mipi_dsi_attach(dsi); | 279 | ret = mipi_dsi_attach(dsi); |
| 290 | if (ret < 0) { | 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 | drm_panel_remove(&ctx->panel); | 282 | drm_panel_remove(&ctx->panel); |
| 293 | return ret; | 283 | return ret; |
| 294 | } | 284 | } |
| @@ -303,13 +293,11 @@ static void kd35t133_shutdown(struct mipi_dsi_device *dsi) · 8 unmodified lines | |||
| 303 | 293 | ||
| 304 | ret = drm_panel_unprepare(&ctx->panel); | 294 | ret = drm_panel_unprepare(&ctx->panel); |
| 305 | if (ret < 0) | 295 | if (ret < 0) |
| 306 | DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", | 296 | dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); |
| 307 | ret); | ||
| 308 | 297 | ||
| 309 | ret = drm_panel_disable(&ctx->panel); | 298 | ret = drm_panel_disable(&ctx->panel); |
| 310 | if (ret < 0) | 299 | if (ret < 0) |
| 311 | DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", | 300 | dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); |
| 312 | ret); | ||
| 313 | } | 301 | } |
| 314 | 302 | ||
| 315 | static int kd35t133_remove(struct mipi_dsi_device *dsi) | 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 | ret = mipi_dsi_detach(dsi); | 310 | ret = mipi_dsi_detach(dsi); |
| 323 | if (ret < 0) | 311 | if (ret < 0) |
| 324 | DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", | 312 | dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); |
| 325 | ret); | ||
| 326 | 313 | ||
| 327 | drm_panel_remove(&ctx->panel); | 314 | drm_panel_remove(&ctx->panel); |
| 328 | 315 | ||
| @@ -13,7 +13,6 @@ · 12 unmodified lines | |||
| 13 | #include <drm/drm_mipi_dsi.h> | 13 | #include <drm/drm_mipi_dsi.h> |
| 14 | #include <drm/drm_modes.h> | 14 | #include <drm/drm_modes.h> |
| 15 | #include <drm/drm_panel.h> | 15 | #include <drm/drm_panel.h> |
| 16 | #include <drm/drm_print.h> | ||
| 17 | 16 | ||
| 18 | #define K101_IM2BA02_INIT_CMD_LEN 2 | 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 | ret = mipi_dsi_dcs_set_display_off(ctx->dsi); | 374 | ret = mipi_dsi_dcs_set_display_off(ctx->dsi); |
| 376 | if (ret < 0) | 375 | if (ret < 0) |
| 377 | DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", | 376 | dev_err(panel->dev, "failed to set display off: %d\n", ret); |
| 378 | ret); | ||
| 379 | 377 | ||
| 380 | ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); | 378 | ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); |
| 381 | if (ret < 0) | 379 | if (ret < 0) |
| 382 | DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", | 380 | dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); |
| 383 | ret); | ||
| 384 | 381 | ||
| 385 | msleep(200); | 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 | mode = drm_mode_duplicate(connector->dev, &k101_im2ba02_default_mode); | 414 | mode = drm_mode_duplicate(connector->dev, &k101_im2ba02_default_mode); |
| 418 | if (!mode) { | 415 | if (!mode) { |
| 419 | DRM_DEV_ERROR(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n", | 416 | dev_err(&ctx->dsi->dev, "failed to add mode %ux%u@%u\n", |
| 420 | k101_im2ba02_default_mode.hdisplay, | 417 | k101_im2ba02_default_mode.hdisplay, |
| 421 | k101_im2ba02_default_mode.vdisplay, | 418 | k101_im2ba02_default_mode.vdisplay, |
| 422 | drm_mode_vrefresh(&k101_im2ba02_default_mode)); | 419 | drm_mode_vrefresh(&k101_im2ba02_default_mode)); |
| 423 | return -ENOMEM; | 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 | ret = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(ctx->supplies), | 457 | ret = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(ctx->supplies), |
| 461 | ctx->supplies); | 458 | ctx->supplies); |
| 462 | if (ret < 0) { | 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 | return ret; | 461 | return ret; |
| 465 | } | 462 | } |
| 466 | 463 | ||
| 467 | ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); | 464 | ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); |
| 468 | if (IS_ERR(ctx->reset)) { | 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 | return PTR_ERR(ctx->reset); | 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 | if (ret) | 474 | if (ret) |
| 478 | return ret; | 475 | return ret; |
| 479 | 476 | ||
| 480 | ret = drm_panel_add(&ctx->panel); | 477 | drm_panel_add(&ctx->panel); |
| 481 | if (ret < 0) | ||
| 482 | return ret; | ||
| 483 | 478 | ||
| 484 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO; | 479 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO; |
| 485 | dsi->format = MIPI_DSI_FMT_RGB888; | 480 | dsi->format = MIPI_DSI_FMT_RGB888; |
| @@ -7,7 +7,6 @@ · 6 unmodified lines | |||
| 7 | #include <drm/drm_mipi_dsi.h> | 7 | #include <drm/drm_mipi_dsi.h> |
| 8 | #include <drm/drm_modes.h> | 8 | #include <drm/drm_modes.h> |
| 9 | #include <drm/drm_panel.h> | 9 | #include <drm/drm_panel.h> |
| 10 | #include <drm/drm_print.h> | ||
| 11 | 10 | ||
| 12 | #include <linux/gpio/consumer.h> | 11 | #include <linux/gpio/consumer.h> |
| 13 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
| @@ -118,13 +117,11 @@ static int feiyang_unprepare(struct drm_panel *panel) · 104 unmodified lines | |||
| 118 | 117 | ||
| 119 | ret = mipi_dsi_dcs_set_display_off(ctx->dsi); | 118 | ret = mipi_dsi_dcs_set_display_off(ctx->dsi); |
| 120 | if (ret < 0) | 119 | if (ret < 0) |
| 121 | DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", | 120 | dev_err(panel->dev, "failed to set display off: %d\n", ret); |
| 122 | ret); | ||
| 123 | 121 | ||
| 124 | ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); | 122 | ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); |
| 125 | if (ret < 0) | 123 | if (ret < 0) |
| 126 | DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", | 124 | dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); |
| 127 | ret); | ||
| 128 | 125 | ||
| 129 | /* T13 (backlight fall + video & logic signal fall) T13 >= 200ms */ | 126 | /* T13 (backlight fall + video & logic signal fall) T13 >= 200ms */ |
| 130 | msleep(200); | 127 | msleep(200); |
| @@ -165,10 +162,10 @@ static int feiyang_get_modes(struct drm_panel *panel, · 34 unmodified lines | |||
| 165 | 162 | ||
| 166 | mode = drm_mode_duplicate(connector->dev, &feiyang_default_mode); | 163 | mode = drm_mode_duplicate(connector->dev, &feiyang_default_mode); |
| 167 | if (!mode) { | 164 | if (!mode) { |
| 168 | DRM_DEV_ERROR(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n", | 165 | dev_err(&ctx->dsi->dev, "failed to add mode %ux%u@%u\n", |
| 169 | feiyang_default_mode.hdisplay, | 166 | feiyang_default_mode.hdisplay, |
| 170 | feiyang_default_mode.vdisplay, | 167 | feiyang_default_mode.vdisplay, |
| 171 | drm_mode_vrefresh(&feiyang_default_mode)); | 168 | drm_mode_vrefresh(&feiyang_default_mode)); |
| 172 | return -ENOMEM; | 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 | ctx->dvdd = devm_regulator_get(&dsi->dev, "dvdd"); | 202 | ctx->dvdd = devm_regulator_get(&dsi->dev, "dvdd"); |
| 206 | if (IS_ERR(ctx->dvdd)) { | 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 | return PTR_ERR(ctx->dvdd); | 205 | return PTR_ERR(ctx->dvdd); |
| 209 | } | 206 | } |
| 210 | 207 | ||
| 211 | ctx->avdd = devm_regulator_get(&dsi->dev, "avdd"); | 208 | ctx->avdd = devm_regulator_get(&dsi->dev, "avdd"); |
| 212 | if (IS_ERR(ctx->avdd)) { | 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 | return PTR_ERR(ctx->avdd); | 211 | return PTR_ERR(ctx->avdd); |
| 215 | } | 212 | } |
| 216 | 213 | ||
| 217 | ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); | 214 | ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); |
| 218 | if (IS_ERR(ctx->reset)) { | 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 | return PTR_ERR(ctx->reset); | 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 | if (ret) | 221 | if (ret) |
| 225 | return ret; | 222 | return ret; |
| 226 | 223 | ||
| 227 | ret = drm_panel_add(&ctx->panel); | 224 | drm_panel_add(&ctx->panel); |
| 228 | if (ret < 0) | ||
| 229 | return ret; | ||
| 230 | 225 | ||
| 231 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST; | 226 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST; |
| 232 | dsi->format = MIPI_DSI_FMT_RGB888; | 227 | dsi->format = MIPI_DSI_FMT_RGB888; |
| @@ -33,7 +33,6 @@ · 32 unmodified lines | |||
| 33 | 33 | ||
| 34 | #include <drm/drm_modes.h> | 34 | #include <drm/drm_modes.h> |
| 35 | #include <drm/drm_panel.h> | 35 | #include <drm/drm_panel.h> |
| 36 | #include <drm/drm_print.h> | ||
| 37 | 36 | ||
| 38 | #define ILI9322_CHIP_ID 0x00 | 37 | #define ILI9322_CHIP_ID 0x00 |
| 39 | #define ILI9322_CHIP_ID_MAGIC 0x96 | 38 | #define ILI9322_CHIP_ID_MAGIC 0x96 |
| @@ -683,7 +682,7 @@ static int ili9322_get_modes(struct drm_panel *panel, · 643 unmodified lines | |||
| 683 | break; | 682 | break; |
| 684 | } | 683 | } |
| 685 | if (!mode) { | 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 | return -EINVAL; | 686 | return -EINVAL; |
| 688 | } | 687 | } |
| 689 | drm_mode_set_name(mode); | 688 | drm_mode_set_name(mode); |
| @@ -892,7 +891,9 @@ static int ili9322_probe(struct spi_device *spi) · 202 unmodified lines | |||
| 892 | drm_panel_init(&ili->panel, dev, &ili9322_drm_funcs, | 891 | drm_panel_init(&ili->panel, dev, &ili9322_drm_funcs, |
| 893 | DRM_MODE_CONNECTOR_DPI); | 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 | static int ili9322_remove(struct spi_device *spi) | 899 | static int ili9322_remove(struct spi_device *spi) |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include <linux/fb.h> | 10 | #include <linux/fb.h> |
| 11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/of_device.h> | ||
| 13 | 14 | ||
| 14 | #include <linux/gpio/consumer.h> | 15 | #include <linux/gpio/consumer.h> |
| 15 | #include <linux/regulator/consumer.h> | 16 | #include <linux/regulator/consumer.h> |
| @@ -20,14 +21,6 @@ · 4 unmodified lines | |||
| 20 | 21 | ||
| 21 | #include <video/mipi_display.h> | 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 | enum ili9881c_op { | 24 | enum ili9881c_op { |
| 32 | ILI9881C_SWITCH_PAGE, | 25 | ILI9881C_SWITCH_PAGE, |
| 33 | ILI9881C_COMMAND, | 26 | ILI9881C_COMMAND, |
| @@ -45,6 +38,21 @@ struct ili9881c_instr { · 11 unmodified lines | |||
| 45 | } arg; | 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 | #define ILI9881C_SWITCH_PAGE_INSTR(_page) \ | 56 | #define ILI9881C_SWITCH_PAGE_INSTR(_page) \ |
| 49 | { \ | 57 | { \ |
| 50 | .op = ILI9881C_SWITCH_PAGE, \ | 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 | ILI9881C_SWITCH_PAGE_INSTR(3), | 76 | ILI9881C_SWITCH_PAGE_INSTR(3), |
| 69 | ILI9881C_COMMAND_INSTR(0x01, 0x00), | 77 | ILI9881C_COMMAND_INSTR(0x01, 0x00), |
| 70 | ILI9881C_COMMAND_INSTR(0x02, 0x00), | 78 | ILI9881C_COMMAND_INSTR(0x02, 0x00), |
| @@ -252,6 +260,199 @@ static const struct ili9881c_instr ili9881c_init[] = { · 181 unmodified lines | |||
| 252 | ILI9881C_COMMAND_INSTR(0xD3, 0x3F), | 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 | static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel) | 456 | static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel) |
| 256 | { | 457 | { |
| 257 | return container_of(panel, struct ili9881c, panel); | 458 | return container_of(panel, struct ili9881c, panel); |
| @@ -311,8 +512,8 @@ static int ili9881c_prepare(struct drm_panel *panel) · 53 unmodified lines | |||
| 311 | gpiod_set_value(ctx->reset, 0); | 512 | gpiod_set_value(ctx->reset, 0); |
| 312 | msleep(20); | 513 | msleep(20); |
| 313 | 514 | ||
| 314 | for (i = 0; i < ARRAY_SIZE(ili9881c_init); i++) { | 515 | for (i = 0; i < ctx->desc->init_length; i++) { |
| 315 | const struct ili9881c_instr *instr = &ili9881c_init[i]; | 516 | const struct ili9881c_instr *instr = &ctx->desc->init[i]; |
| 316 | 517 | ||
| 317 | if (instr->op == ILI9881C_SWITCH_PAGE) | 518 | if (instr->op == ILI9881C_SWITCH_PAGE) |
| 318 | ret = ili9881c_switch_page(ctx, instr->arg.page); | 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 | return 0; | 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 | .clock = 62000, | 573 | .clock = 62000, |
| 373 | 574 | ||
| 374 | .hdisplay = 720, | 575 | .hdisplay = 720, |
| @@ -380,6 +581,26 @@ static const struct drm_display_mode bananapi_default_mode = { · 5 unmodified lines | |||
| 380 | .vsync_start = 1280 + 10, | 581 | .vsync_start = 1280 + 10, |
| 381 | .vsync_end = 1280 + 10 + 10, | 582 | .vsync_end = 1280 + 10 + 10, |
| 382 | .vtotal = 1280 + 10 + 10 + 20, | 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 | static int ili9881c_get_modes(struct drm_panel *panel, | 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 | struct ili9881c *ctx = panel_to_ili9881c(panel); | 609 | struct ili9881c *ctx = panel_to_ili9881c(panel); |
| 389 | struct drm_display_mode *mode; | 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 | if (!mode) { | 613 | if (!mode) { |
| 393 | dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n", | 614 | dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n", |
| 394 | bananapi_default_mode.hdisplay, | 615 | ctx->desc->mode->hdisplay, |
| 395 | bananapi_default_mode.vdisplay, | 616 | ctx->desc->mode->vdisplay, |
| 396 | drm_mode_vrefresh(&bananapi_default_mode)); | 617 | drm_mode_vrefresh(ctx->desc->mode)); |
| 397 | return -ENOMEM; | 618 | return -ENOMEM; |
| 398 | } | 619 | } |
| 399 | 620 | ||
| @@ -402,8 +623,8 @@ static int ili9881c_get_modes(struct drm_panel *panel, · 2 unmodified lines | |||
| 402 | mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; | 623 | mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; |
| 403 | drm_mode_probed_add(connector, mode); | 624 | drm_mode_probed_add(connector, mode); |
| 404 | 625 | ||
| 405 | connector->display_info.width_mm = 62; | 626 | connector->display_info.width_mm = mode->width_mm; |
| 406 | connector->display_info.height_mm = 110; | 627 | connector->display_info.height_mm = mode->height_mm; |
| 407 | 628 | ||
| 408 | return 1; | 629 | return 1; |
| 409 | } | 630 | } |
| @@ -426,6 +647,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) · 16 unmodified lines | |||
| 426 | return -ENOMEM; | 647 | return -ENOMEM; |
| 427 | mipi_dsi_set_drvdata(dsi, ctx); | 648 | mipi_dsi_set_drvdata(dsi, ctx); |
| 428 | ctx->dsi = dsi; | 649 | ctx->dsi = dsi; |
| 650 | ctx->desc = of_device_get_match_data(&dsi->dev); | ||
| 429 | 651 | ||
| 430 | drm_panel_init(&ctx->panel, &dsi->dev, &ili9881c_funcs, | 652 | drm_panel_init(&ctx->panel, &dsi->dev, &ili9881c_funcs, |
| 431 | DRM_MODE_CONNECTOR_DSI); | 653 | DRM_MODE_CONNECTOR_DSI); |
| @@ -446,9 +668,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) · 14 unmodified lines | |||
| 446 | if (ret) | 668 | if (ret) |
| 447 | return ret; | 669 | return ret; |
| 448 | 670 | ||
| 449 | ret = drm_panel_add(&ctx->panel); | 671 | drm_panel_add(&ctx->panel); |
| 450 | if (ret < 0) | ||
| 451 | return ret; | ||
| 452 | 672 | ||
| 453 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE; | 673 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE; |
| 454 | dsi->format = MIPI_DSI_FMT_RGB888; | 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 | return 0; | 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 | static const struct of_device_id ili9881c_of_match[] = { | 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 | MODULE_DEVICE_TABLE(of, ili9881c_of_match); | 707 | MODULE_DEVICE_TABLE(of, ili9881c_of_match); |
| @@ -17,7 +17,6 @@ · 16 unmodified lines | |||
| 17 | #include <drm/drm_mipi_dsi.h> | 17 | #include <drm/drm_mipi_dsi.h> |
| 18 | #include <drm/drm_modes.h> | 18 | #include <drm/drm_modes.h> |
| 19 | #include <drm/drm_panel.h> | 19 | #include <drm/drm_panel.h> |
| 20 | #include <drm/drm_print.h> | ||
| 21 | 20 | ||
| 22 | struct panel_init_cmd { | 21 | struct panel_init_cmd { |
| 23 | size_t len; | 22 | size_t len; |
| @@ -85,13 +84,11 @@ static int innolux_panel_unprepare(struct drm_panel *panel) · 61 unmodified lines | |||
| 85 | 84 | ||
| 86 | err = mipi_dsi_dcs_set_display_off(innolux->link); | 85 | err = mipi_dsi_dcs_set_display_off(innolux->link); |
| 87 | if (err < 0) | 86 | if (err < 0) |
| 88 | DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", | 87 | dev_err(panel->dev, "failed to set display off: %d\n", err); |
| 89 | err); | ||
| 90 | 88 | ||
| 91 | err = mipi_dsi_dcs_enter_sleep_mode(innolux->link); | 89 | err = mipi_dsi_dcs_enter_sleep_mode(innolux->link); |
| 92 | if (err < 0) { | 90 | if (err < 0) { |
| 93 | DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", | 91 | dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); |
| 94 | err); | ||
| 95 | return err; | 92 | return err; |
| 96 | } | 93 | } |
| 97 | 94 | ||
| @@ -147,8 +144,7 @@ static int innolux_panel_prepare(struct drm_panel *panel) · 49 unmodified lines | |||
| 147 | err = mipi_dsi_generic_write(innolux->link, cmd->data, | 144 | err = mipi_dsi_generic_write(innolux->link, cmd->data, |
| 148 | cmd->len); | 145 | cmd->len); |
| 149 | if (err < 0) { | 146 | if (err < 0) { |
| 150 | dev_err(panel->dev, | 147 | dev_err(panel->dev, "failed to write command %u\n", i); |
| 151 | "failed to write command %u\n", i); | ||
| 152 | goto poweroff; | 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 | err = mipi_dsi_dcs_nop(innolux->link); | 156 | err = mipi_dsi_dcs_nop(innolux->link); |
| 161 | if (err < 0) { | 157 | if (err < 0) { |
| 162 | dev_err(panel->dev, | 158 | dev_err(panel->dev, "failed to send DCS nop: %d\n", err); |
| 163 | "failed to send DCS nop: %d\n", err); | ||
| 164 | goto poweroff; | 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 | err = mipi_dsi_dcs_exit_sleep_mode(innolux->link); | 164 | err = mipi_dsi_dcs_exit_sleep_mode(innolux->link); |
| 170 | if (err < 0) { | 165 | if (err < 0) { |
| 171 | DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n", | 166 | dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); |
| 172 | err); | ||
| 173 | goto poweroff; | 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 | err = mipi_dsi_dcs_set_display_on(innolux->link); | 173 | err = mipi_dsi_dcs_set_display_on(innolux->link); |
| 180 | if (err < 0) { | 174 | if (err < 0) { |
| 181 | DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", | 175 | dev_err(panel->dev, "failed to set display on: %d\n", err); |
| 182 | err); | ||
| 183 | goto poweroff; | 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 | mode = drm_mode_duplicate(connector->dev, m); | 392 | mode = drm_mode_duplicate(connector->dev, m); |
| 400 | if (!mode) { | 393 | if (!mode) { |
| 401 | DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n", | 394 | dev_err(panel->dev, "failed to add mode %ux%u@%u\n", |
| 402 | m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); | 395 | m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); |
| 403 | return -ENOMEM; | 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 | if (err) | 468 | if (err) |
| 476 | return err; | 469 | return err; |
| 477 | 470 | ||
| 478 | err = drm_panel_add(&innolux->base); | 471 | drm_panel_add(&innolux->base); |
| 479 | if (err < 0) | ||
| 480 | return err; | ||
| 481 | 472 | ||
| 482 | mipi_dsi_set_drvdata(dsi, innolux); | 473 | mipi_dsi_set_drvdata(dsi, innolux); |
| 483 | innolux->link = dsi; | 474 | innolux->link = dsi; |
| @@ -514,17 +505,15 @@ static int innolux_panel_remove(struct mipi_dsi_device *dsi) · 30 unmodified lines | |||
| 514 | 505 | ||
| 515 | err = drm_panel_unprepare(&innolux->base); | 506 | err = drm_panel_unprepare(&innolux->base); |
| 516 | if (err < 0) | 507 | if (err < 0) |
| 517 | DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n", | 508 | dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err); |
| 518 | err); | ||
| 519 | 509 | ||
| 520 | err = drm_panel_disable(&innolux->base); | 510 | err = drm_panel_disable(&innolux->base); |
| 521 | if (err < 0) | 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 | err = mipi_dsi_detach(dsi); | 514 | err = mipi_dsi_detach(dsi); |
| 525 | if (err < 0) | 515 | if (err < 0) |
| 526 | DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n", | 516 | dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); |
| 527 | err); | ||
| 528 | 517 | ||
| 529 | innolux_panel_del(innolux); | 518 | innolux_panel_del(innolux); |
| 530 | 519 | ||
| @@ -440,9 +440,9 @@ static int jdi_panel_add(struct jdi_panel *jdi) · 439 unmodified lines | |||
| 440 | drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs, | 440 | drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs, |
| 441 | DRM_MODE_CONNECTOR_DSI); | 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 | static void jdi_panel_del(struct jdi_panel *jdi) | 448 | static void jdi_panel_del(struct jdi_panel *jdi) |
| @@ -16,7 +16,6 @@ · 15 unmodified lines | |||
| 16 | #include <drm/drm_mipi_dsi.h> | 16 | #include <drm/drm_mipi_dsi.h> |
| 17 | #include <drm/drm_modes.h> | 17 | #include <drm/drm_modes.h> |
| 18 | #include <drm/drm_panel.h> | 18 | #include <drm/drm_panel.h> |
| 19 | #include <drm/drm_print.h> | ||
| 20 | 19 | ||
| 21 | struct kingdisplay_panel { | 20 | struct kingdisplay_panel { |
| 22 | struct drm_panel base; | 21 | struct drm_panel base; |
| @@ -191,8 +190,7 @@ static int kingdisplay_panel_disable(struct drm_panel *panel) · 168 unmodified lines | |||
| 191 | 190 | ||
| 192 | err = mipi_dsi_dcs_set_display_off(kingdisplay->link); | 191 | err = mipi_dsi_dcs_set_display_off(kingdisplay->link); |
| 193 | if (err < 0) | 192 | if (err < 0) |
| 194 | DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", | 193 | dev_err(panel->dev, "failed to set display off: %d\n", err); |
| 195 | err); | ||
| 196 | 194 | ||
| 197 | kingdisplay->enabled = false; | 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 | err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->link); | 208 | err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->link); |
| 211 | if (err < 0) { | 209 | if (err < 0) { |
| 212 | DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", | 210 | dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); |
| 213 | err); | ||
| 214 | return err; | 211 | return err; |
| 215 | } | 212 | } |
| 216 | 213 | ||
| @@ -255,16 +252,14 @@ static int kingdisplay_panel_prepare(struct drm_panel *panel) · 38 unmodified lines | |||
| 255 | err = mipi_dsi_generic_write(kingdisplay->link, &init_code[i], | 252 | err = mipi_dsi_generic_write(kingdisplay->link, &init_code[i], |
| 256 | sizeof(struct kingdisplay_panel_cmd)); | 253 | sizeof(struct kingdisplay_panel_cmd)); |
| 257 | if (err < 0) { | 254 | if (err < 0) { |
| 258 | DRM_DEV_ERROR(panel->dev, "failed write init cmds: %d\n", | 255 | dev_err(panel->dev, "failed write init cmds: %d\n", err); |
| 259 | err); | ||
| 260 | goto poweroff; | 256 | goto poweroff; |
| 261 | } | 257 | } |
| 262 | } | 258 | } |
| 263 | 259 | ||
| 264 | err = mipi_dsi_dcs_exit_sleep_mode(kingdisplay->link); | 260 | err = mipi_dsi_dcs_exit_sleep_mode(kingdisplay->link); |
| 265 | if (err < 0) { | 261 | if (err < 0) { |
| 266 | DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n", | 262 | dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); |
| 267 | err); | ||
| 268 | goto poweroff; | 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 | err = mipi_dsi_dcs_set_display_on(kingdisplay->link); | 269 | err = mipi_dsi_dcs_set_display_on(kingdisplay->link); |
| 275 | if (err < 0) { | 270 | if (err < 0) { |
| 276 | DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", | 271 | dev_err(panel->dev, "failed to set display on: %d\n", err); |
| 277 | err); | ||
| 278 | goto poweroff; | 272 | goto poweroff; |
| 279 | } | 273 | } |
| 280 | 274 | ||
| @@ -290,8 +284,7 @@ poweroff: · 9 unmodified lines | |||
| 290 | 284 | ||
| 291 | regulator_err = regulator_disable(kingdisplay->supply); | 285 | regulator_err = regulator_disable(kingdisplay->supply); |
| 292 | if (regulator_err) | 286 | if (regulator_err) |
| 293 | DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", | 287 | dev_err(panel->dev, "failed to disable regulator: %d\n", regulator_err); |
| 294 | regulator_err); | ||
| 295 | 288 | ||
| 296 | return err; | 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 | mode = drm_mode_duplicate(connector->dev, &default_mode); | 321 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 329 | if (!mode) { | 322 | if (!mode) { |
| 330 | DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n", | 323 | dev_err(panel->dev, "failed to add mode %ux%u@%u\n", |
| 331 | default_mode.hdisplay, default_mode.vdisplay, | 324 | default_mode.hdisplay, default_mode.vdisplay, |
| 332 | drm_mode_vrefresh(&default_mode)); | 325 | drm_mode_vrefresh(&default_mode)); |
| 333 | return -ENOMEM; | 326 | return -ENOMEM; |
| 334 | } | 327 | } |
| 335 | 328 | ||
| @@ -382,7 +375,9 @@ static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay) · 46 unmodified lines | |||
| 382 | if (err) | 375 | if (err) |
| 383 | return err; | 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 | static void kingdisplay_panel_del(struct kingdisplay_panel *kingdisplay) | 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 | err = drm_panel_unprepare(&kingdisplay->base); | 417 | err = drm_panel_unprepare(&kingdisplay->base); |
| 423 | if (err < 0) | 418 | if (err < 0) |
| 424 | DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n", | 419 | dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err); |
| 425 | err); | ||
| 426 | 420 | ||
| 427 | err = drm_panel_disable(&kingdisplay->base); | 421 | err = drm_panel_disable(&kingdisplay->base); |
| 428 | if (err < 0) | 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 | err = mipi_dsi_detach(dsi); | 425 | err = mipi_dsi_detach(dsi); |
| 432 | if (err < 0) | 426 | if (err < 0) |
| 433 | DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n", | 427 | dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); |
| 434 | err); | ||
| 435 | 428 | ||
| 436 | kingdisplay_panel_del(kingdisplay); | 429 | kingdisplay_panel_del(kingdisplay); |
| 437 | 430 | ||
| @@ -17,7 +17,6 @@ · 16 unmodified lines | |||
| 17 | #include <drm/drm_mipi_dsi.h> | 17 | #include <drm/drm_mipi_dsi.h> |
| 18 | #include <drm/drm_modes.h> | 18 | #include <drm/drm_modes.h> |
| 19 | #include <drm/drm_panel.h> | 19 | #include <drm/drm_panel.h> |
| 20 | #include <drm/drm_print.h> | ||
| 21 | 20 | ||
| 22 | struct ltk050h3146w_cmd { | 21 | struct ltk050h3146w_cmd { |
| 23 | char cmd; | 22 | char cmd; |
| @@ -314,8 +313,7 @@ static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx) · 290 unmodified lines | |||
| 314 | 313 | ||
| 315 | ret = mipi_dsi_dcs_set_tear_on(dsi, 1); | 314 | ret = mipi_dsi_dcs_set_tear_on(dsi, 1); |
| 316 | if (ret < 0) { | 315 | if (ret < 0) { |
| 317 | DRM_DEV_ERROR(ctx->dev, "failed to set tear on: %d\n", | 316 | dev_err(ctx->dev, "failed to set tear on: %d\n", ret); |
| 318 | ret); | ||
| 319 | return ret; | 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 | ret = ltk050h3146w_a2_select_page(ctx, page); | 359 | ret = ltk050h3146w_a2_select_page(ctx, page); |
| 362 | if (ret < 0) { | 360 | if (ret < 0) { |
| 363 | DRM_DEV_ERROR(ctx->dev, "failed to select page %d: %d\n", | 361 | dev_err(ctx->dev, "failed to select page %d: %d\n", page, ret); |
| 364 | page, ret); | ||
| 365 | return ret; | 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 | ret = mipi_dsi_generic_write(dsi, &cmds[i], | 366 | ret = mipi_dsi_generic_write(dsi, &cmds[i], |
| 370 | sizeof(struct ltk050h3146w_cmd)); | 367 | sizeof(struct ltk050h3146w_cmd)); |
| 371 | if (ret < 0) { | 368 | if (ret < 0) { |
| 372 | DRM_DEV_ERROR(ctx->dev, | 369 | dev_err(ctx->dev, "failed to write page %d init cmds: %d\n", page, ret); |
| 373 | "failed to write page %d init cmds: %d\n", | ||
| 374 | page, ret); | ||
| 375 | return ret; | 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 | ret = ltk050h3146w_a2_select_page(ctx, 0); | 401 | ret = ltk050h3146w_a2_select_page(ctx, 0); |
| 407 | if (ret < 0) { | 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 | return ret; | 404 | return ret; |
| 410 | } | 405 | } |
| 411 | 406 | ||
| 412 | /* vendor code called this without param, where there should be one */ | 407 | /* vendor code called this without param, where there should be one */ |
| 413 | ret = mipi_dsi_dcs_set_tear_on(dsi, 0); | 408 | ret = mipi_dsi_dcs_set_tear_on(dsi, 0); |
| 414 | if (ret < 0) { | 409 | if (ret < 0) { |
| 415 | DRM_DEV_ERROR(ctx->dev, "failed to set tear on: %d\n", | 410 | dev_err(ctx->dev, "failed to set tear on: %d\n", ret); |
| 416 | ret); | ||
| 417 | return ret; | 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 | ret = mipi_dsi_dcs_set_display_off(dsi); | 447 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 454 | if (ret < 0) { | 448 | if (ret < 0) { |
| 455 | DRM_DEV_ERROR(ctx->dev, "failed to set display off: %d\n", | 449 | dev_err(ctx->dev, "failed to set display off: %d\n", ret); |
| 456 | ret); | ||
| 457 | return ret; | 450 | return ret; |
| 458 | } | 451 | } |
| 459 | 452 | ||
| 460 | mipi_dsi_dcs_enter_sleep_mode(dsi); | 453 | mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 461 | if (ret < 0) { | 454 | if (ret < 0) { |
| 462 | DRM_DEV_ERROR(ctx->dev, "failed to enter sleep mode: %d\n", | 455 | dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret); |
| 463 | ret); | ||
| 464 | return ret; | 456 | return ret; |
| 465 | } | 457 | } |
| 466 | 458 | ||
| @@ -481,17 +473,15 @@ static int ltk050h3146w_prepare(struct drm_panel *panel) · 14 unmodified lines | |||
| 481 | if (ctx->prepared) | 473 | if (ctx->prepared) |
| 482 | return 0; | 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 | ret = regulator_enable(ctx->vci); | 477 | ret = regulator_enable(ctx->vci); |
| 486 | if (ret < 0) { | 478 | if (ret < 0) { |
| 487 | DRM_DEV_ERROR(ctx->dev, | 479 | dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret); |
| 488 | "Failed to enable vci supply: %d\n", ret); | ||
| 489 | return ret; | 480 | return ret; |
| 490 | } | 481 | } |
| 491 | ret = regulator_enable(ctx->iovcc); | 482 | ret = regulator_enable(ctx->iovcc); |
| 492 | if (ret < 0) { | 483 | if (ret < 0) { |
| 493 | DRM_DEV_ERROR(ctx->dev, | 484 | dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); |
| 494 | "Failed to enable iovcc supply: %d\n", ret); | ||
| 495 | goto disable_vci; | 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 | ret = ctx->panel_desc->init(ctx); | 493 | ret = ctx->panel_desc->init(ctx); |
| 504 | if (ret < 0) { | 494 | if (ret < 0) { |
| 505 | DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", | 495 | dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); |
| 506 | ret); | ||
| 507 | goto disable_iovcc; | 496 | goto disable_iovcc; |
| 508 | } | 497 | } |
| 509 | 498 | ||
| 510 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | 499 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 511 | if (ret < 0) { | 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 | goto disable_iovcc; | 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 | ret = mipi_dsi_dcs_set_display_on(dsi); | 508 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 520 | if (ret < 0) { | 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 | goto disable_iovcc; | 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 | ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); | 567 | ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); |
| 579 | if (IS_ERR(ctx->reset_gpio)) { | 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 | return PTR_ERR(ctx->reset_gpio); | 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 | if (IS_ERR(ctx->vci)) { | 574 | if (IS_ERR(ctx->vci)) { |
| 586 | ret = PTR_ERR(ctx->vci); | 575 | ret = PTR_ERR(ctx->vci); |
| 587 | if (ret != -EPROBE_DEFER) | 576 | if (ret != -EPROBE_DEFER) |
| 588 | DRM_DEV_ERROR(dev, | 577 | dev_err(dev, "Failed to request vci regulator: %d\n", ret); |
| 589 | "Failed to request vci regulator: %d\n", | ||
| 590 | ret); | ||
| 591 | return ret; | 578 | return ret; |
| 592 | } | 579 | } |
| 593 | 580 | ||
| @@ -595,9 +582,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) · 1 unmodified line | |||
| 595 | if (IS_ERR(ctx->iovcc)) { | 582 | if (IS_ERR(ctx->iovcc)) { |
| 596 | ret = PTR_ERR(ctx->iovcc); | 583 | ret = PTR_ERR(ctx->iovcc); |
| 597 | if (ret != -EPROBE_DEFER) | 584 | if (ret != -EPROBE_DEFER) |
| 598 | DRM_DEV_ERROR(dev, | 585 | dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); |
| 599 | "Failed to request iovcc regulator: %d\n", | ||
| 600 | ret); | ||
| 601 | return ret; | 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 | ret = mipi_dsi_attach(dsi); | 607 | ret = mipi_dsi_attach(dsi); |
| 623 | if (ret < 0) { | 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 | drm_panel_remove(&ctx->panel); | 610 | drm_panel_remove(&ctx->panel); |
| 626 | return ret; | 611 | return ret; |
| 627 | } | 612 | } |
| @@ -636,13 +621,11 @@ static void ltk050h3146w_shutdown(struct mipi_dsi_device *dsi) · 8 unmodified lines | |||
| 636 | 621 | ||
| 637 | ret = drm_panel_unprepare(&ctx->panel); | 622 | ret = drm_panel_unprepare(&ctx->panel); |
| 638 | if (ret < 0) | 623 | if (ret < 0) |
| 639 | DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", | 624 | dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); |
| 640 | ret); | ||
| 641 | 625 | ||
| 642 | ret = drm_panel_disable(&ctx->panel); | 626 | ret = drm_panel_disable(&ctx->panel); |
| 643 | if (ret < 0) | 627 | if (ret < 0) |
| 644 | DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", | 628 | dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); |
| 645 | ret); | ||
| 646 | } | 629 | } |
| 647 | 630 | ||
| 648 | static int ltk050h3146w_remove(struct mipi_dsi_device *dsi) | 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 | ret = mipi_dsi_detach(dsi); | 638 | ret = mipi_dsi_detach(dsi); |
| 656 | if (ret < 0) | 639 | if (ret < 0) |
| 657 | DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", | 640 | dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); |
| 658 | ret); | ||
| 659 | 641 | ||
| 660 | drm_panel_remove(&ctx->panel); | 642 | drm_panel_remove(&ctx->panel); |
| 661 | 643 | ||
| @@ -20,7 +20,6 @@ · 19 unmodified lines | |||
| 20 | #include <drm/drm_mipi_dsi.h> | 20 | #include <drm/drm_mipi_dsi.h> |
| 21 | #include <drm/drm_modes.h> | 21 | #include <drm/drm_modes.h> |
| 22 | #include <drm/drm_panel.h> | 22 | #include <drm/drm_panel.h> |
| 23 | #include <drm/drm_print.h> | ||
| 24 | 23 | ||
| 25 | struct ltk500hd1829 { | 24 | struct ltk500hd1829 { |
| 26 | struct device *dev; | 25 | struct device *dev; |
| @@ -278,13 +277,11 @@ static int ltk500hd1829_unprepare(struct drm_panel *panel) · 251 unmodified lines | |||
| 278 | 277 | ||
| 279 | ret = mipi_dsi_dcs_set_display_off(dsi); | 278 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 280 | if (ret < 0) | 279 | if (ret < 0) |
| 281 | DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n", | 280 | dev_err(panel->dev, "failed to set display off: %d\n", ret); |
| 282 | ret); | ||
| 283 | 281 | ||
| 284 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); | 282 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 285 | if (ret < 0) { | 283 | if (ret < 0) { |
| 286 | DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n", | 284 | dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); |
| 287 | ret); | ||
| 288 | } | 285 | } |
| 289 | 286 | ||
| 290 | /* 120ms to enter sleep mode */ | 287 | /* 120ms to enter sleep mode */ |
| @@ -310,14 +307,12 @@ static int ltk500hd1829_prepare(struct drm_panel *panel) · 19 unmodified lines | |||
| 310 | 307 | ||
| 311 | ret = regulator_enable(ctx->vcc); | 308 | ret = regulator_enable(ctx->vcc); |
| 312 | if (ret < 0) { | 309 | if (ret < 0) { |
| 313 | DRM_DEV_ERROR(ctx->dev, | 310 | dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret); |
| 314 | "Failed to enable vci supply: %d\n", ret); | ||
| 315 | return ret; | 311 | return ret; |
| 316 | } | 312 | } |
| 317 | ret = regulator_enable(ctx->iovcc); | 313 | ret = regulator_enable(ctx->iovcc); |
| 318 | if (ret < 0) { | 314 | if (ret < 0) { |
| 319 | DRM_DEV_ERROR(ctx->dev, | 315 | dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); |
| 320 | "Failed to enable iovcc supply: %d\n", ret); | ||
| 321 | goto disable_vcc; | 316 | goto disable_vcc; |
| 322 | } | 317 | } |
| 323 | 318 | ||
| @@ -333,16 +328,14 @@ static int ltk500hd1829_prepare(struct drm_panel *panel) · 9 unmodified lines | |||
| 333 | ret = mipi_dsi_generic_write(dsi, &init_code[i], | 328 | ret = mipi_dsi_generic_write(dsi, &init_code[i], |
| 334 | sizeof(struct ltk500hd1829_cmd)); | 329 | sizeof(struct ltk500hd1829_cmd)); |
| 335 | if (ret < 0) { | 330 | if (ret < 0) { |
| 336 | DRM_DEV_ERROR(panel->dev, | 331 | dev_err(panel->dev, "failed to write init cmds: %d\n", ret); |
| 337 | "failed to write init cmds: %d\n", ret); | ||
| 338 | goto disable_iovcc; | 332 | goto disable_iovcc; |
| 339 | } | 333 | } |
| 340 | } | 334 | } |
| 341 | 335 | ||
| 342 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | 336 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 343 | if (ret < 0) { | 337 | if (ret < 0) { |
| 344 | DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n", | 338 | dev_err(panel->dev, "failed to exit sleep mode: %d\n", ret); |
| 345 | ret); | ||
| 346 | goto disable_iovcc; | 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 | ret = mipi_dsi_dcs_set_display_on(dsi); | 345 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 353 | if (ret < 0) { | 346 | if (ret < 0) { |
| 354 | DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n", | 347 | dev_err(panel->dev, "failed to set display on: %d\n", ret); |
| 355 | ret); | ||
| 356 | goto disable_iovcc; | 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 | mode = drm_mode_duplicate(connector->dev, &default_mode); | 382 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 391 | if (!mode) { | 383 | if (!mode) { |
| 392 | DRM_DEV_ERROR(ctx->dev, "failed to add mode %ux%ux@%u\n", | 384 | dev_err(ctx->dev, "failed to add mode %ux%u@%u\n", |
| 393 | default_mode.hdisplay, default_mode.vdisplay, | 385 | default_mode.hdisplay, default_mode.vdisplay, |
| 394 | drm_mode_vrefresh(&default_mode)); | 386 | drm_mode_vrefresh(&default_mode)); |
| 395 | return -ENOMEM; | 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 | ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); | 416 | ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); |
| 425 | if (IS_ERR(ctx->reset_gpio)) { | 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 | return PTR_ERR(ctx->reset_gpio); | 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 | if (IS_ERR(ctx->vcc)) { | 423 | if (IS_ERR(ctx->vcc)) { |
| 432 | ret = PTR_ERR(ctx->vcc); | 424 | ret = PTR_ERR(ctx->vcc); |
| 433 | if (ret != -EPROBE_DEFER) | 425 | if (ret != -EPROBE_DEFER) |
| 434 | DRM_DEV_ERROR(dev, | 426 | dev_err(dev, "Failed to request vcc regulator: %d\n", ret); |
| 435 | "Failed to request vcc regulator: %d\n", | ||
| 436 | ret); | ||
| 437 | return ret; | 427 | return ret; |
| 438 | } | 428 | } |
| 439 | 429 | ||
| @@ -441,9 +431,7 @@ static int ltk500hd1829_probe(struct mipi_dsi_device *dsi) · 1 unmodified line | |||
| 441 | if (IS_ERR(ctx->iovcc)) { | 431 | if (IS_ERR(ctx->iovcc)) { |
| 442 | ret = PTR_ERR(ctx->iovcc); | 432 | ret = PTR_ERR(ctx->iovcc); |
| 443 | if (ret != -EPROBE_DEFER) | 433 | if (ret != -EPROBE_DEFER) |
| 444 | DRM_DEV_ERROR(dev, | 434 | dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); |
| 445 | "Failed to request iovcc regulator: %d\n", | ||
| 446 | ret); | ||
| 447 | return ret; | 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 | ret = mipi_dsi_attach(dsi); | 456 | ret = mipi_dsi_attach(dsi); |
| 469 | if (ret < 0) { | 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 | drm_panel_remove(&ctx->panel); | 459 | drm_panel_remove(&ctx->panel); |
| 472 | return ret; | 460 | return ret; |
| 473 | } | 461 | } |
| @@ -482,13 +470,11 @@ static void ltk500hd1829_shutdown(struct mipi_dsi_device *dsi) · 8 unmodified lines | |||
| 482 | 470 | ||
| 483 | ret = drm_panel_unprepare(&ctx->panel); | 471 | ret = drm_panel_unprepare(&ctx->panel); |
| 484 | if (ret < 0) | 472 | if (ret < 0) |
| 485 | DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", | 473 | dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); |
| 486 | ret); | ||
| 487 | 474 | ||
| 488 | ret = drm_panel_disable(&ctx->panel); | 475 | ret = drm_panel_disable(&ctx->panel); |
| 489 | if (ret < 0) | 476 | if (ret < 0) |
| 490 | DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", | 477 | dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); |
| 491 | ret); | ||
| 492 | } | 478 | } |
| 493 | 479 | ||
| 494 | static int ltk500hd1829_remove(struct mipi_dsi_device *dsi) | 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 | ret = mipi_dsi_detach(dsi); | 487 | ret = mipi_dsi_detach(dsi); |
| 502 | if (ret < 0) | 488 | if (ret < 0) |
| 503 | DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n", | 489 | dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); |
| 504 | ret); | ||
| 505 | 490 | ||
| 506 | drm_panel_remove(&ctx->panel); | 491 | drm_panel_remove(&ctx->panel); |
| 507 | 492 | ||
| @@ -198,7 +198,9 @@ static int lb035q02_probe(struct spi_device *spi) · 197 unmodified lines | |||
| 198 | drm_panel_init(&lcd->panel, &lcd->spi->dev, &lb035q02_funcs, | 198 | drm_panel_init(&lcd->panel, &lcd->spi->dev, &lb035q02_funcs, |
| 199 | DRM_MODE_CONNECTOR_DPI); | 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 | static int lb035q02_remove(struct spi_device *spi) | 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 | drm_panel_init(&ctx->panel, &spi->dev, &lg4573_drm_funcs, | 261 | drm_panel_init(&ctx->panel, &spi->dev, &lg4573_drm_funcs, |
| 262 | DRM_MODE_CONNECTOR_DPI); | 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 | static int lg4573_remove(struct spi_device *spi) | 269 | static int lg4573_remove(struct spi_device *spi) |
| @@ -37,6 +37,8 @@ struct panel_lvds { · 36 unmodified lines | |||
| 37 | 37 | ||
| 38 | struct gpio_desc *enable_gpio; | 38 | struct gpio_desc *enable_gpio; |
| 39 | struct gpio_desc *reset_gpio; | 39 | struct gpio_desc *reset_gpio; |
| 40 | |||
| 41 | enum drm_panel_orientation orientation; | ||
| 40 | }; | 42 | }; |
| 41 | 43 | ||
| 42 | static inline struct panel_lvds *to_panel_lvds(struct drm_panel *panel) | 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 | connector->display_info.bus_flags = lvds->data_mirror | 101 | connector->display_info.bus_flags = lvds->data_mirror |
| 100 | ? DRM_BUS_FLAG_DATA_LSB_TO_MSB | 102 | ? DRM_BUS_FLAG_DATA_LSB_TO_MSB |
| 101 | : DRM_BUS_FLAG_DATA_MSB_TO_LSB; | 103 | : DRM_BUS_FLAG_DATA_MSB_TO_LSB; |
| 104 | drm_connector_set_panel_orientation(connector, lvds->orientation); | ||
| 102 | 105 | ||
| 103 | return 1; | 106 | return 1; |
| 104 | } | 107 | } |
| @@ -116,6 +119,12 @@ static int panel_lvds_parse_dt(struct panel_lvds *lvds) · 11 unmodified lines | |||
| 116 | const char *mapping; | 119 | const char *mapping; |
| 117 | int ret; | 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 | ret = of_get_display_timing(np, "panel-timing", &timing); | 128 | ret = of_get_display_timing(np, "panel-timing", &timing); |
| 120 | if (ret < 0) { | 129 | if (ret < 0) { |
| 121 | dev_err(lvds->dev, "%pOF: problems parsing panel-timing (%d)\n", | 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 | if (ret) | 236 | if (ret) |
| 228 | return ret; | 237 | return ret; |
| 229 | 238 | ||
| 230 | ret = drm_panel_add(&lvds->panel); | 239 | drm_panel_add(&lvds->panel); |
| 231 | if (ret < 0) | ||
| 232 | return ret; | ||
| 233 | 240 | ||
| 234 | dev_set_drvdata(lvds->dev, lvds); | 241 | dev_set_drvdata(lvds->dev, lvds); |
| 235 | return 0; | 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 | drm_panel_init(&lcd->panel, &lcd->spi->dev, &nl8048_funcs, | 207 | drm_panel_init(&lcd->panel, &lcd->spi->dev, &nl8048_funcs, |
| 208 | DRM_MODE_CONNECTOR_DPI); | 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 | static int nl8048_remove(struct spi_device *spi) | 215 | static int nl8048_remove(struct spi_device *spi) |
| @@ -35,7 +35,6 @@ · 34 unmodified lines | |||
| 35 | #include <drm/drm_mipi_dsi.h> | 35 | #include <drm/drm_mipi_dsi.h> |
| 36 | #include <drm/drm_modes.h> | 36 | #include <drm/drm_modes.h> |
| 37 | #include <drm/drm_panel.h> | 37 | #include <drm/drm_panel.h> |
| 38 | #include <drm/drm_print.h> | ||
| 39 | 38 | ||
| 40 | #define MCS_CMD_MAUCCTR 0xF0 /* Manufacturer command enable */ | 39 | #define MCS_CMD_MAUCCTR 0xF0 /* Manufacturer command enable */ |
| 41 | #define MCS_CMD_READ_ID1 0xDA | 40 | #define MCS_CMD_READ_ID1 0xDA |
| @@ -376,6 +375,10 @@ struct nt35510 { · 334 unmodified lines | |||
| 376 | }; | 375 | }; |
| 377 | 376 | ||
| 378 | /* Manufacturer command has strictly this byte sequence */ | 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 | static const u8 nt35510_mauc_select_page_0[] = { 0x55, 0xAA, 0x52, 0x08, 0x00 }; | 382 | static const u8 nt35510_mauc_select_page_0[] = { 0x55, 0xAA, 0x52, 0x08, 0x00 }; |
| 380 | static const u8 nt35510_mauc_select_page_1[] = { 0x55, 0xAA, 0x52, 0x08, 0x01 }; | 383 | static const u8 nt35510_mauc_select_page_1[] = { 0x55, 0xAA, 0x52, 0x08, 0x01 }; |
| 381 | static const u8 nt35510_vgh_on[] = { 0x01 }; | 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 | chunk = 15; | 403 | chunk = 15; |
| 401 | ret = mipi_dsi_dcs_write(dsi, cmd, seqp, chunk); | 404 | ret = mipi_dsi_dcs_write(dsi, cmd, seqp, chunk); |
| 402 | if (ret < 0) { | 405 | if (ret < 0) { |
| 403 | DRM_DEV_ERROR(nt->dev, | 406 | dev_err(nt->dev, "error sending DCS command seq cmd %02x\n", cmd); |
| 404 | "error sending DCS command seq cmd %02x\n", | ||
| 405 | cmd); | ||
| 406 | return ret; | 407 | return ret; |
| 407 | } | 408 | } |
| 408 | cmdwritten += chunk; | 409 | cmdwritten += chunk; |
| @@ -414,16 +415,13 @@ static int nt35510_send_long(struct nt35510 *nt, struct mipi_dsi_device *dsi, · 5 unmodified lines | |||
| 414 | chunk = 15; | 415 | chunk = 15; |
| 415 | ret = mipi_dsi_generic_write(dsi, seqp, chunk); | 416 | ret = mipi_dsi_generic_write(dsi, seqp, chunk); |
| 416 | if (ret < 0) { | 417 | if (ret < 0) { |
| 417 | DRM_DEV_ERROR(nt->dev, | 418 | dev_err(nt->dev, "error sending generic write seq %02x\n", cmd); |
| 418 | "error sending generic write seq %02x\n", | ||
| 419 | cmd); | ||
| 420 | return ret; | 419 | return ret; |
| 421 | } | 420 | } |
| 422 | cmdwritten += chunk; | 421 | cmdwritten += chunk; |
| 423 | seqp += chunk; | 422 | seqp += chunk; |
| 424 | } | 423 | } |
| 425 | DRM_DEV_DEBUG(nt->dev, "sent command %02x %02x bytes\n", | 424 | dev_dbg(nt->dev, "sent command %02x %02x bytes\n", cmd, cmdlen); |
| 426 | cmd, cmdlen); | ||
| 427 | return 0; | 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 | ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID1, &id1, 1); | 434 | ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID1, &id1, 1); |
| 437 | if (ret < 0) { | 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 | return ret; | 437 | return ret; |
| 440 | } | 438 | } |
| 441 | ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID2, &id2, 1); | 439 | ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID2, &id2, 1); |
| 442 | if (ret < 0) { | 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 | return ret; | 442 | return ret; |
| 445 | } | 443 | } |
| 446 | ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID3, &id3, 1); | 444 | ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID3, &id3, 1); |
| 447 | if (ret < 0) { | 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 | return ret; | 447 | return ret; |
| 450 | } | 448 | } |
| 451 | 449 | ||
| @@ -454,9 +452,7 @@ static int nt35510_read_id(struct nt35510 *nt) · 2 unmodified lines | |||
| 454 | * ID (e.g. Hydis 0x55), driver ID (e.g. NT35510 0xc0) and | 452 | * ID (e.g. Hydis 0x55), driver ID (e.g. NT35510 0xc0) and |
| 455 | * version. | 453 | * version. |
| 456 | */ | 454 | */ |
| 457 | DRM_DEV_INFO(nt->dev, | 455 | dev_info(nt->dev, "MTP ID manufacturer: %02x version: %02x driver: %02x\n", id1, id2, id3); |
| 458 | "MTP ID manufacturer: %02x version: %02x driver: %02x\n", | ||
| 459 | id1, id2, id3); | ||
| 460 | 456 | ||
| 461 | return 0; | 457 | return 0; |
| 462 | } | 458 | } |
| @@ -657,7 +653,7 @@ static int nt35510_set_brightness(struct backlight_device *bl) · 194 unmodified lines | |||
| 657 | u8 brightness = bl->props.brightness; | 653 | u8 brightness = bl->props.brightness; |
| 658 | int ret; | 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 | ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, | 657 | ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, |
| 662 | &brightness, | 658 | &brightness, |
| 663 | sizeof(brightness)); | 659 | sizeof(brightness)); |
| @@ -698,6 +694,18 @@ static int nt35510_power_on(struct nt35510 *nt) · 34 unmodified lines | |||
| 698 | usleep_range(120000, 140000); | 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 | ret = nt35510_read_id(nt); | 709 | ret = nt35510_read_id(nt); |
| 702 | if (ret) | 710 | if (ret) |
| 703 | return ret; | 711 | return ret; |
| @@ -780,8 +788,7 @@ static int nt35510_unprepare(struct drm_panel *panel) · 76 unmodified lines | |||
| 780 | 788 | ||
| 781 | ret = mipi_dsi_dcs_set_display_off(dsi); | 789 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 782 | if (ret) { | 790 | if (ret) { |
| 783 | DRM_DEV_ERROR(nt->dev, "failed to turn display off (%d)\n", | 791 | dev_err(nt->dev, "failed to turn display off (%d)\n", ret); |
| 784 | ret); | ||
| 785 | return ret; | 792 | return ret; |
| 786 | } | 793 | } |
| 787 | usleep_range(10000, 20000); | 794 | usleep_range(10000, 20000); |
| @@ -789,8 +796,7 @@ static int nt35510_unprepare(struct drm_panel *panel) · 1 unmodified line | |||
| 789 | /* Enter sleep mode */ | 796 | /* Enter sleep mode */ |
| 790 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); | 797 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 791 | if (ret) { | 798 | if (ret) { |
| 792 | DRM_DEV_ERROR(nt->dev, "failed to enter sleep mode (%d)\n", | 799 | dev_err(nt->dev, "failed to enter sleep mode (%d)\n", ret); |
| 793 | ret); | ||
| 794 | return ret; | 800 | return ret; |
| 795 | } | 801 | } |
| 796 | 802 | ||
| @@ -817,8 +823,7 @@ static int nt35510_prepare(struct drm_panel *panel) · 20 unmodified lines | |||
| 817 | /* Exit sleep mode */ | 823 | /* Exit sleep mode */ |
| 818 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | 824 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 819 | if (ret) { | 825 | if (ret) { |
| 820 | DRM_DEV_ERROR(nt->dev, "failed to exit sleep mode (%d)\n", | 826 | dev_err(nt->dev, "failed to exit sleep mode (%d)\n", ret); |
| 821 | ret); | ||
| 822 | return ret; | 827 | return ret; |
| 823 | } | 828 | } |
| 824 | /* Up to 120 ms */ | 829 | /* Up to 120 ms */ |
| @@ -826,8 +831,7 @@ static int nt35510_prepare(struct drm_panel *panel) · 1 unmodified line | |||
| 826 | 831 | ||
| 827 | ret = mipi_dsi_dcs_set_display_on(dsi); | 832 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 828 | if (ret) { | 833 | if (ret) { |
| 829 | DRM_DEV_ERROR(nt->dev, "failed to turn display on (%d)\n", | 834 | dev_err(nt->dev, "failed to turn display on (%d)\n", ret); |
| 830 | ret); | ||
| 831 | return ret; | 835 | return ret; |
| 832 | } | 836 | } |
| 833 | /* Some 10 ms */ | 837 | /* Some 10 ms */ |
| @@ -848,7 +852,7 @@ static int nt35510_get_modes(struct drm_panel *panel, · 14 unmodified lines | |||
| 848 | info->height_mm = nt->conf->height_mm; | 852 | info->height_mm = nt->conf->height_mm; |
| 849 | mode = drm_mode_duplicate(connector->dev, &nt->conf->mode); | 853 | mode = drm_mode_duplicate(connector->dev, &nt->conf->mode); |
| 850 | if (!mode) { | 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 | return -EINVAL; | 856 | return -EINVAL; |
| 853 | } | 857 | } |
| 854 | drm_mode_set_name(mode); | 858 | drm_mode_set_name(mode); |
| @@ -947,7 +951,7 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) · 92 unmodified lines | |||
| 947 | bl = devm_backlight_device_register(dev, "nt35510", dev, nt, | 951 | bl = devm_backlight_device_register(dev, "nt35510", dev, nt, |
| 948 | &nt35510_bl_ops, NULL); | 952 | &nt35510_bl_ops, NULL); |
| 949 | if (IS_ERR(bl)) { | 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 | return PTR_ERR(bl); | 955 | return PTR_ERR(bl); |
| 952 | } | 956 | } |
| 953 | bl->props.max_brightness = 255; | 957 | bl->props.max_brightness = 255; |
| @@ -956,9 +960,7 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) · 2 unmodified lines | |||
| 956 | nt->panel.backlight = bl; | 960 | nt->panel.backlight = bl; |
| 957 | } | 961 | } |
| 958 | 962 | ||
| 959 | ret = drm_panel_add(&nt->panel); | 963 | drm_panel_add(&nt->panel); |
| 960 | if (ret < 0) | ||
| 961 | return ret; | ||
| 962 | 964 | ||
| 963 | ret = mipi_dsi_attach(dsi); | 965 | ret = mipi_dsi_attach(dsi); |
| 964 | if (ret < 0) | 966 | if (ret < 0) |
| @@ -6,7 +6,6 @@ · 5 unmodified lines | |||
| 6 | * Copyright (C) 2019, Paul Cercueil <paul@crapouillou.net> | 6 | * Copyright (C) 2019, Paul Cercueil <paul@crapouillou.net> |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/backlight.h> | ||
| 10 | #include <linux/delay.h> | 9 | #include <linux/delay.h> |
| 11 | #include <linux/device.h> | 10 | #include <linux/device.h> |
| 12 | #include <linux/gpio/consumer.h> | 11 | #include <linux/gpio/consumer.h> |
| @@ -57,14 +56,11 @@ struct nt39016_panel_info { · 44 unmodified lines | |||
| 57 | 56 | ||
| 58 | struct nt39016 { | 57 | struct nt39016 { |
| 59 | struct drm_panel drm_panel; | 58 | struct drm_panel drm_panel; |
| 60 | struct device *dev; | ||
| 61 | struct regmap *map; | 59 | struct regmap *map; |
| 62 | struct regulator *supply; | 60 | struct regulator *supply; |
| 63 | const struct nt39016_panel_info *panel_info; | 61 | const struct nt39016_panel_info *panel_info; |
| 64 | 62 | ||
| 65 | struct gpio_desc *reset_gpio; | 63 | struct gpio_desc *reset_gpio; |
| 66 | |||
| 67 | struct backlight_device *backlight; | ||
| 68 | }; | 64 | }; |
| 69 | 65 | ||
| 70 | static inline struct nt39016 *to_nt39016(struct drm_panel *panel) | 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 | err = regulator_enable(panel->supply); | 124 | err = regulator_enable(panel->supply); |
| 129 | if (err) { | 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 | return err; | 127 | return err; |
| 132 | } | 128 | } |
| 133 | 129 | ||
| @@ -146,7 +142,7 @@ static int nt39016_prepare(struct drm_panel *drm_panel) · 12 unmodified lines | |||
| 146 | err = regmap_multi_reg_write(panel->map, nt39016_panel_regs, | 142 | err = regmap_multi_reg_write(panel->map, nt39016_panel_regs, |
| 147 | ARRAY_SIZE(nt39016_panel_regs)); | 143 | ARRAY_SIZE(nt39016_panel_regs)); |
| 148 | if (err) { | 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 | goto err_disable_regulator; | 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 | ret = regmap_write(panel->map, NT39016_REG_SYSTEM, | 172 | ret = regmap_write(panel->map, NT39016_REG_SYSTEM, |
| 177 | NT39016_SYSTEM_RESET_N | NT39016_SYSTEM_STANDBY); | 173 | NT39016_SYSTEM_RESET_N | NT39016_SYSTEM_STANDBY); |
| 178 | if (ret) { | 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 | return ret; | 176 | return ret; |
| 181 | } | 177 | } |
| 182 | 178 | ||
| 183 | if (panel->backlight) { | 179 | if (drm_panel->backlight) { |
| 184 | /* Wait for the picture to be ready before enabling backlight */ | 180 | /* Wait for the picture to be ready before enabling backlight */ |
| 185 | msleep(150); | 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 | static int nt39016_disable(struct drm_panel *drm_panel) | 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 | struct nt39016 *panel = to_nt39016(drm_panel); | 189 | struct nt39016 *panel = to_nt39016(drm_panel); |
| 196 | int err; | 190 | int err; |
| 197 | 191 | ||
| 198 | backlight_disable(panel->backlight); | ||
| 199 | |||
| 200 | err = regmap_write(panel->map, NT39016_REG_SYSTEM, | 192 | err = regmap_write(panel->map, NT39016_REG_SYSTEM, |
| 201 | NT39016_SYSTEM_RESET_N); | 193 | NT39016_SYSTEM_RESET_N); |
| 202 | if (err) { | 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 | return err; | 196 | return err; |
| 205 | } | 197 | } |
| 206 | 198 | ||
| @@ -259,7 +251,6 @@ static int nt39016_probe(struct spi_device *spi) · 52 unmodified lines | |||
| 259 | if (!panel) | 251 | if (!panel) |
| 260 | return -ENOMEM; | 252 | return -ENOMEM; |
| 261 | 253 | ||
| 262 | panel->dev = dev; | ||
| 263 | spi_set_drvdata(spi, panel); | 254 | spi_set_drvdata(spi, panel); |
| 264 | 255 | ||
| 265 | panel->panel_info = of_device_get_match_data(dev); | 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 | panel->supply = devm_regulator_get(dev, "power"); | 260 | panel->supply = devm_regulator_get(dev, "power"); |
| 270 | if (IS_ERR(panel->supply)) { | 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 | return PTR_ERR(panel->supply); | 263 | return PTR_ERR(panel->supply); |
| 273 | } | 264 | } |
| 274 | 265 | ||
| 275 | panel->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); | 266 | panel->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); |
| 276 | if (IS_ERR(panel->reset_gpio)) { | 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 | return PTR_ERR(panel->reset_gpio); | 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 | spi->mode = SPI_MODE_3 | SPI_3WIRE; | 273 | spi->mode = SPI_MODE_3 | SPI_3WIRE; |
| 283 | err = spi_setup(spi); | 274 | err = spi_setup(spi); |
| 284 | if (err) { | 275 | if (err) { |
| 285 | dev_err(dev, "Failed to setup SPI"); | 276 | dev_err(dev, "Failed to setup SPI\n"); |
| 286 | return err; | 277 | return err; |
| 287 | } | 278 | } |
| 288 | 279 | ||
| 289 | panel->map = devm_regmap_init_spi(spi, &nt39016_regmap_config); | 280 | panel->map = devm_regmap_init_spi(spi, &nt39016_regmap_config); |
| 290 | if (IS_ERR(panel->map)) { | 281 | if (IS_ERR(panel->map)) { |
| 291 | dev_err(dev, "Failed to init regmap"); | 282 | dev_err(dev, "Failed to init regmap\n"); |
| 292 | return PTR_ERR(panel->map); | 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 | drm_panel_init(&panel->drm_panel, dev, &nt39016_funcs, | 286 | drm_panel_init(&panel->drm_panel, dev, &nt39016_funcs, |
| 304 | DRM_MODE_CONNECTOR_DPI); | 287 | DRM_MODE_CONNECTOR_DPI); |
| 305 | 288 | ||
| 306 | err = drm_panel_add(&panel->drm_panel); | 289 | err = drm_panel_of_backlight(&panel->drm_panel); |
| 307 | if (err < 0) { | 290 | if (err) { |
| 308 | dev_err(dev, "Failed to register panel"); | 291 | if (err != -EPROBE_DEFER) |
| 292 | dev_err(dev, "Failed to get backlight handle\n"); | ||
| 309 | return err; | 293 | return err; |
| 310 | } | 294 | } |
| 311 | 295 | ||
| 296 | drm_panel_add(&panel->drm_panel); | ||
| 297 | |||
| 312 | return 0; | 298 | return 0; |
| 313 | } | 299 | } |
| 314 | 300 | ||
| @@ -283,7 +283,9 @@ static int lcd_olinuxino_probe(struct i2c_client *client, · 282 unmodified lines | |||
| 283 | if (ret) | 283 | if (ret) |
| 284 | return ret; | 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 | static int lcd_olinuxino_remove(struct i2c_client *client) | 291 | static int lcd_olinuxino_remove(struct i2c_client *client) |
| @@ -17,7 +17,6 @@ · 16 unmodified lines | |||
| 17 | #include <drm/drm_mipi_dsi.h> | 17 | #include <drm/drm_mipi_dsi.h> |
| 18 | #include <drm/drm_modes.h> | 18 | #include <drm/drm_modes.h> |
| 19 | #include <drm/drm_panel.h> | 19 | #include <drm/drm_panel.h> |
| 20 | #include <drm/drm_print.h> | ||
| 21 | 20 | ||
| 22 | #define OTM8009A_BACKLIGHT_DEFAULT 240 | 21 | #define OTM8009A_BACKLIGHT_DEFAULT 240 |
| 23 | #define OTM8009A_BACKLIGHT_MAX 255 | 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 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | 96 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); |
| 98 | 97 | ||
| 99 | if (mipi_dsi_dcs_write_buffer(dsi, data, len) < 0) | 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 | static void otm8009a_dcs_write_buf_hs(struct otm8009a *ctx, const void *data, | 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 | ret = regulator_enable(ctx->supply); | 313 | ret = regulator_enable(ctx->supply); |
| 315 | if (ret < 0) { | 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 | return ret; | 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 | mode = drm_mode_duplicate(connector->dev, &default_mode); | 355 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 357 | if (!mode) { | 356 | if (!mode) { |
| 358 | DRM_ERROR("failed to add mode %ux%ux@%u\n", | 357 | dev_err(panel->dev, "failed to add mode %ux%u@%u\n", |
| 359 | default_mode.hdisplay, default_mode.vdisplay, | 358 | default_mode.hdisplay, default_mode.vdisplay, |
| 360 | drm_mode_vrefresh(&default_mode)); | 359 | drm_mode_vrefresh(&default_mode)); |
| 361 | return -ENOMEM; | 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 | u8 data[2]; | 389 | u8 data[2]; |
| 391 | 390 | ||
| 392 | if (!ctx->prepared) { | 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 | return -ENXIO; | 393 | return -ENXIO; |
| 395 | } | 394 | } |
| 396 | 395 | ||
| @@ -164,7 +164,9 @@ static int osd101t2587_panel_add(struct osd101t2587_panel *osd101t2587) · 163 unmodified lines | |||
| 164 | if (ret) | 164 | if (ret) |
| 165 | return ret; | 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 | static int osd101t2587_panel_probe(struct mipi_dsi_device *dsi) | 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 | if (ret) | 206 | if (ret) |
| 207 | return ret; | 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 | static void wuxga_nt_panel_del(struct wuxga_nt_panel *wuxga_nt) | 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 | struct rpi_touchscreen *ts; | 361 | struct rpi_touchscreen *ts; |
| 362 | struct device_node *endpoint, *dsi_host_node; | 362 | struct device_node *endpoint, *dsi_host_node; |
| 363 | struct mipi_dsi_host *host; | 363 | struct mipi_dsi_host *host; |
| 364 | int ret, ver; | 364 | int ver; |
| 365 | struct mipi_dsi_device_info info = { | 365 | struct mipi_dsi_device_info info = { |
| 366 | .type = RPI_DSI_DRIVER_NAME, | 366 | .type = RPI_DSI_DRIVER_NAME, |
| 367 | .channel = 0, | 367 | .channel = 0, |
| @@ -429,9 +429,7 @@ static int rpi_touchscreen_probe(struct i2c_client *i2c, · 61 unmodified lines | |||
| 429 | /* This appears last, as it's what will unblock the DSI host | 429 | /* This appears last, as it's what will unblock the DSI host |
| 430 | * driver's component bind function. | 430 | * driver's component bind function. |
| 431 | */ | 431 | */ |
| 432 | ret = drm_panel_add(&ts->base); | 432 | drm_panel_add(&ts->base); |
| 433 | if (ret) | ||
| 434 | return ret; | ||
| 435 | 433 | ||
| 436 | return 0; | 434 | return 0; |
| 437 | 435 | ||
| @@ -19,7 +19,6 @@ · 18 unmodified lines | |||
| 19 | #include <drm/drm_crtc.h> | 19 | #include <drm/drm_crtc.h> |
| 20 | #include <drm/drm_mipi_dsi.h> | 20 | #include <drm/drm_mipi_dsi.h> |
| 21 | #include <drm/drm_panel.h> | 21 | #include <drm/drm_panel.h> |
| 22 | #include <drm/drm_print.h> | ||
| 23 | 22 | ||
| 24 | /* Panel specific color-format bits */ | 23 | /* Panel specific color-format bits */ |
| 25 | #define COL_FMT_16BPP 0x55 | 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 | ret = rad_panel_push_cmd_list(dsi); | 329 | ret = rad_panel_push_cmd_list(dsi); |
| 331 | if (ret < 0) { | 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 | goto fail; | 332 | goto fail; |
| 334 | } | 333 | } |
| 335 | 334 | ||
| @@ -341,7 +340,7 @@ static int rad_panel_enable(struct drm_panel *panel) · 5 unmodified lines | |||
| 341 | /* Software reset */ | 340 | /* Software reset */ |
| 342 | ret = mipi_dsi_dcs_soft_reset(dsi); | 341 | ret = mipi_dsi_dcs_soft_reset(dsi); |
| 343 | if (ret < 0) { | 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 | goto fail; | 344 | goto fail; |
| 346 | } | 345 | } |
| 347 | 346 | ||
| @@ -350,33 +349,32 @@ static int rad_panel_enable(struct drm_panel *panel) · 2 unmodified lines | |||
| 350 | /* Set DSI mode */ | 349 | /* Set DSI mode */ |
| 351 | ret = mipi_dsi_generic_write(dsi, (u8[]){ 0xC2, 0x0B }, 2); | 350 | ret = mipi_dsi_generic_write(dsi, (u8[]){ 0xC2, 0x0B }, 2); |
| 352 | if (ret < 0) { | 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 | goto fail; | 353 | goto fail; |
| 355 | } | 354 | } |
| 356 | /* Set tear ON */ | 355 | /* Set tear ON */ |
| 357 | ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); | 356 | ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); |
| 358 | if (ret < 0) { | 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 | goto fail; | 359 | goto fail; |
| 361 | } | 360 | } |
| 362 | /* Set tear scanline */ | 361 | /* Set tear scanline */ |
| 363 | ret = mipi_dsi_dcs_set_tear_scanline(dsi, 0x380); | 362 | ret = mipi_dsi_dcs_set_tear_scanline(dsi, 0x380); |
| 364 | if (ret < 0) { | 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 | goto fail; | 365 | goto fail; |
| 367 | } | 366 | } |
| 368 | /* Set pixel format */ | 367 | /* Set pixel format */ |
| 369 | ret = mipi_dsi_dcs_set_pixel_format(dsi, color_format); | 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", | 369 | dev_dbg(dev, "Interface color format set to 0x%x\n", color_format); |
| 371 | color_format); | ||
| 372 | if (ret < 0) { | 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 | goto fail; | 372 | goto fail; |
| 375 | } | 373 | } |
| 376 | /* Exit sleep mode */ | 374 | /* Exit sleep mode */ |
| 377 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | 375 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 378 | if (ret < 0) { | 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 | goto fail; | 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 | ret = mipi_dsi_dcs_set_display_on(dsi); | 383 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 386 | if (ret < 0) { | 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 | goto fail; | 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 | ret = mipi_dsi_dcs_set_display_off(dsi); | 417 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 420 | if (ret < 0) { | 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 | return ret; | 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 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); | 425 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 428 | if (ret < 0) { | 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 | return ret; | 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 | mode = drm_mode_duplicate(connector->dev, &default_mode); | 441 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 444 | if (!mode) { | 442 | if (!mode) { |
| 445 | DRM_DEV_ERROR(panel->dev, "failed to add mode %ux%ux@%u\n", | 443 | dev_err(panel->dev, "failed to add mode %ux%u@%u\n", |
| 446 | default_mode.hdisplay, default_mode.vdisplay, | 444 | default_mode.hdisplay, default_mode.vdisplay, |
| 447 | drm_mode_vrefresh(&default_mode)); | 445 | drm_mode_vrefresh(&default_mode)); |
| 448 | return -ENOMEM; | 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 | DRM_MODE_CONNECTOR_DSI); | 607 | DRM_MODE_CONNECTOR_DSI); |
| 610 | dev_set_drvdata(dev, panel); | 608 | dev_set_drvdata(dev, panel); |
| 611 | 609 | ||
| 612 | ret = drm_panel_add(&panel->panel); | 610 | drm_panel_add(&panel->panel); |
| 613 | if (ret) | ||
| 614 | return ret; | ||
| 615 | 611 | ||
| 616 | ret = mipi_dsi_attach(dsi); | 612 | ret = mipi_dsi_attach(dsi); |
| 617 | if (ret) | 613 | if (ret) |
| @@ -628,8 +624,7 @@ static int rad_panel_remove(struct mipi_dsi_device *dsi) · 10 unmodified lines | |||
| 628 | 624 | ||
| 629 | ret = mipi_dsi_detach(dsi); | 625 | ret = mipi_dsi_detach(dsi); |
| 630 | if (ret) | 626 | if (ret) |
| 631 | DRM_DEV_ERROR(dev, "Failed to detach from host (%d)\n", | 627 | dev_err(dev, "Failed to detach from host (%d)\n", ret); |
| 632 | ret); | ||
| 633 | 628 | ||
| 634 | drm_panel_remove(&rad->panel); | 629 | drm_panel_remove(&rad->panel); |
| 635 | 630 | ||
| @@ -17,7 +17,6 @@ · 16 unmodified lines | |||
| 17 | #include <drm/drm_mipi_dsi.h> | 17 | #include <drm/drm_mipi_dsi.h> |
| 18 | #include <drm/drm_modes.h> | 18 | #include <drm/drm_modes.h> |
| 19 | #include <drm/drm_panel.h> | 19 | #include <drm/drm_panel.h> |
| 20 | #include <drm/drm_print.h> | ||
| 21 | 20 | ||
| 22 | /*** Manufacturer Command Set ***/ | 21 | /*** Manufacturer Command Set ***/ |
| 23 | #define MCS_CMD_MODE_SW 0xFE /* CMD Mode Switch */ | 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 | err = mipi_dsi_dcs_write_buffer(dsi, data, len); | 110 | err = mipi_dsi_dcs_write_buffer(dsi, data, len); |
| 112 | if (err < 0) | 111 | if (err < 0) |
| 113 | DRM_ERROR_RATELIMITED("MIPI DSI DCS write buffer failed: %d\n", | 112 | dev_err_ratelimited(ctx->dev, "MIPI DSI DCS write buffer failed: %d\n", err); |
| 114 | err); | ||
| 115 | } | 113 | } |
| 116 | 114 | ||
| 117 | static void rm68200_dcs_write_cmd(struct rm68200 *ctx, u8 cmd, u8 value) | 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 | err = mipi_dsi_dcs_write(dsi, cmd, &value, 1); | 120 | err = mipi_dsi_dcs_write(dsi, cmd, &value, 1); |
| 123 | if (err < 0) | 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 | #define dcs_write_seq(ctx, seq...) \ | 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 | ret = mipi_dsi_dcs_set_display_off(dsi); | 255 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 258 | if (ret) | 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 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); | 259 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 262 | if (ret) | 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 | msleep(120); | 263 | msleep(120); |
| 266 | 264 | ||
| @@ -287,7 +285,7 @@ static int rm68200_prepare(struct drm_panel *panel) · 20 unmodified lines | |||
| 287 | 285 | ||
| 288 | ret = regulator_enable(ctx->supply); | 286 | ret = regulator_enable(ctx->supply); |
| 289 | if (ret < 0) { | 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 | return ret; | 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 | mode = drm_mode_duplicate(connector->dev, &default_mode); | 335 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 338 | if (!mode) { | 336 | if (!mode) { |
| 339 | DRM_ERROR("failed to add mode %ux%ux@%u\n", | 337 | dev_err(panel->dev, "failed to add mode %ux%u@%u\n", |
| 340 | default_mode.hdisplay, default_mode.vdisplay, | 338 | default_mode.hdisplay, default_mode.vdisplay, |
| 341 | drm_mode_vrefresh(&default_mode)); | 339 | drm_mode_vrefresh(&default_mode)); |
| 342 | return -ENOMEM; | 340 | return -ENOMEM; |
| 343 | } | 341 | } |
| 344 | 342 | ||
| @@ -23,7 +23,6 @@ · 22 unmodified lines | |||
| 23 | #include <drm/drm_mipi_dsi.h> | 23 | #include <drm/drm_mipi_dsi.h> |
| 24 | #include <drm/drm_modes.h> | 24 | #include <drm/drm_modes.h> |
| 25 | #include <drm/drm_panel.h> | 25 | #include <drm/drm_panel.h> |
| 26 | #include <drm/drm_print.h> | ||
| 27 | 26 | ||
| 28 | struct rb070d30_panel { | 27 | struct rb070d30_panel { |
| 29 | struct drm_panel panel; | 28 | struct drm_panel panel; |
| @@ -50,7 +49,7 @@ static int rb070d30_panel_prepare(struct drm_panel *panel) · 20 unmodified lines | |||
| 50 | 49 | ||
| 51 | ret = regulator_enable(ctx->supply); | 50 | ret = regulator_enable(ctx->supply); |
| 52 | if (ret < 0) { | 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 | return ret; | 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 | mode = drm_mode_duplicate(connector->dev, &default_mode); | 117 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 119 | if (!mode) { | 118 | if (!mode) { |
| 120 | DRM_DEV_ERROR(&ctx->dsi->dev, | 119 | dev_err(&ctx->dsi->dev, "Failed to add mode " DRM_MODE_FMT "\n", |
| 121 | "Failed to add mode " DRM_MODE_FMT "\n", | 120 | DRM_MODE_ARG(&default_mode)); |
| 122 | DRM_MODE_ARG(&default_mode)); | ||
| 123 | return -EINVAL; | 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 | ctx->gpios.reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); | 165 | ctx->gpios.reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); |
| 168 | if (IS_ERR(ctx->gpios.reset)) { | 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 | return PTR_ERR(ctx->gpios.reset); | 168 | return PTR_ERR(ctx->gpios.reset); |
| 171 | } | 169 | } |
| 172 | 170 | ||
| 173 | ctx->gpios.power = devm_gpiod_get(&dsi->dev, "power", GPIOD_OUT_LOW); | 171 | ctx->gpios.power = devm_gpiod_get(&dsi->dev, "power", GPIOD_OUT_LOW); |
| 174 | if (IS_ERR(ctx->gpios.power)) { | 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 | return PTR_ERR(ctx->gpios.power); | 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 | ctx->gpios.updn = devm_gpiod_get(&dsi->dev, "updn", GPIOD_OUT_LOW); | 181 | ctx->gpios.updn = devm_gpiod_get(&dsi->dev, "updn", GPIOD_OUT_LOW); |
| 184 | if (IS_ERR(ctx->gpios.updn)) { | 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 | return PTR_ERR(ctx->gpios.updn); | 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 | ctx->gpios.shlr = devm_gpiod_get(&dsi->dev, "shlr", GPIOD_OUT_LOW); | 191 | ctx->gpios.shlr = devm_gpiod_get(&dsi->dev, "shlr", GPIOD_OUT_LOW); |
| 194 | if (IS_ERR(ctx->gpios.shlr)) { | 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 | return PTR_ERR(ctx->gpios.shlr); | 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 | if (ret) | 198 | if (ret) |
| 201 | return ret; | 199 | return ret; |
| 202 | 200 | ||
| 203 | ret = drm_panel_add(&ctx->panel); | 201 | drm_panel_add(&ctx->panel); |
| 204 | if (ret < 0) | ||
| 205 | return ret; | ||
| 206 | 202 | ||
| 207 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM; | 203 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM; |
| 208 | dsi->format = MIPI_DSI_FMT_RGB888; | 204 | dsi->format = MIPI_DSI_FMT_RGB888; |
| @@ -21,7 +21,6 @@ · 20 unmodified lines | |||
| 21 | 21 | ||
| 22 | #include <drm/drm_modes.h> | 22 | #include <drm/drm_modes.h> |
| 23 | #include <drm/drm_panel.h> | 23 | #include <drm/drm_panel.h> |
| 24 | #include <drm/drm_print.h> | ||
| 25 | 24 | ||
| 26 | /* Manufacturer Command Set */ | 25 | /* Manufacturer Command Set */ |
| 27 | #define MCS_MANPWR 0xb0 | 26 | #define MCS_MANPWR 0xb0 |
| @@ -269,7 +268,7 @@ static int ld9040_get_modes(struct drm_panel *panel, · 241 unmodified lines | |||
| 269 | 268 | ||
| 270 | mode = drm_mode_create(connector->dev); | 269 | mode = drm_mode_create(connector->dev); |
| 271 | if (!mode) { | 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 | return 0; | 272 | return 0; |
| 274 | } | 273 | } |
| 275 | 274 | ||
| @@ -354,7 +353,9 @@ static int ld9040_probe(struct spi_device *spi) · 78 unmodified lines | |||
| 354 | drm_panel_init(&ctx->panel, dev, &ld9040_drm_funcs, | 353 | drm_panel_init(&ctx->panel, dev, &ld9040_drm_funcs, |
| 355 | DRM_MODE_CONNECTOR_DPI); | 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 | static int ld9040_remove(struct spi_device *spi) | 361 | static int ld9040_remove(struct spi_device *spi) |
| @@ -7,7 +7,6 @@ · 6 unmodified lines | |||
| 7 | #include <drm/drm_modes.h> | 7 | #include <drm/drm_modes.h> |
| 8 | #include <drm/drm_mipi_dsi.h> | 8 | #include <drm/drm_mipi_dsi.h> |
| 9 | #include <drm/drm_panel.h> | 9 | #include <drm/drm_panel.h> |
| 10 | #include <drm/drm_print.h> | ||
| 11 | 10 | ||
| 12 | #include <linux/gpio/consumer.h> | 11 | #include <linux/gpio/consumer.h> |
| 13 | #include <linux/regulator/consumer.h> | 12 | #include <linux/regulator/consumer.h> |
| @@ -55,8 +54,7 @@ static int s6d16d0_unprepare(struct drm_panel *panel) · 41 unmodified lines | |||
| 55 | /* Enter sleep mode */ | 54 | /* Enter sleep mode */ |
| 56 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); | 55 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 57 | if (ret) { | 56 | if (ret) { |
| 58 | DRM_DEV_ERROR(s6->dev, "failed to enter sleep mode (%d)\n", | 57 | dev_err(s6->dev, "failed to enter sleep mode (%d)\n", ret); |
| 59 | ret); | ||
| 60 | return ret; | 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 | ret = regulator_enable(s6->supply); | 74 | ret = regulator_enable(s6->supply); |
| 77 | if (ret) { | 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 | return ret; | 77 | return ret; |
| 80 | } | 78 | } |
| 81 | 79 | ||
| @@ -90,15 +88,13 @@ static int s6d16d0_prepare(struct drm_panel *panel) · 8 unmodified lines | |||
| 90 | ret = mipi_dsi_dcs_set_tear_on(dsi, | 88 | ret = mipi_dsi_dcs_set_tear_on(dsi, |
| 91 | MIPI_DSI_DCS_TEAR_MODE_VBLANK); | 89 | MIPI_DSI_DCS_TEAR_MODE_VBLANK); |
| 92 | if (ret) { | 90 | if (ret) { |
| 93 | DRM_DEV_ERROR(s6->dev, "failed to enable vblank TE (%d)\n", | 91 | dev_err(s6->dev, "failed to enable vblank TE (%d)\n", ret); |
| 94 | ret); | ||
| 95 | return ret; | 92 | return ret; |
| 96 | } | 93 | } |
| 97 | /* Exit sleep mode and power on */ | 94 | /* Exit sleep mode and power on */ |
| 98 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | 95 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 99 | if (ret) { | 96 | if (ret) { |
| 100 | DRM_DEV_ERROR(s6->dev, "failed to exit sleep mode (%d)\n", | 97 | dev_err(s6->dev, "failed to exit sleep mode (%d)\n", ret); |
| 101 | ret); | ||
| 102 | return ret; | 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 | ret = mipi_dsi_dcs_set_display_on(dsi); | 110 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 115 | if (ret) { | 111 | if (ret) { |
| 116 | DRM_DEV_ERROR(s6->dev, "failed to turn display on (%d)\n", | 112 | dev_err(s6->dev, "failed to turn display on (%d)\n", ret); |
| 117 | ret); | ||
| 118 | return ret; | 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 | ret = mipi_dsi_dcs_set_display_off(dsi); | 125 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 131 | if (ret) { | 126 | if (ret) { |
| 132 | DRM_DEV_ERROR(s6->dev, "failed to turn display off (%d)\n", | 127 | dev_err(s6->dev, "failed to turn display off (%d)\n", ret); |
| 133 | ret); | ||
| 134 | return ret; | 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 | mode = drm_mode_duplicate(connector->dev, &samsung_s6d16d0_mode); | 139 | mode = drm_mode_duplicate(connector->dev, &samsung_s6d16d0_mode); |
| 146 | if (!mode) { | 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 | return -EINVAL; | 142 | return -EINVAL; |
| 149 | } | 143 | } |
| 150 | drm_mode_set_name(mode); | 144 | drm_mode_set_name(mode); |
| @@ -204,17 +198,14 @@ static int s6d16d0_probe(struct mipi_dsi_device *dsi) · 53 unmodified lines | |||
| 204 | if (IS_ERR(s6->reset_gpio)) { | 198 | if (IS_ERR(s6->reset_gpio)) { |
| 205 | ret = PTR_ERR(s6->reset_gpio); | 199 | ret = PTR_ERR(s6->reset_gpio); |
| 206 | if (ret != -EPROBE_DEFER) | 200 | if (ret != -EPROBE_DEFER) |
| 207 | DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n", | 201 | dev_err(dev, "failed to request GPIO (%d)\n", ret); |
| 208 | ret); | ||
| 209 | return ret; | 202 | return ret; |
| 210 | } | 203 | } |
| 211 | 204 | ||
| 212 | drm_panel_init(&s6->panel, dev, &s6d16d0_drm_funcs, | 205 | drm_panel_init(&s6->panel, dev, &s6d16d0_drm_funcs, |
| 213 | DRM_MODE_CONNECTOR_DSI); | 206 | DRM_MODE_CONNECTOR_DSI); |
| 214 | 207 | ||
| 215 | ret = drm_panel_add(&s6->panel); | 208 | drm_panel_add(&s6->panel); |
| 216 | if (ret < 0) | ||
| 217 | return ret; | ||
| 218 | 209 | ||
| 219 | ret = mipi_dsi_attach(dsi); | 210 | ret = mipi_dsi_attach(dsi); |
| 220 | if (ret < 0) | 211 | if (ret < 0) |
| @@ -18,7 +18,6 @@ · 17 unmodified lines | |||
| 18 | #include <drm/drm_mipi_dsi.h> | 18 | #include <drm/drm_mipi_dsi.h> |
| 19 | #include <drm/drm_modes.h> | 19 | #include <drm/drm_modes.h> |
| 20 | #include <drm/drm_panel.h> | 20 | #include <drm/drm_panel.h> |
| 21 | #include <drm/drm_print.h> | ||
| 22 | 21 | ||
| 23 | #define S6E3HA2_MIN_BRIGHTNESS 0 | 22 | #define S6E3HA2_MIN_BRIGHTNESS 0 |
| 24 | #define S6E3HA2_MAX_BRIGHTNESS 100 | 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 | mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); | 651 | mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); |
| 653 | if (!mode) { | 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 | ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, | 654 | ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, |
| 656 | drm_mode_vrefresh(ctx->desc->mode)); | 655 | drm_mode_vrefresh(ctx->desc->mode)); |
| 657 | return -ENOMEM; | 656 | return -ENOMEM; |
| @@ -733,9 +732,7 @@ static int s6e3ha2_probe(struct mipi_dsi_device *dsi) · 75 unmodified lines | |||
| 733 | drm_panel_init(&ctx->panel, dev, &s6e3ha2_drm_funcs, | 732 | drm_panel_init(&ctx->panel, dev, &s6e3ha2_drm_funcs, |
| 734 | DRM_MODE_CONNECTOR_DSI); | 733 | DRM_MODE_CONNECTOR_DSI); |
| 735 | 734 | ||
| 736 | ret = drm_panel_add(&ctx->panel); | 735 | drm_panel_add(&ctx->panel); |
| 737 | if (ret < 0) | ||
| 738 | goto unregister_backlight; | ||
| 739 | 736 | ||
| 740 | ret = mipi_dsi_attach(dsi); | 737 | ret = mipi_dsi_attach(dsi); |
| 741 | if (ret < 0) | 738 | if (ret < 0) |
| @@ -745,8 +742,6 @@ static int s6e3ha2_probe(struct mipi_dsi_device *dsi) · 3 unmodified lines | |||
| 745 | 742 | ||
| 746 | remove_panel: | 743 | remove_panel: |
| 747 | drm_panel_remove(&ctx->panel); | 744 | drm_panel_remove(&ctx->panel); |
| 748 | |||
| 749 | unregister_backlight: | ||
| 750 | backlight_device_unregister(ctx->bl_dev); | 745 | backlight_device_unregister(ctx->bl_dev); |
| 751 | 746 | ||
| 752 | return ret; | 747 | return ret; |
| @@ -19,7 +19,6 @@ · 18 unmodified lines | |||
| 19 | #include <drm/drm_mipi_dsi.h> | 19 | #include <drm/drm_mipi_dsi.h> |
| 20 | #include <drm/drm_modes.h> | 20 | #include <drm/drm_modes.h> |
| 21 | #include <drm/drm_panel.h> | 21 | #include <drm/drm_panel.h> |
| 22 | #include <drm/drm_print.h> | ||
| 23 | 22 | ||
| 24 | #define MCS_LEVEL2_KEY 0xf0 | 23 | #define MCS_LEVEL2_KEY 0xf0 |
| 25 | #define MCS_MTP_KEY 0xf1 | 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 | mode = drm_mode_duplicate(connector->dev, &default_mode); | 406 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 408 | if (!mode) { | 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 | default_mode.hdisplay, default_mode.vdisplay, | 409 | default_mode.hdisplay, default_mode.vdisplay, |
| 411 | drm_mode_vrefresh(&default_mode)); | 410 | drm_mode_vrefresh(&default_mode)); |
| 412 | return -ENOMEM; | 411 | return -ENOMEM; |
| @@ -479,9 +478,7 @@ static int s6e63j0x03_probe(struct mipi_dsi_device *dsi) · 66 unmodified lines | |||
| 479 | ctx->bl_dev->props.brightness = DEFAULT_BRIGHTNESS; | 478 | ctx->bl_dev->props.brightness = DEFAULT_BRIGHTNESS; |
| 480 | ctx->bl_dev->props.power = FB_BLANK_POWERDOWN; | 479 | ctx->bl_dev->props.power = FB_BLANK_POWERDOWN; |
| 481 | 480 | ||
| 482 | ret = drm_panel_add(&ctx->panel); | 481 | drm_panel_add(&ctx->panel); |
| 483 | if (ret < 0) | ||
| 484 | goto unregister_backlight; | ||
| 485 | 482 | ||
| 486 | ret = mipi_dsi_attach(dsi); | 483 | ret = mipi_dsi_attach(dsi); |
| 487 | if (ret < 0) | 484 | if (ret < 0) |
| @@ -491,8 +488,6 @@ static int s6e63j0x03_probe(struct mipi_dsi_device *dsi) · 3 unmodified lines | |||
| 491 | 488 | ||
| 492 | remove_panel: | 489 | remove_panel: |
| 493 | drm_panel_remove(&ctx->panel); | 490 | drm_panel_remove(&ctx->panel); |
| 494 | |||
| 495 | unregister_backlight: | ||
| 496 | backlight_device_unregister(ctx->bl_dev); | 491 | backlight_device_unregister(ctx->bl_dev); |
| 497 | 492 | ||
| 498 | return ret; | 493 | return ret; |
| @@ -10,7 +10,6 @@ · 9 unmodified lines | |||
| 10 | 10 | ||
| 11 | #include <drm/drm_modes.h> | 11 | #include <drm/drm_modes.h> |
| 12 | #include <drm/drm_panel.h> | 12 | #include <drm/drm_panel.h> |
| 13 | #include <drm/drm_print.h> | ||
| 14 | 13 | ||
| 15 | #include <linux/backlight.h> | 14 | #include <linux/backlight.h> |
| 16 | #include <linux/delay.h> | 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 | if (ctx->error < 0 || len == 0) | 156 | if (ctx->error < 0 || len == 0) |
| 158 | return; | 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 | ret = s6e63m0_spi_write_word(ctx, *data); | 160 | ret = s6e63m0_spi_write_word(ctx, *data); |
| 162 | 161 | ||
| 163 | while (!ret && --len) { | 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 | if (ret) { | 167 | if (ret) { |
| 169 | DRM_DEV_ERROR(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, | 168 | dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, (int)len, data); |
| 170 | (int)len, data); | ||
| 171 | ctx->error = ret; | 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 | mode = drm_mode_duplicate(connector->dev, &default_mode); | 367 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 370 | if (!mode) { | 368 | if (!mode) { |
| 371 | DRM_ERROR("failed to add mode %ux%ux@%u\n", | 369 | dev_err(panel->dev, "failed to add mode %ux%u@%u\n", |
| 372 | default_mode.hdisplay, default_mode.vdisplay, | 370 | default_mode.hdisplay, default_mode.vdisplay, |
| 373 | drm_mode_vrefresh(&default_mode)); | 371 | drm_mode_vrefresh(&default_mode)); |
| 374 | return -ENOMEM; | 372 | return -ENOMEM; |
| 375 | } | 373 | } |
| 376 | 374 | ||
| @@ -425,8 +423,7 @@ static int s6e63m0_backlight_register(struct s6e63m0 *ctx) · 48 unmodified lines | |||
| 425 | &props); | 423 | &props); |
| 426 | if (IS_ERR(ctx->bl_dev)) { | 424 | if (IS_ERR(ctx->bl_dev)) { |
| 427 | ret = PTR_ERR(ctx->bl_dev); | 425 | ret = PTR_ERR(ctx->bl_dev); |
| 428 | DRM_DEV_ERROR(dev, "error registering backlight device (%d)\n", | 426 | dev_err(dev, "error registering backlight device (%d)\n", ret); |
| 429 | ret); | ||
| 430 | } | 427 | } |
| 431 | 428 | ||
| 432 | return ret; | 429 | return ret; |
| @@ -453,14 +450,13 @@ static int s6e63m0_probe(struct spi_device *spi) · 20 unmodified lines | |||
| 453 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), | 450 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), |
| 454 | ctx->supplies); | 451 | ctx->supplies); |
| 455 | if (ret < 0) { | 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 | return ret; | 454 | return ret; |
| 458 | } | 455 | } |
| 459 | 456 | ||
| 460 | ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); | 457 | ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); |
| 461 | if (IS_ERR(ctx->reset_gpio)) { | 458 | if (IS_ERR(ctx->reset_gpio)) { |
| 462 | DRM_DEV_ERROR(dev, "cannot get reset-gpios %ld\n", | 459 | dev_err(dev, "cannot get reset-gpios %ld\n", PTR_ERR(ctx->reset_gpio)); |
| 463 | PTR_ERR(ctx->reset_gpio)); | ||
| 464 | return PTR_ERR(ctx->reset_gpio); | 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 | spi->mode = SPI_MODE_3; | 464 | spi->mode = SPI_MODE_3; |
| 469 | ret = spi_setup(spi); | 465 | ret = spi_setup(spi); |
| 470 | if (ret < 0) { | 466 | if (ret < 0) { |
| 471 | DRM_DEV_ERROR(dev, "spi setup failed.\n"); | 467 | dev_err(dev, "spi setup failed.\n"); |
| 472 | return ret; | 468 | return ret; |
| 473 | } | 469 | } |
| 474 | 470 | ||
| @@ -479,7 +475,9 @@ static int s6e63m0_probe(struct spi_device *spi) · 4 unmodified lines | |||
| 479 | if (ret < 0) | 475 | if (ret < 0) |
| 480 | return ret; | 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 | static int s6e63m0_remove(struct spi_device *spi) | 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 | drm_panel_init(&ctx->panel, dev, &s6e88a0_ams452ef01_panel_funcs, | 242 | drm_panel_init(&ctx->panel, dev, &s6e88a0_ams452ef01_panel_funcs, |
| 243 | DRM_MODE_CONNECTOR_DSI); | 243 | DRM_MODE_CONNECTOR_DSI); |
| 244 | 244 | ||
| 245 | ret = drm_panel_add(&ctx->panel); | 245 | drm_panel_add(&ctx->panel); |
| 246 | if (ret < 0) { | ||
| 247 | dev_err(dev, "Failed to add panel: %d\n", ret); | ||
| 248 | return ret; | ||
| 249 | } | ||
| 250 | 246 | ||
| 251 | ret = mipi_dsi_attach(dsi); | 247 | ret = mipi_dsi_attach(dsi); |
| 252 | if (ret < 0) { | 248 | if (ret < 0) { |
| @@ -25,7 +25,6 @@ · 24 unmodified lines | |||
| 25 | #include <drm/drm_mipi_dsi.h> | 25 | #include <drm/drm_mipi_dsi.h> |
| 26 | #include <drm/drm_modes.h> | 26 | #include <drm/drm_modes.h> |
| 27 | #include <drm/drm_panel.h> | 27 | #include <drm/drm_panel.h> |
| 28 | #include <drm/drm_print.h> | ||
| 29 | 28 | ||
| 30 | #define LDI_MTP_LENGTH 24 | 29 | #define LDI_MTP_LENGTH 24 |
| 31 | #define GAMMA_LEVEL_NUM 25 | 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 | mode = drm_mode_create(connector->dev); | 928 | mode = drm_mode_create(connector->dev); |
| 930 | if (!mode) { | 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 | return 0; | 931 | return 0; |
| 933 | } | 932 | } |
| 934 | 933 | ||
| @@ -1020,9 +1019,7 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi) · 85 unmodified lines | |||
| 1020 | drm_panel_init(&ctx->panel, dev, &s6e8aa0_drm_funcs, | 1019 | drm_panel_init(&ctx->panel, dev, &s6e8aa0_drm_funcs, |
| 1021 | DRM_MODE_CONNECTOR_DSI); | 1020 | DRM_MODE_CONNECTOR_DSI); |
| 1022 | 1021 | ||
| 1023 | ret = drm_panel_add(&ctx->panel); | 1022 | drm_panel_add(&ctx->panel); |
| 1024 | if (ret < 0) | ||
| 1025 | return ret; | ||
| 1026 | 1023 | ||
| 1027 | ret = mipi_dsi_attach(dsi); | 1024 | ret = mipi_dsi_attach(dsi); |
| 1028 | if (ret < 0) | 1025 | if (ret < 0) |
| @@ -258,9 +258,7 @@ static int seiko_panel_probe(struct device *dev, · 257 unmodified lines | |||
| 258 | if (err) | 258 | if (err) |
| 259 | return err; | 259 | return err; |
| 260 | 260 | ||
| 261 | err = drm_panel_add(&panel->base); | 261 | drm_panel_add(&panel->base); |
| 262 | if (err < 0) | ||
| 263 | return err; | ||
| 264 | 262 | ||
| 265 | dev_set_drvdata(dev, panel); | 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 | if (ret) | 325 | if (ret) |
| 326 | return ret; | 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 | static void sharp_panel_del(struct sharp_panel *sharp) | 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 | drm_panel_init(&lcd->panel, &pdev->dev, &ls037v7dw01_funcs, | 187 | drm_panel_init(&lcd->panel, &pdev->dev, &ls037v7dw01_funcs, |
| 188 | DRM_MODE_CONNECTOR_DPI); | 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 | static int ls037v7dw01_remove(struct platform_device *pdev) | 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 | if (ret) | 261 | if (ret) |
| 262 | return ret; | 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 | static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt) | 269 | static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt) |
| @@ -112,6 +112,8 @@ struct panel_simple { · 111 unmodified lines | |||
| 112 | struct gpio_desc *hpd_gpio; | 112 | struct gpio_desc *hpd_gpio; |
| 113 | 113 | ||
| 114 | struct drm_display_mode override_mode; | 114 | struct drm_display_mode override_mode; |
| 115 | |||
| 116 | enum drm_panel_orientation orientation; | ||
| 115 | }; | 117 | }; |
| 116 | 118 | ||
| 117 | static inline struct panel_simple *to_panel_simple(struct drm_panel *panel) | 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 | /* add hard-coded panel modes */ | 373 | /* add hard-coded panel modes */ |
| 372 | num += panel_simple_get_non_edid_modes(p, connector); | 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 | return num; | 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 | struct panel_simple *panel; | 505 | struct panel_simple *panel; |
| 501 | struct display_timing dt; | 506 | struct display_timing dt; |
| 502 | struct device_node *ddc; | 507 | struct device_node *ddc; |
| 508 | int connector_type; | ||
| 509 | u32 bus_flags; | ||
| 503 | int err; | 510 | int err; |
| 504 | 511 | ||
| 505 | panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); | 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 | return err; | 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 | ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0); | 546 | ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0); |
| 534 | if (ddc) { | 547 | if (ddc) { |
| 535 | panel->ddc = of_find_i2c_adapter_by_node(ddc); | 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 | panel_simple_parse_panel_timing_node(dev, panel, &dt); | 562 | panel_simple_parse_panel_timing_node(dev, panel, &dt); |
| 550 | } | 563 | } |
| 551 | 564 | ||
| 552 | if (desc->connector_type == DRM_MODE_CONNECTOR_LVDS) { | 565 | connector_type = desc->connector_type; |
| 553 | /* Catch common mistakes for LVDS panels. */ | 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 | WARN_ON(desc->bus_flags & | 573 | WARN_ON(desc->bus_flags & |
| 555 | ~(DRM_BUS_FLAG_DE_LOW | | 574 | ~(DRM_BUS_FLAG_DE_LOW | |
| 556 | DRM_BUS_FLAG_DE_HIGH | | 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 | WARN_ON((desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_SPWG || | 583 | WARN_ON((desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_SPWG || |
| 565 | desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA) && | 584 | desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA) && |
| 566 | desc->bpc != 8); | 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, | 621 | drm_panel_init(&panel->base, dev, &panel_simple_funcs, connector_type); |
| 570 | desc->connector_type); | ||
| 571 | 622 | ||
| 572 | err = drm_panel_of_backlight(&panel->base); | 623 | err = drm_panel_of_backlight(&panel->base); |
| 573 | if (err) | 624 | if (err) |
| 574 | goto free_ddc; | 625 | goto free_ddc; |
| 575 | 626 | ||
| 576 | err = drm_panel_add(&panel->base); | 627 | drm_panel_add(&panel->base); |
| 577 | if (err < 0) | ||
| 578 | goto free_ddc; | ||
| 579 | 628 | ||
| 580 | dev_set_drvdata(dev, panel); | 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 | static const struct panel_desc boe_hv070wsa = { | 1240 | static const struct panel_desc boe_hv070wsa = { |
| 1192 | .modes = &boe_hv070wsa_mode, | 1241 | .modes = &boe_hv070wsa_mode, |
| 1193 | .num_modes = 1, | 1242 | .num_modes = 1, |
| 1243 | .bpc = 8, | ||
| 1194 | .size = { | 1244 | .size = { |
| 1195 | .width = 154, | 1245 | .width = 154, |
| 1196 | .height = 90, | 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 | static const struct drm_display_mode boe_nv101wxmn51_modes[] = { | 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 | static const struct drm_display_mode chunghwa_claa070wp03xg_mode = { | 1500 | static const struct drm_display_mode chunghwa_claa070wp03xg_mode = { |
| 1418 | .clock = 66770, | 1501 | .clock = 66770, |
| 1419 | .hdisplay = 800, | 1502 | .hdisplay = 800, |
| @@ -2258,6 +2341,34 @@ static const struct panel_desc ivo_m133nwf4_r0 = { · 838 unmodified lines | |||
| 2258 | .connector_type = DRM_MODE_CONNECTOR_eDP, | 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 | static const struct display_timing koe_tx14d24vm1bpa_timing = { | 2372 | static const struct display_timing koe_tx14d24vm1bpa_timing = { |
| 2262 | .pixelclock = { 5580000, 5850000, 6200000 }, | 2373 | .pixelclock = { 5580000, 5850000, 6200000 }, |
| 2263 | .hactive = { 320, 320, 320 }, | 2374 | .hactive = { 320, 320, 320 }, |
| @@ -2946,7 +3057,7 @@ static const struct panel_desc ortustech_com43h4m85ulc = { · 682 unmodified lines | |||
| 2946 | .width = 56, | 3057 | .width = 56, |
| 2947 | .height = 93, | 3058 | .height = 93, |
| 2948 | }, | 3059 | }, |
| 2949 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, | 3060 | .bus_format = MEDIA_BUS_FMT_RGB666_1X18, |
| 2950 | .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, | 3061 | .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, |
| 2951 | .connector_type = DRM_MODE_CONNECTOR_DPI, | 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 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, | 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 | static const struct drm_display_mode qd43003c0_40_mode = { | 3140 | static const struct drm_display_mode qd43003c0_40_mode = { |
| 3005 | .clock = 9000, | 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 = { | 3440 | static const struct drm_display_mode sharp_ls020b1dd01d_modes[] = { |
| 3305 | .pixelclock = { 2000000, 4200000, 5000000 }, | 3441 | { /* 50 Hz */ |
| 3306 | .hactive = { 240, 240, 240 }, | 3442 | .clock = 3000, |
| 3307 | .hfront_porch = { 66, 66, 66 }, | 3443 | .hdisplay = 240, |
| 3308 | .hback_porch = { 1, 1, 1 }, | 3444 | .hsync_start = 240 + 58, |
| 3309 | .hsync_len = { 1, 1, 1 }, | 3445 | .hsync_end = 240 + 58 + 1, |
| 3310 | .vactive = { 160, 160, 160 }, | 3446 | .htotal = 240 + 58 + 1 + 1, |
| 3311 | .vfront_porch = { 52, 52, 52 }, | 3447 | .vdisplay = 160, |
| 3312 | .vback_porch = { 6, 6, 6 }, | 3448 | .vsync_start = 160 + 24, |
| 3313 | .vsync_len = { 10, 10, 10 }, | 3449 | .vsync_end = 160 + 24 + 10, |
| 3314 | .flags = DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW, | 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 | static const struct panel_desc sharp_ls020b1dd01d = { | 3467 | static const struct panel_desc sharp_ls020b1dd01d = { |
| 3318 | .timings = &sharp_ls020b1dd01d_timing, | 3468 | .modes = sharp_ls020b1dd01d_modes, |
| 3319 | .num_timings = 1, | 3469 | .num_modes = ARRAY_SIZE(sharp_ls020b1dd01d_modes), |
| 3320 | .bpc = 6, | 3470 | .bpc = 6, |
| 3321 | .size = { | 3471 | .size = { |
| 3322 | .width = 42, | 3472 | .width = 42, |
| @@ -3820,6 +3970,9 @@ static const struct of_device_id platform_of_match[] = { · 497 unmodified lines | |||
| 3820 | }, { | 3970 | }, { |
| 3821 | .compatible = "cdtech,s070wv95-ct16", | 3971 | .compatible = "cdtech,s070wv95-ct16", |
| 3822 | .data = &cdtech_s070wv95_ct16, | 3972 | .data = &cdtech_s070wv95_ct16, |
| 3973 | }, { | ||
| 3974 | .compatible = "chefree,ch101olhlwh-002", | ||
| 3975 | .data = &chefree_ch101olhlwh_002, | ||
| 3823 | }, { | 3976 | }, { |
| 3824 | .compatible = "chunghwa,claa070wp03xg", | 3977 | .compatible = "chunghwa,claa070wp03xg", |
| 3825 | .data = &chunghwa_claa070wp03xg, | 3978 | .data = &chunghwa_claa070wp03xg, |
| @@ -3922,6 +4075,9 @@ static const struct of_device_id platform_of_match[] = { · 96 unmodified lines | |||
| 3922 | }, { | 4075 | }, { |
| 3923 | .compatible = "ivo,m133nwf4-r0", | 4076 | .compatible = "ivo,m133nwf4-r0", |
| 3924 | .data = &ivo_m133nwf4_r0, | 4077 | .data = &ivo_m133nwf4_r0, |
| 4078 | }, { | ||
| 4079 | .compatible = "kingdisplay,kd116n21-30nv-a010", | ||
| 4080 | .data = &kingdisplay_kd116n21_30nv_a010, | ||
| 3925 | }, { | 4081 | }, { |
| 3926 | .compatible = "koe,tx14d24vm1bpa", | 4082 | .compatible = "koe,tx14d24vm1bpa", |
| 3927 | .data = &koe_tx14d24vm1bpa, | 4083 | .data = &koe_tx14d24vm1bpa, |
| @@ -4012,6 +4168,9 @@ static const struct of_device_id platform_of_match[] = { · 84 unmodified lines | |||
| 4012 | }, { | 4168 | }, { |
| 4013 | .compatible = "pda,91-00156-a0", | 4169 | .compatible = "pda,91-00156-a0", |
| 4014 | .data = &pda_91_00156_a0, | 4170 | .data = &pda_91_00156_a0, |
| 4171 | }, { | ||
| 4172 | .compatible = "powertip,ph800480t013-idf02", | ||
| 4173 | .data = &powertip_ph800480t013_idf02, | ||
| 4015 | }, { | 4174 | }, { |
| 4016 | .compatible = "qiaodian,qd43003c0-40", | 4175 | .compatible = "qiaodian,qd43003c0-40", |
| 4017 | .data = &qd43003c0_40, | 4176 | .data = &qd43003c0_40, |
| @@ -7,7 +7,6 @@ · 6 unmodified lines | |||
| 7 | #include <drm/drm_mipi_dsi.h> | 7 | #include <drm/drm_mipi_dsi.h> |
| 8 | #include <drm/drm_modes.h> | 8 | #include <drm/drm_modes.h> |
| 9 | #include <drm/drm_panel.h> | 9 | #include <drm/drm_panel.h> |
| 10 | #include <drm/drm_print.h> | ||
| 11 | 10 | ||
| 12 | #include <linux/gpio/consumer.h> | 11 | #include <linux/gpio/consumer.h> |
| 13 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
| @@ -269,10 +268,9 @@ static int st7701_get_modes(struct drm_panel *panel, · 255 unmodified lines | |||
| 269 | 268 | ||
| 270 | mode = drm_mode_duplicate(connector->dev, desc_mode); | 269 | mode = drm_mode_duplicate(connector->dev, desc_mode); |
| 271 | if (!mode) { | 270 | if (!mode) { |
| 272 | DRM_DEV_ERROR(&st7701->dsi->dev, | 271 | dev_err(&st7701->dsi->dev, "failed to add mode %ux%u@%u\n", |
| 273 | "failed to add mode %ux%ux@%u\n", | 272 | desc_mode->hdisplay, desc_mode->vdisplay, |
| 274 | desc_mode->hdisplay, desc_mode->vdisplay, | 273 | drm_mode_vrefresh(desc_mode)); |
| 275 | drm_mode_vrefresh(desc_mode)); | ||
| 276 | return -ENOMEM; | 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 | st7701->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); | 357 | st7701->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); |
| 360 | if (IS_ERR(st7701->reset)) { | 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 | return PTR_ERR(st7701->reset); | 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 | if (ret) | 378 | if (ret) |
| 381 | return ret; | 379 | return ret; |
| 382 | 380 | ||
| 383 | ret = drm_panel_add(&st7701->panel); | 381 | drm_panel_add(&st7701->panel); |
| 384 | if (ret < 0) | ||
| 385 | return ret; | ||
| 386 | 382 | ||
| 387 | mipi_dsi_set_drvdata(dsi, st7701); | 383 | mipi_dsi_set_drvdata(dsi, st7701); |
| 388 | st7701->dsi = dsi; | 384 | st7701->dsi = dsi; |
| @@ -22,7 +22,6 @@ · 21 unmodified lines | |||
| 22 | #include <drm/drm_mipi_dsi.h> | 22 | #include <drm/drm_mipi_dsi.h> |
| 23 | #include <drm/drm_modes.h> | 23 | #include <drm/drm_modes.h> |
| 24 | #include <drm/drm_panel.h> | 24 | #include <drm/drm_panel.h> |
| 25 | #include <drm/drm_print.h> | ||
| 26 | 25 | ||
| 27 | #define DRV_NAME "panel-sitronix-st7703" | 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 | ret = ctx->desc->init_sequence(ctx); | 364 | ret = ctx->desc->init_sequence(ctx); |
| 366 | if (ret < 0) { | 365 | if (ret < 0) { |
| 367 | DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", | 366 | dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); |
| 368 | ret); | ||
| 369 | return ret; | 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 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | 372 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 375 | if (ret < 0) { | 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 | return ret; | 375 | return ret; |
| 378 | } | 376 | } |
| 379 | 377 | ||
| @@ -384,7 +382,7 @@ static int st7703_enable(struct drm_panel *panel) · 4 unmodified lines | |||
| 384 | if (ret) | 382 | if (ret) |
| 385 | return ret; | 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 | return 0; | 387 | return 0; |
| 390 | } | 388 | } |
| @@ -397,13 +395,11 @@ static int st7703_disable(struct drm_panel *panel) · 6 unmodified lines | |||
| 397 | 395 | ||
| 398 | ret = mipi_dsi_dcs_set_display_off(dsi); | 396 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 399 | if (ret < 0) | 397 | if (ret < 0) |
| 400 | DRM_DEV_ERROR(ctx->dev, | 398 | dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret); |
| 401 | "Failed to turn off the display: %d\n", ret); | ||
| 402 | 399 | ||
| 403 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); | 400 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 404 | if (ret < 0) | 401 | if (ret < 0) |
| 405 | DRM_DEV_ERROR(ctx->dev, | 402 | dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret); |
| 406 | "Failed to enter sleep mode: %d\n", ret); | ||
| 407 | 403 | ||
| 408 | return 0; | 404 | return 0; |
| 409 | } | 405 | } |
| @@ -431,17 +427,15 @@ static int st7703_prepare(struct drm_panel *panel) · 21 unmodified lines | |||
| 431 | if (ctx->prepared) | 427 | if (ctx->prepared) |
| 432 | return 0; | 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 | ret = regulator_enable(ctx->vcc); | 431 | ret = regulator_enable(ctx->vcc); |
| 436 | if (ret < 0) { | 432 | if (ret < 0) { |
| 437 | DRM_DEV_ERROR(ctx->dev, | 433 | dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret); |
| 438 | "Failed to enable vcc supply: %d\n", ret); | ||
| 439 | return ret; | 434 | return ret; |
| 440 | } | 435 | } |
| 441 | ret = regulator_enable(ctx->iovcc); | 436 | ret = regulator_enable(ctx->iovcc); |
| 442 | if (ret < 0) { | 437 | if (ret < 0) { |
| 443 | DRM_DEV_ERROR(ctx->dev, | 438 | dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); |
| 444 | "Failed to enable iovcc supply: %d\n", ret); | ||
| 445 | goto disable_vcc; | 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 | mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); | 462 | mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); |
| 469 | if (!mode) { | 463 | if (!mode) { |
| 470 | DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n", | 464 | dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", |
| 471 | ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, | 465 | ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, |
| 472 | drm_mode_vrefresh(ctx->desc->mode)); | 466 | drm_mode_vrefresh(ctx->desc->mode)); |
| 473 | return -ENOMEM; | 467 | return -ENOMEM; |
| 474 | } | 468 | } |
| 475 | 469 | ||
| @@ -496,7 +490,7 @@ static int allpixelson_set(void *data, u64 val) · 20 unmodified lines | |||
| 496 | struct st7703 *ctx = data; | 490 | struct st7703 *ctx = data; |
| 497 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | 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 | dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON); | 494 | dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON); |
| 501 | msleep(val * 1000); | 495 | msleep(val * 1000); |
| 502 | /* Reset the panel to get video back */ | 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 | ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); | 532 | ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); |
| 539 | if (IS_ERR(ctx->reset_gpio)) { | 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 | return PTR_ERR(ctx->reset_gpio); | 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 | if (IS_ERR(ctx->vcc)) { | 548 | if (IS_ERR(ctx->vcc)) { |
| 555 | ret = PTR_ERR(ctx->vcc); | 549 | ret = PTR_ERR(ctx->vcc); |
| 556 | if (ret != -EPROBE_DEFER) | 550 | if (ret != -EPROBE_DEFER) |
| 557 | DRM_DEV_ERROR(dev, | 551 | dev_err(dev, "Failed to request vcc regulator: %d\n", ret); |
| 558 | "Failed to request vcc regulator: %d\n", | ||
| 559 | ret); | ||
| 560 | return ret; | 552 | return ret; |
| 561 | } | 553 | } |
| 562 | ctx->iovcc = devm_regulator_get(dev, "iovcc"); | 554 | ctx->iovcc = devm_regulator_get(dev, "iovcc"); |
| 563 | if (IS_ERR(ctx->iovcc)) { | 555 | if (IS_ERR(ctx->iovcc)) { |
| 564 | ret = PTR_ERR(ctx->iovcc); | 556 | ret = PTR_ERR(ctx->iovcc); |
| 565 | if (ret != -EPROBE_DEFER) | 557 | if (ret != -EPROBE_DEFER) |
| 566 | DRM_DEV_ERROR(dev, | 558 | dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); |
| 567 | "Failed to request iovcc regulator: %d\n", | ||
| 568 | ret); | ||
| 569 | return ret; | 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 | ret = mipi_dsi_attach(dsi); | 571 | ret = mipi_dsi_attach(dsi); |
| 582 | if (ret < 0) { | 572 | if (ret < 0) { |
| 583 | DRM_DEV_ERROR(dev, | 573 | dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret); |
| 584 | "mipi_dsi_attach failed (%d). Is host ready?\n", | ||
| 585 | ret); | ||
| 586 | drm_panel_remove(&ctx->panel); | 574 | drm_panel_remove(&ctx->panel); |
| 587 | return ret; | 575 | return ret; |
| 588 | } | 576 | } |
| 589 | 577 | ||
| 590 | DRM_DEV_INFO(dev, "%ux%u@%u %ubpp dsi %udl - ready\n", | 578 | dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n", |
| 591 | ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, | 579 | ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, |
| 592 | drm_mode_vrefresh(ctx->desc->mode), | 580 | drm_mode_vrefresh(ctx->desc->mode), |
| 593 | mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); | 581 | mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); |
| 594 | 582 | ||
| 595 | st7703_debugfs_init(ctx); | 583 | st7703_debugfs_init(ctx); |
| 596 | return 0; | 584 | return 0; |
| @@ -603,13 +591,11 @@ static void st7703_shutdown(struct mipi_dsi_device *dsi) · 6 unmodified lines | |||
| 603 | 591 | ||
| 604 | ret = drm_panel_unprepare(&ctx->panel); | 592 | ret = drm_panel_unprepare(&ctx->panel); |
| 605 | if (ret < 0) | 593 | if (ret < 0) |
| 606 | DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", | 594 | dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); |
| 607 | ret); | ||
| 608 | 595 | ||
| 609 | ret = drm_panel_disable(&ctx->panel); | 596 | ret = drm_panel_disable(&ctx->panel); |
| 610 | if (ret < 0) | 597 | if (ret < 0) |
| 611 | DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", | 598 | dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); |
| 612 | ret); | ||
| 613 | } | 599 | } |
| 614 | 600 | ||
| 615 | static int st7703_remove(struct mipi_dsi_device *dsi) | 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 | ret = mipi_dsi_detach(dsi); | 608 | ret = mipi_dsi_detach(dsi); |
| 623 | if (ret < 0) | 609 | if (ret < 0) |
| 624 | DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", | 610 | dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); |
| 625 | ret); | ||
| 626 | 611 | ||
| 627 | drm_panel_remove(&ctx->panel); | 612 | drm_panel_remove(&ctx->panel); |
| 628 | 613 | ||
| @@ -382,9 +382,7 @@ static int st7789v_probe(struct spi_device *spi) · 381 unmodified lines | |||
| 382 | if (ret) | 382 | if (ret) |
| 383 | return ret; | 383 | return ret; |
| 384 | 384 | ||
| 385 | ret = drm_panel_add(&ctx->panel); | 385 | drm_panel_add(&ctx->panel); |
| 386 | if (ret < 0) | ||
| 387 | return ret; | ||
| 388 | 386 | ||
| 389 | return 0; | 387 | return 0; |
| 390 | } | 388 | } |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | |||
| 20 | #include <drm/drm_mipi_dsi.h> | 20 | #include <drm/drm_mipi_dsi.h> |
| 21 | #include <drm/drm_modes.h> | 21 | #include <drm/drm_modes.h> |
| 22 | #include <drm/drm_panel.h> | 22 | #include <drm/drm_panel.h> |
| 23 | #include <drm/drm_print.h> | ||
| 24 | 23 | ||
| 25 | #define ACX424_DCS_READ_ID1 0xDA | 24 | #define ACX424_DCS_READ_ID1 0xDA |
| 26 | #define ACX424_DCS_READ_ID2 0xDB | 25 | #define ACX424_DCS_READ_ID2 0xDB |
| @@ -110,13 +109,11 @@ static int acx424akp_set_brightness(struct backlight_device *bl) · 83 unmodified lines | |||
| 110 | SCALE_FACTOR_NS_DIV_MHZ); | 109 | SCALE_FACTOR_NS_DIV_MHZ); |
| 111 | 110 | ||
| 112 | /* Set up PWM dutycycle ONE byte (differs from the standard) */ | 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 | ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, | 113 | ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, |
| 115 | &pwm_ratio, 1); | 114 | &pwm_ratio, 1); |
| 116 | if (ret < 0) { | 115 | if (ret < 0) { |
| 117 | DRM_DEV_ERROR(acx->dev, | 116 | dev_err(acx->dev, "failed to set display PWM ratio (%d)\n", ret); |
| 118 | "failed to set display PWM ratio (%d)\n", | ||
| 119 | ret); | ||
| 120 | return ret; | 117 | return ret; |
| 121 | } | 118 | } |
| 122 | 119 | ||
| @@ -132,40 +129,30 @@ static int acx424akp_set_brightness(struct backlight_device *bl) · 9 unmodified lines | |||
| 132 | par = 0xaa; | 129 | par = 0xaa; |
| 133 | ret = mipi_dsi_dcs_write(dsi, 0xf3, &par, 1); | 130 | ret = mipi_dsi_dcs_write(dsi, 0xf3, &par, 1); |
| 134 | if (ret < 0) { | 131 | if (ret < 0) { |
| 135 | DRM_DEV_ERROR(acx->dev, | 132 | dev_err(acx->dev, "failed to unlock CMD 2 (%d)\n", ret); |
| 136 | "failed to unlock CMD 2 (%d)\n", | ||
| 137 | ret); | ||
| 138 | return ret; | 133 | return ret; |
| 139 | } | 134 | } |
| 140 | par = 0x01; | 135 | par = 0x01; |
| 141 | ret = mipi_dsi_dcs_write(dsi, 0x00, &par, 1); | 136 | ret = mipi_dsi_dcs_write(dsi, 0x00, &par, 1); |
| 142 | if (ret < 0) { | 137 | if (ret < 0) { |
| 143 | DRM_DEV_ERROR(acx->dev, | 138 | dev_err(acx->dev, "failed to enter page 1 (%d)\n", ret); |
| 144 | "failed to enter page 1 (%d)\n", | ||
| 145 | ret); | ||
| 146 | return ret; | 139 | return ret; |
| 147 | } | 140 | } |
| 148 | par = 0x01; | 141 | par = 0x01; |
| 149 | ret = mipi_dsi_dcs_write(dsi, 0x7d, &par, 1); | 142 | ret = mipi_dsi_dcs_write(dsi, 0x7d, &par, 1); |
| 150 | if (ret < 0) { | 143 | if (ret < 0) { |
| 151 | DRM_DEV_ERROR(acx->dev, | 144 | dev_err(acx->dev, "failed to disable MTP reload (%d)\n", ret); |
| 152 | "failed to disable MTP reload (%d)\n", | ||
| 153 | ret); | ||
| 154 | return ret; | 145 | return ret; |
| 155 | } | 146 | } |
| 156 | ret = mipi_dsi_dcs_write(dsi, 0x22, &pwm_div, 1); | 147 | ret = mipi_dsi_dcs_write(dsi, 0x22, &pwm_div, 1); |
| 157 | if (ret < 0) { | 148 | if (ret < 0) { |
| 158 | DRM_DEV_ERROR(acx->dev, | 149 | dev_err(acx->dev, "failed to set PWM divisor (%d)\n", ret); |
| 159 | "failed to set PWM divisor (%d)\n", | ||
| 160 | ret); | ||
| 161 | return ret; | 150 | return ret; |
| 162 | } | 151 | } |
| 163 | par = 0xaa; | 152 | par = 0xaa; |
| 164 | ret = mipi_dsi_dcs_write(dsi, 0x7f, &par, 1); | 153 | ret = mipi_dsi_dcs_write(dsi, 0x7f, &par, 1); |
| 165 | if (ret < 0) { | 154 | if (ret < 0) { |
| 166 | DRM_DEV_ERROR(acx->dev, | 155 | dev_err(acx->dev, "failed to lock CMD 2 (%d)\n", ret); |
| 167 | "failed to lock CMD 2 (%d)\n", | ||
| 168 | ret); | ||
| 169 | return ret; | 156 | return ret; |
| 170 | } | 157 | } |
| 171 | 158 | ||
| @@ -174,9 +161,7 @@ static int acx424akp_set_brightness(struct backlight_device *bl) · 2 unmodified lines | |||
| 174 | ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, | 161 | ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, |
| 175 | &par, 1); | 162 | &par, 1); |
| 176 | if (ret < 0) { | 163 | if (ret < 0) { |
| 177 | DRM_DEV_ERROR(acx->dev, | 164 | dev_err(acx->dev, "failed to enable display backlight (%d)\n", ret); |
| 178 | "failed to enable display backlight (%d)\n", | ||
| 179 | ret); | ||
| 180 | return ret; | 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 | ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID1, &vendor, 1); | 182 | ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID1, &vendor, 1); |
| 198 | if (ret < 0) { | 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 | return ret; | 185 | return ret; |
| 201 | } | 186 | } |
| 202 | ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID2, &version, 1); | 187 | ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID2, &version, 1); |
| 203 | if (ret < 0) { | 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 | return ret; | 190 | return ret; |
| 206 | } | 191 | } |
| 207 | ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID3, &panel, 1); | 192 | ret = mipi_dsi_dcs_read(dsi, ACX424_DCS_READ_ID3, &panel, 1); |
| 208 | if (ret < 0) { | 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 | return ret; | 195 | return ret; |
| 211 | } | 196 | } |
| 212 | 197 | ||
| 213 | if (vendor == 0x00) { | 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 | return -ENODEV; | 200 | return -ENODEV; |
| 216 | } | 201 | } |
| 217 | 202 | ||
| @@ -220,14 +205,12 @@ static int acx424akp_read_id(struct acx424akp *acx) · 2 unmodified lines | |||
| 220 | case DISPLAY_SONY_ACX424AKP_ID1: | 205 | case DISPLAY_SONY_ACX424AKP_ID1: |
| 221 | case DISPLAY_SONY_ACX424AKP_ID2: | 206 | case DISPLAY_SONY_ACX424AKP_ID2: |
| 222 | case DISPLAY_SONY_ACX424AKP_ID3: | 207 | case DISPLAY_SONY_ACX424AKP_ID3: |
| 223 | DRM_DEV_INFO(acx->dev, | 208 | dev_info(acx->dev, "MTP vendor: %02x, version: %02x, panel: %02x\n", |
| 224 | "MTP vendor: %02x, version: %02x, panel: %02x\n", | 209 | vendor, version, panel); |
| 225 | vendor, version, panel); | ||
| 226 | break; | 210 | break; |
| 227 | default: | 211 | default: |
| 228 | DRM_DEV_INFO(acx->dev, | 212 | dev_info(acx->dev, "unknown vendor: %02x, version: %02x, panel: %02x\n", |
| 229 | "unknown vendor: %02x, version: %02x, panel: %02x\n", | 213 | vendor, version, panel); |
| 230 | vendor, version, panel); | ||
| 231 | break; | 214 | break; |
| 232 | } | 215 | } |
| 233 | 216 | ||
| @@ -240,7 +223,7 @@ static int acx424akp_power_on(struct acx424akp *acx) · 6 unmodified lines | |||
| 240 | 223 | ||
| 241 | ret = regulator_enable(acx->supply); | 224 | ret = regulator_enable(acx->supply); |
| 242 | if (ret) { | 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 | return ret; | 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 | ret = acx424akp_read_id(acx); | 260 | ret = acx424akp_read_id(acx); |
| 278 | if (ret) { | 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 | goto err_power_off; | 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 | ret = mipi_dsi_dcs_set_tear_on(dsi, | 267 | ret = mipi_dsi_dcs_set_tear_on(dsi, |
| 285 | MIPI_DSI_DCS_TEAR_MODE_VBLANK); | 268 | MIPI_DSI_DCS_TEAR_MODE_VBLANK); |
| 286 | if (ret) { | 269 | if (ret) { |
| 287 | DRM_DEV_ERROR(acx->dev, "failed to enable vblank TE (%d)\n", | 270 | dev_err(acx->dev, "failed to enable vblank TE (%d)\n", ret); |
| 288 | ret); | ||
| 289 | goto err_power_off; | 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 | ret = mipi_dsi_dcs_write(dsi, ACX424_DCS_SET_MDDI, | 284 | ret = mipi_dsi_dcs_write(dsi, ACX424_DCS_SET_MDDI, |
| 303 | &mddi, sizeof(mddi)); | 285 | &mddi, sizeof(mddi)); |
| 304 | if (ret < 0) { | 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 | goto err_power_off; | 288 | goto err_power_off; |
| 307 | } | 289 | } |
| 308 | 290 | ||
| 309 | /* Exit sleep mode */ | 291 | /* Exit sleep mode */ |
| 310 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | 292 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 311 | if (ret) { | 293 | if (ret) { |
| 312 | DRM_DEV_ERROR(acx->dev, "failed to exit sleep mode (%d)\n", | 294 | dev_err(acx->dev, "failed to exit sleep mode (%d)\n", ret); |
| 313 | ret); | ||
| 314 | goto err_power_off; | 295 | goto err_power_off; |
| 315 | } | 296 | } |
| 316 | msleep(140); | 297 | msleep(140); |
| 317 | 298 | ||
| 318 | ret = mipi_dsi_dcs_set_display_on(dsi); | 299 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 319 | if (ret) { | 300 | if (ret) { |
| 320 | DRM_DEV_ERROR(acx->dev, "failed to turn display on (%d)\n", | 301 | dev_err(acx->dev, "failed to turn display on (%d)\n", ret); |
| 321 | ret); | ||
| 322 | goto err_power_off; | 302 | goto err_power_off; |
| 323 | } | 303 | } |
| 324 | if (acx->video_mode) { | 304 | if (acx->video_mode) { |
| @@ -351,24 +331,20 @@ static int acx424akp_unprepare(struct drm_panel *panel) · 26 unmodified lines | |||
| 351 | ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, | 331 | ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, |
| 352 | &par, 1); | 332 | &par, 1); |
| 353 | if (ret) { | 333 | if (ret) { |
| 354 | DRM_DEV_ERROR(acx->dev, | 334 | dev_err(acx->dev, "failed to disable display backlight (%d)\n", ret); |
| 355 | "failed to disable display backlight (%d)\n", | ||
| 356 | ret); | ||
| 357 | return ret; | 335 | return ret; |
| 358 | } | 336 | } |
| 359 | 337 | ||
| 360 | ret = mipi_dsi_dcs_set_display_off(dsi); | 338 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 361 | if (ret) { | 339 | if (ret) { |
| 362 | DRM_DEV_ERROR(acx->dev, "failed to turn display off (%d)\n", | 340 | dev_err(acx->dev, "failed to turn display off (%d)\n", ret); |
| 363 | ret); | ||
| 364 | return ret; | 341 | return ret; |
| 365 | } | 342 | } |
| 366 | 343 | ||
| 367 | /* Enter sleep mode */ | 344 | /* Enter sleep mode */ |
| 368 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); | 345 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 369 | if (ret) { | 346 | if (ret) { |
| 370 | DRM_DEV_ERROR(acx->dev, "failed to enter sleep mode (%d)\n", | 347 | dev_err(acx->dev, "failed to enter sleep mode (%d)\n", ret); |
| 371 | ret); | ||
| 372 | return ret; | 348 | return ret; |
| 373 | } | 349 | } |
| 374 | msleep(85); | 350 | msleep(85); |
| @@ -418,7 +394,7 @@ static int acx424akp_get_modes(struct drm_panel *panel, · 43 unmodified lines | |||
| 418 | mode = drm_mode_duplicate(connector->dev, | 394 | mode = drm_mode_duplicate(connector->dev, |
| 419 | &sony_acx424akp_cmd_mode); | 395 | &sony_acx424akp_cmd_mode); |
| 420 | if (!mode) { | 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 | return -EINVAL; | 398 | return -EINVAL; |
| 423 | } | 399 | } |
| 424 | drm_mode_set_name(mode); | 400 | drm_mode_set_name(mode); |
| @@ -486,8 +462,7 @@ static int acx424akp_probe(struct mipi_dsi_device *dsi) · 61 unmodified lines | |||
| 486 | if (IS_ERR(acx->reset_gpio)) { | 462 | if (IS_ERR(acx->reset_gpio)) { |
| 487 | ret = PTR_ERR(acx->reset_gpio); | 463 | ret = PTR_ERR(acx->reset_gpio); |
| 488 | if (ret != -EPROBE_DEFER) | 464 | if (ret != -EPROBE_DEFER) |
| 489 | DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n", | 465 | dev_err(dev, "failed to request GPIO (%d)\n", ret); |
| 490 | ret); | ||
| 491 | return ret; | 466 | return ret; |
| 492 | } | 467 | } |
| 493 | 468 | ||
| @@ -497,16 +472,14 @@ static int acx424akp_probe(struct mipi_dsi_device *dsi) · 3 unmodified lines | |||
| 497 | acx->bl = devm_backlight_device_register(dev, "acx424akp", dev, acx, | 472 | acx->bl = devm_backlight_device_register(dev, "acx424akp", dev, acx, |
| 498 | &acx424akp_bl_ops, NULL); | 473 | &acx424akp_bl_ops, NULL); |
| 499 | if (IS_ERR(acx->bl)) { | 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 | return PTR_ERR(acx->bl); | 476 | return PTR_ERR(acx->bl); |
| 502 | } | 477 | } |
| 503 | acx->bl->props.max_brightness = 1023; | 478 | acx->bl->props.max_brightness = 1023; |
| 504 | acx->bl->props.brightness = 512; | 479 | acx->bl->props.brightness = 512; |
| 505 | acx->bl->props.power = FB_BLANK_POWERDOWN; | 480 | acx->bl->props.power = FB_BLANK_POWERDOWN; |
| 506 | 481 | ||
| 507 | ret = drm_panel_add(&acx->panel); | 482 | drm_panel_add(&acx->panel); |
| 508 | if (ret < 0) | ||
| 509 | return ret; | ||
| 510 | 483 | ||
| 511 | ret = mipi_dsi_attach(dsi); | 484 | ret = mipi_dsi_attach(dsi); |
| 512 | if (ret < 0) { | 485 | if (ret < 0) { |
| @@ -650,12 +650,7 @@ static int acx565akm_probe(struct spi_device *spi) · 649 unmodified lines | |||
| 650 | drm_panel_init(&lcd->panel, &lcd->spi->dev, &acx565akm_funcs, | 650 | drm_panel_init(&lcd->panel, &lcd->spi->dev, &acx565akm_funcs, |
| 651 | DRM_MODE_CONNECTOR_DPI); | 651 | DRM_MODE_CONNECTOR_DPI); |
| 652 | 652 | ||
| 653 | ret = drm_panel_add(&lcd->panel); | 653 | drm_panel_add(&lcd->panel); |
| 654 | if (ret < 0) { | ||
| 655 | if (lcd->has_bc) | ||
| 656 | acx565akm_backlight_cleanup(lcd); | ||
| 657 | return ret; | ||
| 658 | } | ||
| 659 | 654 | ||
| 660 | return 0; | 655 | return 0; |
| 661 | } | 656 | } |
| @@ -350,7 +350,9 @@ static int td028ttec1_probe(struct spi_device *spi) · 349 unmodified lines | |||
| 350 | if (ret) | 350 | if (ret) |
| 351 | return ret; | 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 | static int td028ttec1_remove(struct spi_device *spi) | 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 | drm_panel_init(&lcd->panel, &lcd->spi->dev, &td043mtea1_funcs, | 460 | drm_panel_init(&lcd->panel, &lcd->spi->dev, &td043mtea1_funcs, |
| 461 | DRM_MODE_CONNECTOR_DPI); | 461 | DRM_MODE_CONNECTOR_DPI); |
| 462 | 462 | ||
| 463 | ret = drm_panel_add(&lcd->panel); | 463 | drm_panel_add(&lcd->panel); |
| 464 | if (ret < 0) { | ||
| 465 | sysfs_remove_group(&spi->dev.kobj, &td043mtea1_attr_group); | ||
| 466 | return ret; | ||
| 467 | } | ||
| 468 | 464 | ||
| 469 | return 0; | 465 | return 0; |
| 470 | } | 466 | } |
| @@ -12,7 +12,6 @@ · 11 unmodified lines | |||
| 12 | */ | 12 | */ |
| 13 | #include <drm/drm_modes.h> | 13 | #include <drm/drm_modes.h> |
| 14 | #include <drm/drm_panel.h> | 14 | #include <drm/drm_panel.h> |
| 15 | #include <drm/drm_print.h> | ||
| 16 | 15 | ||
| 17 | #include <linux/bitops.h> | 16 | #include <linux/bitops.h> |
| 18 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
| @@ -238,7 +237,7 @@ static u8 tpg110_readwrite_reg(struct tpg110 *tpg, bool write, · 219 unmodified lines | |||
| 238 | spi_message_add_tail(&t[1], &m); | 237 | spi_message_add_tail(&t[1], &m); |
| 239 | ret = spi_sync(tpg->spi, &m); | 238 | ret = spi_sync(tpg->spi, &m); |
| 240 | if (ret) { | 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 | return ret; | 241 | return ret; |
| 243 | } | 242 | } |
| 244 | if (write) | 243 | if (write) |
| @@ -265,18 +264,18 @@ static int tpg110_startup(struct tpg110 *tpg) · 20 unmodified lines | |||
| 265 | /* De-assert the reset signal */ | 264 | /* De-assert the reset signal */ |
| 266 | gpiod_set_value_cansleep(tpg->grestb, 0); | 265 | gpiod_set_value_cansleep(tpg->grestb, 0); |
| 267 | usleep_range(1000, 2000); | 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 | /* Test display communication */ | 269 | /* Test display communication */ |
| 271 | tpg110_write_reg(tpg, TPG110_TEST, 0x55); | 270 | tpg110_write_reg(tpg, TPG110_TEST, 0x55); |
| 272 | val = tpg110_read_reg(tpg, TPG110_TEST); | 271 | val = tpg110_read_reg(tpg, TPG110_TEST); |
| 273 | if (val != 0x55) { | 272 | if (val != 0x55) { |
| 274 | DRM_DEV_ERROR(tpg->dev, "failed communication test\n"); | 273 | dev_err(tpg->dev, "failed communication test\n"); |
| 275 | return -ENODEV; | 274 | return -ENODEV; |
| 276 | } | 275 | } |
| 277 | 276 | ||
| 278 | val = tpg110_read_reg(tpg, TPG110_CHIPID); | 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 | val >> 4, val & 0x0f); | 279 | val >> 4, val & 0x0f); |
| 281 | 280 | ||
| 282 | /* Show display resolution */ | 281 | /* Show display resolution */ |
| @@ -284,27 +283,25 @@ static int tpg110_startup(struct tpg110 *tpg) · 1 unmodified line | |||
| 284 | val &= TPG110_RES_MASK; | 283 | val &= TPG110_RES_MASK; |
| 285 | switch (val) { | 284 | switch (val) { |
| 286 | case TPG110_RES_400X240_D: | 285 | case TPG110_RES_400X240_D: |
| 287 | DRM_DEV_INFO(tpg->dev, | 286 | dev_info(tpg->dev, "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)\n"); |
| 288 | "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)\n"); | ||
| 289 | break; | 287 | break; |
| 290 | case TPG110_RES_480X272_D: | 288 | case TPG110_RES_480X272_D: |
| 291 | DRM_DEV_INFO(tpg->dev, | 289 | dev_info(tpg->dev, "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)\n"); |
| 292 | "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)\n"); | ||
| 293 | break; | 290 | break; |
| 294 | case TPG110_RES_480X640: | 291 | case TPG110_RES_480X640: |
| 295 | DRM_DEV_INFO(tpg->dev, "480x640 RGB\n"); | 292 | dev_info(tpg->dev, "480x640 RGB\n"); |
| 296 | break; | 293 | break; |
| 297 | case TPG110_RES_480X272: | 294 | case TPG110_RES_480X272: |
| 298 | DRM_DEV_INFO(tpg->dev, "480x272 RGB\n"); | 295 | dev_info(tpg->dev, "480x272 RGB\n"); |
| 299 | break; | 296 | break; |
| 300 | case TPG110_RES_640X480: | 297 | case TPG110_RES_640X480: |
| 301 | DRM_DEV_INFO(tpg->dev, "640x480 RGB\n"); | 298 | dev_info(tpg->dev, "640x480 RGB\n"); |
| 302 | break; | 299 | break; |
| 303 | case TPG110_RES_800X480: | 300 | case TPG110_RES_800X480: |
| 304 | DRM_DEV_INFO(tpg->dev, "800x480 RGB\n"); | 301 | dev_info(tpg->dev, "800x480 RGB\n"); |
| 305 | break; | 302 | break; |
| 306 | default: | 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 | break; | 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 | if (i == ARRAY_SIZE(tpg110_modes)) { | 321 | if (i == ARRAY_SIZE(tpg110_modes)) { |
| 325 | DRM_DEV_ERROR(tpg->dev, "unsupported mode (%02x) detected\n", | 322 | dev_err(tpg->dev, "unsupported mode (%02x) detected\n", val); |
| 326 | val); | ||
| 327 | return -ENODEV; | 323 | return -ENODEV; |
| 328 | } | 324 | } |
| 329 | 325 | ||
| 330 | val = tpg110_read_reg(tpg, TPG110_CTRL2); | 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 | (val & TPG110_CTRL2_RES_PM_CTRL) ? "software" : "hardware"); | 328 | (val & TPG110_CTRL2_RES_PM_CTRL) ? "software" : "hardware"); |
| 333 | /* Take control over resolution and standby */ | 329 | /* Take control over resolution and standby */ |
| 334 | val |= TPG110_CTRL2_RES_PM_CTRL; | 330 | val |= TPG110_CTRL2_RES_PM_CTRL; |
| @@ -414,15 +410,15 @@ static int tpg110_probe(struct spi_device *spi) · 79 unmodified lines | |||
| 414 | /* We get the physical display dimensions from the DT */ | 410 | /* We get the physical display dimensions from the DT */ |
| 415 | ret = of_property_read_u32(np, "width-mm", &tpg->width); | 411 | ret = of_property_read_u32(np, "width-mm", &tpg->width); |
| 416 | if (ret) | 412 | if (ret) |
| 417 | DRM_DEV_ERROR(dev, "no panel width specified\n"); | 413 | dev_err(dev, "no panel width specified\n"); |
| 418 | ret = of_property_read_u32(np, "height-mm", &tpg->height); | 414 | ret = of_property_read_u32(np, "height-mm", &tpg->height); |
| 419 | if (ret) | 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 | /* This asserts the GRESTB signal, putting the display into reset */ | 418 | /* This asserts the GRESTB signal, putting the display into reset */ |
| 423 | tpg->grestb = devm_gpiod_get(dev, "grestb", GPIOD_OUT_HIGH); | 419 | tpg->grestb = devm_gpiod_get(dev, "grestb", GPIOD_OUT_HIGH); |
| 424 | if (IS_ERR(tpg->grestb)) { | 420 | if (IS_ERR(tpg->grestb)) { |
| 425 | DRM_DEV_ERROR(dev, "no GRESTB GPIO\n"); | 421 | dev_err(dev, "no GRESTB GPIO\n"); |
| 426 | return -ENODEV; | 422 | return -ENODEV; |
| 427 | } | 423 | } |
| 428 | 424 | ||
| @@ -430,7 +426,7 @@ static int tpg110_probe(struct spi_device *spi) · 1 unmodified line | |||
| 430 | spi->mode |= SPI_3WIRE_HIZ; | 426 | spi->mode |= SPI_3WIRE_HIZ; |
| 431 | ret = spi_setup(spi); | 427 | ret = spi_setup(spi); |
| 432 | if (ret < 0) { | 428 | if (ret < 0) { |
| 433 | DRM_DEV_ERROR(dev, "spi setup failed.\n"); | 429 | dev_err(dev, "spi setup failed.\n"); |
| 434 | return ret; | 430 | return ret; |
| 435 | } | 431 | } |
| 436 | tpg->spi = spi; | 432 | tpg->spi = spi; |
| @@ -448,7 +444,9 @@ static int tpg110_probe(struct spi_device *spi) · 11 unmodified lines | |||
| 448 | 444 | ||
| 449 | spi_set_drvdata(spi, tpg); | 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 | static int tpg110_remove(struct spi_device *spi) | 452 | static int tpg110_remove(struct spi_device *spi) |
| @@ -17,7 +17,6 @@ · 16 unmodified lines | |||
| 17 | #include <drm/drm_mipi_dsi.h> | 17 | #include <drm/drm_mipi_dsi.h> |
| 18 | #include <drm/drm_modes.h> | 18 | #include <drm/drm_modes.h> |
| 19 | #include <drm/drm_panel.h> | 19 | #include <drm/drm_panel.h> |
| 20 | #include <drm/drm_print.h> | ||
| 21 | 20 | ||
| 22 | static const char * const regulator_names[] = { | 21 | static const char * const regulator_names[] = { |
| 23 | "vdda", | 22 | "vdda", |
| @@ -231,9 +230,7 @@ static int truly_dcs_write(struct drm_panel *panel, u32 command) · 207 unmodified lines | |||
| 231 | for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) { | 230 | for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) { |
| 232 | ret = mipi_dsi_dcs_write(ctx->dsi[i], command, NULL, 0); | 231 | ret = mipi_dsi_dcs_write(ctx->dsi[i], command, NULL, 0); |
| 233 | if (ret < 0) { | 232 | if (ret < 0) { |
| 234 | DRM_DEV_ERROR(ctx->dev, | 233 | dev_err(ctx->dev, "cmd 0x%x failed for dsi = %d\n", command, i); |
| 235 | "cmd 0x%x failed for dsi = %d\n", | ||
| 236 | 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 | for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) { | 247 | for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) { |
| 251 | ret = mipi_dsi_dcs_write_buffer(ctx->dsi[i], buf, size); | 248 | ret = mipi_dsi_dcs_write_buffer(ctx->dsi[i], buf, size); |
| 252 | if (ret < 0) { | 249 | if (ret < 0) { |
| 253 | DRM_DEV_ERROR(ctx->dev, | 250 | dev_err(ctx->dev, "failed to tx cmd [%d], err: %d\n", i, ret); |
| 254 | "failed to tx cmd [%d], err: %d\n", i, ret); | ||
| 255 | return ret; | 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 | ret = regulator_set_load(ctx->supplies[i].consumer, | 296 | ret = regulator_set_load(ctx->supplies[i].consumer, |
| 301 | regulator_disable_loads[i]); | 297 | regulator_disable_loads[i]); |
| 302 | if (ret) { | 298 | if (ret) { |
| 303 | DRM_DEV_ERROR(ctx->dev, | 299 | dev_err(ctx->dev, "regulator_set_load failed %d\n", ret); |
| 304 | "regulator_set_load failed %d\n", ret); | ||
| 305 | return ret; | 300 | return ret; |
| 306 | } | 301 | } |
| 307 | } | 302 | } |
| 308 | 303 | ||
| 309 | ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); | 304 | ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); |
| 310 | if (ret) { | 305 | if (ret) { |
| 311 | DRM_DEV_ERROR(ctx->dev, | 306 | dev_err(ctx->dev, "regulator_bulk_disable failed %d\n", ret); |
| 312 | "regulator_bulk_disable failed %d\n", ret); | ||
| 313 | } | 307 | } |
| 314 | return ret; | 308 | return ret; |
| 315 | } | 309 | } |
| @@ -325,8 +319,7 @@ static int truly_nt35597_disable(struct drm_panel *panel) · 9 unmodified lines | |||
| 325 | if (ctx->backlight) { | 319 | if (ctx->backlight) { |
| 326 | ret = backlight_disable(ctx->backlight); | 320 | ret = backlight_disable(ctx->backlight); |
| 327 | if (ret < 0) | 321 | if (ret < 0) |
| 328 | DRM_DEV_ERROR(ctx->dev, "backlight disable failed %d\n", | 322 | dev_err(ctx->dev, "backlight disable failed %d\n", ret); |
| 329 | ret); | ||
| 330 | } | 323 | } |
| 331 | 324 | ||
| 332 | ctx->enabled = false; | 325 | ctx->enabled = false; |
| @@ -346,9 +339,7 @@ static int truly_nt35597_unprepare(struct drm_panel *panel) · 13 unmodified lines | |||
| 346 | 339 | ||
| 347 | ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_OFF); | 340 | ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_OFF); |
| 348 | if (ret < 0) { | 341 | if (ret < 0) { |
| 349 | DRM_DEV_ERROR(ctx->dev, | 342 | dev_err(ctx->dev, "set_display_off cmd failed ret = %d\n", ret); |
| 350 | "set_display_off cmd failed ret = %d\n", | ||
| 351 | ret); | ||
| 352 | } | 343 | } |
| 353 | 344 | ||
| 354 | /* 120ms delay required here as per DCS spec */ | 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 | ret = truly_dcs_write(panel, MIPI_DCS_ENTER_SLEEP_MODE); | 348 | ret = truly_dcs_write(panel, MIPI_DCS_ENTER_SLEEP_MODE); |
| 358 | if (ret < 0) { | 349 | if (ret < 0) { |
| 359 | DRM_DEV_ERROR(ctx->dev, | 350 | dev_err(ctx->dev, "enter_sleep cmd failed ret = %d\n", ret); |
| 360 | "enter_sleep cmd failed ret = %d\n", ret); | ||
| 361 | } | 351 | } |
| 362 | 352 | ||
| 363 | ret = truly_nt35597_power_off(ctx); | 353 | ret = truly_nt35597_power_off(ctx); |
| 364 | if (ret < 0) | 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 | ctx->prepared = false; | 357 | ctx->prepared = false; |
| 368 | return ret; | 358 | return ret; |
| @@ -396,18 +386,14 @@ static int truly_nt35597_prepare(struct drm_panel *panel) · 27 unmodified lines | |||
| 396 | panel_on_cmds[i].size, | 386 | panel_on_cmds[i].size, |
| 397 | panel_on_cmds[i].commands); | 387 | panel_on_cmds[i].commands); |
| 398 | if (ret < 0) { | 388 | if (ret < 0) { |
| 399 | DRM_DEV_ERROR(ctx->dev, | 389 | dev_err(ctx->dev, "cmd set tx failed i = %d ret = %d\n", i, ret); |
| 400 | "cmd set tx failed i = %d ret = %d\n", | ||
| 401 | i, ret); | ||
| 402 | goto power_off; | 390 | goto power_off; |
| 403 | } | 391 | } |
| 404 | } | 392 | } |
| 405 | 393 | ||
| 406 | ret = truly_dcs_write(panel, MIPI_DCS_EXIT_SLEEP_MODE); | 394 | ret = truly_dcs_write(panel, MIPI_DCS_EXIT_SLEEP_MODE); |
| 407 | if (ret < 0) { | 395 | if (ret < 0) { |
| 408 | DRM_DEV_ERROR(ctx->dev, | 396 | dev_err(ctx->dev, "exit_sleep_mode cmd failed ret = %d\n", ret); |
| 409 | "exit_sleep_mode cmd failed ret = %d\n", | ||
| 410 | ret); | ||
| 411 | goto power_off; | 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 | ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_ON); | 403 | ret = truly_dcs_write(panel, MIPI_DCS_SET_DISPLAY_ON); |
| 418 | if (ret < 0) { | 404 | if (ret < 0) { |
| 419 | DRM_DEV_ERROR(ctx->dev, | 405 | dev_err(ctx->dev, "set_display_on cmd failed ret = %d\n", ret); |
| 420 | "set_display_on cmd failed ret = %d\n", ret); | ||
| 421 | goto power_off; | 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 | power_off: | 416 | power_off: |
| 432 | if (truly_nt35597_power_off(ctx)) | 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 | return ret; | 419 | return ret; |
| 435 | } | 420 | } |
| 436 | 421 | ||
| @@ -445,8 +430,7 @@ static int truly_nt35597_enable(struct drm_panel *panel) · 8 unmodified lines | |||
| 445 | if (ctx->backlight) { | 430 | if (ctx->backlight) { |
| 446 | ret = backlight_enable(ctx->backlight); | 431 | ret = backlight_enable(ctx->backlight); |
| 447 | if (ret < 0) | 432 | if (ret < 0) |
| 448 | DRM_DEV_ERROR(ctx->dev, "backlight enable failed %d\n", | 433 | dev_err(ctx->dev, "backlight enable failed %d\n", ret); |
| 449 | ret); | ||
| 450 | } | 434 | } |
| 451 | 435 | ||
| 452 | ctx->enabled = true; | 436 | ctx->enabled = true; |
| @@ -464,8 +448,7 @@ static int truly_nt35597_get_modes(struct drm_panel *panel, · 11 unmodified lines | |||
| 464 | config = ctx->config; | 448 | config = ctx->config; |
| 465 | mode = drm_mode_create(connector->dev); | 449 | mode = drm_mode_create(connector->dev); |
| 466 | if (!mode) { | 450 | if (!mode) { |
| 467 | DRM_DEV_ERROR(ctx->dev, | 451 | dev_err(ctx->dev, "failed to create a new display mode\n"); |
| 468 | "failed to create a new display mode\n"); | ||
| 469 | return 0; | 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 | ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); | 485 | ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); |
| 503 | if (IS_ERR(ctx->reset_gpio)) { | 486 | if (IS_ERR(ctx->reset_gpio)) { |
| 504 | DRM_DEV_ERROR(dev, "cannot get reset gpio %ld\n", | 487 | dev_err(dev, "cannot get reset gpio %ld\n", PTR_ERR(ctx->reset_gpio)); |
| 505 | PTR_ERR(ctx->reset_gpio)); | ||
| 506 | return PTR_ERR(ctx->reset_gpio); | 488 | return PTR_ERR(ctx->reset_gpio); |
| 507 | } | 489 | } |
| 508 | 490 | ||
| 509 | ctx->mode_gpio = devm_gpiod_get(dev, "mode", GPIOD_OUT_LOW); | 491 | ctx->mode_gpio = devm_gpiod_get(dev, "mode", GPIOD_OUT_LOW); |
| 510 | if (IS_ERR(ctx->mode_gpio)) { | 492 | if (IS_ERR(ctx->mode_gpio)) { |
| 511 | DRM_DEV_ERROR(dev, "cannot get mode gpio %ld\n", | 493 | dev_err(dev, "cannot get mode gpio %ld\n", PTR_ERR(ctx->mode_gpio)); |
| 512 | PTR_ERR(ctx->mode_gpio)); | ||
| 513 | return PTR_ERR(ctx->mode_gpio); | 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 | dsi1 = of_graph_get_remote_node(dsi->dev.of_node, 1, -1); | 566 | dsi1 = of_graph_get_remote_node(dsi->dev.of_node, 1, -1); |
| 586 | if (!dsi1) { | 567 | if (!dsi1) { |
| 587 | DRM_DEV_ERROR(dev, | 568 | dev_err(dev, "failed to get remote node for dsi1_device\n"); |
| 588 | "failed to get remote node for dsi1_device\n"); | ||
| 589 | return -ENODEV; | 569 | return -ENODEV; |
| 590 | } | 570 | } |
| 591 | 571 | ||
| 592 | dsi1_host = of_find_mipi_dsi_host_by_node(dsi1); | 572 | dsi1_host = of_find_mipi_dsi_host_by_node(dsi1); |
| 593 | of_node_put(dsi1); | 573 | of_node_put(dsi1); |
| 594 | if (!dsi1_host) { | 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 | return -EPROBE_DEFER; | 576 | return -EPROBE_DEFER; |
| 597 | } | 577 | } |
| 598 | 578 | ||
| 599 | /* register the second DSI device */ | 579 | /* register the second DSI device */ |
| 600 | dsi1_device = mipi_dsi_device_register_full(dsi1_host, &info); | 580 | dsi1_device = mipi_dsi_device_register_full(dsi1_host, &info); |
| 601 | if (IS_ERR(dsi1_device)) { | 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 | return PTR_ERR(dsi1_device); | 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 | ret = truly_nt35597_panel_add(ctx); | 592 | ret = truly_nt35597_panel_add(ctx); |
| 613 | if (ret) { | 593 | if (ret) { |
| 614 | DRM_DEV_ERROR(dev, "failed to add panel\n"); | 594 | dev_err(dev, "failed to add panel\n"); |
| 615 | goto err_panel_add; | 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 | MIPI_DSI_CLOCK_NON_CONTINUOUS; | 603 | MIPI_DSI_CLOCK_NON_CONTINUOUS; |
| 624 | ret = mipi_dsi_attach(dsi_dev); | 604 | ret = mipi_dsi_attach(dsi_dev); |
| 625 | if (ret < 0) { | 605 | if (ret < 0) { |
| 626 | DRM_DEV_ERROR(dev, | 606 | dev_err(dev, "dsi attach failed i = %d\n", i); |
| 627 | "dsi attach failed i = %d\n", i); | ||
| 628 | goto err_dsi_attach; | 607 | goto err_dsi_attach; |
| 629 | } | 608 | } |
| 630 | } | 609 | } |
| @@ -14,7 +14,6 @@ · 13 unmodified lines | |||
| 14 | #include <drm/drm_mipi_dsi.h> | 14 | #include <drm/drm_mipi_dsi.h> |
| 15 | #include <drm/drm_modes.h> | 15 | #include <drm/drm_modes.h> |
| 16 | #include <drm/drm_panel.h> | 16 | #include <drm/drm_panel.h> |
| 17 | #include <drm/drm_print.h> | ||
| 18 | 17 | ||
| 19 | struct visionox_rm69299 { | 18 | struct visionox_rm69299 { |
| 20 | struct drm_panel panel; | 19 | struct drm_panel panel; |
| @@ -69,16 +68,14 @@ static int visionox_rm69299_unprepare(struct drm_panel *panel) · 48 unmodified lines | |||
| 69 | 68 | ||
| 70 | ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0); | 69 | ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0); |
| 71 | if (ret < 0) | 70 | if (ret < 0) |
| 72 | DRM_DEV_ERROR(ctx->panel.dev, | 71 | dev_err(ctx->panel.dev, "set_display_off cmd failed ret = %d\n", ret); |
| 73 | "set_display_off cmd failed ret = %d\n", ret); | ||
| 74 | 72 | ||
| 75 | /* 120ms delay required here as per DCS spec */ | 73 | /* 120ms delay required here as per DCS spec */ |
| 76 | msleep(120); | 74 | msleep(120); |
| 77 | 75 | ||
| 78 | ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0); | 76 | ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0); |
| 79 | if (ret < 0) { | 77 | if (ret < 0) { |
| 80 | DRM_DEV_ERROR(ctx->panel.dev, | 78 | dev_err(ctx->panel.dev, "enter_sleep cmd failed ret = %d\n", ret); |
| 81 | "enter_sleep cmd failed ret = %d\n", ret); | ||
| 82 | } | 79 | } |
| 83 | 80 | ||
| 84 | ret = visionox_rm69299_power_off(ctx); | 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 | ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xfe, 0x00 }, 2); | 101 | ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xfe, 0x00 }, 2); |
| 105 | if (ret < 0) { | 102 | if (ret < 0) { |
| 106 | DRM_DEV_ERROR(ctx->panel.dev, | 103 | dev_err(ctx->panel.dev, "cmd set tx 0 failed, ret = %d\n", ret); |
| 107 | "cmd set tx 0 failed, ret = %d\n", ret); | ||
| 108 | goto power_off; | 104 | goto power_off; |
| 109 | } | 105 | } |
| 110 | 106 | ||
| 111 | ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xc2, 0x08 }, 2); | 107 | ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xc2, 0x08 }, 2); |
| 112 | if (ret < 0) { | 108 | if (ret < 0) { |
| 113 | DRM_DEV_ERROR(ctx->panel.dev, | 109 | dev_err(ctx->panel.dev, "cmd set tx 1 failed, ret = %d\n", ret); |
| 114 | "cmd set tx 1 failed, ret = %d\n", ret); | ||
| 115 | goto power_off; | 110 | goto power_off; |
| 116 | } | 111 | } |
| 117 | 112 | ||
| 118 | ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x35, 0x00 }, 2); | 113 | ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x35, 0x00 }, 2); |
| 119 | if (ret < 0) { | 114 | if (ret < 0) { |
| 120 | DRM_DEV_ERROR(ctx->panel.dev, | 115 | dev_err(ctx->panel.dev, "cmd set tx 2 failed, ret = %d\n", ret); |
| 121 | "cmd set tx 2 failed, ret = %d\n", ret); | ||
| 122 | goto power_off; | 116 | goto power_off; |
| 123 | } | 117 | } |
| 124 | 118 | ||
| 125 | ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x51, 0xff }, 2); | 119 | ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x51, 0xff }, 2); |
| 126 | if (ret < 0) { | 120 | if (ret < 0) { |
| 127 | DRM_DEV_ERROR(ctx->panel.dev, | 121 | dev_err(ctx->panel.dev, "cmd set tx 3 failed, ret = %d\n", ret); |
| 128 | "cmd set tx 3 failed, ret = %d\n", ret); | ||
| 129 | goto power_off; | 122 | goto power_off; |
| 130 | } | 123 | } |
| 131 | 124 | ||
| 132 | ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); | 125 | ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); |
| 133 | if (ret < 0) { | 126 | if (ret < 0) { |
| 134 | DRM_DEV_ERROR(ctx->panel.dev, | 127 | dev_err(ctx->panel.dev, "exit_sleep_mode cmd failed ret = %d\n", ret); |
| 135 | "exit_sleep_mode cmd failed ret = %d\n", ret); | ||
| 136 | goto power_off; | 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 | ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); | 134 | ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); |
| 143 | if (ret < 0) { | 135 | if (ret < 0) { |
| 144 | DRM_DEV_ERROR(ctx->panel.dev, | 136 | dev_err(ctx->panel.dev, "set_display_on cmd failed ret = %d\n", ret); |
| 145 | "set_display_on cmd failed ret = %d\n", ret); | ||
| 146 | goto power_off; | 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 | mode = drm_mode_create(connector->dev); | 171 | mode = drm_mode_create(connector->dev); |
| 181 | if (!mode) { | 172 | if (!mode) { |
| 182 | DRM_DEV_ERROR(ctx->panel.dev, | 173 | dev_err(ctx->panel.dev, "failed to create a new display mode\n"); |
| 183 | "failed to create a new display mode\n"); | ||
| 184 | return 0; | 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 | ctx->reset_gpio = devm_gpiod_get(ctx->panel.dev, | 215 | ctx->reset_gpio = devm_gpiod_get(ctx->panel.dev, |
| 226 | "reset", GPIOD_OUT_LOW); | 216 | "reset", GPIOD_OUT_LOW); |
| 227 | if (IS_ERR(ctx->reset_gpio)) { | 217 | if (IS_ERR(ctx->reset_gpio)) { |
| 228 | DRM_DEV_ERROR(dev, "cannot get reset gpio %ld\n", | 218 | dev_err(dev, "cannot get reset gpio %ld\n", PTR_ERR(ctx->reset_gpio)); |
| 229 | PTR_ERR(ctx->reset_gpio)); | ||
| 230 | return PTR_ERR(ctx->reset_gpio); | 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 | MIPI_DSI_CLOCK_NON_CONTINUOUS; | 231 | MIPI_DSI_CLOCK_NON_CONTINUOUS; |
| 243 | ret = mipi_dsi_attach(dsi); | 232 | ret = mipi_dsi_attach(dsi); |
| 244 | if (ret < 0) { | 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 | goto err_dsi_attach; | 235 | goto err_dsi_attach; |
| 247 | } | 236 | } |
| 248 | 237 | ||
| 249 | ret = regulator_set_load(ctx->supplies[0].consumer, 32000); | 238 | ret = regulator_set_load(ctx->supplies[0].consumer, 32000); |
| 250 | if (ret) { | 239 | if (ret) { |
| 251 | DRM_DEV_ERROR(dev, | 240 | dev_err(dev, "regulator set load failed for vdda supply ret = %d\n", ret); |
| 252 | "regulator set load failed for vdda supply ret = %d\n", | ||
| 253 | ret); | ||
| 254 | goto err_set_load; | 241 | goto err_set_load; |
| 255 | } | 242 | } |
| 256 | 243 | ||
| 257 | ret = regulator_set_load(ctx->supplies[1].consumer, 13200); | 244 | ret = regulator_set_load(ctx->supplies[1].consumer, 13200); |
| 258 | if (ret) { | 245 | if (ret) { |
| 259 | DRM_DEV_ERROR(dev, | 246 | dev_err(dev, "regulator set load failed for vdd3p3 supply ret = %d\n", ret); |
| 260 | "regulator set load failed for vdd3p3 supply ret = %d\n", | ||
| 261 | ret); | ||
| 262 | goto err_set_load; | 247 | goto err_set_load; |
| 263 | } | 248 | } |
| 264 | 249 | ||
| @@ -12,7 +12,6 @@ · 11 unmodified lines | |||
| 12 | #include <drm/drm_mipi_dsi.h> | 12 | #include <drm/drm_mipi_dsi.h> |
| 13 | #include <drm/drm_modes.h> | 13 | #include <drm/drm_modes.h> |
| 14 | #include <drm/drm_panel.h> | 14 | #include <drm/drm_panel.h> |
| 15 | #include <drm/drm_print.h> | ||
| 16 | 15 | ||
| 17 | #include <video/display_timing.h> | 16 | #include <video/display_timing.h> |
| 18 | #include <video/mipi_display.h> | 17 | #include <video/mipi_display.h> |
| @@ -135,7 +134,7 @@ static int xpp055c272_init_sequence(struct xpp055c272 *ctx) · 116 unmodified lines | |||
| 135 | 134 | ||
| 136 | msleep(60); | 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 | return 0; | 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 | ret = mipi_dsi_dcs_set_display_off(dsi); | 150 | ret = mipi_dsi_dcs_set_display_off(dsi); |
| 152 | if (ret < 0) | 151 | if (ret < 0) |
| 153 | DRM_DEV_ERROR(ctx->dev, "failed to set display off: %d\n", | 152 | dev_err(ctx->dev, "failed to set display off: %d\n", ret); |
| 154 | ret); | ||
| 155 | 153 | ||
| 156 | mipi_dsi_dcs_enter_sleep_mode(dsi); | 154 | mipi_dsi_dcs_enter_sleep_mode(dsi); |
| 157 | if (ret < 0) { | 155 | if (ret < 0) { |
| 158 | DRM_DEV_ERROR(ctx->dev, "failed to enter sleep mode: %d\n", | 156 | dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret); |
| 159 | ret); | ||
| 160 | return ret; | 157 | return ret; |
| 161 | } | 158 | } |
| 162 | 159 | ||
| @@ -177,17 +174,15 @@ static int xpp055c272_prepare(struct drm_panel *panel) · 14 unmodified lines | |||
| 177 | if (ctx->prepared) | 174 | if (ctx->prepared) |
| 178 | return 0; | 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 | ret = regulator_enable(ctx->vci); | 178 | ret = regulator_enable(ctx->vci); |
| 182 | if (ret < 0) { | 179 | if (ret < 0) { |
| 183 | DRM_DEV_ERROR(ctx->dev, | 180 | dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret); |
| 184 | "Failed to enable vci supply: %d\n", ret); | ||
| 185 | return ret; | 181 | return ret; |
| 186 | } | 182 | } |
| 187 | ret = regulator_enable(ctx->iovcc); | 183 | ret = regulator_enable(ctx->iovcc); |
| 188 | if (ret < 0) { | 184 | if (ret < 0) { |
| 189 | DRM_DEV_ERROR(ctx->dev, | 185 | dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); |
| 190 | "Failed to enable iovcc supply: %d\n", ret); | ||
| 191 | goto disable_vci; | 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 | ret = xpp055c272_init_sequence(ctx); | 197 | ret = xpp055c272_init_sequence(ctx); |
| 203 | if (ret < 0) { | 198 | if (ret < 0) { |
| 204 | DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", | 199 | dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); |
| 205 | ret); | ||
| 206 | goto disable_iovcc; | 200 | goto disable_iovcc; |
| 207 | } | 201 | } |
| 208 | 202 | ||
| 209 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | 203 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 210 | if (ret < 0) { | 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 | goto disable_iovcc; | 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 | ret = mipi_dsi_dcs_set_display_on(dsi); | 212 | ret = mipi_dsi_dcs_set_display_on(dsi); |
| 219 | if (ret < 0) { | 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 | goto disable_iovcc; | 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 | mode = drm_mode_duplicate(connector->dev, &default_mode); | 251 | mode = drm_mode_duplicate(connector->dev, &default_mode); |
| 258 | if (!mode) { | 252 | if (!mode) { |
| 259 | DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n", | 253 | dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", |
| 260 | default_mode.hdisplay, default_mode.vdisplay, | 254 | default_mode.hdisplay, default_mode.vdisplay, |
| 261 | drm_mode_vrefresh(&default_mode)); | 255 | drm_mode_vrefresh(&default_mode)); |
| 262 | return -ENOMEM; | 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 | ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); | 285 | ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); |
| 292 | if (IS_ERR(ctx->reset_gpio)) { | 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 | return PTR_ERR(ctx->reset_gpio); | 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 | if (IS_ERR(ctx->vci)) { | 292 | if (IS_ERR(ctx->vci)) { |
| 299 | ret = PTR_ERR(ctx->vci); | 293 | ret = PTR_ERR(ctx->vci); |
| 300 | if (ret != -EPROBE_DEFER) | 294 | if (ret != -EPROBE_DEFER) |
| 301 | DRM_DEV_ERROR(dev, | 295 | dev_err(dev, "Failed to request vci regulator: %d\n", ret); |
| 302 | "Failed to request vci regulator: %d\n", | ||
| 303 | ret); | ||
| 304 | return ret; | 296 | return ret; |
| 305 | } | 297 | } |
| 306 | 298 | ||
| @@ -308,9 +300,7 @@ static int xpp055c272_probe(struct mipi_dsi_device *dsi) · 1 unmodified line | |||
| 308 | if (IS_ERR(ctx->iovcc)) { | 300 | if (IS_ERR(ctx->iovcc)) { |
| 309 | ret = PTR_ERR(ctx->iovcc); | 301 | ret = PTR_ERR(ctx->iovcc); |
| 310 | if (ret != -EPROBE_DEFER) | 302 | if (ret != -EPROBE_DEFER) |
| 311 | DRM_DEV_ERROR(dev, | 303 | dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); |
| 312 | "Failed to request iovcc regulator: %d\n", | ||
| 313 | ret); | ||
| 314 | return ret; | 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 | ret = mipi_dsi_attach(dsi); | 325 | ret = mipi_dsi_attach(dsi); |
| 336 | if (ret < 0) { | 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 | drm_panel_remove(&ctx->panel); | 328 | drm_panel_remove(&ctx->panel); |
| 339 | return ret; | 329 | return ret; |
| 340 | } | 330 | } |
| @@ -349,13 +339,11 @@ static void xpp055c272_shutdown(struct mipi_dsi_device *dsi) · 8 unmodified lines | |||
| 349 | 339 | ||
| 350 | ret = drm_panel_unprepare(&ctx->panel); | 340 | ret = drm_panel_unprepare(&ctx->panel); |
| 351 | if (ret < 0) | 341 | if (ret < 0) |
| 352 | DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", | 342 | dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); |
| 353 | ret); | ||
| 354 | 343 | ||
| 355 | ret = drm_panel_disable(&ctx->panel); | 344 | ret = drm_panel_disable(&ctx->panel); |
| 356 | if (ret < 0) | 345 | if (ret < 0) |
| 357 | DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", | 346 | dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); |
| 358 | ret); | ||
| 359 | } | 347 | } |
| 360 | 348 | ||
| 361 | static int xpp055c272_remove(struct mipi_dsi_device *dsi) | 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 | ret = mipi_dsi_detach(dsi); | 356 | ret = mipi_dsi_detach(dsi); |
| 369 | if (ret < 0) | 357 | if (ret < 0) |
| 370 | DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", | 358 | dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); |
| 371 | ret); | ||
| 372 | 359 | ||
| 373 | drm_panel_remove(&ctx->panel); | 360 | drm_panel_remove(&ctx->panel); |
| 374 | 361 | ||
| @@ -1,20 +1,29 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* Copyright 2019 Collabora ltd. */ | 2 | /* Copyright 2019 Collabora ltd. */ |
| 3 | |||
| 4 | #include <linux/clk.h> | ||
| 3 | #include <linux/devfreq.h> | 5 | #include <linux/devfreq.h> |
| 4 | #include <linux/devfreq_cooling.h> | 6 | #include <linux/devfreq_cooling.h> |
| 5 | #include <linux/platform_device.h> | 7 | #include <linux/platform_device.h> |
| 6 | #include <linux/pm_opp.h> | 8 | #include <linux/pm_opp.h> |
| 7 | #include <linux/clk.h> | ||
| 8 | #include <linux/regulator/consumer.h> | ||
| 9 | 9 | ||
| 10 | #include "panfrost_device.h" | 10 | #include "panfrost_device.h" |
| 11 | #include "panfrost_devfreq.h" | 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 | static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, | 28 | static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, |
| 20 | u32 flags) | 29 | u32 flags) |
| @@ -34,30 +43,37 @@ static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, · 13 unmodified lines | |||
| 34 | return 0; | 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; | 48 | pfdevfreq->busy_time = 0; |
| 40 | pfdev->devfreq.idle_time = 0; | 49 | pfdevfreq->idle_time = 0; |
| 41 | pfdev->devfreq.time_last_update = ktime_get(); | 50 | pfdevfreq->time_last_update = ktime_get(); |
| 42 | } | 51 | } |
| 43 | 52 | ||
| 44 | static int panfrost_devfreq_get_dev_status(struct device *dev, | 53 | static int panfrost_devfreq_get_dev_status(struct device *dev, |
| 45 | struct devfreq_dev_status *status) | 54 | struct devfreq_dev_status *status) |
| 46 | { | 55 | { |
| 47 | struct panfrost_device *pfdev = dev_get_drvdata(dev); | 56 | struct panfrost_device *pfdev = dev_get_drvdata(dev); |
| 48 | 57 | struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; | |
| 49 | panfrost_devfreq_update_utilization(pfdev); | 58 | unsigned long irqflags; |
| 50 | 59 | ||
| 51 | status->current_frequency = clk_get_rate(pfdev->clock); | 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, | 75 | dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", |
| 60 | status->total_time, | 76 | status->busy_time, status->total_time, |
| 61 | status->busy_time / (status->total_time / 100), | 77 | status->busy_time / (status->total_time / 100), |
| 62 | status->current_frequency / 1000 / 1000); | 78 | status->current_frequency / 1000 / 1000); |
| 63 | 79 | ||
| @@ -77,21 +93,43 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) · 13 unmodified lines | |||
| 77 | unsigned long cur_freq; | 93 | unsigned long cur_freq; |
| 78 | struct device *dev = &pfdev->pdev->dev; | 94 | struct device *dev = &pfdev->pdev->dev; |
| 79 | struct devfreq *devfreq; | 95 | struct devfreq *devfreq; |
| 96 | struct opp_table *opp_table; | ||
| 80 | struct thermal_cooling_device *cooling; | 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 | ret = dev_pm_opp_of_add_table(dev); | 113 | ret = dev_pm_opp_of_add_table(dev); |
| 83 | if (ret == -ENODEV) /* Optional, continue without devfreq */ | 114 | if (ret) { |
| 84 | return 0; | 115 | /* Optional, continue without devfreq */ |
| 85 | else if (ret) | 116 | if (ret == -ENODEV) |
| 86 | return ret; | 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 | cur_freq = clk_get_rate(pfdev->clock); | 126 | cur_freq = clk_get_rate(pfdev->clock); |
| 91 | 127 | ||
| 92 | opp = devfreq_recommended_opp(dev, &cur_freq, 0); | 128 | opp = devfreq_recommended_opp(dev, &cur_freq, 0); |
| 93 | if (IS_ERR(opp)) | 129 | if (IS_ERR(opp)) { |
| 94 | return PTR_ERR(opp); | 130 | ret = PTR_ERR(opp); |
| 131 | goto err_fini; | ||
| 132 | } | ||
| 95 | 133 | ||
| 96 | panfrost_devfreq_profile.initial_freq = cur_freq; | 134 | panfrost_devfreq_profile.initial_freq = cur_freq; |
| 97 | dev_pm_opp_put(opp); | 135 | dev_pm_opp_put(opp); |
| @@ -100,75 +138,94 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) · 2 unmodified lines | |||
| 100 | DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL); | 138 | DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL); |
| 101 | if (IS_ERR(devfreq)) { | 139 | if (IS_ERR(devfreq)) { |
| 102 | DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n"); | 140 | DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n"); |
| 103 | dev_pm_opp_of_remove_table(dev); | 141 | ret = PTR_ERR(devfreq); |
| 104 | return PTR_ERR(devfreq); | 142 | goto err_fini; |
| 105 | } | 143 | } |
| 106 | pfdev->devfreq.devfreq = devfreq; | 144 | pfdevfreq->devfreq = devfreq; |
| 107 | 145 | ||
| 108 | cooling = of_devfreq_cooling_register(dev->of_node, devfreq); | 146 | cooling = of_devfreq_cooling_register(dev->of_node, devfreq); |
| 109 | if (IS_ERR(cooling)) | 147 | if (IS_ERR(cooling)) |
| 110 | DRM_DEV_INFO(dev, "Failed to register cooling device\n"); | 148 | DRM_DEV_INFO(dev, "Failed to register cooling device\n"); |
| 111 | else | 149 | else |
| 112 | pfdev->devfreq.cooling = cooling; | 150 | pfdevfreq->cooling = cooling; |
| 113 | 151 | ||
| 114 | return 0; | 152 | return 0; |
| 153 | |||
| 154 | err_fini: | ||
| 155 | panfrost_devfreq_fini(pfdev); | ||
| 156 | return ret; | ||
| 115 | } | 157 | } |
| 116 | 158 | ||
| 117 | void panfrost_devfreq_fini(struct panfrost_device *pfdev) | 159 | void panfrost_devfreq_fini(struct panfrost_device *pfdev) |
| 118 | { | 160 | { |
| 119 | if (pfdev->devfreq.cooling) | 161 | struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; |
| 120 | devfreq_cooling_unregister(pfdev->devfreq.cooling); | 162 | |
| 121 | dev_pm_opp_of_remove_table(&pfdev->pdev->dev); | 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 | void panfrost_devfreq_resume(struct panfrost_device *pfdev) | 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 | return; | 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 | void panfrost_devfreq_suspend(struct panfrost_device *pfdev) | 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 | return; | 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; | 203 | unsigned long irqflags; |
| 145 | ktime_t last; | ||
| 146 | 204 | ||
| 147 | if (!pfdev->devfreq.devfreq) | 205 | if (!pfdevfreq->devfreq) |
| 148 | return; | 206 | return; |
| 149 | 207 | ||
| 150 | now = ktime_get(); | 208 | spin_lock_irqsave(&pfdevfreq->lock, irqflags); |
| 151 | last = pfdev->devfreq.time_last_update; | ||
| 152 | 209 | ||
| 153 | if (atomic_read(&pfdev->devfreq.busy_count) > 0) | 210 | panfrost_devfreq_update_utilization(pfdevfreq); |
| 154 | pfdev->devfreq.busy_time += ktime_sub(now, last); | ||
| 155 | else | ||
| 156 | pfdev->devfreq.idle_time += ktime_sub(now, last); | ||
| 157 | 211 | ||
| 158 | pfdev->devfreq.time_last_update = now; | 212 | pfdevfreq->busy_count++; |
| 159 | } | ||
| 160 | 213 | ||
| 161 | void panfrost_devfreq_record_busy(struct panfrost_device *pfdev) | 214 | spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); |
| 162 | { | ||
| 163 | panfrost_devfreq_update_utilization(pfdev); | ||
| 164 | atomic_inc(&pfdev->devfreq.busy_count); | ||
| 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); | 230 | spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); |
| 172 | count = atomic_dec_if_positive(&pfdev->devfreq.busy_count); | ||
| 173 | WARN_ON(count < 0); | ||
| 174 | } | 231 | } |
| @@ -4,13 +4,39 @@ · 3 unmodified lines | |||
| 4 | #ifndef __PANFROST_DEVFREQ_H__ | 4 | #ifndef __PANFROST_DEVFREQ_H__ |
| 5 | #define __PANFROST_DEVFREQ_H__ | 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 | int panfrost_devfreq_init(struct panfrost_device *pfdev); | 33 | int panfrost_devfreq_init(struct panfrost_device *pfdev); |
| 8 | void panfrost_devfreq_fini(struct panfrost_device *pfdev); | 34 | void panfrost_devfreq_fini(struct panfrost_device *pfdev); |
| 9 | 35 | ||
| 10 | void panfrost_devfreq_resume(struct panfrost_device *pfdev); | 36 | void panfrost_devfreq_resume(struct panfrost_device *pfdev); |
| 11 | void panfrost_devfreq_suspend(struct panfrost_device *pfdev); | 37 | void panfrost_devfreq_suspend(struct panfrost_device *pfdev); |
| 12 | 38 | ||
| 13 | void panfrost_devfreq_record_busy(struct panfrost_device *pfdev); | 39 | void panfrost_devfreq_record_busy(struct panfrost_devfreq *devfreq); |
| 14 | void panfrost_devfreq_record_idle(struct panfrost_device *pfdev); | 40 | void panfrost_devfreq_record_idle(struct panfrost_devfreq *devfreq); |
| 15 | 41 | ||
| 16 | #endif /* __PANFROST_DEVFREQ_H__ */ | 42 | #endif /* __PANFROST_DEVFREQ_H__ */ |
| @@ -90,9 +90,11 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev) · 89 unmodified lines | |||
| 90 | { | 90 | { |
| 91 | int ret, i; | 91 | int ret, i; |
| 92 | 92 | ||
| 93 | if (WARN(pfdev->comp->num_supplies > ARRAY_SIZE(pfdev->regulators), | 93 | pfdev->regulators = devm_kcalloc(pfdev->dev, pfdev->comp->num_supplies, |
| 94 | "Too many supplies in compatible structure.\n")) | 94 | sizeof(*pfdev->regulators), |
| 95 | return -EINVAL; | 95 | GFP_KERNEL); |
| 96 | if (!pfdev->regulators) | ||
| 97 | return -ENOMEM; | ||
| 96 | 98 | ||
| 97 | for (i = 0; i < pfdev->comp->num_supplies; i++) | 99 | for (i = 0; i < pfdev->comp->num_supplies; i++) |
| 98 | pfdev->regulators[i].supply = pfdev->comp->supply_names[i]; | 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 | static void panfrost_regulator_fini(struct panfrost_device *pfdev) | 122 | static void panfrost_regulator_fini(struct panfrost_device *pfdev) |
| 121 | { | 123 | { |
| 122 | regulator_bulk_disable(pfdev->comp->num_supplies, | 124 | if (!pfdev->regulators) |
| 123 | pfdev->regulators); | 125 | return; |
| 126 | |||
| 127 | regulator_bulk_disable(pfdev->comp->num_supplies, pfdev->regulators); | ||
| 124 | } | 128 | } |
| 125 | 129 | ||
| 126 | static void panfrost_pm_domain_fini(struct panfrost_device *pfdev) | 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 | return err; | 218 | return err; |
| 215 | } | 219 | } |
| 216 | 220 | ||
| 217 | err = panfrost_regulator_init(pfdev); | 221 | err = panfrost_devfreq_init(pfdev); |
| 218 | if (err) | 222 | if (err) { |
| 219 | goto err_out0; | 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 | err = panfrost_reset_init(pfdev); | 235 | err = panfrost_reset_init(pfdev); |
| 222 | if (err) { | 236 | if (err) { |
| 223 | dev_err(pfdev->dev, "reset init failed %d\n", err); | 237 | dev_err(pfdev->dev, "reset init failed %d\n", err); |
| 224 | goto err_out1; | 238 | goto out_regulator; |
| 225 | } | 239 | } |
| 226 | 240 | ||
| 227 | err = panfrost_pm_domain_init(pfdev); | 241 | err = panfrost_pm_domain_init(pfdev); |
| 228 | if (err) | 242 | if (err) |
| 229 | goto err_out2; | 243 | goto out_reset; |
| 230 | 244 | ||
| 231 | res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0); | 245 | res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0); |
| 232 | pfdev->iomem = devm_ioremap_resource(pfdev->dev, res); | 246 | pfdev->iomem = devm_ioremap_resource(pfdev->dev, res); |
| 233 | if (IS_ERR(pfdev->iomem)) { | 247 | if (IS_ERR(pfdev->iomem)) { |
| 234 | dev_err(pfdev->dev, "failed to ioremap iomem\n"); | 248 | dev_err(pfdev->dev, "failed to ioremap iomem\n"); |
| 235 | err = PTR_ERR(pfdev->iomem); | 249 | err = PTR_ERR(pfdev->iomem); |
| 236 | goto err_out3; | 250 | goto out_pm_domain; |
| 237 | } | 251 | } |
| 238 | 252 | ||
| 239 | err = panfrost_gpu_init(pfdev); | 253 | err = panfrost_gpu_init(pfdev); |
| 240 | if (err) | 254 | if (err) |
| 241 | goto err_out3; | 255 | goto out_pm_domain; |
| 242 | 256 | ||
| 243 | err = panfrost_mmu_init(pfdev); | 257 | err = panfrost_mmu_init(pfdev); |
| 244 | if (err) | 258 | if (err) |
| 245 | goto err_out4; | 259 | goto out_gpu; |
| 246 | 260 | ||
| 247 | err = panfrost_job_init(pfdev); | 261 | err = panfrost_job_init(pfdev); |
| 248 | if (err) | 262 | if (err) |
| 249 | goto err_out5; | 263 | goto out_mmu; |
| 250 | 264 | ||
| 251 | err = panfrost_perfcnt_init(pfdev); | 265 | err = panfrost_perfcnt_init(pfdev); |
| 252 | if (err) | 266 | if (err) |
| 253 | goto err_out6; | 267 | goto out_job; |
| 254 | 268 | ||
| 255 | return 0; | 269 | return 0; |
| 256 | err_out6: | 270 | out_job: |
| 257 | panfrost_job_fini(pfdev); | 271 | panfrost_job_fini(pfdev); |
| 258 | err_out5: | 272 | out_mmu: |
| 259 | panfrost_mmu_fini(pfdev); | 273 | panfrost_mmu_fini(pfdev); |
| 260 | err_out4: | 274 | out_gpu: |
| 261 | panfrost_gpu_fini(pfdev); | 275 | panfrost_gpu_fini(pfdev); |
| 262 | err_out3: | 276 | out_pm_domain: |
| 263 | panfrost_pm_domain_fini(pfdev); | 277 | panfrost_pm_domain_fini(pfdev); |
| 264 | err_out2: | 278 | out_reset: |
| 265 | panfrost_reset_fini(pfdev); | 279 | panfrost_reset_fini(pfdev); |
| 266 | err_out1: | 280 | out_regulator: |
| 267 | panfrost_regulator_fini(pfdev); | 281 | panfrost_regulator_fini(pfdev); |
| 268 | err_out0: | 282 | out_devfreq: |
| 283 | panfrost_devfreq_fini(pfdev); | ||
| 284 | out_clk: | ||
| 269 | panfrost_clk_fini(pfdev); | 285 | panfrost_clk_fini(pfdev); |
| 270 | return err; | 286 | return err; |
| 271 | } | 287 | } |
| @@ -278,6 +294,7 @@ void panfrost_device_fini(struct panfrost_device *pfdev) · 6 unmodified lines | |||
| 278 | panfrost_gpu_fini(pfdev); | 294 | panfrost_gpu_fini(pfdev); |
| 279 | panfrost_pm_domain_fini(pfdev); | 295 | panfrost_pm_domain_fini(pfdev); |
| 280 | panfrost_reset_fini(pfdev); | 296 | panfrost_reset_fini(pfdev); |
| 297 | panfrost_devfreq_fini(pfdev); | ||
| 281 | panfrost_regulator_fini(pfdev); | 298 | panfrost_regulator_fini(pfdev); |
| 282 | panfrost_clk_fini(pfdev); | 299 | panfrost_clk_fini(pfdev); |
| 283 | } | 300 | } |
| @@ -13,6 +13,8 @@ · 12 unmodified lines | |||
| 13 | #include <drm/drm_mm.h> | 13 | #include <drm/drm_mm.h> |
| 14 | #include <drm/gpu_scheduler.h> | 14 | #include <drm/gpu_scheduler.h> |
| 15 | 15 | ||
| 16 | #include "panfrost_devfreq.h" | ||
| 17 | |||
| 16 | struct panfrost_device; | 18 | struct panfrost_device; |
| 17 | struct panfrost_mmu; | 19 | struct panfrost_mmu; |
| 18 | struct panfrost_job_slot; | 20 | struct panfrost_job_slot; |
| @@ -20,7 +22,6 @@ struct panfrost_job; · 1 unmodified line | |||
| 20 | struct panfrost_perfcnt; | 22 | struct panfrost_perfcnt; |
| 21 | 23 | ||
| 22 | #define NUM_JOB_SLOTS 3 | 24 | #define NUM_JOB_SLOTS 3 |
| 23 | #define MAX_REGULATORS 2 | ||
| 24 | #define MAX_PM_DOMAINS 3 | 25 | #define MAX_PM_DOMAINS 3 |
| 25 | 26 | ||
| 26 | struct panfrost_features { | 27 | struct panfrost_features { |
| @@ -79,7 +80,7 @@ struct panfrost_device { · 52 unmodified lines | |||
| 79 | void __iomem *iomem; | 80 | void __iomem *iomem; |
| 80 | struct clk *clock; | 81 | struct clk *clock; |
| 81 | struct clk *bus_clock; | 82 | struct clk *bus_clock; |
| 82 | struct regulator_bulk_data regulators[MAX_REGULATORS]; | 83 | struct regulator_bulk_data *regulators; |
| 83 | struct reset_control *rstc; | 84 | struct reset_control *rstc; |
| 84 | /* pm_domains for devices with more than one. */ | 85 | /* pm_domains for devices with more than one. */ |
| 85 | struct device *pm_domain_devs[MAX_PM_DOMAINS]; | 86 | struct device *pm_domain_devs[MAX_PM_DOMAINS]; |
| @@ -107,14 +108,7 @@ struct panfrost_device { · 21 unmodified lines | |||
| 107 | struct list_head shrinker_list; | 108 | struct list_head shrinker_list; |
| 108 | struct shrinker shrinker; | 109 | struct shrinker shrinker; |
| 109 | 110 | ||
| 110 | struct { | 111 | struct panfrost_devfreq pfdevfreq; |
| 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; | ||
| 118 | }; | 112 | }; |
| 119 | 113 | ||
| 120 | struct panfrost_mmu { | 114 | struct panfrost_mmu { |
| @@ -14,7 +14,6 @@ · 13 unmodified lines | |||
| 14 | #include <drm/drm_utils.h> | 14 | #include <drm/drm_utils.h> |
| 15 | 15 | ||
| 16 | #include "panfrost_device.h" | 16 | #include "panfrost_device.h" |
| 17 | #include "panfrost_devfreq.h" | ||
| 18 | #include "panfrost_gem.h" | 17 | #include "panfrost_gem.h" |
| 19 | #include "panfrost_mmu.h" | 18 | #include "panfrost_mmu.h" |
| 20 | #include "panfrost_job.h" | 19 | #include "panfrost_job.h" |
| @@ -606,13 +605,6 @@ static int panfrost_probe(struct platform_device *pdev) · 585 unmodified lines | |||
| 606 | goto err_out0; | 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 | pm_runtime_set_active(pfdev->dev); | 608 | pm_runtime_set_active(pfdev->dev); |
| 617 | pm_runtime_mark_last_busy(pfdev->dev); | 609 | pm_runtime_mark_last_busy(pfdev->dev); |
| 618 | pm_runtime_enable(pfdev->dev); | 610 | pm_runtime_enable(pfdev->dev); |
| @@ -625,16 +617,14 @@ static int panfrost_probe(struct platform_device *pdev) · 6 unmodified lines | |||
| 625 | */ | 617 | */ |
| 626 | err = drm_dev_register(ddev, 0); | 618 | err = drm_dev_register(ddev, 0); |
| 627 | if (err < 0) | 619 | if (err < 0) |
| 628 | goto err_out2; | 620 | goto err_out1; |
| 629 | 621 | ||
| 630 | panfrost_gem_shrinker_init(ddev); | 622 | panfrost_gem_shrinker_init(ddev); |
| 631 | 623 | ||
| 632 | return 0; | 624 | return 0; |
| 633 | 625 | ||
| 634 | err_out2: | ||
| 635 | pm_runtime_disable(pfdev->dev); | ||
| 636 | panfrost_devfreq_fini(pfdev); | ||
| 637 | err_out1: | 626 | err_out1: |
| 627 | pm_runtime_disable(pfdev->dev); | ||
| 638 | panfrost_device_fini(pfdev); | 628 | panfrost_device_fini(pfdev); |
| 639 | err_out0: | 629 | err_out0: |
| 640 | drm_dev_put(ddev); | 630 | drm_dev_put(ddev); |
| @@ -650,7 +640,6 @@ static int panfrost_remove(struct platform_device *pdev) · 9 unmodified lines | |||
| 650 | panfrost_gem_shrinker_cleanup(ddev); | 640 | panfrost_gem_shrinker_cleanup(ddev); |
| 651 | 641 | ||
| 652 | pm_runtime_get_sync(pfdev->dev); | 642 | pm_runtime_get_sync(pfdev->dev); |
| 653 | panfrost_devfreq_fini(pfdev); | ||
| 654 | panfrost_device_fini(pfdev); | 643 | panfrost_device_fini(pfdev); |
| 655 | pm_runtime_put_sync_suspend(pfdev->dev); | 644 | pm_runtime_put_sync_suspend(pfdev->dev); |
| 656 | pm_runtime_disable(pfdev->dev); | 645 | pm_runtime_disable(pfdev->dev); |
| @@ -677,6 +666,7 @@ static const struct of_device_id dt_match[] = { · 20 unmodified lines | |||
| 677 | { .compatible = "arm,mali-t830", .data = &default_data, }, | 666 | { .compatible = "arm,mali-t830", .data = &default_data, }, |
| 678 | { .compatible = "arm,mali-t860", .data = &default_data, }, | 667 | { .compatible = "arm,mali-t860", .data = &default_data, }, |
| 679 | { .compatible = "arm,mali-t880", .data = &default_data, }, | 668 | { .compatible = "arm,mali-t880", .data = &default_data, }, |
| 669 | { .compatible = "arm,mali-bifrost", .data = &default_data, }, | ||
| 680 | {} | 670 | {} |
| 681 | }; | 671 | }; |
| 682 | MODULE_DEVICE_TABLE(of, dt_match); | 672 | MODULE_DEVICE_TABLE(of, dt_match); |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include <linux/io.h> | 10 | #include <linux/io.h> |
| 11 | #include <linux/iopoll.h> | 11 | #include <linux/iopoll.h> |
| 12 | #include <linux/platform_device.h> | 12 | #include <linux/platform_device.h> |
| 13 | #include <linux/pm_runtime.h> | ||
| 13 | 14 | ||
| 14 | #include "panfrost_device.h" | 15 | #include "panfrost_device.h" |
| 15 | #include "panfrost_features.h" | 16 | #include "panfrost_features.h" |
| @@ -368,7 +369,16 @@ void panfrost_gpu_fini(struct panfrost_device *pfdev) · 352 unmodified lines | |||
| 368 | 369 | ||
| 369 | u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev) | 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 | u32 flush_id; |
| 372 | return gpu_read(pfdev, GPU_LATEST_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 | return 0; | 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 | u64 jc_head = job->jc; | 145 | u64 jc_head = job->jc; |
| 146 | int ret; | 146 | int ret; |
| 147 | 147 | ||
| 148 | panfrost_devfreq_record_busy(pfdev); | 148 | panfrost_devfreq_record_busy(&pfdev->pfdevfreq); |
| 149 | 149 | ||
| 150 | ret = pm_runtime_get_sync(pfdev->dev); | 150 | ret = pm_runtime_get_sync(pfdev->dev); |
| 151 | if (ret < 0) | 151 | if (ret < 0) |
| @@ -410,7 +410,7 @@ static void panfrost_job_timedout(struct drm_sched_job *sched_job) · 258 unmodified lines | |||
| 410 | for (i = 0; i < NUM_JOB_SLOTS; i++) { | 410 | for (i = 0; i < NUM_JOB_SLOTS; i++) { |
| 411 | if (pfdev->jobs[i]) { | 411 | if (pfdev->jobs[i]) { |
| 412 | pm_runtime_put_noidle(pfdev->dev); | 412 | pm_runtime_put_noidle(pfdev->dev); |
| 413 | panfrost_devfreq_record_idle(pfdev); | 413 | panfrost_devfreq_record_idle(&pfdev->pfdevfreq); |
| 414 | pfdev->jobs[i] = NULL; | 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 | pfdev->jobs[j] = NULL; | 478 | pfdev->jobs[j] = NULL; |
| 479 | 479 | ||
| 480 | panfrost_mmu_as_put(pfdev, &job->file_priv->mmu); | 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 | dma_fence_signal_locked(job->done_fence); | 483 | dma_fence_signal_locked(job->done_fence); |
| 484 | pm_runtime_put_autosuspend(pfdev->dev); | 484 | pm_runtime_put_autosuspend(pfdev->dev); |
| @@ -581,10 +581,6 @@ int panfrost_job_is_idle(struct panfrost_device *pfdev) · 96 unmodified lines | |||
| 581 | struct panfrost_job_slot *js = pfdev->js; | 581 | struct panfrost_job_slot *js = pfdev->js; |
| 582 | int i; | 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 | for (i = 0; i < NUM_JOB_SLOTS; i++) { | 584 | for (i = 0; i < NUM_JOB_SLOTS; i++) { |
| 589 | /* If there are any jobs in the HW queue, we're not idle */ | 585 | /* If there are any jobs in the HW queue, we're not idle */ |
| 590 | if (atomic_read(&js->queue[i].sched.hw_rq_count)) | 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 | ret = pm_runtime_get_sync(pfdev->dev); | 84 | ret = pm_runtime_get_sync(pfdev->dev); |
| 85 | if (ret < 0) | 85 | if (ret < 0) |
| 86 | return ret; | 86 | goto err_put_pm; |
| 87 | 87 | ||
| 88 | bo = drm_gem_shmem_create(pfdev->ddev, perfcnt->bosize); | 88 | bo = drm_gem_shmem_create(pfdev->ddev, perfcnt->bosize); |
| 89 | if (IS_ERR(bo)) | 89 | if (IS_ERR(bo)) { |
| 90 | return PTR_ERR(bo); | 90 | ret = PTR_ERR(bo); |
| 91 | goto err_put_pm; | ||
| 92 | } | ||
| 91 | 93 | ||
| 92 | /* Map the perfcnt buf in the address space attached to file_priv. */ | 94 | /* Map the perfcnt buf in the address space attached to file_priv. */ |
| 93 | ret = panfrost_gem_open(&bo->base, file_priv); | 95 | ret = panfrost_gem_open(&bo->base, file_priv); |
| @@ -168,6 +170,8 @@ err_close_bo: · 74 unmodified lines | |||
| 168 | panfrost_gem_close(&bo->base, file_priv); | 170 | panfrost_gem_close(&bo->base, file_priv); |
| 169 | err_put_bo: | 171 | err_put_bo: |
| 170 | drm_gem_object_put(&bo->base); | 172 | drm_gem_object_put(&bo->base); |
| 173 | err_put_pm: | ||
| 174 | pm_runtime_put(pfdev->dev); | ||
| 171 | return ret; | 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 | 15 | * The PL110/PL111 is a simple LCD controller that can support TFT |
| 16 | * displays. This driver exposes a standard KMS interface for them. | 16 | * and STN displays. This driver exposes a standard KMS interface |
| 17 | * | 17 | * for them. |
| 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). | ||
| 25 | * | 18 | * |
| 26 | * The driver currently doesn't expose the cursor. The DRM API for | 19 | * The driver currently doesn't expose the cursor. The DRM API for |
| 27 | * cursors requires support for 64x64 ARGB8888 cursor images, while | 20 | * cursors requires support for 64x64 ARGB8888 cursor images, while |
| @@ -29,16 +22,13 @@ · 1 unmodified line | |||
| 29 | * cursors. While one could imagine trying to hack something together | 22 | * cursors. While one could imagine trying to hack something together |
| 30 | * to look at the ARGB8888 and program reasonable in monochrome, we | 23 | * to look at the ARGB8888 and program reasonable in monochrome, we |
| 31 | * just don't expose the cursor at all instead, and leave cursor | 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 | * TODO: | 27 | * TODO: |
| 35 | * | 28 | * |
| 36 | * - Fix race between setting plane base address and getting IRQ for | 29 | * - Fix race between setting plane base address and getting IRQ for |
| 37 | * vsync firing the pageflip completion. | 30 | * vsync firing the pageflip completion. |
| 38 | * | 31 | * |
| 39 | * - Use the "max-memory-bandwidth" DT property to filter the | ||
| 40 | * supported formats. | ||
| 41 | * | ||
| 42 | * - Read back hardware state at boot to skip reprogramming the | 32 | * - Read back hardware state at boot to skip reprogramming the |
| 43 | * hardware when doing a no-op modeset. | 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 | int ret; | 589 | int ret; |
| 590 | 590 | ||
| 591 | ret = qxl_bo_reserve(surf, false); | 591 | ret = qxl_bo_reserve(surf); |
| 592 | if (ret) | 592 | if (ret) |
| 593 | return ret; | 593 | return ret; |
| 594 | 594 | ||
| @@ -162,7 +162,8 @@ static void qxl_update_offset_props(struct qxl_device *qdev) · 161 unmodified lines | |||
| 162 | void qxl_display_read_client_monitors_config(struct qxl_device *qdev) | 162 | void qxl_display_read_client_monitors_config(struct qxl_device *qdev) |
| 163 | { | 163 | { |
| 164 | struct drm_device *dev = &qdev->ddev; | 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 | for (retries = 0; retries < 10; retries++) { | 168 | for (retries = 0; retries < 10; retries++) { |
| 168 | status = qxl_display_copy_rom_client_monitors_config(qdev); | 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 | return; | 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 | qxl_update_offset_props(qdev); | 188 | qxl_update_offset_props(qdev); |
| 188 | drm_modeset_unlock_all(dev); | 189 | DRM_MODESET_LOCK_ALL_END(ctx, ret); |
| 189 | if (!drm_helper_hpd_irq_event(dev)) { | 190 | if (!drm_helper_hpd_irq_event(dev)) { |
| 190 | /* notify that the monitor configuration changed, to | 191 | /* notify that the monitor configuration changed, to |
| 191 | adjust at the arbitrary resolution */ | 192 | adjust at the arbitrary resolution */ |
| @@ -403,18 +404,17 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, · 211 unmodified lines | |||
| 403 | struct qxl_device *qdev = to_qxl(fb->dev); | 404 | struct qxl_device *qdev = to_qxl(fb->dev); |
| 404 | struct drm_clip_rect norect; | 405 | struct drm_clip_rect norect; |
| 405 | struct qxl_bo *qobj; | 406 | struct qxl_bo *qobj; |
| 407 | struct drm_modeset_acquire_ctx ctx; | ||
| 406 | bool is_primary; | 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 | qobj = gem_to_qxl_bo(fb->obj[0]); | 413 | qobj = gem_to_qxl_bo(fb->obj[0]); |
| 412 | /* if we aren't primary surface ignore this */ | 414 | /* if we aren't primary surface ignore this */ |
| 413 | is_primary = qobj->shadow ? qobj->shadow->is_primary : qobj->is_primary; | 415 | is_primary = qobj->shadow ? qobj->shadow->is_primary : qobj->is_primary; |
| 414 | if (!is_primary) { | 416 | if (!is_primary) |
| 415 | drm_modeset_unlock_all(fb->dev); | 417 | goto out_lock_end; |
| 416 | return 0; | ||
| 417 | } | ||
| 418 | 418 | ||
| 419 | if (!num_clips) { | 419 | if (!num_clips) { |
| 420 | num_clips = 1; | 420 | num_clips = 1; |
| @@ -430,7 +430,8 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, · 9 unmodified lines | |||
| 430 | qxl_draw_dirty_fb(qdev, fb, qobj, flags, color, | 430 | qxl_draw_dirty_fb(qdev, fb, qobj, flags, color, |
| 431 | clips, num_clips, inc, 0); | 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 | return 0; | 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 | if (ret) | 96 | if (ret) |
| 97 | goto disable_pci; | 97 | goto disable_pci; |
| 98 | 98 | ||
| 99 | if (is_vga(pdev)) { | 99 | if (is_vga(pdev) && pdev->revision < 5) { |
| 100 | ret = vga_get_interruptible(pdev, VGA_RSRC_LEGACY_IO); | 100 | ret = vga_get_interruptible(pdev, VGA_RSRC_LEGACY_IO); |
| 101 | if (ret) { | 101 | if (ret) { |
| 102 | DRM_ERROR("can't get legacy vga ioports\n"); | 102 | DRM_ERROR("can't get legacy vga ioports\n"); |
| @@ -127,7 +127,7 @@ modeset_cleanup: · 24 unmodified lines | |||
| 127 | unload: | 127 | unload: |
| 128 | qxl_device_fini(qdev); | 128 | qxl_device_fini(qdev); |
| 129 | put_vga: | 129 | put_vga: |
| 130 | if (is_vga(pdev)) | 130 | if (is_vga(pdev) && pdev->revision < 5) |
| 131 | vga_put(pdev, VGA_RSRC_LEGACY_IO); | 131 | vga_put(pdev, VGA_RSRC_LEGACY_IO); |
| 132 | disable_pci: | 132 | disable_pci: |
| 133 | pci_disable_device(pdev); | 133 | pci_disable_device(pdev); |
| @@ -155,7 +155,7 @@ qxl_pci_remove(struct pci_dev *pdev) · 21 unmodified lines | |||
| 155 | 155 | ||
| 156 | drm_dev_unregister(dev); | 156 | drm_dev_unregister(dev); |
| 157 | drm_atomic_helper_shutdown(dev); | 157 | drm_atomic_helper_shutdown(dev); |
| 158 | if (is_vga(pdev)) | 158 | if (is_vga(pdev) && pdev->revision < 5) |
| 159 | vga_put(pdev, VGA_RSRC_LEGACY_IO); | 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 | int qxl_ttm_init(struct qxl_device *qdev); | 350 | int qxl_ttm_init(struct qxl_device *qdev); |
| 351 | void qxl_ttm_fini(struct qxl_device *qdev); | 351 | void qxl_ttm_fini(struct qxl_device *qdev); |
| 352 | int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev, | 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 | /* qxl image */ | 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 | qobj = gem_to_qxl_bo(gobj); | 323 | qobj = gem_to_qxl_bo(gobj); |
| 324 | 324 | ||
| 325 | ret = qxl_bo_reserve(qobj, false); | 325 | ret = qxl_bo_reserve(qobj); |
| 326 | if (ret) | 326 | if (ret) |
| 327 | goto out; | 327 | goto out; |
| 328 | 328 | ||
| @@ -284,7 +284,7 @@ int qxl_bo_pin(struct qxl_bo *bo) · 283 unmodified lines | |||
| 284 | { | 284 | { |
| 285 | int r; | 285 | int r; |
| 286 | 286 | ||
| 287 | r = qxl_bo_reserve(bo, false); | 287 | r = qxl_bo_reserve(bo); |
| 288 | if (r) | 288 | if (r) |
| 289 | return r; | 289 | return r; |
| 290 | 290 | ||
| @@ -302,7 +302,7 @@ int qxl_bo_unpin(struct qxl_bo *bo) · 11 unmodified lines | |||
| 302 | { | 302 | { |
| 303 | int r; | 303 | int r; |
| 304 | 304 | ||
| 305 | r = qxl_bo_reserve(bo, false); | 305 | r = qxl_bo_reserve(bo); |
| 306 | if (r) | 306 | if (r) |
| 307 | return r; | 307 | return r; |
| 308 | 308 | ||
| @@ -27,11 +27,11 @@ · 26 unmodified lines | |||
| 27 | 27 | ||
| 28 | #include "qxl_drv.h" | 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 | int r; | 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 | if (unlikely(r != 0)) { | 35 | if (unlikely(r != 0)) { |
| 36 | if (r != -ERESTARTSYS) { | 36 | if (r != -ERESTARTSYS) { |
| 37 | struct drm_device *ddev = bo->tbo.base.dev; | 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 | return qdev; | 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 | static void qxl_evict_flags(struct ttm_buffer_object *bo, | 51 | static void qxl_evict_flags(struct ttm_buffer_object *bo, |
| 77 | struct ttm_placement *placement) | 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 | int qxl_ttm_io_mem_reserve(struct ttm_bo_device *bdev, | 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 | struct qxl_device *qdev = qxl_get_qdev(bdev); | 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 | switch (mem->mem_type) { | 78 | switch (mem->mem_type) { |
| 110 | case TTM_PL_SYSTEM: | 79 | case TTM_PL_SYSTEM: |
| 111 | /* system memory */ | 80 | /* system memory */ |
| @@ -136,7 +105,7 @@ struct qxl_ttm_tt { · 24 unmodified lines | |||
| 136 | }; | 105 | }; |
| 137 | 106 | ||
| 138 | static int qxl_ttm_backend_bind(struct ttm_tt *ttm, | 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 | struct qxl_ttm_tt *gtt = (void *)ttm; | 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 | static void qxl_move_null(struct ttm_buffer_object *bo, | 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 | BUG_ON(old_mem->mm_node != NULL); | 164 | BUG_ON(old_mem->mm_node != NULL); |
| 196 | *old_mem = *new_mem; | 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 | static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict, | 169 | static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict, |
| 201 | struct ttm_operation_ctx *ctx, | 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 | int ret; | 174 | int ret; |
| 206 | 175 | ||
| 207 | ret = ttm_bo_wait(bo, ctx->interruptible, ctx->no_wait_gpu); | 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 | static void qxl_bo_move_notify(struct ttm_buffer_object *bo, | 187 | static void qxl_bo_move_notify(struct ttm_buffer_object *bo, |
| 219 | bool evict, | 188 | bool evict, |
| 220 | struct ttm_mem_reg *new_mem) | 189 | struct ttm_resource *new_mem) |
| 221 | { | 190 | { |
| 222 | struct qxl_bo *qbo; | 191 | struct qxl_bo *qbo; |
| 223 | struct qxl_device *qdev; | 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 | static struct ttm_bo_driver qxl_bo_driver = { | 203 | static struct ttm_bo_driver qxl_bo_driver = { |
| 235 | .ttm_tt_create = &qxl_ttm_tt_create, | 204 | .ttm_tt_create = &qxl_ttm_tt_create, |
| 236 | .init_mem_type = &qxl_init_mem_type, | ||
| 237 | .eviction_valuable = ttm_bo_eviction_valuable, | 205 | .eviction_valuable = ttm_bo_eviction_valuable, |
| 238 | .evict_flags = &qxl_evict_flags, | 206 | .evict_flags = &qxl_evict_flags, |
| 239 | .move = &qxl_bo_move, | 207 | .move = &qxl_bo_move, |
| @@ -241,6 +209,14 @@ static struct ttm_bo_driver qxl_bo_driver = { · 1 unmodified line | |||
| 241 | .move_notify = &qxl_bo_move_notify, | 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 | int qxl_ttm_init(struct qxl_device *qdev) | 220 | int qxl_ttm_init(struct qxl_device *qdev) |
| 245 | { | 221 | { |
| 246 | int r; | 222 | int r; |
| @@ -258,14 +234,13 @@ int qxl_ttm_init(struct qxl_device *qdev) · 11 unmodified lines | |||
| 258 | } | 234 | } |
| 259 | /* NOTE: this includes the framebuffer (aka surface 0) */ | 235 | /* NOTE: this includes the framebuffer (aka surface 0) */ |
| 260 | num_io_pages = qdev->rom->ram_header_offset / PAGE_SIZE; | 236 | num_io_pages = qdev->rom->ram_header_offset / PAGE_SIZE; |
| 261 | r = ttm_bo_init_mm(&qdev->mman.bdev, TTM_PL_VRAM, | 237 | r = qxl_ttm_init_mem_type(qdev, TTM_PL_VRAM, num_io_pages); |
| 262 | num_io_pages); | ||
| 263 | if (r) { | 238 | if (r) { |
| 264 | DRM_ERROR("Failed initializing VRAM heap.\n"); | 239 | DRM_ERROR("Failed initializing VRAM heap.\n"); |
| 265 | return r; | 240 | return r; |
| 266 | } | 241 | } |
| 267 | r = ttm_bo_init_mm(&qdev->mman.bdev, TTM_PL_PRIV, | 242 | r = qxl_ttm_init_mem_type(qdev, TTM_PL_PRIV, |
| 268 | qdev->surfaceram_size / PAGE_SIZE); | 243 | qdev->surfaceram_size / PAGE_SIZE); |
| 269 | if (r) { | 244 | if (r) { |
| 270 | DRM_ERROR("Failed initializing Surfaces heap.\n"); | 245 | DRM_ERROR("Failed initializing Surfaces heap.\n"); |
| 271 | return r; | 246 | return r; |
| @@ -281,8 +256,8 @@ int qxl_ttm_init(struct qxl_device *qdev) · 9 unmodified lines | |||
| 281 | 256 | ||
| 282 | void qxl_ttm_fini(struct qxl_device *qdev) | 257 | void qxl_ttm_fini(struct qxl_device *qdev) |
| 283 | { | 258 | { |
| 284 | ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_VRAM); | 259 | ttm_range_man_fini(&qdev->mman.bdev, TTM_PL_VRAM); |
| 285 | ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_PRIV); | 260 | ttm_range_man_fini(&qdev->mman.bdev, TTM_PL_PRIV); |
| 286 | ttm_bo_device_release(&qdev->mman.bdev); | 261 | ttm_bo_device_release(&qdev->mman.bdev); |
| 287 | DRM_INFO("qxl: ttm finalized\n"); | 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 | static int qxl_mm_dump_table(struct seq_file *m, void *data) | 268 | static int qxl_mm_dump_table(struct seq_file *m, void *data) |
| 294 | { | 269 | { |
| 295 | struct drm_info_node *node = (struct drm_info_node *)m->private; | 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 | struct drm_printer p = drm_seq_file_printer(m); | 272 | struct drm_printer p = drm_seq_file_printer(m); |
| 298 | 273 | ||
| 299 | spin_lock(&ttm_bo_glob.lru_lock); | 274 | ttm_resource_manager_debug(man, &p); |
| 300 | drm_mm_print(mm, &p); | ||
| 301 | spin_unlock(&ttm_bo_glob.lru_lock); | ||
| 302 | return 0; | 275 | return 0; |
| 303 | } | 276 | } |
| 304 | #endif | 277 | #endif |
| @@ -319,9 +292,9 @@ void qxl_ttm_debugfs_init(struct qxl_device *qdev) · 14 unmodified lines | |||
| 319 | qxl_mem_types_list[i].show = &qxl_mm_dump_table; | 292 | qxl_mem_types_list[i].show = &qxl_mm_dump_table; |
| 320 | qxl_mem_types_list[i].driver_features = 0; | 293 | qxl_mem_types_list[i].driver_features = 0; |
| 321 | if (i == 0) | 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 | else | 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 | qxl_debugfs_add_files(qdev, qxl_mem_types_list, i); | 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 | struct radeon_vm *vm); | 2857 | struct radeon_vm *vm); |
| 2858 | int radeon_vm_bo_update(struct radeon_device *rdev, | 2858 | int radeon_vm_bo_update(struct radeon_device *rdev, |
| 2859 | struct radeon_bo_va *bo_va, | 2859 | struct radeon_bo_va *bo_va, |
| 2860 | struct ttm_mem_reg *mem); | 2860 | struct ttm_resource *mem); |
| 2861 | void radeon_vm_bo_invalidate(struct radeon_device *rdev, | 2861 | void radeon_vm_bo_invalidate(struct radeon_device *rdev, |
| 2862 | struct radeon_bo *bo); | 2862 | struct radeon_bo *bo); |
| 2863 | struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, | 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 | struct radeon_device *rdev = dev->dev_private; | 225 | struct radeon_device *rdev = dev->dev_private; |
| 226 | struct drm_radeon_gem_info *args = data; | 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 | args->vram_size = (u64)man->size << PAGE_SHIFT; | 231 | args->vram_size = (u64)man->size << PAGE_SHIFT; |
| 232 | args->vram_visible = rdev->mc.visible_vram_size; | 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 | void radeon_bo_move_notify(struct ttm_buffer_object *bo, | 776 | void radeon_bo_move_notify(struct ttm_buffer_object *bo, |
| 777 | bool evict, | 777 | bool evict, |
| 778 | struct ttm_mem_reg *new_mem) | 778 | struct ttm_resource *new_mem) |
| 779 | { | 779 | { |
| 780 | struct radeon_bo *rbo; | 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 | bool force_drop); | 165 | bool force_drop); |
| 166 | extern void radeon_bo_move_notify(struct ttm_buffer_object *bo, | 166 | extern void radeon_bo_move_notify(struct ttm_buffer_object *bo, |
| 167 | bool evict, | 167 | bool evict, |
| 168 | struct ttm_mem_reg *new_mem); | 168 | struct ttm_resource *new_mem); |
| 169 | extern int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo); | 169 | extern int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo); |
| 170 | extern int radeon_bo_get_surface_reg(struct radeon_bo *bo); | 170 | extern int radeon_bo_get_surface_reg(struct radeon_bo *bo); |
| 171 | extern void radeon_bo_fence(struct radeon_bo *bo, struct radeon_fence *fence, | 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 | return rdev; | 66 | return rdev; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | 69 | static int radeon_ttm_init_vram(struct radeon_device *rdev) |
| 70 | struct ttm_mem_type_manager *man) | ||
| 71 | { | 70 | { |
| 72 | struct radeon_device *rdev; | 71 | return ttm_range_man_init(&rdev->mman.bdev, TTM_PL_VRAM, |
| 73 | 72 | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC, | |
| 74 | rdev = radeon_get_rdev(bdev); | 73 | TTM_PL_FLAG_WC, false, |
| 74 | rdev->mc.real_vram_size >> PAGE_SHIFT); | ||
| 75 | } | ||
| 75 | 76 | ||
| 76 | switch (type) { | 77 | static int radeon_ttm_init_gtt(struct radeon_device *rdev) |
| 77 | case TTM_PL_SYSTEM: | 78 | { |
| 78 | /* System memory */ | 79 | return ttm_range_man_init(&rdev->mman.bdev, TTM_PL_TT, |
| 79 | man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; | 80 | TTM_PL_MASK_CACHING, |
| 80 | man->available_caching = TTM_PL_MASK_CACHING; | 81 | TTM_PL_FLAG_CACHED, true, |
| 81 | man->default_caching = TTM_PL_FLAG_CACHED; | 82 | rdev->mc.gtt_size >> PAGE_SHIFT); |
| 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; | ||
| 116 | } | 83 | } |
| 117 | 84 | ||
| 118 | static void radeon_evict_flags(struct ttm_buffer_object *bo, | 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 | static void radeon_move_null(struct ttm_buffer_object *bo, | 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 | BUG_ON(old_mem->mm_node != NULL); | 156 | BUG_ON(old_mem->mm_node != NULL); |
| 190 | *old_mem = *new_mem; | 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 | static int radeon_move_blit(struct ttm_buffer_object *bo, | 161 | static int radeon_move_blit(struct ttm_buffer_object *bo, |
| 195 | bool evict, bool no_wait_gpu, | 162 | bool evict, bool no_wait_gpu, |
| 196 | struct ttm_mem_reg *new_mem, | 163 | struct ttm_resource *new_mem, |
| 197 | struct ttm_mem_reg *old_mem) | 164 | struct ttm_resource *old_mem) |
| 198 | { | 165 | { |
| 199 | struct radeon_device *rdev; | 166 | struct radeon_device *rdev; |
| 200 | uint64_t old_start, new_start; | 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 | static int radeon_move_vram_ram(struct ttm_buffer_object *bo, | 216 | static int radeon_move_vram_ram(struct ttm_buffer_object *bo, |
| 250 | bool evict, bool interruptible, | 217 | bool evict, bool interruptible, |
| 251 | bool no_wait_gpu, | 218 | bool no_wait_gpu, |
| 252 | struct ttm_mem_reg *new_mem) | 219 | struct ttm_resource *new_mem) |
| 253 | { | 220 | { |
| 254 | struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu }; | 221 | struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu }; |
| 255 | struct ttm_mem_reg *old_mem = &bo->mem; | 222 | struct ttm_resource *old_mem = &bo->mem; |
| 256 | struct ttm_mem_reg tmp_mem; | 223 | struct ttm_resource tmp_mem; |
| 257 | struct ttm_place placements; | 224 | struct ttm_place placements; |
| 258 | struct ttm_placement placement; | 225 | struct ttm_placement placement; |
| 259 | int r; | 226 | int r; |
| @@ -287,18 +254,18 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo, · 27 unmodified lines | |||
| 287 | } | 254 | } |
| 288 | r = ttm_bo_move_ttm(bo, &ctx, new_mem); | 255 | r = ttm_bo_move_ttm(bo, &ctx, new_mem); |
| 289 | out_cleanup: | 256 | out_cleanup: |
| 290 | ttm_bo_mem_put(bo, &tmp_mem); | 257 | ttm_resource_free(bo, &tmp_mem); |
| 291 | return r; | 258 | return r; |
| 292 | } | 259 | } |
| 293 | 260 | ||
| 294 | static int radeon_move_ram_vram(struct ttm_buffer_object *bo, | 261 | static int radeon_move_ram_vram(struct ttm_buffer_object *bo, |
| 295 | bool evict, bool interruptible, | 262 | bool evict, bool interruptible, |
| 296 | bool no_wait_gpu, | 263 | bool no_wait_gpu, |
| 297 | struct ttm_mem_reg *new_mem) | 264 | struct ttm_resource *new_mem) |
| 298 | { | 265 | { |
| 299 | struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu }; | 266 | struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu }; |
| 300 | struct ttm_mem_reg *old_mem = &bo->mem; | 267 | struct ttm_resource *old_mem = &bo->mem; |
| 301 | struct ttm_mem_reg tmp_mem; | 268 | struct ttm_resource tmp_mem; |
| 302 | struct ttm_placement placement; | 269 | struct ttm_placement placement; |
| 303 | struct ttm_place placements; | 270 | struct ttm_place placements; |
| 304 | int r; | 271 | int r; |
| @@ -325,17 +292,17 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo, · 20 unmodified lines | |||
| 325 | goto out_cleanup; | 292 | goto out_cleanup; |
| 326 | } | 293 | } |
| 327 | out_cleanup: | 294 | out_cleanup: |
| 328 | ttm_bo_mem_put(bo, &tmp_mem); | 295 | ttm_resource_free(bo, &tmp_mem); |
| 329 | return r; | 296 | return r; |
| 330 | } | 297 | } |
| 331 | 298 | ||
| 332 | static int radeon_bo_move(struct ttm_buffer_object *bo, bool evict, | 299 | static int radeon_bo_move(struct ttm_buffer_object *bo, bool evict, |
| 333 | struct ttm_operation_ctx *ctx, | 300 | struct ttm_operation_ctx *ctx, |
| 334 | struct ttm_mem_reg *new_mem) | 301 | struct ttm_resource *new_mem) |
| 335 | { | 302 | { |
| 336 | struct radeon_device *rdev; | 303 | struct radeon_device *rdev; |
| 337 | struct radeon_bo *rbo; | 304 | struct radeon_bo *rbo; |
| 338 | struct ttm_mem_reg *old_mem = &bo->mem; | 305 | struct ttm_resource *old_mem = &bo->mem; |
| 339 | int r; | 306 | int r; |
| 340 | 307 | ||
| 341 | r = ttm_bo_wait(bo, ctx->interruptible, ctx->no_wait_gpu); | 308 | r = ttm_bo_wait(bo, ctx->interruptible, ctx->no_wait_gpu); |
| @@ -392,18 +359,11 @@ memcpy: · 50 unmodified lines | |||
| 392 | return 0; | 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 | struct radeon_device *rdev = radeon_get_rdev(bdev); | 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 | switch (mem->mem_type) { | 367 | switch (mem->mem_type) { |
| 408 | case TTM_PL_SYSTEM: | 368 | case TTM_PL_SYSTEM: |
| 409 | /* system memory */ | 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 | case TTM_PL_VRAM: | 381 | case TTM_PL_VRAM: |
| 422 | mem->bus.offset = mem->start << PAGE_SHIFT; | 382 | mem->bus.offset = mem->start << PAGE_SHIFT; |
| 423 | /* check if it's visible */ | 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 | return -EINVAL; | 385 | return -EINVAL; |
| 426 | mem->bus.base = rdev->mc.aper_base; | 386 | mem->bus.base = rdev->mc.aper_base; |
| 427 | mem->bus.is_iomem = true; | 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 | if (mem->placement & TTM_PL_FLAG_WC) | 393 | if (mem->placement & TTM_PL_FLAG_WC) |
| 434 | mem->bus.addr = | 394 | mem->bus.addr = |
| 435 | ioremap_wc(mem->bus.base + mem->bus.offset, | 395 | ioremap_wc(mem->bus.base + mem->bus.offset, |
| 436 | mem->bus.size); | 396 | bus_size); |
| 437 | else | 397 | else |
| 438 | mem->bus.addr = | 398 | mem->bus.addr = |
| 439 | ioremap(mem->bus.base + mem->bus.offset, | 399 | ioremap(mem->bus.base + mem->bus.offset, |
| 440 | mem->bus.size); | 400 | bus_size); |
| 441 | if (!mem->bus.addr) | 401 | if (!mem->bus.addr) |
| 442 | return -ENOMEM; | 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 | static int radeon_ttm_backend_bind(struct ttm_tt *ttm, | 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 | struct radeon_ttm_tt *gtt = (void*)ttm; | 527 | struct radeon_ttm_tt *gtt = (void*)ttm; |
| 568 | uint32_t flags = RADEON_GART_PAGE_VALID | RADEON_GART_PAGE_READ | | 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 | .ttm_tt_create = &radeon_ttm_tt_create, | 720 | .ttm_tt_create = &radeon_ttm_tt_create, |
| 761 | .ttm_tt_populate = &radeon_ttm_tt_populate, | 721 | .ttm_tt_populate = &radeon_ttm_tt_populate, |
| 762 | .ttm_tt_unpopulate = &radeon_ttm_tt_unpopulate, | 722 | .ttm_tt_unpopulate = &radeon_ttm_tt_unpopulate, |
| 763 | .init_mem_type = &radeon_init_mem_type, | ||
| 764 | .eviction_valuable = ttm_bo_eviction_valuable, | 723 | .eviction_valuable = ttm_bo_eviction_valuable, |
| 765 | .evict_flags = &radeon_evict_flags, | 724 | .evict_flags = &radeon_evict_flags, |
| 766 | .move = &radeon_bo_move, | 725 | .move = &radeon_bo_move, |
| @@ -785,8 +744,8 @@ int radeon_ttm_init(struct radeon_device *rdev) · 18 unmodified lines | |||
| 785 | return r; | 744 | return r; |
| 786 | } | 745 | } |
| 787 | rdev->mman.initialized = true; | 746 | rdev->mman.initialized = true; |
| 788 | r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_VRAM, | 747 | |
| 789 | rdev->mc.real_vram_size >> PAGE_SHIFT); | 748 | r = radeon_ttm_init_vram(rdev); |
| 790 | if (r) { | 749 | if (r) { |
| 791 | DRM_ERROR("Failed initializing VRAM heap.\n"); | 750 | DRM_ERROR("Failed initializing VRAM heap.\n"); |
| 792 | return r; | 751 | return r; |
| @@ -811,8 +770,8 @@ int radeon_ttm_init(struct radeon_device *rdev) · 18 unmodified lines | |||
| 811 | } | 770 | } |
| 812 | DRM_INFO("radeon: %uM of VRAM memory ready\n", | 771 | DRM_INFO("radeon: %uM of VRAM memory ready\n", |
| 813 | (unsigned) (rdev->mc.real_vram_size / (1024 * 1024))); | 772 | (unsigned) (rdev->mc.real_vram_size / (1024 * 1024))); |
| 814 | r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_TT, | 773 | |
| 815 | rdev->mc.gtt_size >> PAGE_SHIFT); | 774 | r = radeon_ttm_init_gtt(rdev); |
| 816 | if (r) { | 775 | if (r) { |
| 817 | DRM_ERROR("Failed initializing GTT heap.\n"); | 776 | DRM_ERROR("Failed initializing GTT heap.\n"); |
| 818 | return r; | 777 | return r; |
| @@ -843,8 +802,8 @@ void radeon_ttm_fini(struct radeon_device *rdev) · 24 unmodified lines | |||
| 843 | } | 802 | } |
| 844 | radeon_bo_unref(&rdev->stolen_vga_memory); | 803 | radeon_bo_unref(&rdev->stolen_vga_memory); |
| 845 | } | 804 | } |
| 846 | ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_VRAM); | 805 | ttm_range_man_fini(&rdev->mman.bdev, TTM_PL_VRAM); |
| 847 | ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_TT); | 806 | ttm_range_man_fini(&rdev->mman.bdev, TTM_PL_TT); |
| 848 | ttm_bo_device_release(&rdev->mman.bdev); | 807 | ttm_bo_device_release(&rdev->mman.bdev); |
| 849 | radeon_gart_fini(rdev); | 808 | radeon_gart_fini(rdev); |
| 850 | rdev->mman.initialized = false; | 809 | rdev->mman.initialized = false; |
| @@ -855,12 +814,12 @@ void radeon_ttm_fini(struct radeon_device *rdev) · 4 unmodified lines | |||
| 855 | * isn't running */ | 814 | * isn't running */ |
| 856 | void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size) | 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 | if (!rdev->mman.initialized) | 819 | if (!rdev->mman.initialized) |
| 861 | return; | 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 | /* this just adjusts TTM size idea, which sets lpfn to the correct value */ | 823 | /* this just adjusts TTM size idea, which sets lpfn to the correct value */ |
| 865 | man->size = size >> PAGE_SHIFT; | 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 | unsigned ttm_pl = *(int*)node->info_ent->data; | 873 | unsigned ttm_pl = *(int*)node->info_ent->data; |
| 915 | struct drm_device *dev = node->minor->dev; | 874 | struct drm_device *dev = node->minor->dev; |
| 916 | struct radeon_device *rdev = dev->dev_private; | 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 | struct drm_printer p = drm_seq_file_printer(m); | 877 | struct drm_printer p = drm_seq_file_printer(m); |
| 919 | 878 | ||
| 920 | man->func->debug(man, &p); | 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 | int radeon_vm_bo_update(struct radeon_device *rdev, | 912 | int radeon_vm_bo_update(struct radeon_device *rdev, |
| 913 | struct radeon_bo_va *bo_va, | 913 | struct radeon_bo_va *bo_va, |
| 914 | struct ttm_mem_reg *mem) | 914 | struct ttm_resource *mem) |
| 915 | { | 915 | { |
| 916 | struct radeon_vm *vm = bo_va->vm; | 916 | struct radeon_vm *vm = bo_va->vm; |
| 917 | struct radeon_ib ib; | 917 | struct radeon_ib ib; |
| @@ -677,15 +677,11 @@ static int rcar_lvds_attach(struct drm_bridge *bridge, · 676 unmodified lines | |||
| 677 | if (ret < 0) | 677 | if (ret < 0) |
| 678 | return ret; | 678 | return ret; |
| 679 | 679 | ||
| 680 | return drm_panel_attach(lvds->panel, connector); | 680 | return 0; |
| 681 | } | 681 | } |
| 682 | 682 | ||
| 683 | static void rcar_lvds_detach(struct drm_bridge *bridge) | 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 | static const struct drm_bridge_funcs rcar_lvds_bridge_ops = { | 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 | "failed to attach encoder: %d\n", ret); | 634 | "failed to attach encoder: %d\n", ret); |
| 635 | goto err_free_connector; | 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 | } else { | 637 | } else { |
| 645 | ret = drm_bridge_attach(encoder, lvds->bridge, NULL, 0); | 638 | ret = drm_bridge_attach(encoder, lvds->bridge, NULL, 0); |
| 646 | if (ret) { | 639 | if (ret) { |
| @@ -676,8 +669,6 @@ static void rockchip_lvds_unbind(struct device *dev, struct device *master, · 29 unmodified lines | |||
| 676 | 669 | ||
| 677 | encoder_funcs = lvds->soc_data->helper_funcs; | 670 | encoder_funcs = lvds->soc_data->helper_funcs; |
| 678 | encoder_funcs->disable(&lvds->encoder); | 671 | encoder_funcs->disable(&lvds->encoder); |
| 679 | if (lvds->panel) | ||
| 680 | drm_panel_detach(lvds->panel); | ||
| 681 | pm_runtime_disable(dev); | 672 | pm_runtime_disable(dev); |
| 682 | drm_connector_cleanup(&lvds->connector); | 673 | drm_connector_cleanup(&lvds->connector); |
| 683 | drm_encoder_cleanup(&lvds->encoder); | 674 | drm_encoder_cleanup(&lvds->encoder); |
| @@ -389,8 +389,6 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force) · 388 unmodified lines | |||
| 389 | dvo->panel = of_drm_find_panel(dvo->panel_node); | 389 | dvo->panel = of_drm_find_panel(dvo->panel_node); |
| 390 | if (IS_ERR(dvo->panel)) | 390 | if (IS_ERR(dvo->panel)) |
| 391 | dvo->panel = NULL; | 391 | dvo->panel = NULL; |
| 392 | else | ||
| 393 | drm_panel_attach(dvo->panel, connector); | ||
| 394 | } | 392 | } |
| 395 | 393 | ||
| 396 | if (dvo->panel) | 394 | if (dvo->panel) |
| @@ -769,7 +769,7 @@ static const struct sunxi_engine_ops sun4i_backend_engine_ops = { · 768 unmodified lines | |||
| 769 | .vblank_quirk = sun4i_backend_vblank_quirk, | 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 | .reg_bits = 32, | 773 | .reg_bits = 32, |
| 774 | .val_bits = 32, | 774 | .val_bits = 32, |
| 775 | .reg_stride = 4, | 775 | .reg_stride = 4, |
| @@ -35,7 +35,7 @@ static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = { · 34 unmodified lines | |||
| 35 | .fb_create = drm_gem_fb_create, | 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 | .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, | 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 | EXPORT_SYMBOL(sun4i_frontend_enable); | 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 | .reg_bits = 32, | 549 | .reg_bits = 32, |
| 550 | .val_bits = 32, | 550 | .val_bits = 32, |
| 551 | .reg_stride = 4, | 551 | .reg_stride = 4, |
| @@ -47,16 +47,13 @@ static int sun4i_lvds_get_modes(struct drm_connector *connector) · 46 unmodified lines | |||
| 47 | return drm_panel_get_modes(lvds->panel, connector); | 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 | .get_modes = sun4i_lvds_get_modes, | 51 | .get_modes = sun4i_lvds_get_modes, |
| 52 | }; | 52 | }; |
| 53 | 53 | ||
| 54 | static void | 54 | static void |
| 55 | sun4i_lvds_connector_destroy(struct drm_connector *connector) | 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 | drm_connector_cleanup(connector); | 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 | drm_connector_attach_encoder(&lvds->connector, | 139 | drm_connector_attach_encoder(&lvds->connector, |
| 143 | &lvds->encoder); | 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 | if (bridge) { | 143 | if (bridge) { |
| @@ -138,16 +138,13 @@ out: · 137 unmodified lines | |||
| 138 | return MODE_OK; | 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 | .get_modes = sun4i_rgb_get_modes, | 142 | .get_modes = sun4i_rgb_get_modes, |
| 143 | }; | 143 | }; |
| 144 | 144 | ||
| 145 | static void | 145 | static void |
| 146 | sun4i_rgb_connector_destroy(struct drm_connector *connector) | 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 | drm_connector_cleanup(connector); | 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 | .disable = sun4i_rgb_encoder_disable, | 184 | .disable = sun4i_rgb_encoder_disable, |
| 188 | .enable = sun4i_rgb_encoder_enable, | 185 | .enable = sun4i_rgb_encoder_enable, |
| 189 | .mode_valid = sun4i_rgb_mode_valid, | 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 | drm_connector_attach_encoder(&rgb->connector, | 231 | drm_connector_attach_encoder(&rgb->connector, |
| 235 | &rgb->encoder); | 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 | if (rgb->bridge) { | 235 | if (rgb->bridge) { |
| @@ -825,7 +825,7 @@ static int sun4i_tcon_init_irq(struct device *dev, · 824 unmodified lines | |||
| 825 | return 0; | 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 | .reg_bits = 32, | 829 | .reg_bits = 32, |
| 830 | .val_bits = 32, | 830 | .val_bits = 32, |
| 831 | .reg_stride = 4, | 831 | .reg_stride = 4, |
| @@ -468,7 +468,7 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder, · 467 unmodified lines | |||
| 468 | regmap_write(tv->regs, SUN4I_TVE_SLAVE_REG, 0); | 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 | .disable = sun4i_tv_disable, | 472 | .disable = sun4i_tv_disable, |
| 473 | .enable = sun4i_tv_enable, | 473 | .enable = sun4i_tv_enable, |
| 474 | .mode_set = sun4i_tv_mode_set, | 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 | return MODE_OK; | 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 | .get_modes = sun4i_tv_comp_get_modes, | 508 | .get_modes = sun4i_tv_comp_get_modes, |
| 509 | .mode_valid = sun4i_tv_comp_mode_valid, | 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 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | 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 | .reg_bits = 32, | 527 | .reg_bits = 32, |
| 528 | .val_bits = 32, | 528 | .val_bits = 32, |
| 529 | .reg_stride = 4, | 529 | .reg_stride = 4, |
| @@ -820,7 +820,7 @@ static int sun6i_dsi_get_modes(struct drm_connector *connector) · 819 unmodified lines | |||
| 820 | return drm_panel_get_modes(dsi->panel, connector); | 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 | .get_modes = sun6i_dsi_get_modes, | 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 | dsi->panel = panel; | 973 | dsi->panel = panel; |
| 974 | dsi->device = device; | 974 | dsi->device = device; |
| 975 | 975 | ||
| 976 | drm_panel_attach(dsi->panel, &dsi->connector); | ||
| 977 | drm_kms_helper_hotplug_event(dsi->drm); | 976 | drm_kms_helper_hotplug_event(dsi->drm); |
| 978 | 977 | ||
| 979 | dev_info(host->dev, "Attached device %s\n", device->name); | 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 | struct mipi_dsi_device *device) | 984 | struct mipi_dsi_device *device) |
| 986 | { | 985 | { |
| 987 | struct sun6i_dsi *dsi = host_to_sun6i_dsi(host); | 986 | struct sun6i_dsi *dsi = host_to_sun6i_dsi(host); |
| 988 | struct drm_panel *panel = dsi->panel; | ||
| 989 | 987 | ||
| 990 | dsi->panel = NULL; | 988 | dsi->panel = NULL; |
| 991 | dsi->device = NULL; | 989 | dsi->device = NULL; |
| 992 | 990 | ||
| 993 | drm_panel_detach(panel); | ||
| 994 | drm_kms_helper_hotplug_event(dsi->drm); | 991 | drm_kms_helper_hotplug_event(dsi->drm); |
| 995 | 992 | ||
| 996 | return 0; | 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 | .reg_bits = 32, | 538 | .reg_bits = 32, |
| 539 | .val_bits = 32, | 539 | .val_bits = 32, |
| 540 | .reg_stride = 4, | 540 | .reg_stride = 4, |
| @@ -303,7 +303,7 @@ static const struct sunxi_engine_ops sun8i_engine_ops = { · 302 unmodified lines | |||
| 303 | .layers_init = sun8i_layers_init, | 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 | .reg_bits = 32, | 307 | .reg_bits = 32, |
| 308 | .val_bits = 32, | 308 | .val_bits = 32, |
| 309 | .reg_stride = 4, | 309 | .reg_stride = 4, |
| @@ -298,7 +298,7 @@ static void sun8i_ui_layer_atomic_update(struct drm_plane *plane, · 297 unmodified lines | |||
| 298 | true, zpos, old_zpos); | 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 | .prepare_fb = drm_gem_fb_prepare_fb, | 302 | .prepare_fb = drm_gem_fb_prepare_fb, |
| 303 | .atomic_check = sun8i_ui_layer_atomic_check, | 303 | .atomic_check = sun8i_ui_layer_atomic_check, |
| 304 | .atomic_disable = sun8i_ui_layer_atomic_disable, | 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 | true, zpos, old_zpos); | 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 | .prepare_fb = drm_gem_fb_prepare_fb, | 405 | .prepare_fb = drm_gem_fb_prepare_fb, |
| 406 | .atomic_check = sun8i_vi_layer_atomic_check, | 406 | .atomic_check = sun8i_vi_layer_atomic_check, |
| 407 | .atomic_disable = sun8i_vi_layer_atomic_disable, | 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 | if (IS_ERR(output->panel)) | 1498 | if (IS_ERR(output->panel)) |
| 1499 | output->panel = NULL; | 1499 | output->panel = NULL; |
| 1500 | 1500 | ||
| 1501 | if (output->panel && output->connector.dev) { | 1501 | if (output->panel && output->connector.dev) |
| 1502 | drm_panel_attach(output->panel, &output->connector); | ||
| 1503 | drm_helper_hpd_irq_event(output->connector.dev); | 1502 | drm_helper_hpd_irq_event(output->connector.dev); |
| 1504 | } | ||
| 1505 | } | 1503 | } |
| 1506 | 1504 | ||
| 1507 | return 0; | 1505 | return 0; |
| @@ -179,13 +179,6 @@ void tegra_output_remove(struct tegra_output *output) · 178 unmodified lines | |||
| 179 | int tegra_output_init(struct drm_device *drm, struct tegra_output *output) | 179 | int tegra_output_init(struct drm_device *drm, struct tegra_output *output) |
| 180 | { | 180 | { |
| 181 | int connector_type; | 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 | * The connector is now registered and ready to receive hotplug events | 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 | if (output->hpd_gpio) | 214 | if (output->hpd_gpio) |
| 222 | disable_irq(output->hpd_irq); | 215 | disable_irq(output->hpd_irq); |
| 223 | |||
| 224 | if (output->panel) | ||
| 225 | drm_panel_detach(output->panel); | ||
| 226 | } | 216 | } |
| 227 | 217 | ||
| 228 | void tegra_output_find_possible_crtcs(struct tegra_output *output, | 218 | void tegra_output_find_possible_crtcs(struct tegra_output *output, |
| @@ -19,6 +19,7 @@ · 18 unmodified lines | |||
| 19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
| 20 | #include <linux/pm_runtime.h> | 20 | #include <linux/pm_runtime.h> |
| 21 | #include <linux/regmap.h> | 21 | #include <linux/regmap.h> |
| 22 | #include <linux/sys_soc.h> | ||
| 22 | 23 | ||
| 23 | #include <drm/drm_fourcc.h> | 24 | #include <drm/drm_fourcc.h> |
| 24 | #include <drm/drm_fb_cma_helper.h> | 25 | #include <drm/drm_fb_cma_helper.h> |
| @@ -302,6 +303,8 @@ struct dispc_device { · 277 unmodified lines | |||
| 302 | u32 num_fourccs; | 303 | u32 num_fourccs; |
| 303 | 304 | ||
| 304 | u32 memory_bandwidth_limit; | 305 | u32 memory_bandwidth_limit; |
| 306 | |||
| 307 | struct dispc_errata errata; | ||
| 305 | }; | 308 | }; |
| 306 | 309 | ||
| 307 | static void dispc_write(struct dispc_device *dispc, u16 reg, u32 val) | 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 | return 0; | 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 | int dispc_init(struct tidss_device *tidss) | 2660 | int dispc_init(struct tidss_device *tidss) |
| 2645 | { | 2661 | { |
| 2646 | struct device *dev = tidss->dev; | 2662 | struct device *dev = tidss->dev; |
| @@ -2664,19 +2680,27 @@ int dispc_init(struct tidss_device *tidss) · 17 unmodified lines | |||
| 2664 | if (!dispc) | 2680 | if (!dispc) |
| 2665 | return -ENOMEM; | 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 | dispc->fourccs = devm_kcalloc(dev, ARRAY_SIZE(dispc_color_formats), | 2689 | dispc->fourccs = devm_kcalloc(dev, ARRAY_SIZE(dispc_color_formats), |
| 2668 | sizeof(*dispc->fourccs), GFP_KERNEL); | 2690 | sizeof(*dispc->fourccs), GFP_KERNEL); |
| 2669 | if (!dispc->fourccs) | 2691 | if (!dispc->fourccs) |
| 2670 | return -ENOMEM; | 2692 | return -ENOMEM; |
| 2671 | 2693 | ||
| 2672 | num_fourccs = 0; | 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 | dispc->fourccs[num_fourccs++] = dispc_color_formats[i].fourcc; | 2700 | dispc->fourccs[num_fourccs++] = dispc_color_formats[i].fourcc; |
| 2701 | } | ||
| 2675 | 2702 | ||
| 2676 | dispc->num_fourccs = num_fourccs; | 2703 | dispc->num_fourccs = num_fourccs; |
| 2677 | dispc->tidss = tidss; | ||
| 2678 | dispc->dev = dev; | ||
| 2679 | dispc->feat = feat; | ||
| 2680 | 2704 | ||
| 2681 | dispc_common_regmap = dispc->feat->common_regs; | 2705 | dispc_common_regmap = dispc->feat->common_regs; |
| 2682 | 2706 | ||
| @@ -46,6 +46,10 @@ struct dispc_features_scaling { · 45 unmodified lines | |||
| 46 | u32 xinc_max; | 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 | enum dispc_vp_bus_type { | 53 | enum dispc_vp_bus_type { |
| 50 | DISPC_VP_DPI, /* DPI output */ | 54 | DISPC_VP_DPI, /* DPI output */ |
| 51 | DISPC_VP_OLDI, /* OLDI (LVDS) output */ | 55 | DISPC_VP_OLDI, /* OLDI (LVDS) output */ |
| @@ -4,7 +4,8 @@ · 3 unmodified lines | |||
| 4 | 4 | ||
| 5 | ttm-y := ttm_memory.o ttm_tt.o ttm_bo.o \ | 5 | ttm-y := ttm_memory.o ttm_tt.o ttm_bo.o \ |
| 6 | ttm_bo_util.o ttm_bo_vm.o ttm_module.o \ | 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 | ttm-$(CONFIG_AGP) += ttm_agp_backend.o | 9 | ttm-$(CONFIG_AGP) += ttm_agp_backend.o |
| 9 | ttm-$(CONFIG_DRM_TTM_DMA_PAGE_POOL) += ttm_page_alloc_dma.o | 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 | struct agp_bridge_data *bridge; | 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 | struct ttm_agp_backend *agp_be = container_of(ttm, struct ttm_agp_backend, ttm); | 53 | struct ttm_agp_backend *agp_be = container_of(ttm, struct ttm_agp_backend, ttm); |
| 54 | struct page *dummy_read_page = ttm_bo_glob.dummy_read_page; | 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 | return 0; | 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 | static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo, | 80 | static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo, |
| 96 | struct ttm_placement *placement) | 81 | struct ttm_placement *placement) |
| 97 | { | 82 | { |
| 98 | struct drm_printer p = drm_debug_printer(TTM_PFX); | 83 | struct drm_printer p = drm_debug_printer(TTM_PFX); |
| 99 | int i, ret, mem_type; | 84 | int i, ret, mem_type; |
| 85 | struct ttm_resource_manager *man; | ||
| 100 | 86 | ||
| 101 | drm_printf(&p, "No space for %p (%lu pages, %luK, %luM)\n", | 87 | drm_printf(&p, "No space for %p (%lu pages, %luK, %luM)\n", |
| 102 | bo, bo->mem.num_pages, bo->mem.size >> 10, | 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 | return; | 94 | return; |
| 109 | drm_printf(&p, " placement[%d]=0x%08X (%d)\n", | 95 | drm_printf(&p, " placement[%d]=0x%08X (%d)\n", |
| 110 | i, placement->placement[i].flags, mem_type); | 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 | static void ttm_bo_add_mem_to_lru(struct ttm_buffer_object *bo, | 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 | struct ttm_bo_device *bdev = bo->bdev; | 137 | struct ttm_bo_device *bdev = bo->bdev; |
| 151 | struct ttm_mem_type_manager *man; | 138 | struct ttm_resource_manager *man; |
| 152 | 139 | ||
| 153 | if (!list_empty(&bo->lru)) | 140 | if (!list_empty(&bo->lru)) |
| 154 | return; | 141 | return; |
| @@ -156,10 +143,10 @@ static void ttm_bo_add_mem_to_lru(struct ttm_buffer_object *bo, · 1 unmodified line | |||
| 156 | if (mem->placement & TTM_PL_FLAG_NO_EVICT) | 143 | if (mem->placement & TTM_PL_FLAG_NO_EVICT) |
| 157 | return; | 144 | return; |
| 158 | 145 | ||
| 159 | man = &bdev->man[mem->mem_type]; | 146 | man = ttm_manager_type(bdev, mem->mem_type); |
| 160 | list_add_tail(&bo->lru, &man->lru[bo->priority]); | 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 | !(bo->ttm->page_flags & (TTM_PAGE_FLAG_SG | | 150 | !(bo->ttm->page_flags & (TTM_PAGE_FLAG_SG | |
| 164 | TTM_PAGE_FLAG_SWAPPED))) { | 151 | TTM_PAGE_FLAG_SWAPPED))) { |
| 165 | list_add_tail(&bo->swap, &ttm_bo_glob.swap_lru[bo->priority]); | 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 | for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) { | 211 | for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) { |
| 225 | struct ttm_lru_bulk_move_pos *pos = &bulk->tt[i]; | 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 | if (!pos->first) | 215 | if (!pos->first) |
| 229 | continue; | 216 | continue; |
| @@ -231,14 +218,14 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk) · 1 unmodified line | |||
| 231 | dma_resv_assert_held(pos->first->base.resv); | 218 | dma_resv_assert_held(pos->first->base.resv); |
| 232 | dma_resv_assert_held(pos->last->base.resv); | 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 | list_bulk_move_tail(&man->lru[i], &pos->first->lru, | 222 | list_bulk_move_tail(&man->lru[i], &pos->first->lru, |
| 236 | &pos->last->lru); | 223 | &pos->last->lru); |
| 237 | } | 224 | } |
| 238 | 225 | ||
| 239 | for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) { | 226 | for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) { |
| 240 | struct ttm_lru_bulk_move_pos *pos = &bulk->vram[i]; | 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 | if (!pos->first) | 230 | if (!pos->first) |
| 244 | continue; | 231 | continue; |
| @@ -246,7 +233,7 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk) · 1 unmodified line | |||
| 246 | dma_resv_assert_held(pos->first->base.resv); | 233 | dma_resv_assert_held(pos->first->base.resv); |
| 247 | dma_resv_assert_held(pos->last->base.resv); | 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 | list_bulk_move_tail(&man->lru[i], &pos->first->lru, | 237 | list_bulk_move_tail(&man->lru[i], &pos->first->lru, |
| 251 | &pos->last->lru); | 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 | EXPORT_SYMBOL(ttm_bo_bulk_move_lru_tail); | 255 | EXPORT_SYMBOL(ttm_bo_bulk_move_lru_tail); |
| 269 | 256 | ||
| 270 | static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, | 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 | struct ttm_operation_ctx *ctx) | 259 | struct ttm_operation_ctx *ctx) |
| 273 | { | 260 | { |
| 274 | struct ttm_bo_device *bdev = bo->bdev; | 261 | struct ttm_bo_device *bdev = bo->bdev; |
| 275 | struct ttm_mem_type_manager *old_man = &bdev->man[bo->mem.mem_type]; | 262 | struct ttm_resource_manager *old_man = ttm_manager_type(bdev, bo->mem.mem_type); |
| 276 | struct ttm_mem_type_manager *new_man = &bdev->man[mem->mem_type]; | 263 | struct ttm_resource_manager *new_man = ttm_manager_type(bdev, mem->mem_type); |
| 277 | int ret; | 264 | int ret; |
| 278 | 265 | ||
| 279 | ret = ttm_mem_io_lock(old_man, true); | 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 | * Create and bind a ttm if required. | 273 | * Create and bind a ttm if required. |
| 287 | */ | 274 | */ |
| 288 | 275 | ||
| 289 | if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) { | 276 | if (new_man->use_tt) { |
| 290 | if (bo->ttm == NULL) { | 277 | /* Zero init the new TTM structure if the old location should |
| 291 | bool zero = !(old_man->flags & TTM_MEMTYPE_FLAG_FIXED); | 278 | * have used one as well. |
| 292 | ret = ttm_tt_create(bo, zero); | 279 | */ |
| 293 | if (ret) | 280 | ret = ttm_tt_create(bo, old_man->use_tt); |
| 294 | goto out_err; | 281 | if (ret) |
| 295 | } | 282 | goto out_err; |
| 296 | 283 | ||
| 297 | ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement); | 284 | ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement); |
| 298 | if (ret) | 285 | if (ret) |
| @@ -315,8 +302,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, · 16 unmodified lines | |||
| 315 | if (bdev->driver->move_notify) | 302 | if (bdev->driver->move_notify) |
| 316 | bdev->driver->move_notify(bo, evict, mem); | 303 | bdev->driver->move_notify(bo, evict, mem); |
| 317 | 304 | ||
| 318 | if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) && | 305 | if (old_man->use_tt && new_man->use_tt) |
| 319 | !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) | ||
| 320 | ret = ttm_bo_move_ttm(bo, ctx, mem); | 306 | ret = ttm_bo_move_ttm(bo, ctx, mem); |
| 321 | else if (bdev->driver->move) | 307 | else if (bdev->driver->move) |
| 322 | ret = bdev->driver->move(bo, evict, ctx, mem); | 308 | ret = bdev->driver->move(bo, evict, ctx, mem); |
| @@ -340,8 +326,8 @@ moved: · 17 unmodified lines | |||
| 340 | return 0; | 326 | return 0; |
| 341 | 327 | ||
| 342 | out_err: | 328 | out_err: |
| 343 | new_man = &bdev->man[bo->mem.mem_type]; | 329 | new_man = ttm_manager_type(bdev, bo->mem.mem_type); |
| 344 | if (new_man->flags & TTM_MEMTYPE_FLAG_FIXED) { | 330 | if (!new_man->use_tt) { |
| 345 | ttm_tt_destroy(bo->ttm); | 331 | ttm_tt_destroy(bo->ttm); |
| 346 | bo->ttm = NULL; | 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 | ttm_tt_destroy(bo->ttm); | 351 | ttm_tt_destroy(bo->ttm); |
| 366 | bo->ttm = NULL; | 352 | bo->ttm = NULL; |
| 367 | ttm_bo_mem_put(bo, &bo->mem); | 353 | ttm_resource_free(bo, &bo->mem); |
| 368 | } | 354 | } |
| 369 | 355 | ||
| 370 | static int ttm_bo_individualize_resv(struct ttm_buffer_object *bo) | 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 | struct ttm_buffer_object *bo = | 538 | struct ttm_buffer_object *bo = |
| 553 | container_of(kref, struct ttm_buffer_object, kref); | 539 | container_of(kref, struct ttm_buffer_object, kref); |
| 554 | struct ttm_bo_device *bdev = bo->bdev; | 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 | size_t acc_size = bo->acc_size; | 542 | size_t acc_size = bo->acc_size; |
| 557 | int ret; | 543 | int ret; |
| 558 | 544 | ||
| @@ -643,7 +629,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, · 84 unmodified lines | |||
| 643 | struct ttm_operation_ctx *ctx) | 629 | struct ttm_operation_ctx *ctx) |
| 644 | { | 630 | { |
| 645 | struct ttm_bo_device *bdev = bo->bdev; | 631 | struct ttm_bo_device *bdev = bo->bdev; |
| 646 | struct ttm_mem_reg evict_mem; | 632 | struct ttm_resource evict_mem; |
| 647 | struct ttm_placement placement; | 633 | struct ttm_placement placement; |
| 648 | int ret = 0; | 634 | int ret = 0; |
| 649 | 635 | ||
| @@ -654,10 +640,9 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, · 4 unmodified lines | |||
| 654 | bdev->driver->evict_flags(bo, &placement); | 640 | bdev->driver->evict_flags(bo, &placement); |
| 655 | 641 | ||
| 656 | if (!placement.num_placement && !placement.num_busy_placement) { | 642 | if (!placement.num_placement && !placement.num_busy_placement) { |
| 657 | ret = ttm_bo_pipeline_gutting(bo); | 643 | ttm_bo_wait(bo, false, false); |
| 658 | if (ret) | ||
| 659 | return ret; | ||
| 660 | 644 | ||
| 645 | ttm_bo_cleanup_memtype_use(bo); | ||
| 661 | return ttm_tt_create(bo, false); | 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 | if (unlikely(ret)) { | 665 | if (unlikely(ret)) { |
| 681 | if (ret != -ERESTARTSYS) | 666 | if (ret != -ERESTARTSYS) |
| 682 | pr_err("Buffer eviction failed\n"); | 667 | pr_err("Buffer eviction failed\n"); |
| 683 | ttm_bo_mem_put(bo, &evict_mem); | 668 | ttm_resource_free(bo, &evict_mem); |
| 684 | goto out; | 669 | goto out; |
| 685 | } | 670 | } |
| 686 | bo->evicted = true; | 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 | return r == -EDEADLK ? -EBUSY : r; | 754 | return r == -EDEADLK ? -EBUSY : r; |
| 770 | } | 755 | } |
| 771 | 756 | ||
| 772 | static int ttm_mem_evict_first(struct ttm_bo_device *bdev, | 757 | int ttm_mem_evict_first(struct ttm_bo_device *bdev, |
| 773 | uint32_t mem_type, | 758 | struct ttm_resource_manager *man, |
| 774 | const struct ttm_place *place, | 759 | const struct ttm_place *place, |
| 775 | struct ttm_operation_ctx *ctx, | 760 | struct ttm_operation_ctx *ctx, |
| 776 | struct ww_acquire_ctx *ticket) | 761 | struct ww_acquire_ctx *ticket) |
| 777 | { | 762 | { |
| 778 | struct ttm_buffer_object *bo = NULL, *busy_bo = NULL; | 763 | struct ttm_buffer_object *bo = NULL, *busy_bo = NULL; |
| 779 | struct ttm_mem_type_manager *man = &bdev->man[mem_type]; | ||
| 780 | bool locked = false; | 764 | bool locked = false; |
| 781 | unsigned i; | 765 | unsigned i; |
| 782 | int ret; | 766 | int ret; |
| @@ -842,38 +826,12 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev, · 59 unmodified lines | |||
| 842 | return ret; | 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 | * Add the last move fence to the BO and reserve a new shared slot. | 830 | * Add the last move fence to the BO and reserve a new shared slot. |
| 873 | */ | 831 | */ |
| 874 | static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo, | 832 | static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo, |
| 875 | struct ttm_mem_type_manager *man, | 833 | struct ttm_resource_manager *man, |
| 876 | struct ttm_mem_reg *mem, | 834 | struct ttm_resource *mem, |
| 877 | bool no_wait_gpu) | 835 | bool no_wait_gpu) |
| 878 | { | 836 | { |
| 879 | struct dma_fence *fence; | 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 | static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, | 869 | static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, |
| 912 | const struct ttm_place *place, | 870 | const struct ttm_place *place, |
| 913 | struct ttm_mem_reg *mem, | 871 | struct ttm_resource *mem, |
| 914 | struct ttm_operation_ctx *ctx) | 872 | struct ttm_operation_ctx *ctx) |
| 915 | { | 873 | { |
| 916 | struct ttm_bo_device *bdev = bo->bdev; | 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 | struct ww_acquire_ctx *ticket; | 876 | struct ww_acquire_ctx *ticket; |
| 919 | int ret; | 877 | int ret; |
| 920 | 878 | ||
| 921 | ticket = dma_resv_locking_ctx(bo->base.resv); | 879 | ticket = dma_resv_locking_ctx(bo->base.resv); |
| 922 | do { | 880 | do { |
| 923 | ret = ttm_bo_mem_get(bo, place, mem); | 881 | ret = ttm_resource_alloc(bo, place, mem); |
| 924 | if (likely(!ret)) | 882 | if (likely(!ret)) |
| 925 | break; | 883 | break; |
| 926 | if (unlikely(ret != -ENOSPC)) | 884 | if (unlikely(ret != -ENOSPC)) |
| 927 | return ret; | 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 | ticket); | 887 | ticket); |
| 930 | if (unlikely(ret != 0)) | 888 | if (unlikely(ret != 0)) |
| 931 | return ret; | 889 | return ret; |
| @@ -934,7 +892,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, · 2 unmodified lines | |||
| 934 | return ttm_bo_add_move_fence(bo, man, mem, ctx->no_wait_gpu); | 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 | uint32_t cur_placement, | 896 | uint32_t cur_placement, |
| 939 | uint32_t proposed_placement) | 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 | return result; | 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 | uint32_t mem_type, | 921 | uint32_t mem_type, |
| 964 | const struct ttm_place *place, | 922 | const struct ttm_place *place, |
| 965 | uint32_t *masked_placement) | 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 | static int ttm_bo_mem_placement(struct ttm_buffer_object *bo, | 950 | static int ttm_bo_mem_placement(struct ttm_buffer_object *bo, |
| 993 | const struct ttm_place *place, | 951 | const struct ttm_place *place, |
| 994 | struct ttm_mem_reg *mem, | 952 | struct ttm_resource *mem, |
| 995 | struct ttm_operation_ctx *ctx) | 953 | struct ttm_operation_ctx *ctx) |
| 996 | { | 954 | { |
| 997 | struct ttm_bo_device *bdev = bo->bdev; | 955 | struct ttm_bo_device *bdev = bo->bdev; |
| 998 | uint32_t mem_type = TTM_PL_SYSTEM; | 956 | uint32_t mem_type = TTM_PL_SYSTEM; |
| 999 | struct ttm_mem_type_manager *man; | 957 | struct ttm_resource_manager *man; |
| 1000 | uint32_t cur_flags = 0; | 958 | uint32_t cur_flags = 0; |
| 1001 | int ret; | 959 | int ret; |
| 1002 | 960 | ||
| @@ -1004,8 +962,8 @@ static int ttm_bo_mem_placement(struct ttm_buffer_object *bo, · 1 unmodified line | |||
| 1004 | if (ret) | 962 | if (ret) |
| 1005 | return ret; | 963 | return ret; |
| 1006 | 964 | ||
| 1007 | man = &bdev->man[mem_type]; | 965 | man = ttm_manager_type(bdev, mem_type); |
| 1008 | if (!man->has_type || !man->use_type) | 966 | if (!man || !ttm_resource_manager_used(man)) |
| 1009 | return -EBUSY; | 967 | return -EBUSY; |
| 1010 | 968 | ||
| 1011 | if (!ttm_bo_mt_compatible(man, mem_type, place, &cur_flags)) | 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 | int ttm_bo_mem_space(struct ttm_buffer_object *bo, | 998 | int ttm_bo_mem_space(struct ttm_buffer_object *bo, |
| 1041 | struct ttm_placement *placement, | 999 | struct ttm_placement *placement, |
| 1042 | struct ttm_mem_reg *mem, | 1000 | struct ttm_resource *mem, |
| 1043 | struct ttm_operation_ctx *ctx) | 1001 | struct ttm_operation_ctx *ctx) |
| 1044 | { | 1002 | { |
| 1045 | struct ttm_bo_device *bdev = bo->bdev; | 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 | for (i = 0; i < placement->num_placement; ++i) { | 1011 | for (i = 0; i < placement->num_placement; ++i) { |
| 1054 | const struct ttm_place *place = &placement->placement[i]; | 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 | ret = ttm_bo_mem_placement(bo, place, mem, ctx); | 1015 | ret = ttm_bo_mem_placement(bo, place, mem, ctx); |
| 1058 | if (ret == -EBUSY) | 1016 | if (ret == -EBUSY) |
| @@ -1061,16 +1019,16 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, · 2 unmodified lines | |||
| 1061 | goto error; | 1019 | goto error; |
| 1062 | 1020 | ||
| 1063 | type_found = true; | 1021 | type_found = true; |
| 1064 | ret = ttm_bo_mem_get(bo, place, mem); | 1022 | ret = ttm_resource_alloc(bo, place, mem); |
| 1065 | if (ret == -ENOSPC) | 1023 | if (ret == -ENOSPC) |
| 1066 | continue; | 1024 | continue; |
| 1067 | if (unlikely(ret)) | 1025 | if (unlikely(ret)) |
| 1068 | goto error; | 1026 | goto error; |
| 1069 | 1027 | ||
| 1070 | man = &bdev->man[mem->mem_type]; | 1028 | man = ttm_manager_type(bdev, mem->mem_type); |
| 1071 | ret = ttm_bo_add_move_fence(bo, man, mem, ctx->no_wait_gpu); | 1029 | ret = ttm_bo_add_move_fence(bo, man, mem, ctx->no_wait_gpu); |
| 1072 | if (unlikely(ret)) { | 1030 | if (unlikely(ret)) { |
| 1073 | ttm_bo_mem_put(bo, mem); | 1031 | ttm_resource_free(bo, mem); |
| 1074 | if (ret == -EBUSY) | 1032 | if (ret == -EBUSY) |
| 1075 | continue; | 1033 | continue; |
| 1076 | 1034 | ||
| @@ -1105,9 +1063,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, · 28 unmodified lines | |||
| 1105 | 1063 | ||
| 1106 | error: | 1064 | error: |
| 1107 | if (bo->mem.mem_type == TTM_PL_SYSTEM && !list_empty(&bo->lru)) { | 1065 | if (bo->mem.mem_type == TTM_PL_SYSTEM && !list_empty(&bo->lru)) { |
| 1108 | spin_lock(&ttm_bo_glob.lru_lock); | 1066 | ttm_bo_move_to_lru_tail_unlocked(bo); |
| 1109 | ttm_bo_move_to_lru_tail(bo, NULL); | ||
| 1110 | spin_unlock(&ttm_bo_glob.lru_lock); | ||
| 1111 | } | 1067 | } |
| 1112 | 1068 | ||
| 1113 | return ret; | 1069 | return ret; |
| @@ -1119,7 +1075,7 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo, · 5 unmodified lines | |||
| 1119 | struct ttm_operation_ctx *ctx) | 1075 | struct ttm_operation_ctx *ctx) |
| 1120 | { | 1076 | { |
| 1121 | int ret = 0; | 1077 | int ret = 0; |
| 1122 | struct ttm_mem_reg mem; | 1078 | struct ttm_resource mem; |
| 1123 | 1079 | ||
| 1124 | dma_resv_assert_held(bo->base.resv); | 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 | ret = ttm_bo_handle_move_mem(bo, &mem, false, ctx); | 1095 | ret = ttm_bo_handle_move_mem(bo, &mem, false, ctx); |
| 1140 | out_unlock: | 1096 | out_unlock: |
| 1141 | if (ret) | 1097 | if (ret) |
| 1142 | ttm_bo_mem_put(bo, &mem); | 1098 | ttm_resource_free(bo, &mem); |
| 1143 | return ret; | 1099 | return ret; |
| 1144 | } | 1100 | } |
| 1145 | 1101 | ||
| 1146 | static bool ttm_bo_places_compat(const struct ttm_place *places, | 1102 | static bool ttm_bo_places_compat(const struct ttm_place *places, |
| 1147 | unsigned num_placement, | 1103 | unsigned num_placement, |
| 1148 | struct ttm_mem_reg *mem, | 1104 | struct ttm_resource *mem, |
| 1149 | uint32_t *new_flags) | 1105 | uint32_t *new_flags) |
| 1150 | { | 1106 | { |
| 1151 | unsigned i; | 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 | bool ttm_bo_mem_compat(struct ttm_placement *placement, | 1126 | bool ttm_bo_mem_compat(struct ttm_placement *placement, |
| 1171 | struct ttm_mem_reg *mem, | 1127 | struct ttm_resource *mem, |
| 1172 | uint32_t *new_flags) | 1128 | uint32_t *new_flags) |
| 1173 | { | 1129 | { |
| 1174 | if (ttm_bo_places_compat(placement->placement, placement->num_placement, | 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 | * We might need to add a TTM. | 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 | ret = ttm_tt_create(bo, true); | 1184 | ret = ttm_tt_create(bo, true); |
| 1229 | if (ret) | 1185 | if (ret) |
| 1230 | return ret; | 1186 | return ret; |
| @@ -1335,9 +1291,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, · 104 unmodified lines | |||
| 1335 | return ret; | 1291 | return ret; |
| 1336 | } | 1292 | } |
| 1337 | 1293 | ||
| 1338 | spin_lock(&ttm_bo_glob.lru_lock); | 1294 | ttm_bo_move_to_lru_tail_unlocked(bo); |
| 1339 | ttm_bo_move_to_lru_tail(bo, NULL); | ||
| 1340 | spin_unlock(&ttm_bo_glob.lru_lock); | ||
| 1341 | 1295 | ||
| 1342 | return ret; | 1296 | return ret; |
| 1343 | } | 1297 | } |
| @@ -1426,144 +1380,24 @@ int ttm_bo_create(struct ttm_bo_device *bdev, · 82 unmodified lines | |||
| 1426 | } | 1380 | } |
| 1427 | EXPORT_SYMBOL(ttm_bo_create); | 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 | int ttm_bo_evict_mm(struct ttm_bo_device *bdev, unsigned mem_type) | 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 | if (mem_type == 0 || mem_type >= TTM_NUM_MEM_TYPES) { | 1387 | if (mem_type == 0 || mem_type >= TTM_NUM_MEM_TYPES) { |
| 1517 | pr_err("Illegal memory manager memory type %u\n", mem_type); | 1388 | pr_err("Illegal memory manager memory type %u\n", mem_type); |
| 1518 | return -EINVAL; | 1389 | return -EINVAL; |
| 1519 | } | 1390 | } |
| 1520 | 1391 | ||
| 1521 | if (!man->has_type) { | 1392 | if (!man) { |
| 1522 | pr_err("Memory type %u has not been initialized\n", mem_type); | 1393 | pr_err("Memory type %u has not been initialized\n", mem_type); |
| 1523 | return 0; | 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 | EXPORT_SYMBOL(ttm_bo_evict_mm); | 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 | static void ttm_bo_global_kobj_release(struct kobject *kobj) | 1401 | static void ttm_bo_global_kobj_release(struct kobject *kobj) |
| 1568 | { | 1402 | { |
| 1569 | struct ttm_bo_global *glob = | 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 | struct ttm_bo_global *glob = &ttm_bo_glob; | 1463 | struct ttm_bo_global *glob = &ttm_bo_glob; |
| 1630 | int ret = 0; | 1464 | int ret = 0; |
| 1631 | unsigned i = TTM_NUM_MEM_TYPES; | 1465 | unsigned i; |
| 1632 | struct ttm_mem_type_manager *man; | 1466 | struct ttm_resource_manager *man; |
| 1633 | 1467 | ||
| 1634 | while (i--) { | 1468 | man = ttm_manager_type(bdev, TTM_PL_SYSTEM); |
| 1635 | man = &bdev->man[i]; | 1469 | ttm_resource_manager_set_used(man, false); |
| 1636 | if (man->has_type) { | 1470 | ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, NULL); |
| 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 | } | ||
| 1646 | 1471 | ||
| 1647 | mutex_lock(&ttm_global_mutex); | 1472 | mutex_lock(&ttm_global_mutex); |
| 1648 | list_del(&bdev->device_list); | 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 | spin_lock(&glob->lru_lock); | 1481 | spin_lock(&glob->lru_lock); |
| 1657 | for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) | 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 | pr_debug("Swap list %d was clean\n", i); | 1484 | pr_debug("Swap list %d was clean\n", i); |
| 1660 | spin_unlock(&glob->lru_lock); | 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 | EXPORT_SYMBOL(ttm_bo_device_release); | 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 | int ttm_bo_device_init(struct ttm_bo_device *bdev, | 1511 | int ttm_bo_device_init(struct ttm_bo_device *bdev, |
| 1670 | struct ttm_bo_driver *driver, | 1512 | struct ttm_bo_driver *driver, |
| 1671 | struct address_space *mapping, | 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 | bdev->driver = driver; | 1527 | bdev->driver = driver; |
| 1686 | 1528 | ||
| 1687 | memset(bdev->man, 0, sizeof(bdev->man)); | 1529 | ttm_bo_init_sysman(bdev); |
| 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; | ||
| 1696 | 1530 | ||
| 1697 | bdev->vma_manager = vma_manager; | 1531 | bdev->vma_manager = vma_manager; |
| 1698 | INIT_DELAYED_WORK(&bdev->wq, ttm_bo_delayed_workqueue); | 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 | mutex_unlock(&ttm_global_mutex); | 1538 | mutex_unlock(&ttm_global_mutex); |
| 1705 | 1539 | ||
| 1706 | return 0; | 1540 | return 0; |
| 1707 | out_no_sys: | ||
| 1708 | ttm_bo_global_release(); | ||
| 1709 | return ret; | ||
| 1710 | } | 1541 | } |
| 1711 | EXPORT_SYMBOL(ttm_bo_device_init); | 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 | void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo) | 1556 | void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo) |
| 1726 | { | 1557 | { |
| 1727 | struct ttm_bo_device *bdev = bo->bdev; | 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 | ttm_mem_io_lock(man, false); | 1561 | ttm_mem_io_lock(man, false); |
| 1731 | ttm_bo_unmap_virtual_locked(bo); | 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 | if (bo->mem.mem_type != TTM_PL_SYSTEM || | 1643 | if (bo->mem.mem_type != TTM_PL_SYSTEM || |
| 1813 | bo->ttm->caching_state != tt_cached) { | 1644 | bo->ttm->caching_state != tt_cached) { |
| 1814 | struct ttm_operation_ctx ctx = { false, false }; | 1645 | struct ttm_operation_ctx ctx = { false, false }; |
| 1815 | struct ttm_mem_reg evict_mem; | 1646 | struct ttm_resource evict_mem; |
| 1816 | 1647 | ||
| 1817 | evict_mem = bo->mem; | 1648 | evict_mem = bo->mem; |
| 1818 | evict_mem.mm_node = NULL; | 1649 | evict_mem.mm_node = NULL; |
| @@ -47,15 +47,15 @@ struct ttm_transfer_obj { · 46 unmodified lines | |||
| 47 | 47 | ||
| 48 | void ttm_bo_free_old_node(struct ttm_buffer_object *bo) | 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 | int ttm_bo_move_ttm(struct ttm_buffer_object *bo, | 53 | int ttm_bo_move_ttm(struct ttm_buffer_object *bo, |
| 54 | struct ttm_operation_ctx *ctx, | 54 | struct ttm_operation_ctx *ctx, |
| 55 | struct ttm_mem_reg *new_mem) | 55 | struct ttm_resource *new_mem) |
| 56 | { | 56 | { |
| 57 | struct ttm_tt *ttm = bo->ttm; | 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 | int ret; | 59 | int ret; |
| 60 | 60 | ||
| 61 | if (old_mem->mem_type != TTM_PL_SYSTEM) { | 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 | EXPORT_SYMBOL(ttm_bo_move_ttm); | 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 | if (likely(!man->use_io_reserve_lru)) | 96 | if (likely(!man->use_io_reserve_lru)) |
| 97 | return 0; | 97 | return 0; |
| @@ -103,7 +103,7 @@ int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible) · 5 unmodified lines | |||
| 103 | return 0; | 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 | if (likely(!man->use_io_reserve_lru)) | 108 | if (likely(!man->use_io_reserve_lru)) |
| 109 | return; | 109 | return; |
| @@ -111,7 +111,7 @@ void ttm_mem_io_unlock(struct ttm_mem_type_manager *man) · 1 unmodified line | |||
| 111 | mutex_unlock(&man->io_reserve_mutex); | 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 | struct ttm_buffer_object *bo; | 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 | int ttm_mem_io_reserve(struct ttm_bo_device *bdev, | 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 | int ret; | 133 | int ret; |
| 134 | 134 | ||
| 135 | if (mem->bus.io_reserved_count++) | 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 | if (!bdev->driver->io_mem_reserve) | 138 | if (!bdev->driver->io_mem_reserve) |
| 139 | return 0; | 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 | retry: | 145 | retry: |
| 142 | ret = bdev->driver->io_mem_reserve(bdev, mem); | 146 | ret = bdev->driver->io_mem_reserve(bdev, mem); |
| 143 | if (ret == -ENOSPC) { | 147 | if (ret == -ENOSPC) { |
| @@ -149,7 +153,7 @@ retry: · 5 unmodified lines | |||
| 149 | } | 153 | } |
| 150 | 154 | ||
| 151 | void ttm_mem_io_free(struct ttm_bo_device *bdev, | 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 | if (--mem->bus.io_reserved_count) | 158 | if (--mem->bus.io_reserved_count) |
| 155 | return; | 159 | return; |
| @@ -162,8 +166,8 @@ void ttm_mem_io_free(struct ttm_bo_device *bdev, · 6 unmodified lines | |||
| 162 | 166 | ||
| 163 | int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo) | 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]; | 169 | struct ttm_resource_manager *man = ttm_manager_type(bo->bdev, bo->mem.mem_type); |
| 166 | struct ttm_mem_reg *mem = &bo->mem; | 170 | struct ttm_resource *mem = &bo->mem; |
| 167 | int ret; | 171 | int ret; |
| 168 | 172 | ||
| 169 | if (mem->bus.io_reserved_vm) | 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 | void ttm_mem_io_free_vm(struct ttm_buffer_object *bo) | 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 | if (!mem->bus.io_reserved_vm) | 190 | if (!mem->bus.io_reserved_vm) |
| 187 | return; | 191 | return; |
| @@ -191,11 +195,11 @@ void ttm_mem_io_free_vm(struct ttm_buffer_object *bo) · 3 unmodified lines | |||
| 191 | ttm_mem_io_free(bo->bdev, mem); | 195 | ttm_mem_io_free(bo->bdev, mem); |
| 192 | } | 196 | } |
| 193 | 197 | ||
| 194 | static int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, | 198 | static int ttm_resource_ioremap(struct ttm_bo_device *bdev, |
| 195 | struct ttm_mem_reg *mem, | 199 | struct ttm_resource *mem, |
| 196 | void **virtual) | 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 | int ret; | 203 | int ret; |
| 200 | void *addr; | 204 | void *addr; |
| 201 | 205 | ||
| @@ -209,12 +213,14 @@ static int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, · 7 unmodified lines | |||
| 209 | if (mem->bus.addr) { | 213 | if (mem->bus.addr) { |
| 210 | addr = mem->bus.addr; | 214 | addr = mem->bus.addr; |
| 211 | } else { | 215 | } else { |
| 216 | size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT; | ||
| 217 | |||
| 212 | if (mem->placement & TTM_PL_FLAG_WC) | 218 | if (mem->placement & TTM_PL_FLAG_WC) |
| 213 | addr = ioremap_wc(mem->bus.base + mem->bus.offset, | 219 | addr = ioremap_wc(mem->bus.base + mem->bus.offset, |
| 214 | mem->bus.size); | 220 | bus_size); |
| 215 | else | 221 | else |
| 216 | addr = ioremap(mem->bus.base + mem->bus.offset, | 222 | addr = ioremap(mem->bus.base + mem->bus.offset, |
| 217 | mem->bus.size); | 223 | bus_size); |
| 218 | if (!addr) { | 224 | if (!addr) { |
| 219 | (void) ttm_mem_io_lock(man, false); | 225 | (void) ttm_mem_io_lock(man, false); |
| 220 | ttm_mem_io_free(bdev, mem); | 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 | return 0; | 232 | return 0; |
| 227 | } | 233 | } |
| 228 | 234 | ||
| 229 | static void ttm_mem_reg_iounmap(struct ttm_bo_device *bdev, | 235 | static void ttm_resource_iounmap(struct ttm_bo_device *bdev, |
| 230 | struct ttm_mem_reg *mem, | 236 | struct ttm_resource *mem, |
| 231 | void *virtual) | 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 | if (virtual && mem->bus.addr == NULL) | 243 | if (virtual && mem->bus.addr == NULL) |
| 238 | iounmap(virtual); | 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 | int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, | 307 | int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, |
| 302 | struct ttm_operation_ctx *ctx, | 308 | struct ttm_operation_ctx *ctx, |
| 303 | struct ttm_mem_reg *new_mem) | 309 | struct ttm_resource *new_mem) |
| 304 | { | 310 | { |
| 305 | struct ttm_bo_device *bdev = bo->bdev; | 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 | struct ttm_tt *ttm = bo->ttm; | 313 | struct ttm_tt *ttm = bo->ttm; |
| 308 | struct ttm_mem_reg *old_mem = &bo->mem; | 314 | struct ttm_resource *old_mem = &bo->mem; |
| 309 | struct ttm_mem_reg old_copy = *old_mem; | 315 | struct ttm_resource old_copy = *old_mem; |
| 310 | void *old_iomap; | 316 | void *old_iomap; |
| 311 | void *new_iomap; | 317 | void *new_iomap; |
| 312 | int ret; | 318 | int ret; |
| @@ -319,10 +325,10 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, · 6 unmodified lines | |||
| 319 | if (ret) | 325 | if (ret) |
| 320 | return ret; | 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 | if (ret) | 329 | if (ret) |
| 324 | return ret; | 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 | if (ret) | 332 | if (ret) |
| 327 | goto out; | 333 | goto out; |
| 328 | 334 | ||
| @@ -384,21 +390,21 @@ out2: · 55 unmodified lines | |||
| 384 | *old_mem = *new_mem; | 390 | *old_mem = *new_mem; |
| 385 | new_mem->mm_node = NULL; | 391 | new_mem->mm_node = NULL; |
| 386 | 392 | ||
| 387 | if (man->flags & TTM_MEMTYPE_FLAG_FIXED) { | 393 | if (!man->use_tt) { |
| 388 | ttm_tt_destroy(ttm); | 394 | ttm_tt_destroy(ttm); |
| 389 | bo->ttm = NULL; | 395 | bo->ttm = NULL; |
| 390 | } | 396 | } |
| 391 | 397 | ||
| 392 | out1: | 398 | out1: |
| 393 | ttm_mem_reg_iounmap(bdev, old_mem, new_iomap); | 399 | ttm_resource_iounmap(bdev, old_mem, new_iomap); |
| 394 | out: | 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 | * On error, keep the mm node! | 404 | * On error, keep the mm node! |
| 399 | */ | 405 | */ |
| 400 | if (!ret) | 406 | if (!ret) |
| 401 | ttm_bo_mem_put(bo, &old_copy); | 407 | ttm_resource_free(bo, &old_copy); |
| 402 | return ret; | 408 | return ret; |
| 403 | } | 409 | } |
| 404 | EXPORT_SYMBOL(ttm_bo_move_memcpy); | 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 | unsigned long size, | 508 | unsigned long size, |
| 503 | struct ttm_bo_kmap_obj *map) | 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 | if (bo->mem.bus.addr) { | 513 | if (bo->mem.bus.addr) { |
| 508 | map->bo_kmap_type = ttm_bo_map_premapped; | 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 | unsigned long num_pages, | 532 | unsigned long num_pages, |
| 527 | struct ttm_bo_kmap_obj *map) | 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 | struct ttm_operation_ctx ctx = { | 536 | struct ttm_operation_ctx ctx = { |
| 531 | .interruptible = false, | 537 | .interruptible = false, |
| 532 | .no_wait_gpu = false | 538 | .no_wait_gpu = false |
| @@ -567,8 +573,8 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo, · 34 unmodified lines | |||
| 567 | unsigned long start_page, unsigned long num_pages, | 573 | unsigned long start_page, unsigned long num_pages, |
| 568 | struct ttm_bo_kmap_obj *map) | 574 | struct ttm_bo_kmap_obj *map) |
| 569 | { | 575 | { |
| 570 | struct ttm_mem_type_manager *man = | 576 | struct ttm_resource_manager *man = |
| 571 | &bo->bdev->man[bo->mem.mem_type]; | 577 | ttm_manager_type(bo->bdev, bo->mem.mem_type); |
| 572 | unsigned long offset, size; | 578 | unsigned long offset, size; |
| 573 | int ret; | 579 | int ret; |
| 574 | 580 | ||
| @@ -597,8 +603,8 @@ EXPORT_SYMBOL(ttm_bo_kmap); · 22 unmodified lines | |||
| 597 | void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map) | 603 | void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map) |
| 598 | { | 604 | { |
| 599 | struct ttm_buffer_object *bo = map->bo; | 605 | struct ttm_buffer_object *bo = map->bo; |
| 600 | struct ttm_mem_type_manager *man = | 606 | struct ttm_resource_manager *man = |
| 601 | &bo->bdev->man[bo->mem.mem_type]; | 607 | ttm_manager_type(bo->bdev, bo->mem.mem_type); |
| 602 | 608 | ||
| 603 | if (!map->virtual) | 609 | if (!map->virtual) |
| 604 | return; | 610 | return; |
| @@ -628,11 +634,11 @@ EXPORT_SYMBOL(ttm_bo_kunmap); · 23 unmodified lines | |||
| 628 | int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, | 634 | int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, |
| 629 | struct dma_fence *fence, | 635 | struct dma_fence *fence, |
| 630 | bool evict, | 636 | bool evict, |
| 631 | struct ttm_mem_reg *new_mem) | 637 | struct ttm_resource *new_mem) |
| 632 | { | 638 | { |
| 633 | struct ttm_bo_device *bdev = bo->bdev; | 639 | struct ttm_bo_device *bdev = bo->bdev; |
| 634 | struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type]; | 640 | struct ttm_resource_manager *man = ttm_manager_type(bdev, new_mem->mem_type); |
| 635 | struct ttm_mem_reg *old_mem = &bo->mem; | 641 | struct ttm_resource *old_mem = &bo->mem; |
| 636 | int ret; | 642 | int ret; |
| 637 | struct ttm_buffer_object *ghost_obj; | 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 | if (ret) | 648 | if (ret) |
| 643 | return ret; | 649 | return ret; |
| 644 | 650 | ||
| 645 | if (man->flags & TTM_MEMTYPE_FLAG_FIXED) { | 651 | if (!man->use_tt) { |
| 646 | ttm_tt_destroy(bo->ttm); | 652 | ttm_tt_destroy(bo->ttm); |
| 647 | bo->ttm = NULL; | 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 | * bo to be unbound and destroyed. | 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 | ghost_obj->ttm = NULL; | 681 | ghost_obj->ttm = NULL; |
| 676 | else | 682 | else |
| 677 | bo->ttm = NULL; | 683 | bo->ttm = NULL; |
| @@ -689,13 +695,13 @@ EXPORT_SYMBOL(ttm_bo_move_accel_cleanup); · 11 unmodified lines | |||
| 689 | 695 | ||
| 690 | int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, | 696 | int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, |
| 691 | struct dma_fence *fence, bool evict, | 697 | struct dma_fence *fence, bool evict, |
| 692 | struct ttm_mem_reg *new_mem) | 698 | struct ttm_resource *new_mem) |
| 693 | { | 699 | { |
| 694 | struct ttm_bo_device *bdev = bo->bdev; | 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]; | 703 | struct ttm_resource_manager *from = ttm_manager_type(bdev, old_mem->mem_type); |
| 698 | struct ttm_mem_type_manager *to = &bdev->man[new_mem->mem_type]; | 704 | struct ttm_resource_manager *to = ttm_manager_type(bdev, new_mem->mem_type); |
| 699 | 705 | ||
| 700 | int ret; | 706 | int ret; |
| 701 | 707 | ||
| @@ -727,7 +733,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, · 25 unmodified lines | |||
| 727 | * bo to be unbound and destroyed. | 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 | ghost_obj->ttm = NULL; | 737 | ghost_obj->ttm = NULL; |
| 732 | else | 738 | else |
| 733 | bo->ttm = NULL; | 739 | bo->ttm = NULL; |
| @@ -735,7 +741,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, · 1 unmodified line | |||
| 735 | dma_resv_unlock(&ghost_obj->base._resv); | 741 | dma_resv_unlock(&ghost_obj->base._resv); |
| 736 | ttm_bo_put(ghost_obj); | 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 | * BO doesn't have a TTM we need to bind/unbind. Just remember | 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 | if (ret) | 771 | if (ret) |
| 766 | return ret; | 772 | return ret; |
| 767 | 773 | ||
| 768 | if (to->flags & TTM_MEMTYPE_FLAG_FIXED) { | 774 | if (!to->use_tt) { |
| 769 | ttm_tt_destroy(bo->ttm); | 775 | ttm_tt_destroy(bo->ttm); |
| 770 | bo->ttm = NULL; | 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 | pgoff_t i; | 281 | pgoff_t i; |
| 282 | vm_fault_t ret = VM_FAULT_NOPAGE; | 282 | vm_fault_t ret = VM_FAULT_NOPAGE; |
| 283 | unsigned long address = vmf->address; | 283 | unsigned long address = vmf->address; |
| 284 | struct ttm_mem_type_manager *man = | 284 | struct ttm_resource_manager *man = |
| 285 | &bdev->man[bo->mem.mem_type]; | 285 | ttm_manager_type(bdev, bo->mem.mem_type); |
| 286 | 286 | ||
| 287 | /* | 287 | /* |
| 288 | * Refuse to fault imported pages. This should be handled | 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 | if (bo->moving != moving) { | 310 | if (bo->moving != moving) { |
| 311 | spin_lock(&ttm_bo_glob.lru_lock); | 311 | ttm_bo_move_to_lru_tail_unlocked(bo); |
| 312 | ttm_bo_move_to_lru_tail(bo, NULL); | ||
| 313 | spin_unlock(&ttm_bo_glob.lru_lock); | ||
| 314 | } | 312 | } |
| 315 | dma_fence_put(moving); | 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 | list_for_each_entry(entry, list, head) { | 93 | list_for_each_entry(entry, list, head) { |
| 94 | struct ttm_buffer_object *bo = entry->bo; | 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 | if (ret == -EALREADY && dups) { | 97 | if (ret == -EALREADY && dups) { |
| 98 | struct ttm_validate_buffer *safe = entry; | 98 | struct ttm_validate_buffer *safe = entry; |
| 99 | entry = list_prev_entry(entry, head); | 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 | ttm_eu_backoff_reservation_reverse(list, entry); | 119 | ttm_eu_backoff_reservation_reverse(list, entry); |
| 120 | 120 | ||
| 121 | if (ret == -EDEADLK) { | 121 | if (ret == -EDEADLK) { |
| 122 | if (intr) { | 122 | ret = ttm_bo_reserve_slowpath(bo, intr, ticket); |
| 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 | } | ||
| 129 | } | 123 | } |
| 130 | 124 | ||
| 131 | if (!ret && entry->num_shared) | 125 | if (!ret && entry->num_shared) |
| @@ -133,8 +127,6 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, · 1 unmodified line | |||
| 133 | entry->num_shared); | 127 | entry->num_shared); |
| 134 | 128 | ||
| 135 | if (unlikely(ret != 0)) { | 129 | if (unlikely(ret != 0)) { |
| 136 | if (ret == -EINTR) | ||
| 137 | ret = -ERESTARTSYS; | ||
| 138 | if (ticket) { | 130 | if (ticket) { |
| 139 | ww_acquire_done(ticket); | 131 | ww_acquire_done(ticket); |
| 140 | ww_acquire_fini(ticket); | 132 | ww_acquire_fini(ticket); |
| @@ -44,16 +44,22 @@ · 43 unmodified lines | |||
| 44 | */ | 44 | */ |
| 45 | 45 | ||
| 46 | struct ttm_range_manager { | 46 | struct ttm_range_manager { |
| 47 | struct ttm_resource_manager manager; | ||
| 47 | struct drm_mm mm; | 48 | struct drm_mm mm; |
| 48 | spinlock_t lock; | 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 | struct ttm_buffer_object *bo, | 58 | struct ttm_buffer_object *bo, |
| 53 | const struct ttm_place *place, | 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 | struct drm_mm *mm = &rman->mm; | 63 | struct drm_mm *mm = &rman->mm; |
| 58 | struct drm_mm_node *node; | 64 | struct drm_mm_node *node; |
| 59 | enum drm_mm_insert_mode mode; | 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 | return ret; | 95 | return ret; |
| 90 | } | 96 | } |
| 91 | 97 | ||
| 92 | static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man, | 98 | static void ttm_range_man_free(struct ttm_resource_manager *man, |
| 93 | struct ttm_mem_reg *mem) | 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 | if (mem->mm_node) { | 103 | if (mem->mm_node) { |
| 98 | spin_lock(&rman->lock); | 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, | 113 | static const struct ttm_resource_manager_func ttm_range_manager_func; |
| 108 | unsigned long p_size) | 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 | struct ttm_range_manager *rman; | 123 | struct ttm_range_manager *rman; |
| 111 | 124 | ||
| 112 | rman = kzalloc(sizeof(*rman), GFP_KERNEL); | 125 | rman = kzalloc(sizeof(*rman), GFP_KERNEL); |
| 113 | if (!rman) | 126 | if (!rman) |
| 114 | return -ENOMEM; | 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 | drm_mm_init(&rman->mm, 0, p_size); | 138 | drm_mm_init(&rman->mm, 0, p_size); |
| 117 | spin_lock_init(&rman->lock); | 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 | return 0; | 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 | struct drm_mm *mm = &rman->mm; | 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 | spin_lock(&rman->lock); | 161 | spin_lock(&rman->lock); |
| 128 | if (drm_mm_clean(mm)) { | 162 | drm_mm_clean(mm); |
| 129 | drm_mm_takedown(mm); | 163 | drm_mm_takedown(mm); |
| 130 | spin_unlock(&rman->lock); | ||
| 131 | kfree(rman); | ||
| 132 | man->priv = NULL; | ||
| 133 | return 0; | ||
| 134 | } | ||
| 135 | spin_unlock(&rman->lock); | 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, | 173 | static void ttm_range_man_debug(struct ttm_resource_manager *man, |
| 140 | struct drm_printer *printer) | 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 | spin_lock(&rman->lock); | 178 | spin_lock(&rman->lock); |
| 145 | drm_mm_print(&rman->mm, printer); | 179 | drm_mm_print(&rman->mm, printer); |
| 146 | spin_unlock(&rman->lock); | 180 | spin_unlock(&rman->lock); |
| 147 | } | 181 | } |
| 148 | 182 | ||
| 149 | const struct ttm_mem_type_manager_func ttm_bo_manager_func = { | 183 | static const struct ttm_resource_manager_func ttm_range_manager_func = { |
| 150 | .init = ttm_bo_man_init, | 184 | .alloc = ttm_range_man_alloc, |
| 151 | .takedown = ttm_bo_man_takedown, | 185 | .free = ttm_range_man_free, |
| 152 | .get_node = ttm_bo_man_get_node, | 186 | .debug = ttm_range_man_debug |
| 153 | .put_node = ttm_bo_man_put_node, | ||
| 154 | .debug = ttm_bo_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 | dma_resv_assert_held(bo->base.resv); | 51 | dma_resv_assert_held(bo->base.resv); |
| 52 | 52 | ||
| 53 | if (bo->ttm) | ||
| 54 | return 0; | ||
| 55 | |||
| 53 | if (bdev->need_dma32) | 56 | if (bdev->need_dma32) |
| 54 | page_flags |= TTM_PAGE_FLAG_DMA32; | 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 | page_flags |= TTM_PAGE_FLAG_SG; | 70 | page_flags |= TTM_PAGE_FLAG_SG; |
| 68 | break; | 71 | break; |
| 69 | default: | 72 | default: |
| 70 | bo->ttm = NULL; | ||
| 71 | pr_err("Illegal buffer object type\n"); | 73 | pr_err("Illegal buffer object type\n"); |
| 72 | return -EINVAL; | 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 | struct ttm_operation_ctx *ctx) | 320 | struct ttm_operation_ctx *ctx) |
| 319 | { | 321 | { |
| 320 | int ret = 0; | 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) | 361 | module_platform_driver(v3d_platform_driver); |
| 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); | ||
| 373 | 362 | ||
| 374 | MODULE_ALIAS("platform:v3d-drm"); | 363 | MODULE_ALIAS("platform:v3d-drm"); |
| 375 | MODULE_DESCRIPTION("Broadcom V3D DRM Driver"); | 364 | MODULE_DESCRIPTION("Broadcom V3D DRM Driver"); |
| @@ -471,8 +471,8 @@ static int __init vgem_init(void) · 470 unmodified lines | |||
| 471 | 471 | ||
| 472 | out_put: | 472 | out_put: |
| 473 | drm_dev_put(&vgem_device->drm); | 473 | drm_dev_put(&vgem_device->drm); |
| 474 | platform_device_unregister(vgem_device->platform); | ||
| 474 | return ret; | 475 | return ret; |
| 475 | |||
| 476 | out_unregister: | 476 | out_unregister: |
| 477 | platform_device_unregister(vgem_device->platform); | 477 | platform_device_unregister(vgem_device->platform); |
| 478 | out_free: | 478 | out_free: |
| @@ -4,6 +4,7 @@ config DRM_VIRTIO_GPU · 3 unmodified lines | |||
| 4 | depends on DRM && VIRTIO && MMU | 4 | depends on DRM && VIRTIO && MMU |
| 5 | select DRM_KMS_HELPER | 5 | select DRM_KMS_HELPER |
| 6 | select DRM_GEM_SHMEM_HELPER | 6 | select DRM_GEM_SHMEM_HELPER |
| 7 | select VIRTIO_DMA_SHARED_BUFFER | ||
| 7 | help | 8 | help |
| 8 | This is the virtual GPU driver for virtio. It can be used with | 9 | This is the virtual GPU driver for virtio. It can be used with |
| 9 | QEMU based VMMs (like KVM or Xen). | 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 | count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX); | 165 | count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX); |
| 166 | 166 | ||
| 167 | if (width == 0 || height == 0) { | 167 | if (width == 0 || height == 0) { |
| 168 | width = XRES_DEF; | ||
| 169 | height = YRES_DEF; | ||
| 170 | drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF); | 168 | drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF); |
| 171 | } else { | 169 | } else { |
| 172 | DRM_DEBUG("add mode: %dx%d\n", width, height); | 170 | DRM_DEBUG("add mode: %dx%d\n", width, height); |
| @@ -165,6 +165,7 @@ static unsigned int features[] = { · 164 unmodified lines | |||
| 165 | VIRTIO_GPU_F_VIRGL, | 165 | VIRTIO_GPU_F_VIRGL, |
| 166 | #endif | 166 | #endif |
| 167 | VIRTIO_GPU_F_EDID, | 167 | VIRTIO_GPU_F_EDID, |
| 168 | VIRTIO_GPU_F_RESOURCE_UUID, | ||
| 168 | }; | 169 | }; |
| 169 | static struct virtio_driver virtio_gpu_driver = { | 170 | static struct virtio_driver virtio_gpu_driver = { |
| 170 | .feature_table = features, | 171 | .feature_table = features, |
| @@ -202,6 +203,8 @@ static struct drm_driver driver = { · 31 unmodified lines | |||
| 202 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | 203 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, |
| 203 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | 204 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, |
| 204 | .gem_prime_mmap = drm_gem_prime_mmap, | 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 | .gem_prime_import_sg_table = virtgpu_gem_prime_import_sg_table, | 208 | .gem_prime_import_sg_table = virtgpu_gem_prime_import_sg_table, |
| 206 | 209 | ||
| 207 | .gem_create_object = virtio_gpu_create_object, | 210 | .gem_create_object = virtio_gpu_create_object, |
| @@ -49,6 +49,10 @@ · 48 unmodified lines | |||
| 49 | #define DRIVER_MINOR 1 | 49 | #define DRIVER_MINOR 1 |
| 50 | #define DRIVER_PATCHLEVEL 0 | 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 | struct virtio_gpu_object_params { | 56 | struct virtio_gpu_object_params { |
| 53 | uint32_t format; | 57 | uint32_t format; |
| 54 | uint32_t width; | 58 | uint32_t width; |
| @@ -71,6 +75,9 @@ struct virtio_gpu_object { · 16 unmodified lines | |||
| 71 | uint32_t hw_res_handle; | 75 | uint32_t hw_res_handle; |
| 72 | bool dumb; | 76 | bool dumb; |
| 73 | bool created; | 77 | bool created; |
| 78 | |||
| 79 | int uuid_state; | ||
| 80 | uuid_t uuid; | ||
| 74 | }; | 81 | }; |
| 75 | #define gem_to_virtio_gpu_obj(gobj) \ | 82 | #define gem_to_virtio_gpu_obj(gobj) \ |
| 76 | container_of((gobj), struct virtio_gpu_object, base.base) | 83 | container_of((gobj), struct virtio_gpu_object, base.base) |
| @@ -200,6 +207,7 @@ struct virtio_gpu_device { · 123 unmodified lines | |||
| 200 | bool has_virgl_3d; | 207 | bool has_virgl_3d; |
| 201 | bool has_edid; | 208 | bool has_edid; |
| 202 | bool has_indirect; | 209 | bool has_indirect; |
| 210 | bool has_resource_assign_uuid; | ||
| 203 | 211 | ||
| 204 | struct work_struct config_changed_work; | 212 | struct work_struct config_changed_work; |
| 205 | 213 | ||
| @@ -210,6 +218,9 @@ struct virtio_gpu_device { · 4 unmodified lines | |||
| 210 | struct virtio_gpu_drv_capset *capsets; | 218 | struct virtio_gpu_drv_capset *capsets; |
| 211 | uint32_t num_capsets; | 219 | uint32_t num_capsets; |
| 212 | struct list_head cap_cache; | 220 | struct list_head cap_cache; |
| 221 | |||
| 222 | /* protects resource state when exporting */ | ||
| 223 | spinlock_t resource_export_lock; | ||
| 213 | }; | 224 | }; |
| 214 | 225 | ||
| 215 | struct virtio_gpu_fpriv { | 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 | void virtio_gpu_notify(struct virtio_gpu_device *vgdev); | 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 | /* virtgpu_display.c */ | 354 | /* virtgpu_display.c */ |
| 340 | void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev); | 355 | void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev); |
| 341 | void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev); | 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 | bool virtio_gpu_is_shmem(struct virtio_gpu_object *bo); | 382 | bool virtio_gpu_is_shmem(struct virtio_gpu_object *bo); |
| 368 | 383 | ||
| 369 | /* virtgpu_prime.c */ | 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 | struct drm_gem_object *virtgpu_gem_prime_import_sg_table( | 391 | struct drm_gem_object *virtgpu_gem_prime_import_sg_table( |
| 371 | struct drm_device *dev, struct dma_buf_attachment *attach, | 392 | struct drm_device *dev, struct dma_buf_attachment *attach, |
| 372 | struct sg_table *sgt); | 393 | struct sg_table *sgt); |
| @@ -154,9 +154,8 @@ void virtio_gpu_gem_object_close(struct drm_gem_object *obj, · 153 unmodified lines | |||
| 154 | struct virtio_gpu_object_array *virtio_gpu_array_alloc(u32 nents) | 154 | struct virtio_gpu_object_array *virtio_gpu_array_alloc(u32 nents) |
| 155 | { | 155 | { |
| 156 | struct virtio_gpu_object_array *objs; | 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 | if (!objs) | 159 | if (!objs) |
| 161 | return NULL; | 160 | return NULL; |
| 162 | 161 | ||
| @@ -118,6 +118,7 @@ int virtio_gpu_init(struct drm_device *dev) · 117 unmodified lines | |||
| 118 | vgdev->dev = dev->dev; | 118 | vgdev->dev = dev->dev; |
| 119 | 119 | ||
| 120 | spin_lock_init(&vgdev->display_info_lock); | 120 | spin_lock_init(&vgdev->display_info_lock); |
| 121 | spin_lock_init(&vgdev->resource_export_lock); | ||
| 121 | ida_init(&vgdev->ctx_id_ida); | 122 | ida_init(&vgdev->ctx_id_ida); |
| 122 | ida_init(&vgdev->resource_ida); | 123 | ida_init(&vgdev->resource_ida); |
| 123 | init_waitqueue_head(&vgdev->resp_wq); | 124 | init_waitqueue_head(&vgdev->resp_wq); |
| @@ -146,6 +147,9 @@ int virtio_gpu_init(struct drm_device *dev) · 22 unmodified lines | |||
| 146 | if (virtio_has_feature(vgdev->vdev, VIRTIO_RING_F_INDIRECT_DESC)) { | 147 | if (virtio_has_feature(vgdev->vdev, VIRTIO_RING_F_INDIRECT_DESC)) { |
| 147 | vgdev->has_indirect = true; | 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 | DRM_INFO("features: %cvirgl %cedid\n", | 154 | DRM_INFO("features: %cvirgl %cedid\n", |
| 151 | vgdev->has_virgl_3d ? '+' : '-', | 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 | if (ret < 0) | 151 | if (ret < 0) |
| 152 | return -EINVAL; | 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 | if (!shmem->pages) { | 161 | if (!shmem->pages) { |
| 156 | drm_gem_shmem_unpin(&bo->base.base); | 162 | drm_gem_shmem_unpin(&bo->base.base); |
| 157 | return -EINVAL; | 163 | return -EINVAL; |
| @@ -23,12 +23,102 @@ · 22 unmodified lines | |||
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #include <drm/drm_prime.h> | 25 | #include <drm/drm_prime.h> |
| 26 | #include <linux/virtio_dma_buf.h> | ||
| 26 | 27 | ||
| 27 | #include "virtgpu_drv.h" | 28 | #include "virtgpu_drv.h" |
| 28 | 29 | ||
| 29 | /* Empty Implementations as there should not be any other driver for a virtual | 30 | static int virtgpu_virtio_get_uuid(struct dma_buf *buf, |
| 30 | * device that might share buffers with virtgpu | 31 | uuid_t *uuid) |
| 31 | */ | 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 | struct drm_gem_object *virtgpu_gem_prime_import_sg_table( | 123 | struct drm_gem_object *virtgpu_gem_prime_import_sg_table( |
| 34 | struct drm_device *dev, struct dma_buf_attachment *attach, | 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 | memcpy(cur_p, &output->cursor, sizeof(output->cursor)); | 1107 | memcpy(cur_p, &output->cursor, sizeof(output->cursor)); |
| 1108 | virtio_gpu_queue_cursor(vgdev, vbuf); | 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 | + (i * composer->pitch) | 33 | + (i * composer->pitch) |
| 34 | + (j * composer->cpp); | 34 | + (j * composer->cpp); |
| 35 | /* XRGB format ignores Alpha channel */ | 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 | crc = crc32_le(crc, vaddr_out + src_offset, | 37 | crc = crc32_le(crc, vaddr_out + src_offset, |
| 38 | sizeof(u32)); | 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 | return 0; | 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 | int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name) | 252 | int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name) |
| 237 | { | 253 | { |
| 238 | struct vkms_output *out = drm_crtc_to_vkms_output(crtc); | 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 | ret = vkms_crc_parse_source(src_name, &enabled); | 258 | ret = vkms_crc_parse_source(src_name, &enabled); |
| 243 | 259 | ||
| 244 | spin_lock_irq(&out->lock); | 260 | vkms_set_composer(out, enabled); |
| 245 | out->composer_enabled = enabled; | ||
| 246 | spin_unlock_irq(&out->lock); | ||
| 247 | 261 | ||
| 248 | return ret; | 262 | return ret; |
| 249 | } | 263 | } |
| @@ -190,8 +190,8 @@ static int __init vkms_init(void) · 189 unmodified lines | |||
| 190 | 190 | ||
| 191 | out_put: | 191 | out_put: |
| 192 | drm_dev_put(&vkms_device->drm); | 192 | drm_dev_put(&vkms_device->drm); |
| 193 | platform_device_unregister(vkms_device->platform); | ||
| 193 | return ret; | 194 | return ret; |
| 194 | |||
| 195 | out_unregister: | 195 | out_unregister: |
| 196 | platform_device_unregister(vkms_device->platform); | 196 | platform_device_unregister(vkms_device->platform); |
| 197 | out_free: | 197 | out_free: |
| @@ -1135,14 +1135,14 @@ void vmw_bo_swap_notify(struct ttm_buffer_object *bo) · 1134 unmodified lines | |||
| 1135 | * vmw_bo_move_notify - TTM move_notify_callback | 1135 | * vmw_bo_move_notify - TTM move_notify_callback |
| 1136 | * | 1136 | * |
| 1137 | * @bo: The TTM buffer object about to move. | 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 | * region the move is taking place. | 1139 | * region the move is taking place. |
| 1140 | * | 1140 | * |
| 1141 | * Detaches cached maps and device bindings that require that the | 1141 | * Detaches cached maps and device bindings that require that the |
| 1142 | * buffer doesn't move. | 1142 | * buffer doesn't move. |
| 1143 | */ | 1143 | */ |
| 1144 | void vmw_bo_move_notify(struct ttm_buffer_object *bo, | 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 | struct vmw_buffer_object *vbo; | 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 | return ret; | 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 | static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) | 646 | static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) |
| 624 | { | 647 | { |
| 625 | struct vmw_private *dev_priv; | 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 | DRM_ERROR("Failed initializing TTM buffer object driver.\n"); | 882 | DRM_ERROR("Failed initializing TTM buffer object driver.\n"); |
| 860 | goto out_no_bdev; | 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 | * Enable VRAM, but initially don't use it until SVGA is enabled and | 889 | * Enable VRAM, but initially don't use it until SVGA is enabled and |
| 865 | * unhidden. | 890 | * unhidden. |
| 866 | */ | 891 | */ |
| 867 | ret = ttm_bo_init_mm(&dev_priv->bdev, TTM_PL_VRAM, | 892 | |
| 868 | (dev_priv->vram_size >> PAGE_SHIFT)); | 893 | ret = vmw_vram_manager_init(dev_priv); |
| 869 | if (unlikely(ret != 0)) { | 894 | if (unlikely(ret != 0)) { |
| 870 | DRM_ERROR("Failed initializing memory manager for VRAM.\n"); | 895 | DRM_ERROR("Failed initializing memory manager for VRAM.\n"); |
| 871 | goto out_no_vram; | 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 | dev_priv->has_gmr = true; | 904 | dev_priv->has_gmr = true; |
| 905 | /* TODO: This is most likely not correct */ | ||
| 876 | if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) || | 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, | 907 | refuse_dma || |
| 878 | VMW_PL_GMR) != 0) { | 908 | vmw_gmrid_man_init(dev_priv, VMW_PL_GMR) != 0) { |
| 879 | DRM_INFO("No GMR memory available. " | 909 | DRM_INFO("No GMR memory available. " |
| 880 | "Graphics memory resources are very limited.\n"); | 910 | "Graphics memory resources are very limited.\n"); |
| 881 | dev_priv->has_gmr = false; | 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 | if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS && !refuse_dma) { | 914 | if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS && !refuse_dma) { |
| 885 | dev_priv->has_mob = true; | 915 | dev_priv->has_mob = true; |
| 886 | if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_MOB, | 916 | |
| 887 | VMW_PL_MOB) != 0) { | 917 | if (vmw_gmrid_man_init(dev_priv, VMW_PL_MOB) != 0) { |
| 888 | DRM_INFO("No MOB memory available. " | 918 | DRM_INFO("No MOB memory available. " |
| 889 | "3D will be disabled.\n"); | 919 | "3D will be disabled.\n"); |
| 890 | dev_priv->has_mob = false; | 920 | dev_priv->has_mob = false; |
| @@ -961,10 +991,10 @@ out_no_fifo: · 70 unmodified lines | |||
| 961 | vmw_kms_close(dev_priv); | 991 | vmw_kms_close(dev_priv); |
| 962 | out_no_kms: | 992 | out_no_kms: |
| 963 | if (dev_priv->has_mob) | 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 | if (dev_priv->has_gmr) | 995 | if (dev_priv->has_gmr) |
| 966 | (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); | 996 | vmw_gmrid_man_fini(dev_priv, VMW_PL_GMR); |
| 967 | (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); | 997 | vmw_vram_manager_fini(dev_priv); |
| 968 | out_no_vram: | 998 | out_no_vram: |
| 969 | (void)ttm_bo_device_release(&dev_priv->bdev); | 999 | (void)ttm_bo_device_release(&dev_priv->bdev); |
| 970 | out_no_bdev: | 1000 | out_no_bdev: |
| @@ -1012,12 +1042,12 @@ static void vmw_driver_unload(struct drm_device *dev) · 41 unmodified lines | |||
| 1012 | vmw_overlay_close(dev_priv); | 1042 | vmw_overlay_close(dev_priv); |
| 1013 | 1043 | ||
| 1014 | if (dev_priv->has_gmr) | 1044 | if (dev_priv->has_gmr) |
| 1015 | (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); | 1045 | vmw_gmrid_man_fini(dev_priv, VMW_PL_GMR); |
| 1016 | (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); | ||
| 1017 | 1046 | ||
| 1018 | vmw_release_device_early(dev_priv); | 1047 | vmw_release_device_early(dev_priv); |
| 1019 | if (dev_priv->has_mob) | 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 | (void) ttm_bo_device_release(&dev_priv->bdev); | 1051 | (void) ttm_bo_device_release(&dev_priv->bdev); |
| 1022 | drm_vma_offset_manager_destroy(&dev_priv->vma_manager); | 1052 | drm_vma_offset_manager_destroy(&dev_priv->vma_manager); |
| 1023 | vmw_release_device_late(dev_priv); | 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 | static void __vmw_svga_enable(struct vmw_private *dev_priv) | 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 | spin_lock(&dev_priv->svga_lock); | 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 | vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE); | 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 | spin_unlock(&dev_priv->svga_lock); | 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 | static void __vmw_svga_disable(struct vmw_private *dev_priv) | 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 | spin_lock(&dev_priv->svga_lock); | 1225 | spin_lock(&dev_priv->svga_lock); |
| 1192 | if (dev_priv->bdev.man[TTM_PL_VRAM].use_type) { | 1226 | if (ttm_resource_manager_used(man)) { |
| 1193 | dev_priv->bdev.man[TTM_PL_VRAM].use_type = false; | 1227 | ttm_resource_manager_set_used(man, false); |
| 1194 | vmw_write(dev_priv, SVGA_REG_ENABLE, | 1228 | vmw_write(dev_priv, SVGA_REG_ENABLE, |
| 1195 | SVGA_REG_ENABLE_HIDE | | 1229 | SVGA_REG_ENABLE_HIDE | |
| 1196 | SVGA_REG_ENABLE_ENABLE); | 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 | void vmw_svga_disable(struct vmw_private *dev_priv) | 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 | * Disabling SVGA will turn off device modesetting capabilities, so | 1246 | * Disabling SVGA will turn off device modesetting capabilities, so |
| 1212 | * notify KMS about that so that it doesn't cache atomic state that | 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 | vmw_kms_lost_device(dev_priv->dev); | 1257 | vmw_kms_lost_device(dev_priv->dev); |
| 1223 | ttm_write_lock(&dev_priv->reservation_sem, false); | 1258 | ttm_write_lock(&dev_priv->reservation_sem, false); |
| 1224 | spin_lock(&dev_priv->svga_lock); | 1259 | spin_lock(&dev_priv->svga_lock); |
| 1225 | if (dev_priv->bdev.man[TTM_PL_VRAM].use_type) { | 1260 | if (ttm_resource_manager_used(man)) { |
| 1226 | dev_priv->bdev.man[TTM_PL_VRAM].use_type = false; | 1261 | ttm_resource_manager_set_used(man, false); |
| 1227 | spin_unlock(&dev_priv->svga_lock); | 1262 | spin_unlock(&dev_priv->svga_lock); |
| 1228 | if (ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM)) | 1263 | if (ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM)) |
| 1229 | DRM_ERROR("Failed evicting VRAM buffers.\n"); | 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 | struct vmw_buffer_object *new_backup, | 793 | struct vmw_buffer_object *new_backup, |
| 794 | unsigned long new_backup_offset); | 794 | unsigned long new_backup_offset); |
| 795 | extern void vmw_query_move_notify(struct ttm_buffer_object *bo, | 795 | extern void vmw_query_move_notify(struct ttm_buffer_object *bo, |
| 796 | struct ttm_mem_reg *mem); | 796 | struct ttm_resource *mem); |
| 797 | extern int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob); | 797 | extern int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob); |
| 798 | extern void vmw_resource_evict_all(struct vmw_private *dev_priv); | 798 | extern void vmw_resource_evict_all(struct vmw_private *dev_priv); |
| 799 | extern void vmw_resource_unbind_list(struct vmw_buffer_object *vbo); | 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 | extern void *vmw_bo_map_and_cache(struct vmw_buffer_object *vbo); | 878 | extern void *vmw_bo_map_and_cache(struct vmw_buffer_object *vbo); |
| 879 | extern void vmw_bo_unmap(struct vmw_buffer_object *vbo); | 879 | extern void vmw_bo_unmap(struct vmw_buffer_object *vbo); |
| 880 | extern void vmw_bo_move_notify(struct ttm_buffer_object *bo, | 880 | extern void vmw_bo_move_notify(struct ttm_buffer_object *bo, |
| 881 | struct ttm_mem_reg *mem); | 881 | struct ttm_resource *mem); |
| 882 | extern void vmw_bo_swap_notify(struct ttm_buffer_object *bo); | 882 | extern void vmw_bo_swap_notify(struct ttm_buffer_object *bo); |
| 883 | extern struct vmw_buffer_object * | 883 | extern struct vmw_buffer_object * |
| 884 | vmw_user_bo_noref_lookup(struct ttm_object_file *tfile, u32 handle); | 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 | extern struct ttm_placement vmw_mob_ne_placement; | 1019 | extern struct ttm_placement vmw_mob_ne_placement; |
| 1020 | extern struct ttm_placement vmw_nonfixed_placement; | 1020 | extern struct ttm_placement vmw_nonfixed_placement; |
| 1021 | extern struct ttm_bo_driver vmw_bo_driver; | 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 | extern const struct vmw_sg_table * | 1022 | extern const struct vmw_sg_table * |
| 1025 | vmw_bo_sg_table(struct ttm_buffer_object *bo); | 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 | extern void vmw_piter_start(struct vmw_piter *viter, | 1028 | extern void vmw_piter_start(struct vmw_piter *viter, |
| 1027 | const struct vmw_sg_table *vsgt, | 1029 | const struct vmw_sg_table *vsgt, |
| 1028 | unsigned long p_offs); | 1030 | unsigned long p_offs); |
| @@ -1219,7 +1221,8 @@ int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv); · 190 unmodified lines | |||
| 1219 | * GMR Id manager | 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 | * Prime - vmwgfx_prime.c | 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 | /* Transparent hugepage support - vmwgfx_thp.c */ | 1522 | /* Transparent hugepage support - vmwgfx_thp.c */ |
| 1520 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 1523 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
| 1521 | extern const struct ttm_mem_type_manager_func vmw_thp_func; | 1524 | extern int vmw_thp_init(struct vmw_private *dev_priv); |
| 1522 | #else | 1525 | void vmw_thp_fini(struct vmw_private *dev_priv); |
| 1523 | #define vmw_thp_func ttm_bo_manager_func | ||
| 1524 | #endif | 1526 | #endif |
| 1525 | 1527 | ||
| 1526 | /** | 1528 | /** |
| @@ -37,6 +37,7 @@ · 36 unmodified lines | |||
| 37 | #include <linux/kernel.h> | 37 | #include <linux/kernel.h> |
| 38 | 38 | ||
| 39 | struct vmwgfx_gmrid_man { | 39 | struct vmwgfx_gmrid_man { |
| 40 | struct ttm_resource_manager manager; | ||
| 40 | spinlock_t lock; | 41 | spinlock_t lock; |
| 41 | struct ida gmr_ida; | 42 | struct ida gmr_ida; |
| 42 | uint32_t max_gmr_ids; | 43 | uint32_t max_gmr_ids; |
| @@ -44,13 +45,17 @@ struct vmwgfx_gmrid_man { · 1 unmodified line | |||
| 44 | uint32_t used_gmr_pages; | 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 | struct ttm_buffer_object *bo, | 54 | struct ttm_buffer_object *bo, |
| 49 | const struct ttm_place *place, | 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 = | 58 | struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man); |
| 53 | (struct vmwgfx_gmrid_man *)man->priv; | ||
| 54 | int id; | 59 | int id; |
| 55 | 60 | ||
| 56 | id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL); | 61 | id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL); |
| @@ -79,11 +84,10 @@ nospace: · 22 unmodified lines | |||
| 79 | return -ENOSPC; | 84 | return -ENOSPC; |
| 80 | } | 85 | } |
| 81 | 86 | ||
| 82 | static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man, | 87 | static void vmw_gmrid_man_put_node(struct ttm_resource_manager *man, |
| 83 | struct ttm_mem_reg *mem) | 88 | struct ttm_resource *mem) |
| 84 | { | 89 | { |
| 85 | struct vmwgfx_gmrid_man *gman = | 90 | struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man); |
| 86 | (struct vmwgfx_gmrid_man *)man->priv; | ||
| 87 | 91 | ||
| 88 | if (mem->mm_node) { | 92 | if (mem->mm_node) { |
| 89 | ida_free(&gman->gmr_ida, mem->start); | 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, | 101 | static const struct ttm_resource_manager_func vmw_gmrid_manager_func; |
| 98 | unsigned long p_size) | 102 | |
| 103 | int vmw_gmrid_man_init(struct vmw_private *dev_priv, int type) | ||
| 99 | { | 104 | { |
| 100 | struct vmw_private *dev_priv = | 105 | struct ttm_resource_manager *man; |
| 101 | container_of(man->bdev, struct vmw_private, bdev); | ||
| 102 | struct vmwgfx_gmrid_man *gman = | 106 | struct vmwgfx_gmrid_man *gman = |
| 103 | kzalloc(sizeof(*gman), GFP_KERNEL); | 107 | kzalloc(sizeof(*gman), GFP_KERNEL); |
| 104 | 108 | ||
| 105 | if (unlikely(!gman)) | 109 | if (unlikely(!gman)) |
| 106 | return -ENOMEM; | 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 | spin_lock_init(&gman->lock); | 120 | spin_lock_init(&gman->lock); |
| 109 | gman->used_gmr_pages = 0; | 121 | gman->used_gmr_pages = 0; |
| 110 | ida_init(&gman->gmr_ida); | 122 | ida_init(&gman->gmr_ida); |
| 111 | 123 | ||
| 112 | switch (p_size) { | 124 | switch (type) { |
| 113 | case VMW_PL_GMR: | 125 | case VMW_PL_GMR: |
| 114 | gman->max_gmr_ids = dev_priv->max_gmr_ids; | 126 | gman->max_gmr_ids = dev_priv->max_gmr_ids; |
| 115 | gman->max_gmr_pages = dev_priv->max_gmr_pages; | 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 | default: | 133 | default: |
| 122 | BUG(); | 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 | return 0; | 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 = | 143 | struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, type); |
| 131 | (struct vmwgfx_gmrid_man *)man->priv; | 144 | struct vmwgfx_gmrid_man *gman = to_gmrid_manager(man); |
| 132 | 145 | ||
| 133 | if (gman) { | 146 | ttm_resource_manager_set_used(man, false); |
| 134 | ida_destroy(&gman->gmr_ida); | 147 | |
| 135 | kfree(gman); | 148 | ttm_resource_manager_force_list_clean(&dev_priv->bdev, man); |
| 136 | } | 149 | |
| 137 | return 0; | 150 | ttm_resource_manager_cleanup(man); |
| 138 | } | 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 = { | 158 | static const struct ttm_resource_manager_func vmw_gmrid_manager_func = { |
| 147 | .init = vmw_gmrid_man_init, | 159 | .alloc = vmw_gmrid_man_get_node, |
| 148 | .takedown = vmw_gmrid_man_takedown, | 160 | .free = vmw_gmrid_man_put_node, |
| 149 | .get_node = vmw_gmrid_man_get_node, | ||
| 150 | .put_node = vmw_gmrid_man_put_node, | ||
| 151 | .debug = vmw_gmrid_man_debug | ||
| 152 | }; | 161 | }; |
| @@ -238,10 +238,6 @@ static int vmw_otable_batch_setup(struct vmw_private *dev_priv, · 237 unmodified lines | |||
| 238 | unsigned long offset; | 238 | unsigned long offset; |
| 239 | unsigned long bo_size; | 239 | unsigned long bo_size; |
| 240 | struct vmw_otable *otables = batch->otables; | 240 | struct vmw_otable *otables = batch->otables; |
| 241 | struct ttm_operation_ctx ctx = { | ||
| 242 | .interruptible = false, | ||
| 243 | .no_wait_gpu = false | ||
| 244 | }; | ||
| 245 | SVGAOTableType i; | 241 | SVGAOTableType i; |
| 246 | int ret; | 242 | int ret; |
| 247 | 243 | ||
| @@ -255,24 +251,9 @@ static int vmw_otable_batch_setup(struct vmw_private *dev_priv, · 7 unmodified lines | |||
| 255 | bo_size += otables[i].size; | 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.