Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'drm-misc-next-2025-07-03' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for 6.17:

UAPI Changes:

Cross-subsystem Changes:

Core Changes:

- bridge: More reference counting
- dp: Implement backlight control helpers
- fourcc: Add half-float and 32b float formats, RGB161616, BGR161616
- mipi-dsi: Drop MIPI_DSI_MODE_VSYNC_FLUSH flag
- ttm: Improve eviction

Driver Changes:
- i915: Use backlight control helpers for eDP
- tidss: Add AM65x OLDI bridge support

- panels:
- panel-edp: Add CMN N116BCJ-EAK support
- raydium-rm67200: misc cleanups, optional reset
- new panel: DJN HX83112B

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Maxime Ripard <mripard@redhat.com>
Link: https://lore.kernel.org/r/20250703-chirpy-lilac-dalmatian-2c5838@houat

Dave Airlie 17d081ef ca39a371

+2030 -473
+73
Documentation/devicetree/bindings/display/panel/himax,hx83112b.yaml
··· 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/himax,hx83112b.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Himax HX83112B-based DSI display panels 8 + 9 + maintainers: 10 + - Luca Weiss <luca@lucaweiss.eu> 11 + 12 + description: 13 + The Himax HX83112B is a generic DSI Panel IC used to control 14 + LCD panels. 15 + 16 + allOf: 17 + - $ref: panel-common.yaml# 18 + 19 + properties: 20 + compatible: 21 + contains: 22 + const: djn,98-03057-6598b-i 23 + 24 + reg: 25 + maxItems: 1 26 + 27 + iovcc-supply: 28 + description: I/O voltage rail 29 + 30 + vsn-supply: 31 + description: Positive source voltage rail 32 + 33 + vsp-supply: 34 + description: Negative source voltage rail 35 + 36 + required: 37 + - compatible 38 + - reg 39 + - reset-gpios 40 + - iovcc-supply 41 + - vsn-supply 42 + - vsp-supply 43 + - port 44 + 45 + unevaluatedProperties: false 46 + 47 + examples: 48 + - | 49 + #include <dt-bindings/gpio/gpio.h> 50 + 51 + dsi { 52 + #address-cells = <1>; 53 + #size-cells = <0>; 54 + 55 + panel@0 { 56 + compatible = "djn,98-03057-6598b-i"; 57 + reg = <0>; 58 + 59 + reset-gpios = <&tlmm 61 GPIO_ACTIVE_LOW>; 60 + 61 + iovcc-supply = <&pm8953_l6>; 62 + vsn-supply = <&pmi632_lcdb_ncp>; 63 + vsp-supply = <&pmi632_lcdb_ldo>; 64 + 65 + port { 66 + panel_in_0: endpoint { 67 + remote-endpoint = <&dsi0_out>; 68 + }; 69 + }; 70 + }; 71 + }; 72 + 73 + ...
-1
Documentation/devicetree/bindings/display/panel/raydium,rm67200.yaml
··· 42 42 - compatible 43 43 - port 44 44 - reg 45 - - reset-gpios 46 45 47 46 additionalProperties: false 48 47
+44 -12
Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
··· 64 64 - description: Pixel clock for video port 0. 65 65 - description: Pixel clock for video port 1. 66 66 - description: Pixel clock for video port 2. 67 - - description: Pixel clock for video port 3. 68 - - description: Peripheral(vop grf/dsi) clock. 69 - - description: Alternative pixel clock provided by HDMI0 PHY PLL. 70 - - description: Alternative pixel clock provided by HDMI1 PHY PLL. 67 + - {} 68 + - {} 69 + - {} 70 + - {} 71 71 72 72 clock-names: 73 73 minItems: 5 ··· 77 77 - const: dclk_vp0 78 78 - const: dclk_vp1 79 79 - const: dclk_vp2 80 - - const: dclk_vp3 81 - - const: pclk_vop 82 - - const: pll_hdmiphy0 83 - - const: pll_hdmiphy1 80 + - {} 81 + - {} 82 + - {} 83 + - {} 84 84 85 85 rockchip,grf: 86 86 $ref: /schemas/types.yaml#/definitions/phandle ··· 175 175 then: 176 176 properties: 177 177 clocks: 178 - maxItems: 5 178 + minItems: 5 179 + items: 180 + - {} 181 + - {} 182 + - {} 183 + - {} 184 + - {} 185 + - description: Alternative pixel clock provided by HDMI PHY PLL. 179 186 180 187 clock-names: 181 - maxItems: 5 188 + minItems: 5 189 + items: 190 + - {} 191 + - {} 192 + - {} 193 + - {} 194 + - {} 195 + - const: pll_hdmiphy0 182 196 183 197 interrupts: 184 198 minItems: 4 ··· 222 208 properties: 223 209 clocks: 224 210 minItems: 7 225 - maxItems: 9 211 + items: 212 + - {} 213 + - {} 214 + - {} 215 + - {} 216 + - {} 217 + - description: Pixel clock for video port 3. 218 + - description: Peripheral(vop grf/dsi) clock. 219 + - description: Alternative pixel clock provided by HDMI0 PHY PLL. 220 + - description: Alternative pixel clock provided by HDMI1 PHY PLL. 226 221 227 222 clock-names: 228 223 minItems: 7 229 - maxItems: 9 224 + items: 225 + - {} 226 + - {} 227 + - {} 228 + - {} 229 + - {} 230 + - const: dclk_vp3 231 + - const: pclk_vop 232 + - const: pll_hdmiphy0 233 + - const: pll_hdmiphy1 230 234 231 235 interrupts: 232 236 maxItems: 1
+79
Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/display/ti/ti,am625-oldi.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Texas Instruments AM625 OLDI Transmitter 8 + 9 + maintainers: 10 + - Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> 11 + - Aradhya Bhatia <aradhya.bhatia@linux.dev> 12 + 13 + description: 14 + The AM625 TI Keystone OpenLDI transmitter (OLDI TX) supports serialized RGB 15 + pixel data transmission between host and flat panel display over LVDS (Low 16 + Voltage Differential Sampling) interface. The OLDI TX consists of 7-to-1 data 17 + serializers, and 4-data and 1-clock LVDS outputs. It supports the LVDS output 18 + formats "jeida-18", "jeida-24" and "vesa-18", and can accept 24-bit RGB or 19 + padded and un-padded 18-bit RGB bus formats as input. 20 + 21 + properties: 22 + reg: 23 + maxItems: 1 24 + 25 + clocks: 26 + maxItems: 1 27 + description: serial clock input for the OLDI transmitters 28 + 29 + clock-names: 30 + const: serial 31 + 32 + ti,companion-oldi: 33 + $ref: /schemas/types.yaml#/definitions/phandle 34 + description: 35 + phandle to companion OLDI transmitter. This property is required for both 36 + the OLDI TXes if they are expected to work either in dual-lvds mode or in 37 + clone mode. This property should point to the other OLDI TX's phandle. 38 + 39 + ti,secondary-oldi: 40 + type: boolean 41 + description: 42 + Boolean property to mark the OLDI transmitter as the secondary one, when the 43 + OLDI hardware is expected to run as a companion HW, in cases of dual-lvds 44 + mode or clone mode. The primary OLDI hardware is responsible for all the 45 + hardware configuration. 46 + 47 + ti,oldi-io-ctrl: 48 + $ref: /schemas/types.yaml#/definitions/phandle 49 + description: 50 + phandle to syscon device node mapping OLDI IO_CTRL registers found in the 51 + control MMR region. These registers are required to toggle the I/O lane 52 + power, and control its electrical characteristics. 53 + 54 + ports: 55 + $ref: /schemas/graph.yaml#/properties/ports 56 + 57 + properties: 58 + port@0: 59 + $ref: /schemas/graph.yaml#/properties/port 60 + description: Parallel RGB input port 61 + 62 + port@1: 63 + $ref: /schemas/graph.yaml#/properties/port 64 + description: LVDS output port 65 + 66 + required: 67 + - port@0 68 + - port@1 69 + 70 + required: 71 + - reg 72 + - clocks 73 + - clock-names 74 + - ti,oldi-io-ctrl 75 + - ports 76 + 77 + additionalProperties: false 78 + 79 + ...
+178 -21
Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml
··· 100 100 For AM62A7 DSS, the port is tied off inside the SoC. 101 101 For AM62L DSS, the DSS DPI output port node from video port 1 102 102 or DSI Tx controller node connected to video port 1. 103 + properties: 104 + endpoint@0: 105 + $ref: /schemas/graph.yaml#/properties/endpoint 106 + description: 107 + For AM625 DSS, VP Connection to OLDI0. 108 + For AM65X DSS, OLDI output from the SoC. 109 + 110 + endpoint@1: 111 + $ref: /schemas/graph.yaml#/properties/endpoint 112 + description: 113 + For AM625 DSS, VP Connection to OLDI1. 114 + 115 + anyOf: 116 + - required: 117 + - endpoint 118 + - required: 119 + - endpoint@0 120 + - endpoint@1 103 121 104 122 port@1: 105 123 $ref: /schemas/graph.yaml#/properties/port ··· 139 121 Input memory (from main memory to dispc) bandwidth limit in 140 122 bytes per second 141 123 124 + oldi-transmitters: 125 + description: 126 + Child node under the DSS, to describe all the OLDI transmitters connected 127 + to the DSS videoports. 128 + type: object 129 + additionalProperties: false 130 + 131 + properties: 132 + "#address-cells": 133 + const: 1 134 + 135 + "#size-cells": 136 + const: 0 137 + 138 + patternProperties: 139 + '^oldi@[0-1]$': 140 + $ref: ti,am625-oldi.yaml# 141 + description: OLDI transmitters connected to the DSS VPs 142 + 142 143 allOf: 143 144 - if: 144 145 properties: ··· 166 129 const: ti,am62a7-dss 167 130 then: 168 131 properties: 132 + oldi-transmitters: false 169 133 ports: 170 134 properties: 171 135 port@0: false ··· 180 142 ports: 181 143 properties: 182 144 port@1: false 145 + 146 + - if: 147 + properties: 148 + compatible: 149 + contains: 150 + enum: 151 + - ti,am62l-dss 152 + - ti,am65x-dss 153 + then: 154 + properties: 155 + oldi-transmitters: false 156 + ports: 157 + properties: 158 + port@0: 159 + properties: 160 + endpoint@1: false 183 161 184 162 required: 185 163 - compatible ··· 215 161 #include <dt-bindings/soc/ti,sci_pm_domain.h> 216 162 217 163 dss: dss@4a00000 { 218 - compatible = "ti,am65x-dss"; 219 - reg = <0x04a00000 0x1000>, /* common */ 220 - <0x04a02000 0x1000>, /* vidl1 */ 221 - <0x04a06000 0x1000>, /* vid */ 222 - <0x04a07000 0x1000>, /* ovr1 */ 223 - <0x04a08000 0x1000>, /* ovr2 */ 224 - <0x04a0a000 0x1000>, /* vp1 */ 225 - <0x04a0b000 0x1000>, /* vp2 */ 226 - <0x04a01000 0x1000>; /* common1 */ 164 + compatible = "ti,am65x-dss"; 165 + reg = <0x04a00000 0x1000>, /* common */ 166 + <0x04a02000 0x1000>, /* vidl1 */ 167 + <0x04a06000 0x1000>, /* vid */ 168 + <0x04a07000 0x1000>, /* ovr1 */ 169 + <0x04a08000 0x1000>, /* ovr2 */ 170 + <0x04a0a000 0x1000>, /* vp1 */ 171 + <0x04a0b000 0x1000>, /* vp2 */ 172 + <0x04a01000 0x1000>; /* common1 */ 173 + reg-names = "common", "vidl1", "vid", 174 + "ovr1", "ovr2", "vp1", "vp2", "common1"; 175 + ti,am65x-oldi-io-ctrl = <&dss_oldi_io_ctrl>; 176 + power-domains = <&k3_pds 67 TI_SCI_PD_EXCLUSIVE>; 177 + clocks = <&k3_clks 67 1>, 178 + <&k3_clks 216 1>, 179 + <&k3_clks 67 2>; 180 + clock-names = "fck", "vp1", "vp2"; 181 + interrupts = <GIC_SPI 166 IRQ_TYPE_EDGE_RISING>; 182 + ports { 183 + #address-cells = <1>; 184 + #size-cells = <0>; 185 + port@0 { 186 + reg = <0>; 187 + oldi_out0: endpoint { 188 + remote-endpoint = <&lcd_in0>; 189 + }; 190 + }; 191 + }; 192 + }; 193 + 194 + - | 195 + #include <dt-bindings/interrupt-controller/arm-gic.h> 196 + #include <dt-bindings/interrupt-controller/irq.h> 197 + #include <dt-bindings/soc/ti,sci_pm_domain.h> 198 + 199 + bus { 200 + #address-cells = <2>; 201 + #size-cells = <2>; 202 + dss1: dss@30200000 { 203 + compatible = "ti,am625-dss"; 204 + reg = <0x00 0x30200000 0x00 0x1000>, /* common */ 205 + <0x00 0x30202000 0x00 0x1000>, /* vidl1 */ 206 + <0x00 0x30206000 0x00 0x1000>, /* vid */ 207 + <0x00 0x30207000 0x00 0x1000>, /* ovr1 */ 208 + <0x00 0x30208000 0x00 0x1000>, /* ovr2 */ 209 + <0x00 0x3020a000 0x00 0x1000>, /* vp1 */ 210 + <0x00 0x3020b000 0x00 0x1000>, /* vp2 */ 211 + <0x00 0x30201000 0x00 0x1000>; /* common1 */ 227 212 reg-names = "common", "vidl1", "vid", 228 - "ovr1", "ovr2", "vp1", "vp2", "common1"; 229 - ti,am65x-oldi-io-ctrl = <&dss_oldi_io_ctrl>; 230 - power-domains = <&k3_pds 67 TI_SCI_PD_EXCLUSIVE>; 231 - clocks = <&k3_clks 67 1>, 232 - <&k3_clks 216 1>, 233 - <&k3_clks 67 2>; 213 + "ovr1", "ovr2", "vp1", "vp2", "common1"; 214 + power-domains = <&k3_pds 186 TI_SCI_PD_EXCLUSIVE>; 215 + clocks = <&k3_clks 186 6>, 216 + <&vp1_clock>, 217 + <&k3_clks 186 2>; 234 218 clock-names = "fck", "vp1", "vp2"; 235 - interrupts = <GIC_SPI 166 IRQ_TYPE_EDGE_RISING>; 219 + interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>; 220 + oldi-transmitters { 221 + #address-cells = <1>; 222 + #size-cells = <0>; 223 + oldi0: oldi@0 { 224 + reg = <0>; 225 + clocks = <&k3_clks 186 0>; 226 + clock-names = "serial"; 227 + ti,companion-oldi = <&oldi1>; 228 + ti,oldi-io-ctrl = <&dss_oldi_io_ctrl>; 229 + ports { 230 + #address-cells = <1>; 231 + #size-cells = <0>; 232 + port@0 { 233 + reg = <0>; 234 + oldi0_in: endpoint { 235 + remote-endpoint = <&dpi0_out0>; 236 + }; 237 + }; 238 + port@1 { 239 + reg = <1>; 240 + oldi0_out: endpoint { 241 + remote-endpoint = <&panel_in0>; 242 + }; 243 + }; 244 + }; 245 + }; 246 + oldi1: oldi@1 { 247 + reg = <1>; 248 + clocks = <&k3_clks 186 0>; 249 + clock-names = "serial"; 250 + ti,secondary-oldi; 251 + ti,companion-oldi = <&oldi0>; 252 + ti,oldi-io-ctrl = <&dss_oldi_io_ctrl>; 253 + ports { 254 + #address-cells = <1>; 255 + #size-cells = <0>; 256 + port@0 { 257 + reg = <0>; 258 + oldi1_in: endpoint { 259 + remote-endpoint = <&dpi0_out1>; 260 + }; 261 + }; 262 + port@1 { 263 + reg = <1>; 264 + oldi1_out: endpoint { 265 + remote-endpoint = <&panel_in1>; 266 + }; 267 + }; 268 + }; 269 + }; 270 + }; 236 271 ports { 272 + #address-cells = <1>; 273 + #size-cells = <0>; 274 + port@0 { 237 275 #address-cells = <1>; 238 276 #size-cells = <0>; 239 - port@0 { 240 - reg = <0>; 241 - oldi_out0: endpoint { 242 - remote-endpoint = <&lcd_in0>; 243 - }; 277 + reg = <0>; 278 + dpi0_out0: endpoint@0 { 279 + reg = <0>; 280 + remote-endpoint = <&oldi0_in>; 244 281 }; 282 + dpi0_out1: endpoint@1 { 283 + reg = <1>; 284 + remote-endpoint = <&oldi1_in>; 285 + }; 286 + }; 287 + port@1 { 288 + reg = <1>; 289 + dpi1_out: endpoint { 290 + remote-endpoint = <&hdmi_bridge>; 291 + }; 292 + }; 245 293 }; 294 + }; 246 295 };
+2
Documentation/devicetree/bindings/vendor-prefixes.yaml
··· 398 398 description: Diodes, Inc. 399 399 "^dioo,.*": 400 400 description: Dioo Microcircuit Co., Ltd 401 + "^djn,.*": 402 + description: Shenzhen DJN Optronics Technology Co., Ltd 401 403 "^dlc,.*": 402 404 description: DLC Display Co., Ltd. 403 405 "^dlg,.*":
+3
MAINTAINERS
··· 7499 7499 L: dri-devel@lists.freedesktop.org 7500 7500 S: Maintained 7501 7501 T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7502 + F: drivers/firmware/sysfb*.c 7502 7503 F: drivers/gpu/drm/sysfb/ 7503 7504 F: drivers/video/aperture.c 7504 7505 F: drivers/video/nomodeset.c 7505 7506 F: include/linux/aperture.h 7507 + F: include/linux/sysfb.h 7506 7508 F: include/video/nomodeset.h 7507 7509 7508 7510 DRM DRIVER FOR GENERIC EDP PANELS ··· 8234 8232 L: dri-devel@lists.freedesktop.org 8235 8233 S: Maintained 8236 8234 T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 8235 + F: Documentation/devicetree/bindings/display/ti/ti,am625-oldi.yaml 8237 8236 F: Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml 8238 8237 F: Documentation/devicetree/bindings/display/ti/ti,j721e-dss.yaml 8239 8238 F: Documentation/devicetree/bindings/display/ti/ti,k2g-dss.yaml
+33 -46
drivers/gpu/drm/bridge/samsung-dsim.c
··· 20 20 #include <linux/of.h> 21 21 #include <linux/phy/phy.h> 22 22 #include <linux/platform_device.h> 23 + #include <linux/units.h> 23 24 24 25 #include <video/mipi_display.h> 25 26 ··· 559 558 samsung_dsim_write(dsi, DSIM_SWRST_REG, reset_val); 560 559 } 561 560 562 - #ifndef MHZ 563 - #define MHZ (1000 * 1000) 564 - #endif 565 - 566 561 static unsigned long samsung_dsim_pll_find_pms(struct samsung_dsim *dsi, 567 562 unsigned long fin, 568 563 unsigned long fout, ··· 572 575 u16 _m, best_m; 573 576 u8 _s, best_s; 574 577 575 - p_min = DIV_ROUND_UP(fin, (driver_data->pll_fin_max * MHZ)); 576 - p_max = fin / (driver_data->pll_fin_min * MHZ); 578 + p_min = DIV_ROUND_UP(fin, (driver_data->pll_fin_max * HZ_PER_MHZ)); 579 + p_max = fin / (driver_data->pll_fin_min * HZ_PER_MHZ); 577 580 578 581 for (_p = p_min; _p <= p_max; ++_p) { 579 582 for (_s = 0; _s <= 5; ++_s) { ··· 588 591 589 592 tmp = (u64)_m * fin; 590 593 do_div(tmp, _p); 591 - if (tmp < driver_data->min_freq * MHZ || 592 - tmp > driver_data->max_freq * MHZ) 594 + if (tmp < driver_data->min_freq * HZ_PER_MHZ || 595 + tmp > driver_data->max_freq * HZ_PER_MHZ) 593 596 continue; 594 597 595 598 tmp = (u64)_m * fin; ··· 632 635 * limit. 633 636 */ 634 637 fin = clk_get_rate(clk_get_parent(dsi->pll_clk)); 635 - while (fin > driver_data->pll_fin_max * MHZ) 638 + while (fin > driver_data->pll_fin_max * HZ_PER_MHZ) 636 639 fin /= 2; 637 640 clk_set_rate(dsi->pll_clk, fin); 638 641 ··· 658 661 659 662 if (driver_data->has_freqband) { 660 663 static const unsigned long freq_bands[] = { 661 - 100 * MHZ, 120 * MHZ, 160 * MHZ, 200 * MHZ, 662 - 270 * MHZ, 320 * MHZ, 390 * MHZ, 450 * MHZ, 663 - 510 * MHZ, 560 * MHZ, 640 * MHZ, 690 * MHZ, 664 - 770 * MHZ, 870 * MHZ, 950 * MHZ, 664 + 100 * HZ_PER_MHZ, 120 * HZ_PER_MHZ, 160 * HZ_PER_MHZ, 665 + 200 * HZ_PER_MHZ, 270 * HZ_PER_MHZ, 320 * HZ_PER_MHZ, 666 + 390 * HZ_PER_MHZ, 450 * HZ_PER_MHZ, 510 * HZ_PER_MHZ, 667 + 560 * HZ_PER_MHZ, 640 * HZ_PER_MHZ, 690 * HZ_PER_MHZ, 668 + 770 * HZ_PER_MHZ, 870 * HZ_PER_MHZ, 950 * HZ_PER_MHZ, 665 669 }; 666 670 int band; 667 671 ··· 722 724 esc_div = DIV_ROUND_UP(byte_clk, dsi->esc_clk_rate); 723 725 esc_clk = byte_clk / esc_div; 724 726 725 - if (esc_clk > 20 * MHZ) { 727 + if (esc_clk > 20 * HZ_PER_MHZ) { 726 728 ++esc_div; 727 729 esc_clk = byte_clk / esc_div; 728 730 } ··· 897 899 * The user manual describes that following bits are ignored in 898 900 * command mode. 899 901 */ 900 - if (!(dsi->mode_flags & MIPI_DSI_MODE_VSYNC_FLUSH)) 901 - reg |= DSIM_MFLUSH_VS; 902 902 if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) 903 903 reg |= DSIM_SYNC_INFORM; 904 904 if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) ··· 1232 1236 { 1233 1237 unsigned long flags; 1234 1238 struct samsung_dsim_transfer *xfer; 1235 - bool start = false; 1236 1239 1237 - again: 1238 1240 spin_lock_irqsave(&dsi->transfer_lock, flags); 1239 1241 1240 - if (list_empty(&dsi->transfer_list)) { 1242 + while (!list_empty(&dsi->transfer_list)) { 1243 + xfer = list_first_entry(&dsi->transfer_list, 1244 + struct samsung_dsim_transfer, list); 1245 + 1241 1246 spin_unlock_irqrestore(&dsi->transfer_lock, flags); 1242 - return; 1247 + 1248 + if (xfer->packet.payload_length && 1249 + xfer->tx_done == xfer->packet.payload_length) 1250 + /* waiting for RX */ 1251 + return; 1252 + 1253 + samsung_dsim_send_to_fifo(dsi, xfer); 1254 + 1255 + if (xfer->packet.payload_length || xfer->rx_len) 1256 + return; 1257 + 1258 + xfer->result = 0; 1259 + complete(&xfer->completed); 1260 + 1261 + spin_lock_irqsave(&dsi->transfer_lock, flags); 1262 + 1263 + list_del_init(&xfer->list); 1243 1264 } 1244 1265 1245 - xfer = list_first_entry(&dsi->transfer_list, 1246 - struct samsung_dsim_transfer, list); 1247 - 1248 1266 spin_unlock_irqrestore(&dsi->transfer_lock, flags); 1249 - 1250 - if (xfer->packet.payload_length && 1251 - xfer->tx_done == xfer->packet.payload_length) 1252 - /* waiting for RX */ 1253 - return; 1254 - 1255 - samsung_dsim_send_to_fifo(dsi, xfer); 1256 - 1257 - if (xfer->packet.payload_length || xfer->rx_len) 1258 - return; 1259 - 1260 - xfer->result = 0; 1261 - complete(&xfer->completed); 1262 - 1263 - spin_lock_irqsave(&dsi->transfer_lock, flags); 1264 - 1265 - list_del_init(&xfer->list); 1266 - start = !list_empty(&dsi->transfer_list); 1267 - 1268 - spin_unlock_irqrestore(&dsi->transfer_lock, flags); 1269 - 1270 - if (start) 1271 - goto again; 1272 1267 } 1273 1268 1274 1269 static bool samsung_dsim_transfer_finish(struct samsung_dsim *dsi)
-5
drivers/gpu/drm/bridge/ti-sn65dsi86.c
··· 1677 1677 { 1678 1678 struct ti_sn65dsi86 *pdata = gpiochip_get_data(chip); 1679 1679 1680 - if (!test_bit(offset, pdata->gchip_output)) { 1681 - dev_err(pdata->dev, "Ignoring GPIO set while input\n"); 1682 - return -EPERM; 1683 - } 1684 - 1685 1680 val &= 1; 1686 1681 return regmap_update_bits(pdata->regmap, SN_GPIO_IO_REG, 1687 1682 BIT(SN_GPIO_OUTPUT_SHIFT + offset),
+67 -25
drivers/gpu/drm/display/drm_dp_helper.c
··· 3957 3957 * Returns: %0 on success, negative error code on failure 3958 3958 */ 3959 3959 int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl, 3960 - u16 level) 3960 + u32 level) 3961 3961 { 3962 3962 int ret; 3963 - u8 buf[2] = { 0 }; 3963 + unsigned int offset = DP_EDP_BACKLIGHT_BRIGHTNESS_MSB; 3964 + u8 buf[3] = { 0 }; 3964 3965 3965 3966 /* The panel uses the PWM for controlling brightness levels */ 3966 - if (!bl->aux_set) 3967 + if (!(bl->aux_set || bl->luminance_set)) 3967 3968 return 0; 3968 3969 3969 - if (bl->lsb_reg_used) { 3970 + if (bl->luminance_set) { 3971 + level = level * 1000; 3972 + level &= 0xffffff; 3973 + buf[0] = (level & 0x0000ff); 3974 + buf[1] = (level & 0x00ff00) >> 8; 3975 + buf[2] = (level & 0xff0000) >> 16; 3976 + offset = DP_EDP_PANEL_TARGET_LUMINANCE_VALUE; 3977 + } else if (bl->lsb_reg_used) { 3970 3978 buf[0] = (level & 0xff00) >> 8; 3971 3979 buf[1] = (level & 0x00ff); 3972 3980 } else { 3973 3981 buf[0] = level; 3974 3982 } 3975 3983 3976 - ret = drm_dp_dpcd_write_data(aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB, buf, sizeof(buf)); 3984 + ret = drm_dp_dpcd_write_data(aux, offset, buf, sizeof(buf)); 3977 3985 if (ret < 0) { 3978 3986 drm_err(aux->drm_dev, 3979 3987 "%s: Failed to write aux backlight level: %d\n", ··· 4044 4036 * Returns: %0 on success, negative error code on failure. 4045 4037 */ 4046 4038 int drm_edp_backlight_enable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl, 4047 - const u16 level) 4039 + const u32 level) 4048 4040 { 4049 4041 int ret; 4050 4042 u8 dpcd_buf; ··· 4053 4045 dpcd_buf = DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD; 4054 4046 else 4055 4047 dpcd_buf = DP_EDP_BACKLIGHT_CONTROL_MODE_PWM; 4048 + 4049 + if (bl->luminance_set) 4050 + dpcd_buf |= DP_EDP_PANEL_LUMINANCE_CONTROL_ENABLE; 4056 4051 4057 4052 if (bl->pwmgen_bit_count) { 4058 4053 ret = drm_dp_dpcd_write_byte(aux, DP_EDP_PWMGEN_BIT_COUNT, bl->pwmgen_bit_count); ··· 4220 4209 u8 *current_mode) 4221 4210 { 4222 4211 int ret; 4223 - u8 buf[2]; 4212 + u8 buf[3]; 4224 4213 u8 mode_reg; 4225 4214 4226 4215 ret = drm_dp_dpcd_read_byte(aux, DP_EDP_BACKLIGHT_MODE_SET_REGISTER, &mode_reg); ··· 4237 4226 if (*current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) { 4238 4227 int size = 1 + bl->lsb_reg_used; 4239 4228 4240 - ret = drm_dp_dpcd_read_data(aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB, buf, size); 4241 - if (ret < 0) { 4242 - drm_dbg_kms(aux->drm_dev, "%s: Failed to read backlight level: %d\n", 4243 - aux->name, ret); 4244 - return ret; 4229 + if (bl->luminance_set) { 4230 + ret = drm_dp_dpcd_read_data(aux, DP_EDP_PANEL_TARGET_LUMINANCE_VALUE, 4231 + buf, sizeof(buf)); 4232 + if (ret < 0) { 4233 + drm_dbg_kms(aux->drm_dev, 4234 + "%s: Failed to read backlight level: %d\n", 4235 + aux->name, ret); 4236 + return ret; 4245 4237 } 4246 4238 4247 - if (bl->lsb_reg_used) 4248 - return (buf[0] << 8) | buf[1]; 4249 - else 4250 - return buf[0]; 4239 + /* 4240 + * Incase luminance is set we want to send the value back in nits but since 4241 + * DP_EDP_PANEL_TARGET_LUMINANCE stores values in millinits we need to divide 4242 + * by 1000. 4243 + */ 4244 + return (buf[0] | buf[1] << 8 | buf[2] << 16) / 1000; 4245 + } else { 4246 + ret = drm_dp_dpcd_read_data(aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB, 4247 + buf, size); 4248 + if (ret < 0) { 4249 + drm_dbg_kms(aux->drm_dev, 4250 + "%s: Failed to read backlight level: %d\n", 4251 + aux->name, ret); 4252 + return ret; 4253 + } 4254 + 4255 + if (bl->lsb_reg_used) 4256 + return (buf[0] << 8) | buf[1]; 4257 + else 4258 + return buf[0]; 4259 + } 4251 4260 } 4252 4261 4253 4262 /* ··· 4282 4251 * interface. 4283 4252 * @aux: The DP aux device to use for probing 4284 4253 * @bl: The &drm_edp_backlight_info struct to fill out with information on the backlight 4254 + * @max_luminance: max luminance when need luminance is set as true 4285 4255 * @driver_pwm_freq_hz: Optional PWM frequency from the driver in hz 4286 4256 * @edp_dpcd: A cached copy of the eDP DPCD 4287 4257 * @current_level: Where to store the probed brightness level, if any 4288 4258 * @current_mode: Where to store the currently set backlight control mode 4259 + * @need_luminance: Tells us if a we want to manipulate backlight using luminance values 4289 4260 * 4290 4261 * Initializes a &drm_edp_backlight_info struct by probing @aux for it's backlight capabilities, 4291 4262 * along with also probing the current and maximum supported brightness levels. ··· 4299 4266 */ 4300 4267 int 4301 4268 drm_edp_backlight_init(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl, 4269 + u32 max_luminance, 4302 4270 u16 driver_pwm_freq_hz, const u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE], 4303 - u16 *current_level, u8 *current_mode) 4271 + u32 *current_level, u8 *current_mode, bool need_luminance) 4304 4272 { 4305 4273 int ret; 4306 4274 ··· 4311 4277 bl->aux_set = true; 4312 4278 if (edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT) 4313 4279 bl->lsb_reg_used = true; 4280 + if ((edp_dpcd[0] & DP_EDP_15) && edp_dpcd[3] & 4281 + (DP_EDP_PANEL_LUMINANCE_CONTROL_CAPABLE) && need_luminance) 4282 + bl->luminance_set = true; 4314 4283 4315 4284 /* Sanity check caps */ 4316 - if (!bl->aux_set && !(edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP)) { 4285 + if (!bl->aux_set && !(edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP) && 4286 + !bl->luminance_set) { 4317 4287 drm_dbg_kms(aux->drm_dev, 4318 - "%s: Panel supports neither AUX or PWM brightness control? Aborting\n", 4288 + "%s: Panel does not support AUX, PWM or luminance-based brightness control. Aborting\n", 4319 4289 aux->name); 4320 4290 return -EINVAL; 4321 4291 } 4322 4292 4323 - ret = drm_edp_backlight_probe_max(aux, bl, driver_pwm_freq_hz, edp_dpcd); 4324 - if (ret < 0) 4325 - return ret; 4293 + if (bl->luminance_set) { 4294 + bl->max = max_luminance; 4295 + } else { 4296 + ret = drm_edp_backlight_probe_max(aux, bl, driver_pwm_freq_hz, edp_dpcd); 4297 + if (ret < 0) 4298 + return ret; 4299 + } 4326 4300 4327 4301 ret = drm_edp_backlight_probe_state(aux, bl, current_mode); 4328 4302 if (ret < 0) ··· 4409 4367 { 4410 4368 struct dp_aux_backlight *bl; 4411 4369 struct backlight_properties props = { 0 }; 4412 - u16 current_level; 4370 + u32 current_level; 4413 4371 u8 current_mode; 4414 4372 u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE]; 4415 4373 int ret; ··· 4433 4391 4434 4392 bl->aux = aux; 4435 4393 4436 - ret = drm_edp_backlight_init(aux, &bl->info, 0, edp_dpcd, 4437 - &current_level, &current_mode); 4394 + ret = drm_edp_backlight_init(aux, &bl->info, 0, 0, edp_dpcd, 4395 + &current_level, &current_mode, false); 4438 4396 if (ret < 0) 4439 4397 return ret; 4440 4398
+20 -4
drivers/gpu/drm/drm_bridge.c
··· 295 295 */ 296 296 void drm_bridge_add(struct drm_bridge *bridge) 297 297 { 298 + if (!bridge->container) 299 + DRM_WARN("DRM bridge corrupted or not allocated by devm_drm_bridge_alloc()\n"); 300 + 301 + drm_bridge_get(bridge); 302 + 298 303 mutex_init(&bridge->hpd_mutex); 299 304 300 305 if (bridge->ops & DRM_BRIDGE_OP_HDMI) ··· 347 342 mutex_unlock(&bridge_lock); 348 343 349 344 mutex_destroy(&bridge->hpd_mutex); 345 + 346 + drm_bridge_put(bridge); 350 347 } 351 348 EXPORT_SYMBOL(drm_bridge_remove); 352 349 ··· 414 407 if (!encoder || !bridge) 415 408 return -EINVAL; 416 409 417 - if (previous && (!previous->dev || previous->encoder != encoder)) 418 - return -EINVAL; 410 + drm_bridge_get(bridge); 419 411 420 - if (bridge->dev) 421 - return -EBUSY; 412 + if (previous && (!previous->dev || previous->encoder != encoder)) { 413 + ret = -EINVAL; 414 + goto err_put_bridge; 415 + } 416 + 417 + if (bridge->dev) { 418 + ret = -EBUSY; 419 + goto err_put_bridge; 420 + } 422 421 423 422 bridge->dev = encoder->dev; 424 423 bridge->encoder = encoder; ··· 473 460 "failed to attach bridge %pOF to encoder %s\n", 474 461 bridge->of_node, encoder->name); 475 462 463 + err_put_bridge: 464 + drm_bridge_put(bridge); 476 465 return ret; 477 466 } 478 467 EXPORT_SYMBOL(drm_bridge_attach); ··· 495 480 496 481 list_del(&bridge->chain_node); 497 482 bridge->dev = NULL; 483 + drm_bridge_put(bridge); 498 484 } 499 485 500 486 /**
+44 -24
drivers/gpu/drm/drm_format_helper.c
··· 559 559 drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgb565); 560 560 } 561 561 562 - static __always_inline u32 drm_xrgb8888_to_rgb565_swab(u32 pix) 563 - { 564 - return swab16(drm_pixel_xrgb8888_to_rgb565(pix)); 565 - } 566 - 567 - /* TODO: implement this helper as conversion to RGB565|BIG_ENDIAN */ 568 - static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf, 569 - unsigned int pixels) 570 - { 571 - drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_xrgb8888_to_rgb565_swab); 572 - } 573 - 574 562 /** 575 563 * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer 576 564 * @dst: Array of RGB565 destination buffers ··· 568 580 * @fb: DRM framebuffer 569 581 * @clip: Clip rectangle area to copy 570 582 * @state: Transform and conversion state 571 - * @swab: Swap bytes 572 583 * 573 584 * This function copies parts of a framebuffer to display memory and converts the 574 585 * color format during the process. Destination and framebuffer formats must match. The ··· 582 595 */ 583 596 void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch, 584 597 const struct iosys_map *src, const struct drm_framebuffer *fb, 585 - const struct drm_rect *clip, struct drm_format_conv_state *state, 586 - bool swab) 598 + const struct drm_rect *clip, struct drm_format_conv_state *state) 587 599 { 588 600 static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 589 601 2, 590 602 }; 591 603 592 - void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels); 593 - 594 - if (swab) 595 - xfrm_line = drm_fb_xrgb8888_to_rgb565_swab_line; 596 - else 597 - xfrm_line = drm_fb_xrgb8888_to_rgb565_line; 598 - 599 - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, xfrm_line); 604 + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, 605 + drm_fb_xrgb8888_to_rgb565_line); 600 606 } 601 607 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565); 608 + 609 + static void drm_fb_xrgb8888_to_rgb565be_line(void *dbuf, const void *sbuf, 610 + unsigned int pixels) 611 + { 612 + drm_fb_xfrm_line_32to16(dbuf, sbuf, pixels, drm_pixel_xrgb8888_to_rgb565be); 613 + } 614 + 615 + /** 616 + * drm_fb_xrgb8888_to_rgb565be - Convert XRGB8888 to RGB565|DRM_FORMAT_BIG_ENDIAN clip buffer 617 + * @dst: Array of RGB565BE destination buffers 618 + * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines 619 + * within @dst; can be NULL if scanlines are stored next to each other. 620 + * @src: Array of XRGB8888 source buffer 621 + * @fb: DRM framebuffer 622 + * @clip: Clip rectangle area to copy 623 + * @state: Transform and conversion state 624 + * 625 + * This function copies parts of a framebuffer to display memory and converts the 626 + * color format during the process. Destination and framebuffer formats must match. The 627 + * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at 628 + * least as many entries as there are planes in @fb's format. Each entry stores the 629 + * value for the format's respective color plane at the same index. 630 + * 631 + * This function does not apply clipping on @dst (i.e. the destination is at the 632 + * top-left corner). 633 + * 634 + * Drivers can use this function for RGB565BE devices that don't support XRGB8888 natively. 635 + */ 636 + void drm_fb_xrgb8888_to_rgb565be(struct iosys_map *dst, const unsigned int *dst_pitch, 637 + const struct iosys_map *src, const struct drm_framebuffer *fb, 638 + const struct drm_rect *clip, struct drm_format_conv_state *state) 639 + { 640 + static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 641 + 2, 642 + }; 643 + 644 + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, 645 + drm_fb_xrgb8888_to_rgb565be_line); 646 + } 647 + EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565be); 602 648 603 649 static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsigned int pixels) 604 650 { ··· 1208 1188 return 0; 1209 1189 } else if (fb_format == DRM_FORMAT_XRGB8888) { 1210 1190 if (dst_format == DRM_FORMAT_RGB565) { 1211 - drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, state, false); 1191 + drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, state); 1212 1192 return 0; 1213 1193 } else if (dst_format == DRM_FORMAT_XRGB1555) { 1214 1194 drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip, state);
+6
drivers/gpu/drm/drm_format_internal.h
··· 5 5 6 6 #include <linux/bits.h> 7 7 #include <linux/types.h> 8 + #include <linux/swab.h> 8 9 9 10 /* 10 11 * Each pixel-format conversion helper takes a raw pixel in a ··· 58 57 return ((pix & 0x00f80000) >> 8) | 59 58 ((pix & 0x0000fc00) >> 5) | 60 59 ((pix & 0x000000f8) >> 3); 60 + } 61 + 62 + static inline u32 drm_pixel_xrgb8888_to_rgb565be(u32 pix) 63 + { 64 + return swab16(drm_pixel_xrgb8888_to_rgb565(pix)); 61 65 } 62 66 63 67 static inline u32 drm_pixel_xrgb8888_to_rgbx5551(u32 pix)
+8
drivers/gpu/drm/drm_fourcc.c
··· 238 238 { .format = DRM_FORMAT_ABGR2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, 239 239 { .format = DRM_FORMAT_RGBA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, 240 240 { .format = DRM_FORMAT_BGRA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, 241 + { .format = DRM_FORMAT_RGB161616, .depth = 0, 242 + .num_planes = 1, .char_per_block = { 6, 0, 0 }, 243 + .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 }, 244 + .hsub = 1, .vsub = 1, .has_alpha = false }, 245 + { .format = DRM_FORMAT_BGR161616, .depth = 0, 246 + .num_planes = 1, .char_per_block = { 6, 0, 0 }, 247 + .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 }, 248 + .hsub = 1, .vsub = 1, .has_alpha = false }, 241 249 { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, 242 250 { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, 243 251 { .format = DRM_FORMAT_RGBA8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
+7 -1
drivers/gpu/drm/drm_mipi_dbi.c
··· 230 230 case DRM_FORMAT_XRGB8888: 231 231 switch (dbidev->pixel_format) { 232 232 case DRM_FORMAT_RGB565: 233 - drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip, fmtcnv_state, swap); 233 + if (swap) { 234 + drm_fb_xrgb8888_to_rgb565be(&dst_map, NULL, src, fb, clip, 235 + fmtcnv_state); 236 + } else { 237 + drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip, 238 + fmtcnv_state); 239 + } 234 240 break; 235 241 case DRM_FORMAT_RGB888: 236 242 drm_fb_xrgb8888_to_rgb888(&dst_map, NULL, src, fb, clip, fmtcnv_state);
+7 -2
drivers/gpu/drm/gud/gud_pipe.c
··· 188 188 } else if (format->format == DRM_FORMAT_RGB332) { 189 189 drm_fb_xrgb8888_to_rgb332(&dst, NULL, src, fb, rect, fmtcnv_state); 190 190 } else if (format->format == DRM_FORMAT_RGB565) { 191 - drm_fb_xrgb8888_to_rgb565(&dst, NULL, src, fb, rect, fmtcnv_state, 192 - gud_is_big_endian()); 191 + if (gud_is_big_endian()) { 192 + drm_fb_xrgb8888_to_rgb565be(&dst, NULL, src, fb, rect, 193 + fmtcnv_state); 194 + } else { 195 + drm_fb_xrgb8888_to_rgb565(&dst, NULL, src, fb, rect, 196 + fmtcnv_state); 197 + } 193 198 } else if (format->format == DRM_FORMAT_RGB888) { 194 199 drm_fb_xrgb8888_to_rgb888(&dst, NULL, src, fb, rect, fmtcnv_state); 195 200 } else {
+50 -92
drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
··· 475 475 return connector->panel.backlight.level; 476 476 } 477 477 478 - static int 479 - intel_dp_aux_vesa_set_luminance(struct intel_connector *connector, u32 level) 480 - { 481 - struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); 482 - u8 buf[3]; 483 - int ret; 484 - 485 - level = level * 1000; 486 - level &= 0xffffff; 487 - buf[0] = (level & 0x0000ff); 488 - buf[1] = (level & 0x00ff00) >> 8; 489 - buf[2] = (level & 0xff0000) >> 16; 490 - 491 - ret = drm_dp_dpcd_write(&intel_dp->aux, DP_EDP_PANEL_TARGET_LUMINANCE_VALUE, 492 - buf, sizeof(buf)); 493 - if (ret != sizeof(buf)) { 494 - drm_err(intel_dp->aux.drm_dev, 495 - "%s: Failed to set VESA Aux Luminance: %d\n", 496 - intel_dp->aux.name, ret); 497 - return -EINVAL; 498 - } else { 499 - return 0; 500 - } 501 - } 502 - 503 478 static void 504 479 intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u32 level) 505 480 { 506 481 struct intel_connector *connector = to_intel_connector(conn_state->connector); 507 482 struct intel_panel *panel = &connector->panel; 508 483 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); 509 - 510 - if (panel->backlight.edp.vesa.luminance_control_support) { 511 - if (!intel_dp_aux_vesa_set_luminance(connector, level)) 512 - return; 513 - } 514 484 515 485 if (!panel->backlight.edp.vesa.info.aux_set) { 516 486 const u32 pwm_level = intel_backlight_level_to_pwm(connector, level); ··· 498 528 struct intel_connector *connector = to_intel_connector(conn_state->connector); 499 529 struct intel_panel *panel = &connector->panel; 500 530 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); 501 - int ret; 502 - 503 - if (panel->backlight.edp.vesa.luminance_control_support) { 504 - ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_EDP_BACKLIGHT_MODE_SET_REGISTER, 505 - DP_EDP_PANEL_LUMINANCE_CONTROL_ENABLE); 506 - 507 - if (ret == 1) 508 - return; 509 - 510 - if (!intel_dp_aux_vesa_set_luminance(connector, level)) 511 - return; 512 - } 513 531 514 532 if (!panel->backlight.edp.vesa.info.aux_enable) { 515 533 u32 pwm_level; ··· 538 580 &connector->base.display_info.luminance_range; 539 581 struct intel_dp *intel_dp = intel_attached_dp(connector); 540 582 struct intel_panel *panel = &connector->panel; 541 - u16 current_level; 583 + u32 current_level; 542 584 u8 current_mode; 543 585 int ret; 544 586 545 - if (panel->backlight.edp.vesa.luminance_control_support) { 587 + ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info, 588 + luminance_range->max_luminance, 589 + panel->vbt.backlight.pwm_freq_hz, 590 + intel_dp->edp_dpcd, &current_level, &current_mode, 591 + false); 592 + if (ret < 0) 593 + return ret; 594 + 595 + drm_dbg_kms(display->drm, 596 + "[CONNECTOR:%d:%s] AUX VESA backlight enable is controlled through %s\n", 597 + connector->base.base.id, connector->base.name, 598 + dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_enable)); 599 + drm_dbg_kms(display->drm, 600 + "[CONNECTOR:%d:%s] AUX VESA backlight level is controlled through %s\n", 601 + connector->base.base.id, connector->base.name, 602 + dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_set)); 603 + 604 + if (!panel->backlight.edp.vesa.info.aux_set || 605 + !panel->backlight.edp.vesa.info.aux_enable) { 606 + ret = panel->backlight.pwm_funcs->setup(connector, pipe); 607 + if (ret < 0) { 608 + drm_err(display->drm, 609 + "[CONNECTOR:%d:%s] Failed to setup PWM backlight controls for eDP backlight: %d\n", 610 + connector->base.base.id, connector->base.name, ret); 611 + return ret; 612 + } 613 + } 614 + 615 + if (panel->backlight.edp.vesa.info.luminance_set) { 546 616 if (luminance_range->max_luminance) { 547 - panel->backlight.max = luminance_range->max_luminance; 617 + panel->backlight.max = panel->backlight.edp.vesa.info.max; 548 618 panel->backlight.min = luminance_range->min_luminance; 549 619 } else { 550 620 panel->backlight.max = 512; ··· 583 597 drm_dbg_kms(display->drm, 584 598 "[CONNECTOR:%d:%s] AUX VESA Nits backlight level is controlled through DPCD\n", 585 599 connector->base.base.id, connector->base.name); 586 - } else { 587 - ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info, 588 - panel->vbt.backlight.pwm_freq_hz, intel_dp->edp_dpcd, 589 - &current_level, &current_mode); 590 - if (ret < 0) 591 - return ret; 592 - 593 - drm_dbg_kms(display->drm, 594 - "[CONNECTOR:%d:%s] AUX VESA backlight enable is controlled through %s\n", 595 - connector->base.base.id, connector->base.name, 596 - dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_enable)); 597 - drm_dbg_kms(display->drm, 598 - "[CONNECTOR:%d:%s] AUX VESA backlight level is controlled through %s\n", 599 - connector->base.base.id, connector->base.name, 600 - dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_set)); 601 - 602 - if (!panel->backlight.edp.vesa.info.aux_set || 603 - !panel->backlight.edp.vesa.info.aux_enable) { 604 - ret = panel->backlight.pwm_funcs->setup(connector, pipe); 605 - if (ret < 0) { 606 - drm_err(display->drm, 607 - "[CONNECTOR:%d:%s] Failed to setup PWM backlight controls for eDP backlight: %d\n", 608 - connector->base.base.id, connector->base.name, ret); 609 - return ret; 610 - } 611 - } 612 - 613 - if (panel->backlight.edp.vesa.info.aux_set) { 614 - panel->backlight.max = panel->backlight.edp.vesa.info.max; 615 - panel->backlight.min = 0; 616 - if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) { 617 - panel->backlight.level = current_level; 618 - panel->backlight.enabled = panel->backlight.level != 0; 619 - } else { 620 - panel->backlight.level = panel->backlight.max; 621 - panel->backlight.enabled = false; 622 - } 600 + } else if (panel->backlight.edp.vesa.info.aux_set) { 601 + panel->backlight.max = panel->backlight.edp.vesa.info.max; 602 + panel->backlight.min = 0; 603 + if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) { 604 + panel->backlight.level = current_level; 605 + panel->backlight.enabled = panel->backlight.level != 0; 623 606 } else { 624 - panel->backlight.max = panel->backlight.pwm_level_max; 625 - panel->backlight.min = panel->backlight.pwm_level_min; 626 - if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_PWM) { 627 - panel->backlight.level = 628 - panel->backlight.pwm_funcs->get(connector, pipe); 629 - panel->backlight.enabled = panel->backlight.pwm_enabled; 630 - } else { 631 - panel->backlight.level = panel->backlight.max; 632 - panel->backlight.enabled = false; 633 - } 607 + panel->backlight.level = panel->backlight.max; 608 + panel->backlight.enabled = false; 609 + } 610 + } else { 611 + panel->backlight.max = panel->backlight.pwm_level_max; 612 + panel->backlight.min = panel->backlight.pwm_level_min; 613 + if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_PWM) { 614 + panel->backlight.level = 615 + panel->backlight.pwm_funcs->get(connector, pipe); 616 + panel->backlight.enabled = panel->backlight.pwm_enabled; 617 + } else { 618 + panel->backlight.level = panel->backlight.max; 619 + panel->backlight.enabled = false; 634 620 } 635 621 } 636 622
+1 -1
drivers/gpu/drm/nouveau/dispnv50/disp.c
··· 1839 1839 backlight = nv_connector->backlight; 1840 1840 if (backlight && backlight->uses_dpcd) 1841 1841 drm_edp_backlight_enable(&nv_connector->aux, &backlight->edp_info, 1842 - (u16)backlight->dev->props.brightness); 1842 + backlight->dev->props.brightness); 1843 1843 #endif 1844 1844 1845 1845 break;
+4 -3
drivers/gpu/drm/nouveau/nouveau_backlight.c
··· 245 245 246 246 if (nv_conn->type == DCB_CONNECTOR_eDP) { 247 247 int ret; 248 - u16 current_level; 248 + u32 current_level; 249 249 u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE]; 250 250 u8 current_mode; 251 251 ··· 261 261 NV_DEBUG(drm, "DPCD backlight controls supported on %s\n", 262 262 nv_conn->base.name); 263 263 264 - ret = drm_edp_backlight_init(&nv_conn->aux, &bl->edp_info, 0, edp_dpcd, 265 - &current_level, &current_mode); 264 + ret = drm_edp_backlight_init(&nv_conn->aux, &bl->edp_info, 265 + 0, 0, edp_dpcd, 266 + &current_level, &current_mode, false); 266 267 if (ret < 0) 267 268 return ret; 268 269
+10
drivers/gpu/drm/panel/Kconfig
··· 193 193 Say Y here if you want to enable support for Himax HX83112A-based 194 194 display panels, such as the one found in the Fairphone 4 smartphone. 195 195 196 + config DRM_PANEL_HIMAX_HX83112B 197 + tristate "Himax HX83112B-based DSI panel" 198 + depends on OF 199 + depends on DRM_MIPI_DSI 200 + depends on BACKLIGHT_CLASS_DEVICE 201 + select DRM_KMS_HELPER 202 + help 203 + Say Y here if you want to enable support for Himax HX83112B-based 204 + display panels, such as the one found in the Fairphone 3 smartphone. 205 + 196 206 config DRM_PANEL_HIMAX_HX8394 197 207 tristate "HIMAX HX8394 MIPI-DSI LCD panels" 198 208 depends on OF
+1
drivers/gpu/drm/panel/Makefile
··· 20 20 obj-$(CONFIG_DRM_PANEL_HIMAX_HX8279) += panel-himax-hx8279.o 21 21 obj-$(CONFIG_DRM_PANEL_HIMAX_HX83102) += panel-himax-hx83102.o 22 22 obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112A) += panel-himax-hx83112a.o 23 + obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112B) += panel-himax-hx83112b.o 23 24 obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o 24 25 obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o 25 26 obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
+1
drivers/gpu/drm/panel/panel-edp.c
··· 1967 1967 EDP_PANEL_ENTRY('C', 'M', 'N', 0x115e, &delay_200_500_e80_d50, "N116BCA-EA1"), 1968 1968 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1160, &delay_200_500_e80_d50, "N116BCJ-EAK"), 1969 1969 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1161, &delay_200_500_e80, "N116BCP-EA2"), 1970 + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1163, &delay_200_500_e80_d50, "N116BCJ-EAK"), 1970 1971 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), 1971 1972 EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"), 1972 1973 EDP_PANEL_ENTRY('C', 'M', 'N', 0x142e, &delay_200_500_e80_d50, "N140BGA-EA4"),
+430
drivers/gpu/drm/panel/panel-himax-hx83112b.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree. 4 + * Copyright (c) 2025 Luca Weiss <luca@lucaweiss.eu> 5 + */ 6 + 7 + #include <linux/backlight.h> 8 + #include <linux/delay.h> 9 + #include <linux/gpio/consumer.h> 10 + #include <linux/mod_devicetable.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 + #include <drm/drm_probe_helper.h> 20 + 21 + /* Manufacturer specific DSI commands */ 22 + #define HX83112B_SETPOWER1 0xb1 23 + #define HX83112B_SETDISP 0xb2 24 + #define HX83112B_SETDRV 0xb4 25 + #define HX83112B_SETEXTC 0xb9 26 + #define HX83112B_SETBANK 0xbd 27 + #define HX83112B_SETDGCLUT 0xc1 28 + #define HX83112B_SETDISMO 0xc2 29 + #define HX83112B_UNKNOWN1 0xc6 30 + #define HX83112B_SETPANEL 0xcc 31 + #define HX83112B_UNKNOWN2 0xd1 32 + #define HX83112B_SETPOWER2 0xd2 33 + #define HX83112B_SETGIP0 0xd3 34 + #define HX83112B_SETGIP1 0xd5 35 + #define HX83112B_SETGIP2 0xd6 36 + #define HX83112B_SETGIP3 0xd8 37 + #define HX83112B_SETIDLE 0xdd 38 + #define HX83112B_UNKNOWN3 0xe7 39 + #define HX83112B_UNKNOWN4 0xe9 40 + 41 + struct hx83112b_panel { 42 + struct drm_panel panel; 43 + struct mipi_dsi_device *dsi; 44 + struct regulator_bulk_data *supplies; 45 + struct gpio_desc *reset_gpio; 46 + }; 47 + 48 + static const struct regulator_bulk_data hx83112b_supplies[] = { 49 + { .supply = "iovcc" }, 50 + { .supply = "vsn" }, 51 + { .supply = "vsp" }, 52 + }; 53 + 54 + static inline struct hx83112b_panel *to_hx83112b_panel(struct drm_panel *panel) 55 + { 56 + return container_of(panel, struct hx83112b_panel, panel); 57 + } 58 + 59 + static void hx83112b_reset(struct hx83112b_panel *ctx) 60 + { 61 + gpiod_set_value_cansleep(ctx->reset_gpio, 0); 62 + usleep_range(10000, 11000); 63 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 64 + usleep_range(10000, 11000); 65 + gpiod_set_value_cansleep(ctx->reset_gpio, 0); 66 + usleep_range(10000, 11000); 67 + } 68 + 69 + static int hx83112b_on(struct hx83112b_panel *ctx) 70 + { 71 + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; 72 + 73 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETEXTC, 0x83, 0x11, 0x2b); 74 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01); 75 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISMO, 0x08, 0x70); 76 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03); 77 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 0x04, 0x38, 0x08, 0x70); 78 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); 79 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETPOWER1, 80 + 0xf8, 0x27, 0x27, 0x00, 0x00, 0x0b, 0x0e, 81 + 0x0b, 0x0e, 0x33); 82 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETPOWER2, 0x2d, 0x2d); 83 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 84 + 0x80, 0x02, 0x18, 0x80, 0x70, 0x00, 0x08, 85 + 0x1c, 0x08, 0x11, 0x05); 86 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xd1); 87 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 0x00, 0x08); 88 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 89 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02); 90 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 0xb5, 0x0a); 91 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); 92 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETIDLE, 93 + 0x00, 0x00, 0x08, 0x1c, 0x08, 0x34, 0x34, 94 + 0x88); 95 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDRV, 96 + 0x65, 0x6b, 0x00, 0x00, 0xd0, 0xd4, 0x36, 97 + 0xcf, 0x06, 0xce, 0x00, 0xce, 0x00, 0x00, 98 + 0x00, 0x07, 0x00, 0x2a, 0x07, 0x01, 0x07, 99 + 0x00, 0x00, 0x2a); 100 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03); 101 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc3); 102 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDRV, 0x01, 0x67, 0x2a); 103 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 104 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); 105 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT, 0x01); 106 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01); 107 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT, 108 + 0xff, 0xfb, 0xf9, 0xf6, 0xf4, 0xf1, 0xef, 109 + 0xea, 0xe7, 0xe5, 0xe2, 0xdf, 0xdd, 0xda, 110 + 0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc5, 0xbe, 111 + 0xb7, 0xb0, 0xa8, 0xa0, 0x98, 0x8e, 0x85, 112 + 0x7b, 0x72, 0x69, 0x5e, 0x53, 0x48, 0x3e, 113 + 0x35, 0x2b, 0x22, 0x17, 0x0d, 0x09, 0x07, 114 + 0x05, 0x01, 0x00, 0x26, 0xf0, 0x86, 0x25, 115 + 0x6e, 0xb6, 0xdd, 0xf3, 0xd8, 0xcc, 0x9b, 116 + 0x00); 117 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02); 118 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT, 119 + 0xff, 0xfb, 0xf9, 0xf6, 0xf4, 0xf1, 0xef, 120 + 0xea, 0xe7, 0xe5, 0xe2, 0xdf, 0xdd, 0xda, 121 + 0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc5, 0xbe, 122 + 0xb7, 0xb0, 0xa8, 0xa0, 0x98, 0x8e, 0x85, 123 + 0x7b, 0x72, 0x69, 0x5e, 0x53, 0x48, 0x3e, 124 + 0x35, 0x2b, 0x22, 0x17, 0x0d, 0x09, 0x07, 125 + 0x05, 0x01, 0x00, 0x26, 0xf0, 0x86, 0x25, 126 + 0x6e, 0xb6, 0xdd, 0xf3, 0xd8, 0xcc, 0x9b, 127 + 0x00); 128 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03); 129 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT, 130 + 0xff, 0xfb, 0xf9, 0xf6, 0xf4, 0xf1, 0xef, 131 + 0xea, 0xe7, 0xe5, 0xe2, 0xdf, 0xdd, 0xda, 132 + 0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc5, 0xbe, 133 + 0xb7, 0xb0, 0xa8, 0xa0, 0x98, 0x8e, 0x85, 134 + 0x7b, 0x72, 0x69, 0x5e, 0x53, 0x48, 0x3e, 135 + 0x35, 0x2b, 0x22, 0x17, 0x0d, 0x09, 0x07, 136 + 0x05, 0x01, 0x00, 0x26, 0xf0, 0x86, 0x25, 137 + 0x6e, 0xb6, 0xdd, 0xf3, 0xd8, 0xcc, 0x9b, 138 + 0x00); 139 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); 140 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISMO, 0xc8); 141 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETPANEL, 0x08); 142 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP0, 143 + 0x81, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 144 + 0x04, 0x00, 0x01, 0x13, 0x40, 0x04, 0x09, 145 + 0x09, 0x0b, 0x0b, 0x32, 0x10, 0x08, 0x00, 146 + 0x08, 0x32, 0x10, 0x08, 0x00, 0x08, 0x32, 147 + 0x10, 0x08, 0x00, 0x08, 0x00, 0x00, 0x0a, 148 + 0x08, 0x7b); 149 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc5); 150 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN1, 0xf7); 151 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 152 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xd4); 153 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN1, 0x6e); 154 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 155 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xef); 156 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP0, 0x0c); 157 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 158 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01); 159 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc8); 160 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP0, 0xa1); 161 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 162 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); 163 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP1, 164 + 0x18, 0x18, 0x19, 0x18, 0x18, 0x20, 0x18, 165 + 0x18, 0x18, 0x10, 0x10, 0x18, 0x18, 0x00, 166 + 0x00, 0x18, 0x18, 0x01, 0x01, 0x18, 0x18, 167 + 0x28, 0x28, 0x18, 0x18, 0x18, 0x18, 0x18, 168 + 0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x35, 169 + 0x35, 0x36, 0x36, 0x37, 0x37, 0x18, 0x18, 170 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xfc, 171 + 0xfc, 0x00, 0x00, 0xfc, 0xfc, 0x00, 0x00); 172 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP2, 173 + 0x18, 0x18, 0x19, 0x18, 0x18, 0x20, 0x19, 174 + 0x18, 0x18, 0x10, 0x10, 0x18, 0x18, 0x00, 175 + 0x00, 0x18, 0x18, 0x01, 0x01, 0x18, 0x18, 176 + 0x28, 0x28, 0x18, 0x18, 0x18, 0x18, 0x18, 177 + 0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x35, 178 + 0x35, 0x36, 0x36, 0x37, 0x37, 0x18, 0x18, 179 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); 180 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3, 181 + 0xaa, 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa, 182 + 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa, 0xaa, 183 + 0xab, 0xaf, 0xef, 0xaa, 0xaa, 0xaa, 0xaa, 184 + 0xaf, 0xea, 0xaa); 185 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01); 186 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3, 187 + 0xaa, 0xaa, 0xab, 0xaf, 0xea, 0xaa, 0xaa, 188 + 0xaa, 0xae, 0xaf, 0xea, 0xaa); 189 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02); 190 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3, 191 + 0xaa, 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa, 192 + 0xaa, 0xaa, 0xaf, 0xea, 0xaa); 193 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03); 194 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3, 195 + 0xba, 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa, 196 + 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xba, 0xaa, 197 + 0xaa, 0xaf, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 198 + 0xaf, 0xea, 0xaa); 199 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); 200 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xe4); 201 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 0x17, 0x69); 202 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 203 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 204 + 0x09, 0x09, 0x00, 0x07, 0xe8, 0x00, 0x26, 205 + 0x00, 0x07, 0x00, 0x00, 0xe8, 0x32, 0x00, 206 + 0xe9, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x01, 207 + 0x01, 0x00, 0x12, 0x04); 208 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01); 209 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 210 + 0x02, 0x00, 0x01, 0x20, 0x01, 0x18, 0x08, 211 + 0xa8, 0x09); 212 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02); 213 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 0x20, 0x20, 0x00); 214 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03); 215 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 216 + 0x00, 0xdc, 0x11, 0x70, 0x00, 0x20); 217 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc9); 218 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 219 + 0x2a, 0xce, 0x02, 0x70, 0x01, 0x04); 220 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 221 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); 222 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN2, 0x27); 223 + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 224 + mipi_dsi_msleep(&dsi_ctx, 120); 225 + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 226 + mipi_dsi_msleep(&dsi_ctx, 20); 227 + mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0x0000); 228 + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 229 + 0x24); 230 + mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); 231 + 232 + return dsi_ctx.accum_err; 233 + } 234 + 235 + static int hx83112b_off(struct hx83112b_panel *ctx) 236 + { 237 + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; 238 + 239 + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); 240 + mipi_dsi_msleep(&dsi_ctx, 20); 241 + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 242 + mipi_dsi_msleep(&dsi_ctx, 120); 243 + 244 + return dsi_ctx.accum_err; 245 + } 246 + 247 + static int hx83112b_prepare(struct drm_panel *panel) 248 + { 249 + struct hx83112b_panel *ctx = to_hx83112b_panel(panel); 250 + struct device *dev = &ctx->dsi->dev; 251 + int ret; 252 + 253 + ret = regulator_bulk_enable(ARRAY_SIZE(hx83112b_supplies), ctx->supplies); 254 + if (ret < 0) { 255 + dev_err(dev, "Failed to enable regulators: %d\n", ret); 256 + return ret; 257 + } 258 + 259 + hx83112b_reset(ctx); 260 + 261 + ret = hx83112b_on(ctx); 262 + if (ret < 0) { 263 + dev_err(dev, "Failed to initialize panel: %d\n", ret); 264 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 265 + regulator_bulk_disable(ARRAY_SIZE(hx83112b_supplies), ctx->supplies); 266 + return ret; 267 + } 268 + 269 + return 0; 270 + } 271 + 272 + static int hx83112b_unprepare(struct drm_panel *panel) 273 + { 274 + struct hx83112b_panel *ctx = to_hx83112b_panel(panel); 275 + struct device *dev = &ctx->dsi->dev; 276 + int ret; 277 + 278 + ret = hx83112b_off(ctx); 279 + if (ret < 0) 280 + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); 281 + 282 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 283 + regulator_bulk_disable(ARRAY_SIZE(hx83112b_supplies), ctx->supplies); 284 + 285 + return 0; 286 + } 287 + 288 + static const struct drm_display_mode hx83112b_mode = { 289 + .clock = (1080 + 40 + 4 + 12) * (2160 + 32 + 2 + 2) * 60 / 1000, 290 + .hdisplay = 1080, 291 + .hsync_start = 1080 + 40, 292 + .hsync_end = 1080 + 40 + 4, 293 + .htotal = 1080 + 40 + 4 + 12, 294 + .vdisplay = 2160, 295 + .vsync_start = 2160 + 32, 296 + .vsync_end = 2160 + 32 + 2, 297 + .vtotal = 2160 + 32 + 2 + 2, 298 + .width_mm = 65, 299 + .height_mm = 128, 300 + .type = DRM_MODE_TYPE_DRIVER, 301 + }; 302 + 303 + static int hx83112b_get_modes(struct drm_panel *panel, 304 + struct drm_connector *connector) 305 + { 306 + return drm_connector_helper_get_modes_fixed(connector, &hx83112b_mode); 307 + } 308 + 309 + static const struct drm_panel_funcs hx83112b_panel_funcs = { 310 + .prepare = hx83112b_prepare, 311 + .unprepare = hx83112b_unprepare, 312 + .get_modes = hx83112b_get_modes, 313 + }; 314 + 315 + static int hx83112b_bl_update_status(struct backlight_device *bl) 316 + { 317 + struct mipi_dsi_device *dsi = bl_get_data(bl); 318 + u16 brightness = backlight_get_brightness(bl); 319 + int ret; 320 + 321 + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 322 + 323 + ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); 324 + if (ret < 0) 325 + return ret; 326 + 327 + dsi->mode_flags |= MIPI_DSI_MODE_LPM; 328 + 329 + return 0; 330 + } 331 + 332 + static const struct backlight_ops hx83112b_bl_ops = { 333 + .update_status = hx83112b_bl_update_status, 334 + }; 335 + 336 + static struct backlight_device * 337 + hx83112b_create_backlight(struct mipi_dsi_device *dsi) 338 + { 339 + struct device *dev = &dsi->dev; 340 + const struct backlight_properties props = { 341 + .type = BACKLIGHT_RAW, 342 + .brightness = 4095, 343 + .max_brightness = 4095, 344 + }; 345 + 346 + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, 347 + &hx83112b_bl_ops, &props); 348 + } 349 + 350 + static int hx83112b_probe(struct mipi_dsi_device *dsi) 351 + { 352 + struct device *dev = &dsi->dev; 353 + struct hx83112b_panel *ctx; 354 + int ret; 355 + 356 + ctx = devm_drm_panel_alloc(dev, struct hx83112b_panel, panel, 357 + &hx83112b_panel_funcs, 358 + DRM_MODE_CONNECTOR_DSI); 359 + if (IS_ERR(ctx)) 360 + return PTR_ERR(ctx); 361 + 362 + ret = devm_regulator_bulk_get_const(dev, 363 + ARRAY_SIZE(hx83112b_supplies), 364 + hx83112b_supplies, 365 + &ctx->supplies); 366 + if (ret < 0) 367 + return ret; 368 + 369 + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 370 + if (IS_ERR(ctx->reset_gpio)) 371 + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 372 + "Failed to get reset-gpios\n"); 373 + 374 + ctx->dsi = dsi; 375 + mipi_dsi_set_drvdata(dsi, ctx); 376 + 377 + dsi->lanes = 4; 378 + dsi->format = MIPI_DSI_FMT_RGB888; 379 + dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST | 380 + MIPI_DSI_CLOCK_NON_CONTINUOUS | 381 + MIPI_DSI_MODE_VIDEO_NO_HSA | MIPI_DSI_MODE_LPM; 382 + 383 + ctx->panel.prepare_prev_first = true; 384 + 385 + ctx->panel.backlight = hx83112b_create_backlight(dsi); 386 + if (IS_ERR(ctx->panel.backlight)) 387 + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), 388 + "Failed to create backlight\n"); 389 + 390 + drm_panel_add(&ctx->panel); 391 + 392 + ret = mipi_dsi_attach(dsi); 393 + if (ret < 0) { 394 + drm_panel_remove(&ctx->panel); 395 + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); 396 + } 397 + 398 + return 0; 399 + } 400 + 401 + static void hx83112b_remove(struct mipi_dsi_device *dsi) 402 + { 403 + struct hx83112b_panel *ctx = mipi_dsi_get_drvdata(dsi); 404 + int ret; 405 + 406 + ret = mipi_dsi_detach(dsi); 407 + if (ret < 0) 408 + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 409 + 410 + drm_panel_remove(&ctx->panel); 411 + } 412 + 413 + static const struct of_device_id hx83112b_of_match[] = { 414 + { .compatible = "djn,98-03057-6598b-i" }, 415 + { /* sentinel */ } 416 + }; 417 + MODULE_DEVICE_TABLE(of, hx83112b_of_match); 418 + 419 + static struct mipi_dsi_driver hx83112b_driver = { 420 + .probe = hx83112b_probe, 421 + .remove = hx83112b_remove, 422 + .driver = { 423 + .name = "panel-himax-hx83112b", 424 + .of_match_table = hx83112b_of_match, 425 + }, 426 + }; 427 + module_mipi_dsi_driver(hx83112b_driver); 428 + 429 + MODULE_DESCRIPTION("DRM driver for hx83112b-equipped DSI panels"); 430 + MODULE_LICENSE("GPL");
+17 -22
drivers/gpu/drm/panel/panel-raydium-rm67200.c
··· 36 36 37 37 static void raydium_rm67200_reset(struct raydium_rm67200 *ctx) 38 38 { 39 - gpiod_set_value_cansleep(ctx->reset_gpio, 0); 40 - msleep(60); 41 - gpiod_set_value_cansleep(ctx->reset_gpio, 1); 42 - msleep(60); 43 - gpiod_set_value_cansleep(ctx->reset_gpio, 0); 44 - msleep(60); 39 + if (ctx->reset_gpio) { 40 + gpiod_set_value_cansleep(ctx->reset_gpio, 0); 41 + msleep(60); 42 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 43 + msleep(60); 44 + gpiod_set_value_cansleep(ctx->reset_gpio, 0); 45 + msleep(60); 46 + } 45 47 } 46 48 47 49 static void raydium_rm67200_write(struct mipi_dsi_multi_context *ctx, ··· 320 318 static int raydium_rm67200_prepare(struct drm_panel *panel) 321 319 { 322 320 struct raydium_rm67200 *ctx = to_raydium_rm67200(panel); 321 + struct mipi_dsi_multi_context mctx = { .dsi = ctx->dsi }; 323 322 int ret; 324 323 325 324 ret = regulator_bulk_enable(ctx->num_supplies, ctx->supplies); ··· 330 327 raydium_rm67200_reset(ctx); 331 328 332 329 msleep(60); 330 + 331 + ctx->panel_info->panel_setup(&mctx); 332 + mipi_dsi_dcs_exit_sleep_mode_multi(&mctx); 333 + mipi_dsi_msleep(&mctx, 120); 334 + mipi_dsi_dcs_set_display_on_multi(&mctx); 335 + mipi_dsi_msleep(&mctx, 30); 333 336 334 337 return 0; 335 338 } ··· 350 341 msleep(60); 351 342 352 343 return 0; 353 - } 354 - 355 - static int raydium_rm67200_enable(struct drm_panel *panel) 356 - { 357 - struct raydium_rm67200 *rm67200 = to_raydium_rm67200(panel); 358 - struct mipi_dsi_multi_context ctx = { .dsi = rm67200->dsi }; 359 - 360 - rm67200->panel_info->panel_setup(&ctx); 361 - mipi_dsi_dcs_exit_sleep_mode_multi(&ctx); 362 - mipi_dsi_msleep(&ctx, 120); 363 - mipi_dsi_dcs_set_display_on_multi(&ctx); 364 - mipi_dsi_msleep(&ctx, 30); 365 - 366 - return ctx.accum_err; 367 344 } 368 345 369 346 static int raydium_rm67200_disable(struct drm_panel *panel) ··· 376 381 .prepare = raydium_rm67200_prepare, 377 382 .unprepare = raydium_rm67200_unprepare, 378 383 .get_modes = raydium_rm67200_get_modes, 379 - .enable = raydium_rm67200_enable, 380 384 .disable = raydium_rm67200_disable, 381 385 }; 382 386 ··· 403 409 if (ret < 0) 404 410 return ret; 405 411 406 - ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 412 + ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 407 413 if (IS_ERR(ctx->reset_gpio)) 408 414 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 409 415 "Failed to get reset-gpios\n"); ··· 464 470 .vtotal = 1952, 465 471 .width_mm = 68, /* 68.04mm */ 466 472 .height_mm = 121, /* 120.96mm */ 473 + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, 467 474 .type = DRM_MODE_TYPE_DRIVER, 468 475 }, 469 476 .regulators = w552793baa_regulators,
+1 -1
drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c
··· 244 244 .init_func = s6d7aa0_lsl080al02_init, 245 245 .off_func = s6d7aa0_lsl080al02_off, 246 246 .drm_mode = &s6d7aa0_lsl080al02_mode, 247 - .mode_flags = MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_NO_HFP, 247 + .mode_flags = MIPI_DSI_MODE_VIDEO_NO_HFP, 248 248 .bus_flags = 0, 249 249 250 250 .has_backlight = false,
+1 -1
drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
··· 992 992 dsi->lanes = 4; 993 993 dsi->format = MIPI_DSI_FMT_RGB888; 994 994 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST 995 - | MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_AUTO_VERT; 995 + | MIPI_DSI_MODE_VIDEO_AUTO_VERT; 996 996 997 997 ret = s6e8aa0_parse_dt(ctx); 998 998 if (ret < 0)
+3 -2
drivers/gpu/drm/panthor/panthor_gpu.c
··· 297 297 298 298 gpu_write64(ptdev, pwron_reg, mask); 299 299 300 - ret = gpu_read64_relaxed_poll_timeout(ptdev, pwrtrans_reg, val, 301 - !(mask & val), 100, timeout_us); 300 + ret = gpu_read64_relaxed_poll_timeout(ptdev, rdy_reg, val, 301 + (mask & val) == val, 302 + 100, timeout_us); 302 303 if (ret) { 303 304 drm_err(&ptdev->base, "timeout waiting on %s:%llx readiness", 304 305 blk_name, mask);
+25 -1
drivers/gpu/drm/scheduler/tests/mock_scheduler.c
··· 200 200 return &job->hw_fence; 201 201 } 202 202 203 + /* 204 + * Normally, drivers would take appropriate measures in this callback, such as 205 + * killing the entity the faulty job is associated with, resetting the hardware 206 + * and / or resubmitting non-faulty jobs. 207 + * 208 + * For the mock scheduler, there are no hardware rings to be resetted nor jobs 209 + * to be resubmitted. Thus, this function merely ensures that 210 + * a) timedout fences get signaled properly and removed from the pending list 211 + * b) the mock scheduler framework gets informed about the timeout via a flag 212 + * c) The drm_sched_job, not longer needed, gets freed 213 + */ 203 214 static enum drm_gpu_sched_stat 204 215 mock_sched_timedout_job(struct drm_sched_job *sched_job) 205 216 { 217 + struct drm_mock_scheduler *sched = drm_sched_to_mock_sched(sched_job->sched); 206 218 struct drm_mock_sched_job *job = drm_sched_job_to_mock_job(sched_job); 219 + unsigned long flags; 207 220 208 - job->flags |= DRM_MOCK_SCHED_JOB_TIMEDOUT; 221 + spin_lock_irqsave(&sched->lock, flags); 222 + if (!dma_fence_is_signaled_locked(&job->hw_fence)) { 223 + list_del(&job->link); 224 + job->flags |= DRM_MOCK_SCHED_JOB_TIMEDOUT; 225 + dma_fence_set_error(&job->hw_fence, -ETIMEDOUT); 226 + dma_fence_signal_locked(&job->hw_fence); 227 + } 228 + spin_unlock_irqrestore(&sched->lock, flags); 229 + 230 + dma_fence_put(&job->hw_fence); 231 + drm_sched_job_cleanup(sched_job); 232 + /* Mock job itself is freed by the kunit framework. */ 209 233 210 234 return DRM_GPU_SCHED_STAT_NOMINAL; 211 235 }
+4 -4
drivers/gpu/drm/tests/drm_format_helper_test.c
··· 735 735 NULL : &result->dst_pitch; 736 736 737 737 drm_fb_xrgb8888_to_rgb565(&dst, dst_pitch, &src, &fb, &params->clip, 738 - &fmtcnv_state, false); 738 + &fmtcnv_state); 739 739 buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); 740 740 KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); 741 741 742 742 buf = dst.vaddr; /* restore original value of buf */ 743 - drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, &params->clip, 744 - &fmtcnv_state, true); 743 + drm_fb_xrgb8888_to_rgb565be(&dst, &result->dst_pitch, &src, &fb, &params->clip, 744 + &fmtcnv_state); 745 745 buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); 746 746 KUNIT_EXPECT_MEMEQ(test, buf, result->expected_swab, dst_size); 747 747 ··· 749 749 memset(buf, 0, dst_size); 750 750 751 751 drm_fb_xrgb8888_to_rgb565(&dst, dst_pitch, &src, &fb, &params->clip, 752 - &fmtcnv_state, false); 752 + &fmtcnv_state); 753 753 buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); 754 754 KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); 755 755 }
+2 -1
drivers/gpu/drm/tidss/Makefile
··· 7 7 tidss_irq.o \ 8 8 tidss_plane.o \ 9 9 tidss_scale_coefs.o \ 10 - tidss_dispc.o 10 + tidss_dispc.o \ 11 + tidss_oldi.o 11 12 12 13 obj-$(CONFIG_DRM_TIDSS) += tidss.o
+56 -36
drivers/gpu/drm/tidss/tidss_dispc.c
··· 146 146 const struct dispc_features dispc_am65x_feats = { 147 147 .max_pclk_khz = { 148 148 [DISPC_VP_DPI] = 165000, 149 - [DISPC_VP_OLDI] = 165000, 149 + [DISPC_VP_OLDI_AM65X] = 165000, 150 150 }, 151 151 152 152 .scaling = { ··· 176 176 .vp_name = { "vp1", "vp2" }, 177 177 .ovr_name = { "ovr1", "ovr2" }, 178 178 .vpclk_name = { "vp1", "vp2" }, 179 - .vp_bus_type = { DISPC_VP_OLDI, DISPC_VP_DPI }, 179 + .vp_bus_type = { DISPC_VP_OLDI_AM65X, DISPC_VP_DPI }, 180 180 181 181 .vp_feat = { .color = { 182 182 .has_ctm = true, ··· 491 491 void __iomem *base_ovr[TIDSS_MAX_PORTS]; 492 492 void __iomem *base_vp[TIDSS_MAX_PORTS]; 493 493 494 - struct regmap *oldi_io_ctrl; 494 + struct regmap *am65x_oldi_io_ctrl; 495 495 496 496 struct clk *vp_clk[TIDSS_MAX_PORTS]; 497 497 ··· 564 564 void __iomem *base = dispc->base_vp[hw_videoport]; 565 565 566 566 return ioread32(base + reg); 567 + } 568 + 569 + int tidss_configure_oldi(struct tidss_device *tidss, u32 hw_videoport, 570 + u32 oldi_cfg) 571 + { 572 + u32 count = 0; 573 + u32 oldi_reset_bit = BIT(5 + hw_videoport); 574 + 575 + dispc_vp_write(tidss->dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, oldi_cfg); 576 + 577 + while (!(oldi_reset_bit & dispc_read(tidss->dispc, DSS_SYSSTATUS)) && 578 + count < 10000) 579 + count++; 580 + 581 + if (!(oldi_reset_bit & dispc_read(tidss->dispc, DSS_SYSSTATUS))) 582 + return -ETIMEDOUT; 583 + 584 + return 0; 585 + } 586 + 587 + void tidss_disable_oldi(struct tidss_device *tidss, u32 hw_videoport) 588 + { 589 + dispc_vp_write(tidss->dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, 0); 567 590 } 568 591 569 592 /* ··· 1039 1016 } 1040 1017 } 1041 1018 1042 - enum dispc_oldi_mode_reg_val { SPWG_18 = 0, JEIDA_24 = 1, SPWG_24 = 2 }; 1043 - 1044 1019 struct dispc_bus_format { 1045 1020 u32 bus_fmt; 1046 1021 u32 data_width; 1047 1022 bool is_oldi_fmt; 1048 - enum dispc_oldi_mode_reg_val oldi_mode_reg_val; 1023 + enum oldi_mode_reg_val am65x_oldi_mode_reg_val; 1049 1024 }; 1050 1025 1051 1026 static const struct dispc_bus_format dispc_bus_formats[] = { ··· 1087 1066 return -EINVAL; 1088 1067 } 1089 1068 1090 - if (dispc->feat->vp_bus_type[hw_videoport] != DISPC_VP_OLDI && 1069 + if (dispc->feat->vp_bus_type[hw_videoport] != DISPC_VP_OLDI_AM65X && 1091 1070 fmt->is_oldi_fmt) { 1092 1071 dev_dbg(dispc->dev, "%s: %s is not OLDI-port\n", 1093 1072 __func__, dispc->feat->vp_name[hw_videoport]); ··· 1097 1076 return 0; 1098 1077 } 1099 1078 1100 - static void dispc_oldi_tx_power(struct dispc_device *dispc, bool power) 1079 + static void dispc_am65x_oldi_tx_power(struct dispc_device *dispc, bool power) 1101 1080 { 1102 - u32 val = power ? 0 : OLDI_PWRDN_TX; 1081 + u32 val = power ? 0 : AM65X_OLDI_PWRDN_TX; 1103 1082 1104 - if (WARN_ON(!dispc->oldi_io_ctrl)) 1083 + if (WARN_ON(!dispc->am65x_oldi_io_ctrl)) 1105 1084 return; 1106 1085 1107 - regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT0_IO_CTRL, 1108 - OLDI_PWRDN_TX, val); 1109 - regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT1_IO_CTRL, 1110 - OLDI_PWRDN_TX, val); 1111 - regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT2_IO_CTRL, 1112 - OLDI_PWRDN_TX, val); 1113 - regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT3_IO_CTRL, 1114 - OLDI_PWRDN_TX, val); 1115 - regmap_update_bits(dispc->oldi_io_ctrl, OLDI_CLK_IO_CTRL, 1116 - OLDI_PWRDN_TX, val); 1086 + regmap_update_bits(dispc->am65x_oldi_io_ctrl, AM65X_OLDI_DAT0_IO_CTRL, 1087 + AM65X_OLDI_PWRDN_TX, val); 1088 + regmap_update_bits(dispc->am65x_oldi_io_ctrl, AM65X_OLDI_DAT1_IO_CTRL, 1089 + AM65X_OLDI_PWRDN_TX, val); 1090 + regmap_update_bits(dispc->am65x_oldi_io_ctrl, AM65X_OLDI_DAT2_IO_CTRL, 1091 + AM65X_OLDI_PWRDN_TX, val); 1092 + regmap_update_bits(dispc->am65x_oldi_io_ctrl, AM65X_OLDI_DAT3_IO_CTRL, 1093 + AM65X_OLDI_PWRDN_TX, val); 1094 + regmap_update_bits(dispc->am65x_oldi_io_ctrl, AM65X_OLDI_CLK_IO_CTRL, 1095 + AM65X_OLDI_PWRDN_TX, val); 1117 1096 } 1118 1097 1119 1098 static void dispc_set_num_datalines(struct dispc_device *dispc, ··· 1142 1121 VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, v, 10, 8); 1143 1122 } 1144 1123 1145 - static void dispc_enable_oldi(struct dispc_device *dispc, u32 hw_videoport, 1146 - const struct dispc_bus_format *fmt) 1124 + static void dispc_enable_am65x_oldi(struct dispc_device *dispc, u32 hw_videoport, 1125 + const struct dispc_bus_format *fmt) 1147 1126 { 1148 1127 u32 oldi_cfg = 0; 1149 1128 u32 oldi_reset_bit = BIT(5 + hw_videoport); ··· 1162 1141 1163 1142 oldi_cfg |= BIT(7); /* DEPOL */ 1164 1143 1165 - oldi_cfg = FLD_MOD(oldi_cfg, fmt->oldi_mode_reg_val, 3, 1); 1144 + oldi_cfg = FLD_MOD(oldi_cfg, fmt->am65x_oldi_mode_reg_val, 3, 1); 1166 1145 1167 1146 oldi_cfg |= BIT(12); /* SOFTRST */ 1168 1147 ··· 1191 1170 if (WARN_ON(!fmt)) 1192 1171 return; 1193 1172 1194 - if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) { 1195 - dispc_oldi_tx_power(dispc, true); 1173 + if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI_AM65X) { 1174 + dispc_am65x_oldi_tx_power(dispc, true); 1196 1175 1197 - dispc_enable_oldi(dispc, hw_videoport, fmt); 1176 + dispc_enable_am65x_oldi(dispc, hw_videoport, fmt); 1198 1177 } 1199 1178 } 1200 1179 ··· 1250 1229 align = true; 1251 1230 1252 1231 /* always use DE_HIGH for OLDI */ 1253 - if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) 1232 + if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI_AM65X) 1254 1233 ieo = false; 1255 1234 1256 1235 dispc_vp_write(dispc, hw_videoport, DISPC_VP_POL_FREQ, ··· 1276 1255 1277 1256 void dispc_vp_unprepare(struct dispc_device *dispc, u32 hw_videoport) 1278 1257 { 1279 - if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) { 1258 + if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI_AM65X) { 1280 1259 dispc_vp_write(dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, 0); 1281 1260 1282 - dispc_oldi_tx_power(dispc, false); 1261 + dispc_am65x_oldi_tx_power(dispc, false); 1283 1262 } 1284 1263 } 1285 1264 ··· 1441 1420 * Calculate the percentage difference between the requested pixel clock rate 1442 1421 * and the effective rate resulting from calculating the clock divider value. 1443 1422 */ 1444 - static 1445 1423 unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate) 1446 1424 { 1447 1425 int r = rate / 100, rr = real_rate / 100; ··· 2872 2852 static int dispc_init_am65x_oldi_io_ctrl(struct device *dev, 2873 2853 struct dispc_device *dispc) 2874 2854 { 2875 - dispc->oldi_io_ctrl = 2855 + dispc->am65x_oldi_io_ctrl = 2876 2856 syscon_regmap_lookup_by_phandle(dev->of_node, 2877 2857 "ti,am65x-oldi-io-ctrl"); 2878 - if (PTR_ERR(dispc->oldi_io_ctrl) == -ENODEV) { 2879 - dispc->oldi_io_ctrl = NULL; 2880 - } else if (IS_ERR(dispc->oldi_io_ctrl)) { 2858 + if (PTR_ERR(dispc->am65x_oldi_io_ctrl) == -ENODEV) { 2859 + dispc->am65x_oldi_io_ctrl = NULL; 2860 + } else if (IS_ERR(dispc->am65x_oldi_io_ctrl)) { 2881 2861 dev_err(dev, "%s: syscon_regmap_lookup_by_phandle failed %ld\n", 2882 - __func__, PTR_ERR(dispc->oldi_io_ctrl)); 2883 - return PTR_ERR(dispc->oldi_io_ctrl); 2862 + __func__, PTR_ERR(dispc->am65x_oldi_io_ctrl)); 2863 + return PTR_ERR(dispc->am65x_oldi_io_ctrl); 2884 2864 } 2885 2865 return 0; 2886 2866 }
+6 -1
drivers/gpu/drm/tidss/tidss_dispc.h
··· 58 58 59 59 enum dispc_vp_bus_type { 60 60 DISPC_VP_DPI, /* DPI output */ 61 - DISPC_VP_OLDI, /* OLDI (LVDS) output */ 61 + DISPC_VP_OLDI_AM65X, /* OLDI (LVDS) output for AM65x DSS */ 62 62 DISPC_VP_INTERNAL, /* SoC internal routing */ 63 63 DISPC_VP_TIED_OFF, /* Tied off / Unavailable */ 64 64 DISPC_VP_MAX_BUS_TYPE, ··· 100 100 extern const struct dispc_features dispc_am62l_feats; 101 101 extern const struct dispc_features dispc_am65x_feats; 102 102 extern const struct dispc_features dispc_j721e_feats; 103 + 104 + int tidss_configure_oldi(struct tidss_device *tidss, u32 hw_videoport, 105 + u32 oldi_cfg); 106 + void tidss_disable_oldi(struct tidss_device *tidss, u32 hw_videoport); 107 + unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate); 103 108 104 109 void dispc_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask); 105 110 dispc_irq_t dispc_read_and_clear_irqstatus(struct dispc_device *dispc);
+23 -6
drivers/gpu/drm/tidss/tidss_dispc_regs.h
··· 226 226 #define DISPC_VP_DSS_DMA_THREADSIZE 0x170 /* J721E */ 227 227 #define DISPC_VP_DSS_DMA_THREADSIZE_STATUS 0x174 /* J721E */ 228 228 229 + /* OLDI Config Bits (DISPC_VP_DSS_OLDI_CFG) */ 230 + #define OLDI_ENABLE BIT(0) 231 + #define OLDI_MAP (BIT(1) | BIT(2) | BIT(3)) 232 + #define OLDI_SRC BIT(4) 233 + #define OLDI_CLONE_MODE BIT(5) 234 + #define OLDI_MASTERSLAVE BIT(6) 235 + #define OLDI_DEPOL BIT(7) 236 + #define OLDI_MSB BIT(8) 237 + #define OLDI_LBEN BIT(9) 238 + #define OLDI_LBDATA BIT(10) 239 + #define OLDI_DUALMODESYNC BIT(11) 240 + #define OLDI_SOFTRST BIT(12) 241 + #define OLDI_TPATCFG BIT(13) 242 + 243 + /* LVDS Format values for OLDI_MAP field in DISPC_VP_OLDI_CFG register */ 244 + enum oldi_mode_reg_val { SPWG_18 = 0, JEIDA_24 = 1, SPWG_24 = 2 }; 245 + 229 246 /* 230 247 * OLDI IO_CTRL register offsets. On AM654 the registers are found 231 248 * from CTRL_MMR0, there the syscon regmap should map 0x14 bytes from 232 249 * CTRLMMR0P1_OLDI_DAT0_IO_CTRL to CTRLMMR0P1_OLDI_CLK_IO_CTRL 233 250 * register range. 234 251 */ 235 - #define OLDI_DAT0_IO_CTRL 0x00 236 - #define OLDI_DAT1_IO_CTRL 0x04 237 - #define OLDI_DAT2_IO_CTRL 0x08 238 - #define OLDI_DAT3_IO_CTRL 0x0C 239 - #define OLDI_CLK_IO_CTRL 0x10 252 + #define AM65X_OLDI_DAT0_IO_CTRL 0x00 253 + #define AM65X_OLDI_DAT1_IO_CTRL 0x04 254 + #define AM65X_OLDI_DAT2_IO_CTRL 0x08 255 + #define AM65X_OLDI_DAT3_IO_CTRL 0x0C 256 + #define AM65X_OLDI_CLK_IO_CTRL 0x10 240 257 241 - #define OLDI_PWRDN_TX BIT(8) 258 + #define AM65X_OLDI_PWRDN_TX BIT(8) 242 259 243 260 #endif /* __TIDSS_DISPC_REGS_H */
+9
drivers/gpu/drm/tidss/tidss_drv.c
··· 24 24 #include "tidss_drv.h" 25 25 #include "tidss_kms.h" 26 26 #include "tidss_irq.h" 27 + #include "tidss_oldi.h" 27 28 28 29 /* Power management */ 29 30 ··· 148 147 return ret; 149 148 } 150 149 150 + ret = tidss_oldi_init(tidss); 151 + if (ret) 152 + return dev_err_probe(dev, ret, "failed to init OLDI\n"); 153 + 151 154 pm_runtime_enable(dev); 152 155 153 156 pm_runtime_set_autosuspend_delay(dev, 1000); ··· 208 203 pm_runtime_dont_use_autosuspend(dev); 209 204 pm_runtime_disable(dev); 210 205 206 + tidss_oldi_deinit(tidss); 207 + 211 208 return ret; 212 209 } 213 210 ··· 233 226 #endif 234 227 pm_runtime_dont_use_autosuspend(dev); 235 228 pm_runtime_disable(dev); 229 + 230 + tidss_oldi_deinit(tidss); 236 231 237 232 /* devm allocated dispc goes away with the dev so mark it NULL */ 238 233 dispc_remove(tidss);
+5
drivers/gpu/drm/tidss/tidss_drv.h
··· 11 11 12 12 #define TIDSS_MAX_PORTS 4 13 13 #define TIDSS_MAX_PLANES 4 14 + #define TIDSS_MAX_OLDI_TXES 2 14 15 15 16 typedef u32 dispc_irq_t; 17 + struct tidss_oldi; 16 18 17 19 struct tidss_device { 18 20 struct drm_device ddev; /* DRM device for DSS */ ··· 28 26 29 27 unsigned int num_planes; 30 28 struct drm_plane *planes[TIDSS_MAX_PLANES]; 29 + 30 + unsigned int num_oldis; 31 + struct tidss_oldi *oldis[TIDSS_MAX_OLDI_TXES]; 31 32 32 33 unsigned int irq; 33 34
+1 -1
drivers/gpu/drm/tidss/tidss_kms.c
··· 144 144 dev_dbg(dev, "Setting up panel for port %d\n", i); 145 145 146 146 switch (feat->vp_bus_type[i]) { 147 - case DISPC_VP_OLDI: 147 + case DISPC_VP_OLDI_AM65X: 148 148 enc_type = DRM_MODE_ENCODER_LVDS; 149 149 conn_type = DRM_MODE_CONNECTOR_LVDS; 150 150 break;
+598
drivers/gpu/drm/tidss/tidss_oldi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Copyright (C) 2025 - Texas Instruments Incorporated 4 + * 5 + * Aradhya Bhatia <a-bhatia1@ti.com> 6 + */ 7 + 8 + #include <linux/clk.h> 9 + #include <linux/of.h> 10 + #include <linux/of_graph.h> 11 + #include <linux/mfd/syscon.h> 12 + #include <linux/media-bus-format.h> 13 + #include <linux/regmap.h> 14 + 15 + #include <drm/drm_atomic_helper.h> 16 + #include <drm/drm_bridge.h> 17 + #include <drm/drm_of.h> 18 + 19 + #include "tidss_dispc.h" 20 + #include "tidss_dispc_regs.h" 21 + #include "tidss_oldi.h" 22 + 23 + struct tidss_oldi { 24 + struct tidss_device *tidss; 25 + struct device *dev; 26 + 27 + struct drm_bridge bridge; 28 + struct drm_bridge *next_bridge; 29 + 30 + enum tidss_oldi_link_type link_type; 31 + const struct oldi_bus_format *bus_format; 32 + u32 oldi_instance; 33 + int companion_instance; /* -1 when OLDI TX operates in Single-Link */ 34 + u32 parent_vp; 35 + 36 + struct clk *serial; 37 + struct regmap *io_ctrl; 38 + }; 39 + 40 + struct oldi_bus_format { 41 + u32 bus_fmt; 42 + u32 data_width; 43 + enum oldi_mode_reg_val oldi_mode_reg_val; 44 + u32 input_bus_fmt; 45 + }; 46 + 47 + static const struct oldi_bus_format oldi_bus_formats[] = { 48 + { MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, 18, SPWG_18, MEDIA_BUS_FMT_RGB666_1X18 }, 49 + { MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 24, SPWG_24, MEDIA_BUS_FMT_RGB888_1X24 }, 50 + { MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 24, JEIDA_24, MEDIA_BUS_FMT_RGB888_1X24 }, 51 + }; 52 + 53 + #define OLDI_IDLE_CLK_HZ 25000000 /*25 MHz */ 54 + 55 + static inline struct tidss_oldi * 56 + drm_bridge_to_tidss_oldi(struct drm_bridge *bridge) 57 + { 58 + return container_of(bridge, struct tidss_oldi, bridge); 59 + } 60 + 61 + static int tidss_oldi_bridge_attach(struct drm_bridge *bridge, 62 + struct drm_encoder *encoder, 63 + enum drm_bridge_attach_flags flags) 64 + { 65 + struct tidss_oldi *oldi = drm_bridge_to_tidss_oldi(bridge); 66 + 67 + if (!oldi->next_bridge) { 68 + dev_err(oldi->dev, 69 + "%s: OLDI%u Failure attach next bridge\n", 70 + __func__, oldi->oldi_instance); 71 + return -ENODEV; 72 + } 73 + 74 + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { 75 + dev_err(oldi->dev, 76 + "%s: OLDI%u DRM_BRIDGE_ATTACH_NO_CONNECTOR is mandatory.\n", 77 + __func__, oldi->oldi_instance); 78 + return -EINVAL; 79 + } 80 + 81 + return drm_bridge_attach(encoder, oldi->next_bridge, bridge, flags); 82 + } 83 + 84 + static int 85 + tidss_oldi_set_serial_clk(struct tidss_oldi *oldi, unsigned long rate) 86 + { 87 + unsigned long new_rate; 88 + int ret; 89 + 90 + ret = clk_set_rate(oldi->serial, rate); 91 + if (ret) { 92 + dev_err(oldi->dev, 93 + "OLDI%u: failed to set serial clk rate to %lu Hz\n", 94 + oldi->oldi_instance, rate); 95 + return ret; 96 + } 97 + 98 + new_rate = clk_get_rate(oldi->serial); 99 + 100 + if (dispc_pclk_diff(rate, new_rate) > 5) 101 + dev_warn(oldi->dev, 102 + "OLDI%u Clock rate %lu differs over 5%% from requested %lu\n", 103 + oldi->oldi_instance, new_rate, rate); 104 + 105 + dev_dbg(oldi->dev, "OLDI%u: new rate %lu Hz (requested %lu Hz)\n", 106 + oldi->oldi_instance, clk_get_rate(oldi->serial), rate); 107 + 108 + return 0; 109 + } 110 + 111 + static void tidss_oldi_tx_power(struct tidss_oldi *oldi, bool enable) 112 + { 113 + u32 mask; 114 + 115 + /* 116 + * The power control bits are Active Low, and remain powered off by 117 + * default. That is, the bits are set to 1. To power on the OLDI TXes, 118 + * the bits must be cleared to 0. Since there are cases where not all 119 + * OLDI TXes are being used, the power logic selectively powers them 120 + * on. 121 + * Setting the variable 'val' to particular bit masks, makes sure that 122 + * the undesired OLDI TXes remain powered off. 123 + */ 124 + 125 + if (enable) { 126 + switch (oldi->link_type) { 127 + case OLDI_MODE_SINGLE_LINK: 128 + /* Power-on only the required OLDI TX's IO*/ 129 + mask = OLDI_PWRDOWN_TX(oldi->oldi_instance) | OLDI_PWRDN_BG; 130 + break; 131 + case OLDI_MODE_CLONE_SINGLE_LINK: 132 + case OLDI_MODE_DUAL_LINK: 133 + /* Power-on both the OLDI TXes' IOs */ 134 + mask = OLDI_PWRDOWN_TX(oldi->oldi_instance) | 135 + OLDI_PWRDOWN_TX(oldi->companion_instance) | 136 + OLDI_PWRDN_BG; 137 + break; 138 + default: 139 + /* 140 + * This code execution should never reach here as any 141 + * OLDI with an unsupported OLDI mode would never get 142 + * registered in the first place. 143 + * However, power-off the OLDI in concern just in case. 144 + */ 145 + mask = OLDI_PWRDOWN_TX(oldi->oldi_instance); 146 + enable = false; 147 + break; 148 + } 149 + } else { 150 + switch (oldi->link_type) { 151 + case OLDI_MODE_CLONE_SINGLE_LINK: 152 + case OLDI_MODE_DUAL_LINK: 153 + mask = OLDI_PWRDOWN_TX(oldi->oldi_instance) | 154 + OLDI_PWRDOWN_TX(oldi->companion_instance) | 155 + OLDI_PWRDN_BG; 156 + break; 157 + case OLDI_MODE_SINGLE_LINK: 158 + default: 159 + mask = OLDI_PWRDOWN_TX(oldi->oldi_instance); 160 + break; 161 + } 162 + } 163 + 164 + regmap_update_bits(oldi->io_ctrl, OLDI_PD_CTRL, mask, enable ? 0 : mask); 165 + } 166 + 167 + static int tidss_oldi_config(struct tidss_oldi *oldi) 168 + { 169 + const struct oldi_bus_format *bus_fmt = NULL; 170 + u32 oldi_cfg = 0; 171 + int ret; 172 + 173 + bus_fmt = oldi->bus_format; 174 + 175 + /* 176 + * MASTERSLAVE and SRC bits of OLDI Config are always set to 0. 177 + */ 178 + 179 + if (bus_fmt->data_width == 24) 180 + oldi_cfg |= OLDI_MSB; 181 + else if (bus_fmt->data_width != 18) 182 + dev_warn(oldi->dev, 183 + "OLDI%u: DSS port width %d not supported\n", 184 + oldi->oldi_instance, bus_fmt->data_width); 185 + 186 + oldi_cfg |= OLDI_DEPOL; 187 + 188 + oldi_cfg = (oldi_cfg & (~OLDI_MAP)) | (bus_fmt->oldi_mode_reg_val << 1); 189 + 190 + oldi_cfg |= OLDI_SOFTRST; 191 + 192 + oldi_cfg |= OLDI_ENABLE; 193 + 194 + switch (oldi->link_type) { 195 + case OLDI_MODE_SINGLE_LINK: 196 + /* All configuration is done for this mode. */ 197 + break; 198 + 199 + case OLDI_MODE_CLONE_SINGLE_LINK: 200 + oldi_cfg |= OLDI_CLONE_MODE; 201 + break; 202 + 203 + case OLDI_MODE_DUAL_LINK: 204 + /* data-mapping field also indicates dual-link mode */ 205 + oldi_cfg |= BIT(3); 206 + oldi_cfg |= OLDI_DUALMODESYNC; 207 + break; 208 + 209 + default: 210 + dev_err(oldi->dev, "OLDI%u: Unsupported mode.\n", 211 + oldi->oldi_instance); 212 + return -EINVAL; 213 + } 214 + 215 + ret = tidss_configure_oldi(oldi->tidss, oldi->parent_vp, oldi_cfg); 216 + if (ret == -ETIMEDOUT) 217 + dev_warn(oldi->dev, "OLDI%u: timeout waiting for OLDI reset done.\n", 218 + oldi->oldi_instance); 219 + 220 + return ret; 221 + } 222 + 223 + static void tidss_oldi_atomic_pre_enable(struct drm_bridge *bridge, 224 + struct drm_atomic_state *state) 225 + { 226 + struct tidss_oldi *oldi = drm_bridge_to_tidss_oldi(bridge); 227 + struct drm_connector *connector; 228 + struct drm_connector_state *conn_state; 229 + struct drm_crtc_state *crtc_state; 230 + struct drm_display_mode *mode; 231 + 232 + if (oldi->link_type == OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK) 233 + return; 234 + 235 + connector = drm_atomic_get_new_connector_for_encoder(state, 236 + bridge->encoder); 237 + if (WARN_ON(!connector)) 238 + return; 239 + 240 + conn_state = drm_atomic_get_new_connector_state(state, connector); 241 + if (WARN_ON(!conn_state)) 242 + return; 243 + 244 + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); 245 + if (WARN_ON(!crtc_state)) 246 + return; 247 + 248 + mode = &crtc_state->adjusted_mode; 249 + 250 + /* Configure the OLDI params*/ 251 + tidss_oldi_config(oldi); 252 + 253 + /* Set the OLDI serial clock (7 times the pixel clock) */ 254 + tidss_oldi_set_serial_clk(oldi, mode->clock * 7 * 1000); 255 + 256 + /* Enable OLDI IO power */ 257 + tidss_oldi_tx_power(oldi, true); 258 + } 259 + 260 + static void tidss_oldi_atomic_post_disable(struct drm_bridge *bridge, 261 + struct drm_atomic_state *state) 262 + { 263 + struct tidss_oldi *oldi = drm_bridge_to_tidss_oldi(bridge); 264 + 265 + if (oldi->link_type == OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK) 266 + return; 267 + 268 + /* Disable OLDI IO power */ 269 + tidss_oldi_tx_power(oldi, false); 270 + 271 + /* Set the OLDI serial clock to IDLE Frequency */ 272 + tidss_oldi_set_serial_clk(oldi, OLDI_IDLE_CLK_HZ); 273 + 274 + /* Clear OLDI Config */ 275 + tidss_disable_oldi(oldi->tidss, oldi->parent_vp); 276 + } 277 + 278 + #define MAX_INPUT_SEL_FORMATS 1 279 + 280 + static u32 *tidss_oldi_atomic_get_input_bus_fmts(struct drm_bridge *bridge, 281 + struct drm_bridge_state *bridge_state, 282 + struct drm_crtc_state *crtc_state, 283 + struct drm_connector_state *conn_state, 284 + u32 output_fmt, 285 + unsigned int *num_input_fmts) 286 + { 287 + struct tidss_oldi *oldi = drm_bridge_to_tidss_oldi(bridge); 288 + u32 *input_fmts; 289 + int i; 290 + 291 + *num_input_fmts = 0; 292 + 293 + for (i = 0; i < ARRAY_SIZE(oldi_bus_formats); i++) 294 + if (oldi_bus_formats[i].bus_fmt == output_fmt) 295 + break; 296 + 297 + if (i == ARRAY_SIZE(oldi_bus_formats)) 298 + return NULL; 299 + 300 + input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts), 301 + GFP_KERNEL); 302 + if (!input_fmts) 303 + return NULL; 304 + 305 + *num_input_fmts = 1; 306 + input_fmts[0] = oldi_bus_formats[i].input_bus_fmt; 307 + oldi->bus_format = &oldi_bus_formats[i]; 308 + 309 + return input_fmts; 310 + } 311 + 312 + static const struct drm_bridge_funcs tidss_oldi_bridge_funcs = { 313 + .attach = tidss_oldi_bridge_attach, 314 + .atomic_pre_enable = tidss_oldi_atomic_pre_enable, 315 + .atomic_post_disable = tidss_oldi_atomic_post_disable, 316 + .atomic_get_input_bus_fmts = tidss_oldi_atomic_get_input_bus_fmts, 317 + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, 318 + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, 319 + .atomic_reset = drm_atomic_helper_bridge_reset, 320 + }; 321 + 322 + static int get_oldi_mode(struct device_node *oldi_tx, int *companion_instance) 323 + { 324 + struct device_node *companion; 325 + struct device_node *port0, *port1; 326 + u32 companion_reg; 327 + bool secondary_oldi = false; 328 + int pixel_order; 329 + 330 + /* 331 + * Find if the OLDI is paired with another OLDI for combined OLDI 332 + * operation (dual-link or clone). 333 + */ 334 + companion = of_parse_phandle(oldi_tx, "ti,companion-oldi", 0); 335 + if (!companion) 336 + /* 337 + * The OLDI TX does not have a companion, nor is it a 338 + * secondary OLDI. It will operate independently. 339 + */ 340 + return OLDI_MODE_SINGLE_LINK; 341 + 342 + if (of_property_read_u32(companion, "reg", &companion_reg)) 343 + return OLDI_MODE_UNSUPPORTED; 344 + 345 + if (companion_reg > (TIDSS_MAX_OLDI_TXES - 1)) 346 + /* Invalid companion OLDI reg value. */ 347 + return OLDI_MODE_UNSUPPORTED; 348 + 349 + *companion_instance = (int)companion_reg; 350 + 351 + if (of_property_read_bool(oldi_tx, "ti,secondary-oldi")) 352 + secondary_oldi = true; 353 + 354 + /* 355 + * We need to work out if the sink is expecting us to function in 356 + * dual-link mode. We do this by looking at the DT port nodes, the 357 + * OLDI TX ports are connected to. If they are marked as expecting 358 + * even pixels and odd pixels, then we need to enable dual-link. 359 + */ 360 + port0 = of_graph_get_port_by_id(oldi_tx, 1); 361 + port1 = of_graph_get_port_by_id(companion, 1); 362 + pixel_order = drm_of_lvds_get_dual_link_pixel_order(port0, port1); 363 + of_node_put(port0); 364 + of_node_put(port1); 365 + of_node_put(companion); 366 + 367 + switch (pixel_order) { 368 + case -EINVAL: 369 + /* 370 + * The dual-link properties were not found in at least 371 + * one of the sink nodes. Since 2 OLDI ports are present 372 + * in the DT, it can be safely assumed that the required 373 + * configuration is Clone Mode. 374 + */ 375 + return (secondary_oldi ? OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK : 376 + OLDI_MODE_CLONE_SINGLE_LINK); 377 + 378 + case DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS: 379 + /* 380 + * Primary OLDI can only support "ODD" pixels. So, from its 381 + * perspective, the pixel order has to be ODD-EVEN. 382 + */ 383 + return (secondary_oldi ? OLDI_MODE_UNSUPPORTED : 384 + OLDI_MODE_DUAL_LINK); 385 + 386 + case DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS: 387 + /* 388 + * Secondary OLDI can only support "EVEN" pixels. So, from its 389 + * perspective, the pixel order has to be EVEN-ODD. 390 + */ 391 + return (secondary_oldi ? OLDI_MODE_SECONDARY_DUAL_LINK : 392 + OLDI_MODE_UNSUPPORTED); 393 + 394 + default: 395 + return OLDI_MODE_UNSUPPORTED; 396 + } 397 + } 398 + 399 + static int get_parent_dss_vp(struct device_node *oldi_tx, u32 *parent_vp) 400 + { 401 + struct device_node *ep, *dss_port; 402 + int ret; 403 + 404 + ep = of_graph_get_endpoint_by_regs(oldi_tx, OLDI_INPUT_PORT, -1); 405 + if (ep) { 406 + dss_port = of_graph_get_remote_port(ep); 407 + if (!dss_port) { 408 + ret = -ENODEV; 409 + goto err_return_ep_port; 410 + } 411 + 412 + ret = of_property_read_u32(dss_port, "reg", parent_vp); 413 + 414 + of_node_put(dss_port); 415 + err_return_ep_port: 416 + of_node_put(ep); 417 + return ret; 418 + } 419 + 420 + return -ENODEV; 421 + } 422 + 423 + static const struct drm_bridge_timings default_tidss_oldi_timings = { 424 + .input_bus_flags = DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE 425 + | DRM_BUS_FLAG_DE_HIGH, 426 + }; 427 + 428 + void tidss_oldi_deinit(struct tidss_device *tidss) 429 + { 430 + for (int i = 0; i < tidss->num_oldis; i++) { 431 + if (tidss->oldis[i]) { 432 + drm_bridge_remove(&tidss->oldis[i]->bridge); 433 + tidss->oldis[i] = NULL; 434 + } 435 + } 436 + } 437 + 438 + int tidss_oldi_init(struct tidss_device *tidss) 439 + { 440 + struct tidss_oldi *oldi; 441 + struct device_node *child; 442 + struct drm_bridge *bridge; 443 + u32 parent_vp, oldi_instance; 444 + int companion_instance = -1; 445 + enum tidss_oldi_link_type link_type = OLDI_MODE_UNSUPPORTED; 446 + struct device_node *oldi_parent; 447 + int ret = 0; 448 + 449 + tidss->num_oldis = 0; 450 + 451 + oldi_parent = of_get_child_by_name(tidss->dev->of_node, "oldi-transmitters"); 452 + if (!oldi_parent) 453 + /* Return gracefully */ 454 + return 0; 455 + 456 + for_each_available_child_of_node(oldi_parent, child) { 457 + ret = get_parent_dss_vp(child, &parent_vp); 458 + if (ret) { 459 + if (ret == -ENODEV) { 460 + /* 461 + * ENODEV means that this particular OLDI node 462 + * is not connected with the DSS, which is not 463 + * a harmful case. There could be another OLDI 464 + * which may still be connected. 465 + * Continue to search for that. 466 + */ 467 + ret = 0; 468 + continue; 469 + } 470 + goto err_put_node; 471 + } 472 + 473 + ret = of_property_read_u32(child, "reg", &oldi_instance); 474 + if (ret) 475 + goto err_put_node; 476 + 477 + /* 478 + * Now that it's confirmed that OLDI is connected with DSS, 479 + * let's continue getting the OLDI sinks ahead and other OLDI 480 + * properties. 481 + */ 482 + bridge = devm_drm_of_get_bridge(tidss->dev, child, 483 + OLDI_OUTPUT_PORT, 0); 484 + if (IS_ERR(bridge)) { 485 + /* 486 + * Either there was no OLDI sink in the devicetree, or 487 + * the OLDI sink has not been added yet. In any case, 488 + * return. 489 + * We don't want to have an OLDI node connected to DSS 490 + * but not to any sink. 491 + */ 492 + ret = dev_err_probe(tidss->dev, PTR_ERR(bridge), 493 + "no panel/bridge for OLDI%u.\n", 494 + oldi_instance); 495 + goto err_put_node; 496 + } 497 + 498 + link_type = get_oldi_mode(child, &companion_instance); 499 + if (link_type == OLDI_MODE_UNSUPPORTED) { 500 + ret = dev_err_probe(tidss->dev, -EINVAL, 501 + "OLDI%u: Unsupported OLDI connection.\n", 502 + oldi_instance); 503 + goto err_put_node; 504 + } else if ((link_type == OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK) || 505 + (link_type == OLDI_MODE_CLONE_SINGLE_LINK)) { 506 + /* 507 + * The OLDI driver cannot support OLDI clone mode 508 + * properly at present. 509 + * The clone mode requires 2 working encoder-bridge 510 + * pipelines, generating from the same crtc. The DRM 511 + * framework does not support this at present. If 512 + * there were to be, say, 2 OLDI sink bridges each 513 + * connected to an OLDI TXes, they couldn't both be 514 + * supported simultaneously. 515 + * This driver still has some code pertaining to OLDI 516 + * clone mode configuration in DSS hardware for future, 517 + * when there is a better infrastructure in the DRM 518 + * framework to support 2 encoder-bridge pipelines 519 + * simultaneously. 520 + * Till that time, this driver shall error out if it 521 + * detects a clone mode configuration. 522 + */ 523 + ret = dev_err_probe(tidss->dev, -EOPNOTSUPP, 524 + "The OLDI driver does not support Clone Mode at present.\n"); 525 + goto err_put_node; 526 + } else if (link_type == OLDI_MODE_SECONDARY_DUAL_LINK) { 527 + /* 528 + * This is the secondary OLDI node, which serves as a 529 + * companion to the primary OLDI, when it is configured 530 + * for the dual-link mode. Since the primary OLDI will 531 + * be a part of bridge chain, no need to put this one 532 + * too. Continue onto the next OLDI node. 533 + */ 534 + continue; 535 + } 536 + 537 + oldi = devm_kzalloc(tidss->dev, sizeof(*oldi), GFP_KERNEL); 538 + if (!oldi) { 539 + ret = -ENOMEM; 540 + goto err_put_node; 541 + } 542 + 543 + oldi->parent_vp = parent_vp; 544 + oldi->oldi_instance = oldi_instance; 545 + oldi->companion_instance = companion_instance; 546 + oldi->link_type = link_type; 547 + oldi->dev = tidss->dev; 548 + oldi->next_bridge = bridge; 549 + 550 + /* 551 + * Only the primary OLDI needs to reference the io-ctrl system 552 + * registers, and the serial clock. 553 + * We don't require a check for secondary OLDI in dual-link mode 554 + * because the driver will not create a drm_bridge instance. 555 + * But the driver will need to create a drm_bridge instance, 556 + * for secondary OLDI in clone mode (once it is supported). 557 + */ 558 + if (link_type != OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK) { 559 + oldi->io_ctrl = syscon_regmap_lookup_by_phandle(child, 560 + "ti,oldi-io-ctrl"); 561 + if (IS_ERR(oldi->io_ctrl)) { 562 + ret = dev_err_probe(oldi->dev, PTR_ERR(oldi->io_ctrl), 563 + "OLDI%u: syscon_regmap_lookup_by_phandle failed.\n", 564 + oldi_instance); 565 + goto err_put_node; 566 + } 567 + 568 + oldi->serial = of_clk_get_by_name(child, "serial"); 569 + if (IS_ERR(oldi->serial)) { 570 + ret = dev_err_probe(oldi->dev, PTR_ERR(oldi->serial), 571 + "OLDI%u: Failed to get serial clock.\n", 572 + oldi_instance); 573 + goto err_put_node; 574 + } 575 + } 576 + 577 + /* Register the bridge. */ 578 + oldi->bridge.of_node = child; 579 + oldi->bridge.driver_private = oldi; 580 + oldi->bridge.funcs = &tidss_oldi_bridge_funcs; 581 + oldi->bridge.timings = &default_tidss_oldi_timings; 582 + 583 + tidss->oldis[tidss->num_oldis++] = oldi; 584 + oldi->tidss = tidss; 585 + 586 + drm_bridge_add(&oldi->bridge); 587 + } 588 + 589 + of_node_put(child); 590 + of_node_put(oldi_parent); 591 + 592 + return 0; 593 + 594 + err_put_node: 595 + of_node_put(child); 596 + of_node_put(oldi_parent); 597 + return ret; 598 + }
+43
drivers/gpu/drm/tidss/tidss_oldi.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * Copyright (C) 2025 - Texas Instruments Incorporated 4 + * 5 + * Aradhya Bhatia <a-bhatia1@ti.com> 6 + */ 7 + 8 + #ifndef __TIDSS_OLDI_H__ 9 + #define __TIDSS_OLDI_H__ 10 + 11 + #include "tidss_drv.h" 12 + 13 + struct tidss_oldi; 14 + 15 + /* OLDI PORTS */ 16 + #define OLDI_INPUT_PORT 0 17 + #define OLDI_OUTPUT_PORT 1 18 + 19 + /* Control MMR Registers */ 20 + 21 + /* Register offsets */ 22 + #define OLDI_PD_CTRL 0x100 23 + #define OLDI_LB_CTRL 0x104 24 + 25 + /* Power control bits */ 26 + #define OLDI_PWRDOWN_TX(n) BIT(n) 27 + 28 + /* LVDS Bandgap reference Enable/Disable */ 29 + #define OLDI_PWRDN_BG BIT(8) 30 + 31 + enum tidss_oldi_link_type { 32 + OLDI_MODE_UNSUPPORTED, 33 + OLDI_MODE_SINGLE_LINK, 34 + OLDI_MODE_CLONE_SINGLE_LINK, 35 + OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK, 36 + OLDI_MODE_DUAL_LINK, 37 + OLDI_MODE_SECONDARY_DUAL_LINK, 38 + }; 39 + 40 + int tidss_oldi_init(struct tidss_device *tidss); 41 + void tidss_oldi_deinit(struct tidss_device *tidss); 42 + 43 + #endif /* __TIDSS_OLDI_H__ */
+14 -10
drivers/gpu/drm/ttm/ttm_bo.c
··· 526 526 return 0; 527 527 528 528 if (bo->deleted) { 529 - lret = ttm_bo_wait_ctx(bo, walk->ctx); 529 + lret = ttm_bo_wait_ctx(bo, walk->arg.ctx); 530 530 if (!lret) 531 531 ttm_bo_cleanup_memtype_use(bo); 532 532 } else { 533 - lret = ttm_bo_evict(bo, walk->ctx); 533 + lret = ttm_bo_evict(bo, walk->arg.ctx); 534 534 } 535 535 536 536 if (lret) ··· 566 566 struct ttm_bo_evict_walk evict_walk = { 567 567 .walk = { 568 568 .ops = &ttm_evict_walk_ops, 569 - .ctx = ctx, 570 - .ticket = ticket, 569 + .arg = { 570 + .ctx = ctx, 571 + .ticket = ticket, 572 + } 571 573 }, 572 574 .place = place, 573 575 .evictor = evictor, ··· 578 576 }; 579 577 s64 lret; 580 578 581 - evict_walk.walk.trylock_only = true; 579 + evict_walk.walk.arg.trylock_only = true; 582 580 lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1); 583 581 584 582 /* One more attempt if we hit low limit? */ ··· 592 590 /* Reset low limit */ 593 591 evict_walk.try_low = evict_walk.hit_low = false; 594 592 /* If ticket-locking, repeat while making progress. */ 595 - evict_walk.walk.trylock_only = false; 593 + evict_walk.walk.arg.trylock_only = false; 596 594 597 595 retry: 598 596 do { 599 597 /* The walk may clear the evict_walk.walk.ticket field */ 600 - evict_walk.walk.ticket = ticket; 598 + evict_walk.walk.arg.ticket = ticket; 601 599 evict_walk.evicted = 0; 602 600 lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1); 603 601 } while (!lret && evict_walk.evicted); ··· 1108 1106 struct ttm_place place = {.mem_type = bo->resource->mem_type}; 1109 1107 struct ttm_bo_swapout_walk *swapout_walk = 1110 1108 container_of(walk, typeof(*swapout_walk), walk); 1111 - struct ttm_operation_ctx *ctx = walk->ctx; 1109 + struct ttm_operation_ctx *ctx = walk->arg.ctx; 1112 1110 s64 ret; 1113 1111 1114 1112 /* ··· 1219 1217 struct ttm_bo_swapout_walk swapout_walk = { 1220 1218 .walk = { 1221 1219 .ops = &ttm_swap_ops, 1222 - .ctx = ctx, 1223 - .trylock_only = true, 1220 + .arg = { 1221 + .ctx = ctx, 1222 + .trylock_only = true, 1223 + }, 1224 1224 }, 1225 1225 .gfp_flags = gfp_flags, 1226 1226 };
+83 -119
drivers/gpu/drm/ttm/ttm_bo_util.c
··· 773 773 return ret; 774 774 } 775 775 776 - static bool ttm_lru_walk_trylock(struct ttm_operation_ctx *ctx, 777 - struct ttm_buffer_object *bo, 778 - bool *needs_unlock) 776 + static bool ttm_lru_walk_trylock(struct ttm_bo_lru_cursor *curs, 777 + struct ttm_buffer_object *bo) 779 778 { 780 - *needs_unlock = false; 779 + struct ttm_operation_ctx *ctx = curs->arg->ctx; 780 + 781 + curs->needs_unlock = false; 781 782 782 783 if (dma_resv_trylock(bo->base.resv)) { 783 - *needs_unlock = true; 784 + curs->needs_unlock = true; 784 785 return true; 785 786 } 786 787 ··· 793 792 return false; 794 793 } 795 794 796 - static int ttm_lru_walk_ticketlock(struct ttm_lru_walk *walk, 797 - struct ttm_buffer_object *bo, 798 - bool *needs_unlock) 795 + static int ttm_lru_walk_ticketlock(struct ttm_bo_lru_cursor *curs, 796 + struct ttm_buffer_object *bo) 799 797 { 798 + struct ttm_lru_walk_arg *arg = curs->arg; 800 799 struct dma_resv *resv = bo->base.resv; 801 800 int ret; 802 801 803 - if (walk->ctx->interruptible) 804 - ret = dma_resv_lock_interruptible(resv, walk->ticket); 802 + if (arg->ctx->interruptible) 803 + ret = dma_resv_lock_interruptible(resv, arg->ticket); 805 804 else 806 - ret = dma_resv_lock(resv, walk->ticket); 805 + ret = dma_resv_lock(resv, arg->ticket); 807 806 808 807 if (!ret) { 809 - *needs_unlock = true; 808 + curs->needs_unlock = true; 810 809 /* 811 810 * Only a single ticketlock per loop. Ticketlocks are prone 812 811 * to return -EDEADLK causing the eviction to fail, so 813 812 * after waiting for the ticketlock, revert back to 814 813 * trylocking for this walk. 815 814 */ 816 - walk->ticket = NULL; 815 + arg->ticket = NULL; 817 816 } else if (ret == -EDEADLK) { 818 817 /* Caller needs to exit the ww transaction. */ 819 818 ret = -ENOSPC; 820 819 } 821 820 822 821 return ret; 823 - } 824 - 825 - static void ttm_lru_walk_unlock(struct ttm_buffer_object *bo, bool locked) 826 - { 827 - if (locked) 828 - dma_resv_unlock(bo->base.resv); 829 822 } 830 823 831 824 /** ··· 856 861 s64 ttm_lru_walk_for_evict(struct ttm_lru_walk *walk, struct ttm_device *bdev, 857 862 struct ttm_resource_manager *man, s64 target) 858 863 { 859 - struct ttm_resource_cursor cursor; 860 - struct ttm_resource *res; 864 + struct ttm_bo_lru_cursor cursor; 865 + struct ttm_buffer_object *bo; 861 866 s64 progress = 0; 862 867 s64 lret; 863 868 864 - spin_lock(&bdev->lru_lock); 865 - ttm_resource_cursor_init(&cursor, man); 866 - ttm_resource_manager_for_each_res(&cursor, res) { 867 - struct ttm_buffer_object *bo = res->bo; 868 - bool bo_needs_unlock = false; 869 - bool bo_locked = false; 870 - int mem_type; 871 - 872 - /* 873 - * Attempt a trylock before taking a reference on the bo, 874 - * since if we do it the other way around, and the trylock fails, 875 - * we need to drop the lru lock to put the bo. 876 - */ 877 - if (ttm_lru_walk_trylock(walk->ctx, bo, &bo_needs_unlock)) 878 - bo_locked = true; 879 - else if (!walk->ticket || walk->ctx->no_wait_gpu || 880 - walk->trylock_only) 881 - continue; 882 - 883 - if (!ttm_bo_get_unless_zero(bo)) { 884 - ttm_lru_walk_unlock(bo, bo_needs_unlock); 885 - continue; 886 - } 887 - 888 - mem_type = res->mem_type; 889 - spin_unlock(&bdev->lru_lock); 890 - 891 - lret = 0; 892 - if (!bo_locked) 893 - lret = ttm_lru_walk_ticketlock(walk, bo, &bo_needs_unlock); 894 - 895 - /* 896 - * Note that in between the release of the lru lock and the 897 - * ticketlock, the bo may have switched resource, 898 - * and also memory type, since the resource may have been 899 - * freed and allocated again with a different memory type. 900 - * In that case, just skip it. 901 - */ 902 - if (!lret && bo->resource && bo->resource->mem_type == mem_type) 903 - lret = walk->ops->process_bo(walk, bo); 904 - 905 - ttm_lru_walk_unlock(bo, bo_needs_unlock); 906 - ttm_bo_put(bo); 869 + ttm_bo_lru_for_each_reserved_guarded(&cursor, man, &walk->arg, bo) { 870 + lret = walk->ops->process_bo(walk, bo); 907 871 if (lret == -EBUSY || lret == -EALREADY) 908 872 lret = 0; 909 873 progress = (lret < 0) ? lret : progress + lret; 910 - 911 - spin_lock(&bdev->lru_lock); 912 874 if (progress < 0 || progress >= target) 913 875 break; 914 876 } 915 - ttm_resource_cursor_fini(&cursor); 916 - spin_unlock(&bdev->lru_lock); 877 + if (IS_ERR(bo)) 878 + return PTR_ERR(bo); 917 879 918 880 return progress; 919 881 } ··· 908 956 * ttm_bo_lru_cursor_init() - Initialize a struct ttm_bo_lru_cursor 909 957 * @curs: The ttm_bo_lru_cursor to initialize. 910 958 * @man: The ttm resource_manager whose LRU lists to iterate over. 911 - * @ctx: The ttm_operation_ctx to govern the locking. 959 + * @arg: The ttm_lru_walk_arg to govern the walk. 912 960 * 913 - * Initialize a struct ttm_bo_lru_cursor. Currently only trylocking 914 - * or prelocked buffer objects are available as detailed by 915 - * @ctx::resv and @ctx::allow_res_evict. Ticketlocking is not 916 - * supported. 961 + * Initialize a struct ttm_bo_lru_cursor. 917 962 * 918 963 * Return: Pointer to @curs. The function does not fail. 919 964 */ 920 965 struct ttm_bo_lru_cursor * 921 966 ttm_bo_lru_cursor_init(struct ttm_bo_lru_cursor *curs, 922 967 struct ttm_resource_manager *man, 923 - struct ttm_operation_ctx *ctx) 968 + struct ttm_lru_walk_arg *arg) 924 969 { 925 970 memset(curs, 0, sizeof(*curs)); 926 971 ttm_resource_cursor_init(&curs->res_curs, man); 927 - curs->ctx = ctx; 972 + curs->arg = arg; 928 973 929 974 return curs; 930 975 } 931 976 EXPORT_SYMBOL(ttm_bo_lru_cursor_init); 932 977 933 978 static struct ttm_buffer_object * 934 - ttm_bo_from_res_reserved(struct ttm_resource *res, struct ttm_bo_lru_cursor *curs) 979 + __ttm_bo_lru_cursor_next(struct ttm_bo_lru_cursor *curs) 935 980 { 936 - struct ttm_buffer_object *bo = res->bo; 981 + spinlock_t *lru_lock = &curs->res_curs.man->bdev->lru_lock; 982 + struct ttm_resource *res = NULL; 983 + struct ttm_buffer_object *bo; 984 + struct ttm_lru_walk_arg *arg = curs->arg; 985 + bool first = !curs->bo; 937 986 938 - if (!ttm_lru_walk_trylock(curs->ctx, bo, &curs->needs_unlock)) 939 - return NULL; 987 + ttm_bo_lru_cursor_cleanup_bo(curs); 940 988 941 - if (!ttm_bo_get_unless_zero(bo)) { 942 - if (curs->needs_unlock) 943 - dma_resv_unlock(bo->base.resv); 944 - return NULL; 989 + spin_lock(lru_lock); 990 + for (;;) { 991 + int mem_type, ret = 0; 992 + bool bo_locked = false; 993 + 994 + if (first) { 995 + res = ttm_resource_manager_first(&curs->res_curs); 996 + first = false; 997 + } else { 998 + res = ttm_resource_manager_next(&curs->res_curs); 999 + } 1000 + if (!res) 1001 + break; 1002 + 1003 + bo = res->bo; 1004 + if (ttm_lru_walk_trylock(curs, bo)) 1005 + bo_locked = true; 1006 + else if (!arg->ticket || arg->ctx->no_wait_gpu || arg->trylock_only) 1007 + continue; 1008 + 1009 + if (!ttm_bo_get_unless_zero(bo)) { 1010 + if (curs->needs_unlock) 1011 + dma_resv_unlock(bo->base.resv); 1012 + continue; 1013 + } 1014 + 1015 + mem_type = res->mem_type; 1016 + spin_unlock(lru_lock); 1017 + if (!bo_locked) 1018 + ret = ttm_lru_walk_ticketlock(curs, bo); 1019 + 1020 + /* 1021 + * Note that in between the release of the lru lock and the 1022 + * ticketlock, the bo may have switched resource, 1023 + * and also memory type, since the resource may have been 1024 + * freed and allocated again with a different memory type. 1025 + * In that case, just skip it. 1026 + */ 1027 + curs->bo = bo; 1028 + if (!ret && bo->resource && bo->resource->mem_type == mem_type) 1029 + return bo; 1030 + 1031 + ttm_bo_lru_cursor_cleanup_bo(curs); 1032 + if (ret && ret != -EALREADY) 1033 + return ERR_PTR(ret); 1034 + 1035 + spin_lock(lru_lock); 945 1036 } 946 1037 947 - curs->bo = bo; 948 - return bo; 1038 + spin_unlock(lru_lock); 1039 + return res ? bo : NULL; 949 1040 } 950 1041 951 1042 /** ··· 1002 1007 */ 1003 1008 struct ttm_buffer_object *ttm_bo_lru_cursor_next(struct ttm_bo_lru_cursor *curs) 1004 1009 { 1005 - spinlock_t *lru_lock = &curs->res_curs.man->bdev->lru_lock; 1006 - struct ttm_resource *res = NULL; 1007 - struct ttm_buffer_object *bo; 1008 - 1009 - ttm_bo_lru_cursor_cleanup_bo(curs); 1010 - 1011 - spin_lock(lru_lock); 1012 - for (;;) { 1013 - res = ttm_resource_manager_next(&curs->res_curs); 1014 - if (!res) 1015 - break; 1016 - 1017 - bo = ttm_bo_from_res_reserved(res, curs); 1018 - if (bo) 1019 - break; 1020 - } 1021 - 1022 - spin_unlock(lru_lock); 1023 - return res ? bo : NULL; 1010 + return __ttm_bo_lru_cursor_next(curs); 1024 1011 } 1025 1012 EXPORT_SYMBOL(ttm_bo_lru_cursor_next); 1026 1013 ··· 1016 1039 */ 1017 1040 struct ttm_buffer_object *ttm_bo_lru_cursor_first(struct ttm_bo_lru_cursor *curs) 1018 1041 { 1019 - spinlock_t *lru_lock = &curs->res_curs.man->bdev->lru_lock; 1020 - struct ttm_buffer_object *bo; 1021 - struct ttm_resource *res; 1022 - 1023 - spin_lock(lru_lock); 1024 - res = ttm_resource_manager_first(&curs->res_curs); 1025 - if (!res) { 1026 - spin_unlock(lru_lock); 1027 - return NULL; 1028 - } 1029 - 1030 - bo = ttm_bo_from_res_reserved(res, curs); 1031 - spin_unlock(lru_lock); 1032 - 1033 - return bo ? bo : ttm_bo_lru_cursor_next(curs); 1042 + ttm_bo_lru_cursor_cleanup_bo(curs); 1043 + return __ttm_bo_lru_cursor_next(curs); 1034 1044 } 1035 1045 EXPORT_SYMBOL(ttm_bo_lru_cursor_first); 1036 1046
+2 -3
drivers/gpu/drm/vmwgfx/vmwgfx_gem.c
··· 284 284 285 285 seq_printf(m, "\t\t0x%08x: %12zu bytes %s, type = %s", 286 286 id, bo->tbo.base.size, placement, type); 287 - seq_printf(m, ", priority = %u, pin_count = %u, GEM refs = %d, TTM refs = %d", 287 + seq_printf(m, ", priority = %u, pin_count = %u, GEM refs = %d", 288 288 bo->tbo.priority, 289 289 bo->tbo.pin_count, 290 - kref_read(&bo->tbo.base.refcount), 291 - kref_read(&bo->tbo.kref)); 290 + kref_read(&bo->tbo.base.refcount)); 292 291 seq_puts(m, "\n"); 293 292 } 294 293
+7 -1
drivers/gpu/drm/xe/xe_shrinker.c
··· 66 66 struct ttm_resource_manager *man = ttm_manager_type(&xe->ttm, mem_type); 67 67 struct ttm_bo_lru_cursor curs; 68 68 struct ttm_buffer_object *ttm_bo; 69 + struct ttm_lru_walk_arg arg = { 70 + .ctx = ctx, 71 + .trylock_only = true, 72 + }; 69 73 70 74 if (!man || !man->use_tt) 71 75 continue; 72 76 73 - ttm_bo_lru_for_each_reserved_guarded(&curs, man, ctx, ttm_bo) { 77 + ttm_bo_lru_for_each_reserved_guarded(&curs, man, &arg, ttm_bo) { 74 78 if (!ttm_bo_shrink_suitable(ttm_bo, ctx)) 75 79 continue; 76 80 ··· 86 82 if (*scanned >= to_scan) 87 83 break; 88 84 } 85 + /* Trylocks should never error, just fail. */ 86 + xe_assert(xe, !IS_ERR(ttm_bo)); 89 87 } 90 88 91 89 return freed;
+7 -4
include/drm/display/drm_dp_helper.h
··· 843 843 * @lsb_reg_used: Do we also write values to the DP_EDP_BACKLIGHT_BRIGHTNESS_LSB register? 844 844 * @aux_enable: Does the panel support the AUX enable cap? 845 845 * @aux_set: Does the panel support setting the brightness through AUX? 846 + * @luminance_set: Does the panel support setting the brightness through AUX using luminance values? 846 847 * 847 848 * This structure contains various data about an eDP backlight, which can be populated by using 848 849 * drm_edp_backlight_init(). ··· 851 850 struct drm_edp_backlight_info { 852 851 u8 pwmgen_bit_count; 853 852 u8 pwm_freq_pre_divider; 854 - u16 max; 853 + u32 max; 855 854 856 855 bool lsb_reg_used : 1; 857 856 bool aux_enable : 1; 858 857 bool aux_set : 1; 858 + bool luminance_set : 1; 859 859 }; 860 860 861 861 int 862 862 drm_edp_backlight_init(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl, 863 + u32 max_luminance, 863 864 u16 driver_pwm_freq_hz, const u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE], 864 - u16 *current_level, u8 *current_mode); 865 + u32 *current_level, u8 *current_mode, bool need_luminance); 865 866 int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl, 866 - u16 level); 867 + u32 level); 867 868 int drm_edp_backlight_enable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl, 868 - u16 level); 869 + u32 level); 869 870 int drm_edp_backlight_disable(struct drm_dp_aux *aux, const struct drm_edp_backlight_info *bl); 870 871 871 872 #if IS_ENABLED(CONFIG_DRM_KMS_HELPER) && (IS_BUILTIN(CONFIG_BACKLIGHT_CLASS_DEVICE) || \
+4 -2
include/drm/drm_format_helper.h
··· 82 82 const struct drm_rect *clip, struct drm_format_conv_state *state); 83 83 void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch, 84 84 const struct iosys_map *src, const struct drm_framebuffer *fb, 85 - const struct drm_rect *clip, struct drm_format_conv_state *state, 86 - bool swab); 85 + const struct drm_rect *clip, struct drm_format_conv_state *state); 86 + void drm_fb_xrgb8888_to_rgb565be(struct iosys_map *dst, const unsigned int *dst_pitch, 87 + const struct iosys_map *src, const struct drm_framebuffer *fb, 88 + const struct drm_rect *clip, struct drm_format_conv_state *state); 87 89 void drm_fb_xrgb8888_to_xrgb1555(struct iosys_map *dst, const unsigned int *dst_pitch, 88 90 const struct iosys_map *src, const struct drm_framebuffer *fb, 89 91 const struct drm_rect *clip, struct drm_format_conv_state *state);
-2
include/drm/drm_mipi_dsi.h
··· 130 130 #define MIPI_DSI_MODE_VIDEO_NO_HBP BIT(6) 131 131 /* disable hsync-active area */ 132 132 #define MIPI_DSI_MODE_VIDEO_NO_HSA BIT(7) 133 - /* flush display FIFO on vsync pulse */ 134 - #define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8) 135 133 /* disable EoT packets in HS mode */ 136 134 #define MIPI_DSI_MODE_NO_EOT_PACKET BIT(9) 137 135 /* device supports non-continuous clock behavior (DSI spec 5.6.1) */
+27 -17
include/drm/ttm/ttm_bo.h
··· 207 207 }; 208 208 209 209 /** 210 - * struct ttm_lru_walk - Structure describing a LRU walk. 210 + * struct ttm_lru_walk_arg - Common part for the variants of BO LRU walk. 211 211 */ 212 - struct ttm_lru_walk { 213 - /** @ops: Pointer to the ops structure. */ 214 - const struct ttm_lru_walk_ops *ops; 212 + struct ttm_lru_walk_arg { 215 213 /** @ctx: Pointer to the struct ttm_operation_ctx. */ 216 214 struct ttm_operation_ctx *ctx; 217 215 /** @ticket: The struct ww_acquire_ctx if any. */ 218 216 struct ww_acquire_ctx *ticket; 219 217 /** @trylock_only: Only use trylock for locking. */ 220 218 bool trylock_only; 219 + }; 220 + 221 + /** 222 + * struct ttm_lru_walk - Structure describing a LRU walk. 223 + */ 224 + struct ttm_lru_walk { 225 + /** @ops: Pointer to the ops structure. */ 226 + const struct ttm_lru_walk_ops *ops; 227 + /** @arg: Common bo LRU walk arguments. */ 228 + struct ttm_lru_walk_arg arg; 221 229 }; 222 230 223 231 s64 ttm_lru_walk_for_evict(struct ttm_lru_walk *walk, struct ttm_device *bdev, ··· 475 467 /** @res_curs: Embedded struct ttm_resource_cursor. */ 476 468 struct ttm_resource_cursor res_curs; 477 469 /** 478 - * @ctx: The struct ttm_operation_ctx used while looping. 479 - * governs the locking mode. 480 - */ 481 - struct ttm_operation_ctx *ctx; 482 - /** 483 470 * @bo: Buffer object pointer if a buffer object is refcounted, 484 471 * NULL otherwise. 485 472 */ ··· 484 481 * unlock before the next iteration or after loop exit. 485 482 */ 486 483 bool needs_unlock; 484 + /** @arg: Pointer to common BO LRU walk arguments. */ 485 + struct ttm_lru_walk_arg *arg; 487 486 }; 488 487 489 488 void ttm_bo_lru_cursor_fini(struct ttm_bo_lru_cursor *curs); ··· 493 488 struct ttm_bo_lru_cursor * 494 489 ttm_bo_lru_cursor_init(struct ttm_bo_lru_cursor *curs, 495 490 struct ttm_resource_manager *man, 496 - struct ttm_operation_ctx *ctx); 491 + struct ttm_lru_walk_arg *arg); 497 492 498 493 struct ttm_buffer_object *ttm_bo_lru_cursor_first(struct ttm_bo_lru_cursor *curs); 499 494 ··· 504 499 */ 505 500 DEFINE_CLASS(ttm_bo_lru_cursor, struct ttm_bo_lru_cursor *, 506 501 if (_T) {ttm_bo_lru_cursor_fini(_T); }, 507 - ttm_bo_lru_cursor_init(curs, man, ctx), 502 + ttm_bo_lru_cursor_init(curs, man, arg), 508 503 struct ttm_bo_lru_cursor *curs, struct ttm_resource_manager *man, 509 - struct ttm_operation_ctx *ctx); 504 + struct ttm_lru_walk_arg *arg); 510 505 static inline void * 511 506 class_ttm_bo_lru_cursor_lock_ptr(class_ttm_bo_lru_cursor_t *_T) 512 507 { return *_T; } ··· 517 512 * resources on LRU lists. 518 513 * @_cursor: struct ttm_bo_lru_cursor to use for the iteration. 519 514 * @_man: The resource manager whose LRU lists to iterate over. 520 - * @_ctx: The struct ttm_operation_context to govern the @_bo locking. 515 + * @_arg: The struct ttm_lru_walk_arg to govern the LRU walk. 521 516 * @_bo: The struct ttm_buffer_object pointer pointing to the buffer object 522 517 * for the current iteration. 523 518 * ··· 529 524 * up at looping termination, even if terminated prematurely by, for 530 525 * example a return or break statement. Exiting the loop will also unlock 531 526 * (if needed) and unreference @_bo. 527 + * 528 + * Return: If locking of a bo returns an error, then iteration is terminated 529 + * and @_bo is set to a corresponding error pointer. It's illegal to 530 + * dereference @_bo after loop exit. 532 531 */ 533 - #define ttm_bo_lru_for_each_reserved_guarded(_cursor, _man, _ctx, _bo) \ 534 - scoped_guard(ttm_bo_lru_cursor, _cursor, _man, _ctx) \ 535 - for ((_bo) = ttm_bo_lru_cursor_first(_cursor); (_bo); \ 536 - (_bo) = ttm_bo_lru_cursor_next(_cursor)) 532 + #define ttm_bo_lru_for_each_reserved_guarded(_cursor, _man, _arg, _bo) \ 533 + scoped_guard(ttm_bo_lru_cursor, _cursor, _man, _arg) \ 534 + for ((_bo) = ttm_bo_lru_cursor_first(_cursor); \ 535 + !IS_ERR_OR_NULL(_bo); \ 536 + (_bo) = ttm_bo_lru_cursor_next(_cursor)) 537 537 538 538 #endif
+5 -1
include/linux/sysfb.h
··· 7 7 * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com> 8 8 */ 9 9 10 - #include <linux/kernel.h> 10 + #include <linux/err.h> 11 + #include <linux/types.h> 12 + 11 13 #include <linux/platform_data/simplefb.h> 12 14 15 + struct device; 16 + struct platform_device; 13 17 struct screen_info; 14 18 15 19 enum {
+19 -1
include/uapi/drm/drm_fourcc.h
··· 210 210 #define DRM_FORMAT_RGBA1010102 fourcc_code('R', 'A', '3', '0') /* [31:0] R:G:B:A 10:10:10:2 little endian */ 211 211 #define DRM_FORMAT_BGRA1010102 fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */ 212 212 213 + /* 48 bpp RGB */ 214 + #define DRM_FORMAT_RGB161616 fourcc_code('R', 'G', '4', '8') /* [47:0] R:G:B 16:16:16 little endian */ 215 + #define DRM_FORMAT_BGR161616 fourcc_code('B', 'G', '4', '8') /* [47:0] B:G:R 16:16:16 little endian */ 216 + 213 217 /* 64 bpp RGB */ 214 218 #define DRM_FORMAT_XRGB16161616 fourcc_code('X', 'R', '4', '8') /* [63:0] x:R:G:B 16:16:16:16 little endian */ 215 219 #define DRM_FORMAT_XBGR16161616 fourcc_code('X', 'B', '4', '8') /* [63:0] x:B:G:R 16:16:16:16 little endian */ ··· 222 218 #define DRM_FORMAT_ABGR16161616 fourcc_code('A', 'B', '4', '8') /* [63:0] A:B:G:R 16:16:16:16 little endian */ 223 219 224 220 /* 225 - * Floating point 64bpp RGB 221 + * Half-Floating point - 16b/component 226 222 * IEEE 754-2008 binary16 half-precision float 227 223 * [15:0] sign:exponent:mantissa 1:5:10 228 224 */ ··· 231 227 232 228 #define DRM_FORMAT_ARGB16161616F fourcc_code('A', 'R', '4', 'H') /* [63:0] A:R:G:B 16:16:16:16 little endian */ 233 229 #define DRM_FORMAT_ABGR16161616F fourcc_code('A', 'B', '4', 'H') /* [63:0] A:B:G:R 16:16:16:16 little endian */ 230 + 231 + #define DRM_FORMAT_R16F fourcc_code('R', ' ', ' ', 'H') /* [15:0] R 16 little endian */ 232 + #define DRM_FORMAT_GR1616F fourcc_code('G', 'R', ' ', 'H') /* [31:0] G:R 16:16 little endian */ 233 + #define DRM_FORMAT_BGR161616F fourcc_code('B', 'G', 'R', 'H') /* [47:0] B:G:R 16:16:16 little endian */ 234 + 235 + /* 236 + * Floating point - 32b/component 237 + * IEEE 754-2008 binary32 float 238 + * [31:0] sign:exponent:mantissa 1:8:23 239 + */ 240 + #define DRM_FORMAT_R32F fourcc_code('R', ' ', ' ', 'F') /* [31:0] R 32 little endian */ 241 + #define DRM_FORMAT_GR3232F fourcc_code('G', 'R', ' ', 'F') /* [63:0] R:G 32:32 little endian */ 242 + #define DRM_FORMAT_BGR323232F fourcc_code('B', 'G', 'R', 'F') /* [95:0] R:G:B 32:32:32 little endian */ 243 + #define DRM_FORMAT_ABGR32323232F fourcc_code('A', 'B', '8', 'F') /* [127:0] R:G:B:A 32:32:32:32 little endian */ 234 244 235 245 /* 236 246 * RGBA format with 10-bit components packed in 64-bit per pixel, with 6 bits