diff --git a/Documentation/devicetree/bindings/display/panel/display-timing.txt b/Documentation/devicetree/bindings/display/panel/display-timing.txt index 78222ced18743..7f55ad4a40c41 100644 --- a/Documentation/devicetree/bindings/display/panel/display-timing.txt +++ b/Documentation/devicetree/bindings/display/panel/display-timing.txt @@ -1,123 +1 @@ -display-timing bindings -======================= - -display-timings node --------------------- - -required properties: - - none - -optional properties: - - native-mode: The native mode for the display, in case multiple modes are - provided. When omitted, assume the first node is the native. - -timing subnode --------------- - -required properties: - - hactive, vactive: display resolution - - hfront-porch, hback-porch, hsync-len: horizontal display timing parameters - in pixels - vfront-porch, vback-porch, vsync-len: vertical display timing parameters in - lines - - clock-frequency: display clock in Hz - -optional properties: - - hsync-active: hsync pulse is active low/high/ignored - - vsync-active: vsync pulse is active low/high/ignored - - de-active: data-enable pulse is active low/high/ignored - - pixelclk-active: with - - active high = drive pixel data on rising edge/ - sample data on falling edge - - active low = drive pixel data on falling edge/ - sample data on rising edge - - ignored = ignored - - syncclk-active: with - - active high = drive sync on rising edge/ - sample sync on falling edge of pixel - clock - - active low = drive sync on falling edge/ - sample sync on rising edge of pixel - clock - - omitted = same configuration as pixelclk-active - - interlaced (bool): boolean to enable interlaced mode - - doublescan (bool): boolean to enable doublescan mode - - doubleclk (bool): boolean to enable doubleclock mode - -All the optional properties that are not bool follow the following logic: - <1>: high active - <0>: low active - omitted: not used on hardware - -There are different ways of describing the capabilities of a display. The -devicetree representation corresponds to the one commonly found in datasheets -for displays. If a display supports multiple signal timings, the native-mode -can be specified. - -The parameters are defined as: - - +----------+-------------------------------------+----------+-------+ - | | ^ | | | - | | |vback_porch | | | - | | v | | | - +----------#######################################----------+-------+ - | # ^ # | | - | # | # | | - | hback # | # hfront | hsync | - | porch # | hactive # porch | len | - |<-------->#<-------+--------------------------->#<-------->|<----->| - | # | # | | - | # |vactive # | | - | # | # | | - | # v # | | - +----------#######################################----------+-------+ - | | ^ | | | - | | |vfront_porch | | | - | | v | | | - +----------+-------------------------------------+----------+-------+ - | | ^ | | | - | | |vsync_len | | | - | | v | | | - +----------+-------------------------------------+----------+-------+ - -Note: In addition to being used as subnode(s) of display-timings, the timing - subnode may also be used on its own. This is appropriate if only one mode - need be conveyed. In this case, the node should be named 'panel-timing'. - - -Example: - - display-timings { - native-mode = <&timing0>; - timing0: 1080p24 { - /* 1920x1080p24 */ - clock-frequency = <52000000>; - hactive = <1920>; - vactive = <1080>; - hfront-porch = <25>; - hback-porch = <25>; - hsync-len = <25>; - vback-porch = <2>; - vfront-porch = <2>; - vsync-len = <2>; - hsync-active = <1>; - }; - }; - -Every required property also supports the use of ranges, so the commonly used -datasheet description with minimum, typical and maximum values can be used. - -Example: - - timing1: timing { - /* 1920x1080p24 */ - clock-frequency = <148500000>; - hactive = <1920>; - vactive = <1080>; - hsync-len = <0 44 60>; - hfront-porch = <80 88 95>; - hback-porch = <100 148 160>; - vfront-porch = <0 4 6>; - vback-porch = <0 36 50>; - vsync-len = <0 5 6>; - }; +See display-timings.yaml in this directory. diff --git a/Documentation/devicetree/bindings/display/panel/display-timings.yaml b/Documentation/devicetree/bindings/display/panel/display-timings.yaml new file mode 100644 index 0000000000000..c8c0c9cb0492b --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/display-timings.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/display-timings.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: display timing bindings + +maintainers: + - Thierry Reding + - Laurent Pinchart + - Sam Ravnborg + +description: | + A display panel may be able to handle several display timings, + with different resolutions. + The display-timings node makes it possible to specify the timing + and to specify the timing that is native for the display. + +properties: + $nodename: + const: display-timings + + native-mode: + $ref: /schemas/types.yaml#/definitions/phandle + description: | + The default display timing is the one specified as native-mode. + If no native-mode is specified then the first node is assumed the + native mode. + +patternProperties: + "^timing": + type: object + allOf: + - $ref: panel-timing.yaml# + +additionalProperties: false + +examples: + - |+ + + /* + * Example that specifies panel timing using minimum, typical, + * maximum values as commonly used in datasheet description. + * timing1 is the native-mode. + */ + display-timings { + native-mode = <&timing1>; + timing0 { + /* 1920x1080p24 */ + clock-frequency = <148500000>; + hactive = <1920>; + vactive = <1080>; + hsync-len = <0 44 60>; + hfront-porch = <80 88 95>; + hback-porch = <100 148 160>; + vfront-porch = <0 4 6>; + vback-porch = <0 36 50>; + vsync-len = <0 5 6>; + }; + timing1 { + /* 1920x1080p24 */ + clock-frequency = <52000000>; + hactive = <1920>; + vactive = <1080>; + hfront-porch = <25>; + hback-porch = <25>; + hsync-len = <0 25 25>; + vback-porch = <2>; + vfront-porch = <2>; + vsync-len = <2>; + hsync-active = <1>; + pixelclk-active = <1>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/elida,kd35t133.yaml b/Documentation/devicetree/bindings/display/panel/elida,kd35t133.yaml new file mode 100644 index 0000000000000..4bd74eaa61be3 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/elida,kd35t133.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/elida,kd35t133.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Elida KD35T133 3.5in 320x480 DSI panel + +maintainers: + - Heiko Stuebner + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: elida,kd35t133 + reg: true + backlight: true + reset-gpios: true + iovcc-supply: + description: regulator that supplies the iovcc voltage + vdd-supply: + description: regulator that supplies the vdd voltage + +required: + - compatible + - reg + - backlight + - iovcc-supply + - vdd-supply + +additionalProperties: false + +examples: + - | + dsi@ff450000 { + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "elida,kd35t133"; + reg = <0>; + backlight = <&backlight>; + iovcc-supply = <&vcc_1v8>; + vdd-supply = <&vcc3v3_lcd>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml b/Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml new file mode 100644 index 0000000000000..791fc9daa68b5 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/novatek,nt35510.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Novatek NT35510-based display panels + +maintainers: + - Linus Walleij + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + items: + - const: hydis,hva40wv1 + - const: novatek,nt35510 + description: This indicates the panel manufacturer of the panel + that is in turn using the NT35510 panel driver. The compatible + string determines how the NT35510 panel driver shall be configured + to work with the indicated panel. The novatek,nt35510 compatible shall + always be provided as a fallback. + reg: true + reset-gpios: true + vdd-supply: + description: regulator that supplies the vdd voltage + vddi-supply: + description: regulator that supplies the vddi voltage + backlight: true + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + + dsi@a0351000 { + #address-cells = <1>; + #size-cells = <0>; + panel { + compatible = "hydis,hva40wv1", "novatek,nt35510"; + reg = <0>; + vdd-supply = <&ab8500_ldo_aux4_reg>; + vddi-supply = <&ab8500_ldo_aux6_reg>; + reset-gpios = <&gpio4 11 GPIO_ACTIVE_LOW>; + backlight = <&gpio_bl>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/panel-common.yaml b/Documentation/devicetree/bindings/display/panel/panel-common.yaml index ef8d8cdfcede6..ed051ba12084b 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-common.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-common.yaml @@ -54,13 +54,20 @@ properties: # Display Timings panel-timing: - type: object description: Most display panels are restricted to a single resolution and require specific display timings. The panel-timing subnode expresses those - timings as specified in the timing subnode section of the display timing - bindings defined in - Documentation/devicetree/bindings/display/panel/display-timing.txt. + timings. + allOf: + - $ref: panel-timing.yaml# + + display-timings: + description: + Some display panels supports several resolutions with different timing. + The display-timings bindings supports specifying several timings and + optional specify which is the native mode. + allOf: + - $ref: display-timings.yaml# # Connectivity port: diff --git a/Documentation/devicetree/bindings/display/panel/panel-dpi.txt b/Documentation/devicetree/bindings/display/panel/panel-dpi.txt deleted file mode 100644 index 6b203bc4d932f..0000000000000 --- a/Documentation/devicetree/bindings/display/panel/panel-dpi.txt +++ /dev/null @@ -1,50 +0,0 @@ -Generic MIPI DPI Panel -====================== - -Required properties: -- compatible: "panel-dpi" - -Optional properties: -- label: a symbolic name for the panel -- enable-gpios: panel enable gpio -- reset-gpios: GPIO to control the RESET pin -- vcc-supply: phandle of regulator that will be used to enable power to the display -- backlight: phandle of the backlight device - -Required nodes: -- "panel-timing" containing video timings - (Documentation/devicetree/bindings/display/panel/display-timing.txt) -- Video port for DPI input - -Example -------- - -lcd0: display@0 { - compatible = "samsung,lte430wq-f0c", "panel-dpi"; - label = "lcd"; - - backlight = <&backlight>; - - port { - lcd_in: endpoint { - remote-endpoint = <&dpi_out>; - }; - }; - - panel-timing { - clock-frequency = <9200000>; - hactive = <480>; - vactive = <272>; - hfront-porch = <8>; - hback-porch = <4>; - hsync-len = <41>; - vback-porch = <2>; - vfront-porch = <4>; - vsync-len = <10>; - - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <1>; - }; -}; diff --git a/Documentation/devicetree/bindings/display/panel/panel-dpi.yaml b/Documentation/devicetree/bindings/display/panel/panel-dpi.yaml new file mode 100644 index 0000000000000..5275d350f8cb3 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/panel-dpi.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/panel-dpi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic MIPI DPI Panel + +maintainers: + - Sam Ravnborg + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + description: + Shall contain a panel specific compatible and "panel-dpi" + in that order. + items: + - {} + - const: panel-dpi + + data-mapping: + enum: + - rgb24 + - rgb565 + - bgr666 + description: | + Describes the media format, how the display panel is connected + to the display interface. + + backlight: true + enable-gpios: true + height-mm: true + label: true + panel-timing: true + port: true + power-supply: true + reset-gpios: true + width-mm: true + +required: + - panel-timing + - power-supply + +additionalProperties: false + +examples: + - | + panel@0 { + compatible = "osddisplays,osd057T0559-34ts", "panel-dpi"; + label = "osddisplay"; + power-supply = <&vcc_supply>; + data-mapping = "rgb565"; + backlight = <&backlight>; + + port { + lcd_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + panel-timing { + clock-frequency = <9200000>; + hactive = <800>; + vactive = <480>; + hfront-porch = <8>; + hback-porch = <4>; + hsync-len = <41>; + vback-porch = <2>; + vfront-porch = <4>; + vsync-len = <10>; + + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <1>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index e717018d34aee..393ffc6acbba1 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -177,6 +177,8 @@ properties: - nec,nl4827hc19-05b # Netron-DY E231732 7.0" WSVGA TFT LCD panel - netron-dy,e231732 + # NewEast Optoelectronics CO., LTD WJFH116008A eDP TFT LCD panel + - neweast,wjfh116008a # Newhaven Display International 480 x 272 TFT LCD panel - newhaven,nhd-4.3-480272ef-atxl # NLT Technologies, Ltd. 15.6" FHD (1920x1080) LVDS TFT LCD panel diff --git a/Documentation/devicetree/bindings/display/panel/panel-timing.yaml b/Documentation/devicetree/bindings/display/panel/panel-timing.yaml new file mode 100644 index 0000000000000..bd558ad7891ff --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/panel-timing.yaml @@ -0,0 +1,227 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/panel-timing.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: panel timing bindings + +maintainers: + - Thierry Reding + - Sam Ravnborg + +description: | + There are different ways of describing the timing data of a panel. The + devicetree representation corresponds to the one commonly found in datasheets + for panels. + + The parameters are defined as seen in the following illustration. + + +----------+-------------------------------------+----------+-------+ + | | ^ | | | + | | |vback_porch | | | + | | v | | | + +----------#######################################----------+-------+ + | # ^ # | | + | # | # | | + | hback # | # hfront | hsync | + | porch # | hactive # porch | len | + |<-------->#<-------+--------------------------->#<-------->|<----->| + | # | # | | + | # |vactive # | | + | # | # | | + | # v # | | + +----------#######################################----------+-------+ + | | ^ | | | + | | |vfront_porch | | | + | | v | | | + +----------+-------------------------------------+----------+-------+ + | | ^ | | | + | | |vsync_len | | | + | | v | | | + +----------+-------------------------------------+----------+-------+ + + + The following is the panel timings shown with time on the x-axis. + This matches the timing diagrams often found in data sheets. + + Active Front Sync Back + Region Porch Porch + <-----------------------><----------------><-------------><--------------> + //////////////////////| + ////////////////////// | + ////////////////////// |.................. ................ + _______________ + + Timing can be specified either as a typical value or as a tuple + of min, typ, max values. + +properties: + + clock-frequency: + description: Panel clock in Hz + + hactive: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Horizontal panel resolution in pixels + + vactive: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Vertical panel resolution in pixels + + hfront-porch: + description: Horizontal front porch panel timing + oneOf: + - allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - maxItems: 1 + items: + description: typical number of pixels + - allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array + - minItems: 3 + maxItems: 3 + items: + description: min, typ, max number of pixels + + hback-porch: + description: Horizontal back porch timing + oneOf: + - allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - maxItems: 1 + items: + description: typical number of pixels + - allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array + - minItems: 3 + maxItems: 3 + items: + description: min, typ, max number of pixels + + hsync-len: + description: Horizontal sync length panel timing + oneOf: + - allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - maxItems: 1 + items: + description: typical number of pixels + - allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array + - minItems: 3 + maxItems: 3 + items: + description: min, typ, max number of pixels + + vfront-porch: + description: Vertical front porch panel timing + oneOf: + - allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - maxItems: 1 + items: + description: typical number of lines + - allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array + - minItems: 3 + maxItems: 3 + items: + description: min, typ, max number of lines + + vback-porch: + description: Vertical back porch panel timing + oneOf: + - allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - maxItems: 1 + items: + description: typical number of lines + - allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array + - minItems: 3 + maxItems: 3 + items: + description: min, typ, max number of lines + + vsync-len: + description: Vertical sync length panel timing + oneOf: + - allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - maxItems: 1 + items: + description: typical number of lines + - allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array + - minItems: 3 + maxItems: 3 + items: + description: min, typ, max number of lines + + hsync-active: + description: | + Horizontal sync pulse. + 0 selects active low, 1 selects active high. + If omitted then it is not used by the hardware + enum: [0, 1] + + vsync-active: + description: | + Vertical sync pulse. + 0 selects active low, 1 selects active high. + If omitted then it is not used by the hardware + enum: [0, 1] + + de-active: + description: | + Data enable. + 0 selects active low, 1 selects active high. + If omitted then it is not used by the hardware + enum: [0, 1] + + pixelclk-active: + description: | + Data driving on rising or falling edge. + Use 0 to drive pixel data on falling edge and + sample data on rising edge. + Use 1 to drive pixel data on rising edge and + sample data on falling edge + enum: [0, 1] + + syncclk-active: + description: | + Drive sync on rising or sample sync on falling edge. + If not specified then the setup is as specified by pixelclk-active. + Use 0 to drive sync on falling edge and + sample sync on rising edge of pixel clock. + Use 1 to drive sync on rising edge and + sample sync on falling edge of pixel clock + enum: [0, 1] + + interlaced: + type: boolean + description: Enable interlaced mode + + doublescan: + type: boolean + description: Enable double scan mode + + doubleclk: + type: boolean + description: Enable double clock mode + +required: + - clock-frequency + - hactive + - vactive + - hfront-porch + - hback-porch + - hsync-len + - vfront-porch + - vback-porch + - vsync-len + +additionalProperties: false + +... diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.txt deleted file mode 100644 index 5707af89319da..0000000000000 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.txt +++ /dev/null @@ -1,19 +0,0 @@ -Rockchip DRM master device -================================ - -The Rockchip DRM master device is a virtual device needed to list all -vop devices or other display interface nodes that comprise the -graphics subsystem. - -Required properties: -- compatible: Should be "rockchip,display-subsystem" -- ports: Should contain a list of phandles pointing to display interface port - of vop devices. vop definitions as defined in - Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt - -example: - -display-subsystem { - compatible = "rockchip,display-subsystem"; - ports = <&vopl_out>, <&vopb_out>; -}; diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.yaml new file mode 100644 index 0000000000000..ec8ae742d4da2 --- /dev/null +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-drm.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: (GPL-2.0-only) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/rockchip/rockchip-drm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip DRM master device + +maintainers: + - Sandy Huang + - Heiko Stuebner + +description: | + The Rockchip DRM master device is a virtual device needed to list all + vop devices or other display interface nodes that comprise the + graphics subsystem. + +properties: + compatible: + const: rockchip,display-subsystem + + ports: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: | + Should contain a list of phandles pointing to display interface port + of vop devices. vop definitions as defined in + Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt + +required: + - compatible + - ports + +additionalProperties: false + +examples: + - | + display-subsystem { + compatible = "rockchip,display-subsystem"; + ports = <&vopl_out>, <&vopb_out>; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 9a0cca2fd166c..a2da166df1bc7 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -425,6 +425,8 @@ patternProperties: description: Shenzhen Hugsun Technology Co. Ltd. "^hwacom,.*": description: HwaCom Systems Inc. + "^hydis,.*": + description: Hydis Technologies "^hyundai,.*": description: Hyundai Technology "^i2se,.*": @@ -665,6 +667,8 @@ patternProperties: description: Netron DY "^netxeon,.*": description: Shenzhen Netxeon Technology CO., LTD + "^neweast,.*": + description: Guangdong Neweast Optoelectronics CO., LTD "^nexbox,.*": description: Nexbox "^nextthing,.*": diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index ccf5e8e342225..439656f55c5da 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -359,23 +359,6 @@ Contact: Sean Paul Level: Starter -drm_fb_helper tasks -------------------- - -- drm_fb_helper_restore_fbdev_mode_unlocked() should call restore_fbdev_mode() - not the _force variant so it can bail out if there is a master. But first - these igt tests need to be fixed: kms_fbcon_fbt@psr and - kms_fbcon_fbt@psr-suspend. - -- The max connector argument for drm_fb_helper_init() isn't used anymore and - can be removed. - -- The helper doesn't keep an array of connectors anymore so these can be - removed: drm_fb_helper_single_add_all_connectors(), - drm_fb_helper_add_one_connector() and drm_fb_helper_remove_one_connector(). - -Level: Intermediate - connector register/unregister fixes ----------------------------------- diff --git a/MAINTAINERS b/MAINTAINERS index 41f3aa079b099..6ba8b584bf958 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5022,7 +5022,7 @@ L: dri-devel@lists.freedesktop.org L: linaro-mm-sig@lists.linaro.org (moderated for non-subscribers) F: drivers/dma-buf/ F: include/linux/dma-buf* -F: include/linux/reservation.h +F: include/linux/dma-resv.h F: include/linux/*fence.h F: Documentation/driver-api/dma-buf.rst K: dma_(buf|fence|resv) @@ -5336,6 +5336,13 @@ F: drivers/gpu/drm/msm/ F: include/uapi/drm/msm_drm.h F: Documentation/devicetree/bindings/display/msm/ +DRM DRIVER FOR NOVATEK NT35510 PANELS +M: Linus Walleij +T: git git://anongit.freedesktop.org/drm/drm-misc +S: Maintained +F: drivers/gpu/drm/panel/panel-novatek-nt35510.c +F: Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml + DRM DRIVER FOR NVIDIA GEFORCE/QUADRO GPUS M: Ben Skeggs L: dri-devel@lists.freedesktop.org diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig index e7d820ce07241..ef73b678419c6 100644 --- a/drivers/dma-buf/Kconfig +++ b/drivers/dma-buf/Kconfig @@ -39,6 +39,16 @@ config UDMABUF A driver to let userspace turn memfd regions into dma-bufs. Qemu can use this to create host dmabufs for guest framebuffers. +config DMABUF_MOVE_NOTIFY + bool "Move notify between drivers (EXPERIMENTAL)" + default n + help + Don''t pin buffers if the dynamic DMA-buf interface is available on both the + exporter as well as the importer. This fixes a security problem where + userspace is able to pin unrestricted amounts of memory through DMA-buf. + But marked experimental because we don''t jet have a consistent execution + context and memory management between drivers. + config DMABUF_SELFTESTS tristate "Selftests for the dma-buf interfaces" default n diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index c343c7c10b4cc..ccc9eda1bc282 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -525,7 +525,10 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) } if (WARN_ON(exp_info->ops->cache_sgt_mapping && - exp_info->ops->dynamic_mapping)) + (exp_info->ops->pin || exp_info->ops->unpin))) + return ERR_PTR(-EINVAL); + + if (WARN_ON(!exp_info->ops->pin != !exp_info->ops->unpin)) return ERR_PTR(-EINVAL); if (!try_module_get(exp_info->owner)) @@ -652,7 +655,8 @@ EXPORT_SYMBOL_GPL(dma_buf_put); * calls attach() of dma_buf_ops to allow device-specific attach functionality * @dmabuf: [in] buffer to attach device to. * @dev: [in] device to be attached. - * @dynamic_mapping: [in] calling convention for map/unmap + * @importer_ops [in] importer operations for the attachment + * @importer_priv [in] importer private pointer for the attachment * * Returns struct dma_buf_attachment pointer for this attachment. Attachments * must be cleaned up by calling dma_buf_detach(). @@ -668,7 +672,8 @@ EXPORT_SYMBOL_GPL(dma_buf_put); */ struct dma_buf_attachment * dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev, - bool dynamic_mapping) + const struct dma_buf_attach_ops *importer_ops, + void *importer_priv) { struct dma_buf_attachment *attach; int ret; @@ -676,13 +681,17 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev, if (WARN_ON(!dmabuf || !dev)) return ERR_PTR(-EINVAL); + if (WARN_ON(importer_ops && !importer_ops->move_notify)) + return ERR_PTR(-EINVAL); + attach = kzalloc(sizeof(*attach), GFP_KERNEL); if (!attach) return ERR_PTR(-ENOMEM); attach->dev = dev; attach->dmabuf = dmabuf; - attach->dynamic_mapping = dynamic_mapping; + attach->importer_ops = importer_ops; + attach->importer_priv = importer_priv; if (dmabuf->ops->attach) { ret = dmabuf->ops->attach(dmabuf, attach); @@ -701,15 +710,19 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev, dma_buf_is_dynamic(dmabuf)) { struct sg_table *sgt; - if (dma_buf_is_dynamic(attach->dmabuf)) + if (dma_buf_is_dynamic(attach->dmabuf)) { dma_resv_lock(attach->dmabuf->resv, NULL); + ret = dma_buf_pin(attach); + if (ret) + goto err_unlock; + } sgt = dmabuf->ops->map_dma_buf(attach, DMA_BIDIRECTIONAL); if (!sgt) sgt = ERR_PTR(-ENOMEM); if (IS_ERR(sgt)) { ret = PTR_ERR(sgt); - goto err_unlock; + goto err_unpin; } if (dma_buf_is_dynamic(attach->dmabuf)) dma_resv_unlock(attach->dmabuf->resv); @@ -723,6 +736,10 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev, kfree(attach); return ERR_PTR(ret); +err_unpin: + if (dma_buf_is_dynamic(attach->dmabuf)) + dma_buf_unpin(attach); + err_unlock: if (dma_buf_is_dynamic(attach->dmabuf)) dma_resv_unlock(attach->dmabuf->resv); @@ -743,7 +760,7 @@ EXPORT_SYMBOL_GPL(dma_buf_dynamic_attach); struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, struct device *dev) { - return dma_buf_dynamic_attach(dmabuf, dev, false); + return dma_buf_dynamic_attach(dmabuf, dev, NULL, NULL); } EXPORT_SYMBOL_GPL(dma_buf_attach); @@ -766,8 +783,10 @@ void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach) dmabuf->ops->unmap_dma_buf(attach, attach->sgt, attach->dir); - if (dma_buf_is_dynamic(attach->dmabuf)) + if (dma_buf_is_dynamic(attach->dmabuf)) { + dma_buf_unpin(attach); dma_resv_unlock(attach->dmabuf->resv); + } } dma_resv_lock(dmabuf->resv, NULL); @@ -780,6 +799,44 @@ void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach) } EXPORT_SYMBOL_GPL(dma_buf_detach); +/** + * dma_buf_pin - Lock down the DMA-buf + * + * @attach: [in] attachment which should be pinned + * + * Returns: + * 0 on success, negative error code on failure. + */ +int dma_buf_pin(struct dma_buf_attachment *attach) +{ + struct dma_buf *dmabuf = attach->dmabuf; + int ret = 0; + + dma_resv_assert_held(dmabuf->resv); + + if (dmabuf->ops->pin) + ret = dmabuf->ops->pin(attach); + + return ret; +} +EXPORT_SYMBOL_GPL(dma_buf_pin); + +/** + * dma_buf_unpin - Remove lock from DMA-buf + * + * @attach: [in] attachment which should be unpinned + */ +void dma_buf_unpin(struct dma_buf_attachment *attach) +{ + struct dma_buf *dmabuf = attach->dmabuf; + + dma_resv_assert_held(dmabuf->resv); + + if (dmabuf->ops->unpin) + dmabuf->ops->unpin(attach); +} +EXPORT_SYMBOL_GPL(dma_buf_unpin); + /** * dma_buf_map_attachment - Returns the scatterlist table of the attachment; * mapped into _device_ address space. Is a wrapper for map_dma_buf() of the @@ -799,6 +856,7 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, enum dma_data_direction direction) { struct sg_table *sg_table; + int r; might_sleep(); @@ -820,13 +878,23 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, return attach->sgt; } - if (dma_buf_is_dynamic(attach->dmabuf)) + if (dma_buf_is_dynamic(attach->dmabuf)) { dma_resv_assert_held(attach->dmabuf->resv); + if (!IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY)) { + r = dma_buf_pin(attach); + if (r) + return ERR_PTR(r); + } + } sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction); if (!sg_table) sg_table = ERR_PTR(-ENOMEM); + if (IS_ERR(sg_table) && dma_buf_is_dynamic(attach->dmabuf) && + !IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY)) + dma_buf_unpin(attach); + if (!IS_ERR(sg_table) && attach->dmabuf->ops->cache_sgt_mapping) { attach->sgt = sg_table; attach->dir = direction; @@ -865,9 +933,33 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach, dma_resv_assert_held(attach->dmabuf->resv); attach->dmabuf->ops->unmap_dma_buf(attach, sg_table, direction); + + if (dma_buf_is_dynamic(attach->dmabuf) && + !IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY)) + dma_buf_unpin(attach); } EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment); +/** + * dma_buf_move_notify - notify attachments that DMA-buf is moving + * + * @dmabuf: [in] buffer which is moving + * + * Informs all attachmenst that they need to destroy and recreated all their + * mappings. + */ +void dma_buf_move_notify(struct dma_buf *dmabuf) +{ + struct dma_buf_attachment *attach; + + dma_resv_assert_held(dmabuf->resv); + + list_for_each_entry(attach, &dmabuf->attachments, node) + if (attach->importer_ops) + attach->importer_ops->move_notify(attach); +} +EXPORT_SYMBOL_GPL(dma_buf_move_notify); + /** * DOC: cpu access * diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 4bffa08f610ac..43594978958e8 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -54,9 +54,6 @@ config DRM_DEBUG_MM If in doubt, say "N". -config DRM_EXPORT_FOR_TESTS - bool - config DRM_DEBUG_SELFTEST tristate "kselftests for DRM" depends on DRM @@ -470,6 +467,9 @@ config DRM_SAVAGE endif # DRM_LEGACY +config DRM_EXPORT_FOR_TESTS + bool + # Separate option because drm_panel_orientation_quirks.c is shared with fbdev config DRM_PANEL_ORIENTATION_QUIRKS tristate diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index f397ff97b4e44..438d10ae343b5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -415,7 +416,9 @@ static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p, /* Don't move this buffer if we have depleted our allowance * to move it. Don't move anything if the threshold is zero. */ - if (p->bytes_moved < p->bytes_moved_threshold) { + if (p->bytes_moved < p->bytes_moved_threshold && + (!bo->tbo.base.dma_buf || + list_empty(&bo->tbo.base.dma_buf->attachments))) { if (!amdgpu_gmc_vram_full_visible(&adev->gmc) && (bo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)) { /* And don't move a CPU_ACCESS_REQUIRED BO to limited diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index a59cd47aa6c1e..ffeb20f11c07c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -222,6 +222,37 @@ static void amdgpu_dma_buf_detach(struct dma_buf *dmabuf, bo->prime_shared_count--; } +/** + * amdgpu_dma_buf_pin - &dma_buf_ops.pin implementation + * + * @attach: attachment to pin down + * + * Pin the BO which is backing the DMA-buf so that it can't move any more. + */ +static int amdgpu_dma_buf_pin(struct dma_buf_attachment *attach) +{ + struct drm_gem_object *obj = attach->dmabuf->priv; + struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); + + /* pin buffer into GTT */ + return amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT); +} + +/** + * amdgpu_dma_buf_unpin - &dma_buf_ops.unpin implementation + * + * @attach: attachment to unpin + * + * Unpin a previously pinned BO to make it movable again. + */ +static void amdgpu_dma_buf_unpin(struct dma_buf_attachment *attach) +{ + struct drm_gem_object *obj = attach->dmabuf->priv; + struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); + + amdgpu_bo_unpin(bo); +} + /** * amdgpu_dma_buf_map - &dma_buf_ops.map_dma_buf implementation * @attach: DMA-buf attachment @@ -244,9 +275,19 @@ static struct sg_table *amdgpu_dma_buf_map(struct dma_buf_attachment *attach, struct sg_table *sgt; long r; - r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT); - if (r) - return ERR_PTR(r); + if (!bo->pin_count) { + /* move buffer into GTT */ + struct ttm_operation_ctx ctx = { false, false }; + + amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_GTT); + r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); + if (r) + return ERR_PTR(r); + + } else if (!(amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type) & + AMDGPU_GEM_DOMAIN_GTT)) { + return ERR_PTR(-EBUSY); + } sgt = drm_prime_pages_to_sg(bo->tbo.ttm->pages, bo->tbo.num_pages); if (IS_ERR(sgt)) @@ -277,13 +318,9 @@ static void amdgpu_dma_buf_unmap(struct dma_buf_attachment *attach, struct sg_table *sgt, enum dma_data_direction dir) { - struct drm_gem_object *obj = attach->dmabuf->priv; - struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); - dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir); sg_free_table(sgt); kfree(sgt); - amdgpu_bo_unpin(bo); } /** @@ -327,9 +364,10 @@ static int amdgpu_dma_buf_begin_cpu_access(struct dma_buf *dma_buf, } const struct dma_buf_ops amdgpu_dmabuf_ops = { - .dynamic_mapping = true, .attach = amdgpu_dma_buf_attach, .detach = amdgpu_dma_buf_detach, + .pin = amdgpu_dma_buf_pin, + .unpin = amdgpu_dma_buf_unpin, .map_dma_buf = amdgpu_dma_buf_map, .unmap_dma_buf = amdgpu_dma_buf_unmap, .release = drm_gem_dmabuf_release, @@ -412,6 +450,73 @@ amdgpu_dma_buf_create_obj(struct drm_device *dev, struct dma_buf *dma_buf) return ERR_PTR(ret); } +/** + * amdgpu_dma_buf_move_notify - &attach.move_notify implementation + * + * @attach: the DMA-buf attachment + * + * Invalidate the DMA-buf attachment, making sure that the we re-create the + * mapping before the next use. + */ +static void +amdgpu_dma_buf_move_notify(struct dma_buf_attachment *attach) +{ + struct drm_gem_object *obj = attach->importer_priv; + struct ww_acquire_ctx *ticket = dma_resv_locking_ctx(obj->resv); + struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); + struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); + struct ttm_operation_ctx ctx = { false, false }; + struct ttm_placement placement = {}; + struct amdgpu_vm_bo_base *bo_base; + int r; + + if (bo->tbo.mem.mem_type == TTM_PL_SYSTEM) + return; + + r = ttm_bo_validate(&bo->tbo, &placement, &ctx); + if (r) { + DRM_ERROR("Failed to invalidate DMA-buf import (%d))\n", r); + return; + } + + for (bo_base = bo->vm_bo; bo_base; bo_base = bo_base->next) { + struct amdgpu_vm *vm = bo_base->vm; + struct dma_resv *resv = vm->root.base.bo->tbo.base.resv; + + if (ticket) { + /* When we get an error here it means that somebody + * else is holding the VM lock and updating page tables + * So we can just continue here. + */ + r = dma_resv_lock(resv, ticket); + if (r) + continue; + + } else { + /* TODO: This is more problematic and we actually need + * to allow page tables updates without holding the + * lock. + */ + if (!dma_resv_trylock(resv)) + continue; + } + + r = amdgpu_vm_clear_freed(adev, vm, NULL); + if (!r) + r = amdgpu_vm_handle_moved(adev, vm); + + if (r && r != -EBUSY) + DRM_ERROR("Failed to invalidate VM page tables (%d))\n", + r); + + dma_resv_unlock(resv); + } +} + +static const struct dma_buf_attach_ops amdgpu_dma_buf_attach_ops = { + .move_notify = amdgpu_dma_buf_move_notify +}; + /** * amdgpu_gem_prime_import - &drm_driver.gem_prime_import implementation * @dev: DRM device @@ -444,7 +549,8 @@ struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev, if (IS_ERR(obj)) return obj; - attach = dma_buf_dynamic_attach(dma_buf, dev->dev, true); + attach = dma_buf_dynamic_attach(dma_buf, dev->dev, + &amdgpu_dma_buf_attach_ops, obj); if (IS_ERR(attach)) { drm_gem_object_put(obj); return ERR_CAST(attach); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index 2672dc64a3101..9ae7b61f696a2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -336,15 +336,12 @@ int amdgpu_fbdev_init(struct amdgpu_device *adev) drm_fb_helper_prepare(adev->ddev, &rfbdev->helper, &amdgpu_fb_helper_funcs); - ret = drm_fb_helper_init(adev->ddev, &rfbdev->helper, - AMDGPUFB_CONN_LIMIT); + ret = drm_fb_helper_init(adev->ddev, &rfbdev->helper); if (ret) { kfree(rfbdev); return ret; } - drm_fb_helper_single_add_all_connectors(&rfbdev->helper); - /* disable all the possible outputs/crtcs before entering KMS mode */ if (!amdgpu_device_has_dc_support(adev)) drm_helper_disable_unused_functions(adev->ddev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index e4a8c424d290f..1791c084787d7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -31,6 +31,7 @@ */ #include #include +#include #include #include @@ -925,6 +926,9 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, return 0; } + if (bo->tbo.base.import_attach) + dma_buf_pin(bo->tbo.base.import_attach); + bo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; /* force to pin into visible video ram */ if (!(bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS)) @@ -1008,6 +1012,9 @@ int amdgpu_bo_unpin(struct amdgpu_bo *bo) amdgpu_bo_subtract_pin_size(bo); + if (bo->tbo.base.import_attach) + dma_buf_unpin(bo->tbo.base.import_attach); + for (i = 0; i < bo->placement.num_placement; i++) { bo->placements[i].lpfn = 0; bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; @@ -1274,6 +1281,10 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, amdgpu_bo_kunmap(abo); + if (abo->tbo.base.dma_buf && !abo->tbo.base.import_attach && + bo->mem.mem_type != TTM_PL_SYSTEM) + dma_buf_move_notify(abo->tbo.base.dma_buf); + /* remember the eviction */ if (evict) atomic64_inc(&adev->num_evictions); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 4837640530ad2..00c8627eb60e9 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -440,9 +440,6 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, static void dm_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_connector *connector) { - struct amdgpu_dm_connector *master = container_of(mgr, struct amdgpu_dm_connector, mst_mgr); - struct drm_device *dev = master->base.dev; - struct amdgpu_device *adev = dev->dev_private; struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); DRM_INFO("DM_MST: Disabling connector: %p [id: %d] [master: %p]\n", @@ -458,21 +455,11 @@ static void dm_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, } drm_connector_unregister(connector); - if (adev->mode_info.rfbdev) - drm_fb_helper_remove_one_connector(&adev->mode_info.rfbdev->helper, connector); drm_connector_put(connector); } static void dm_dp_mst_register_connector(struct drm_connector *connector) { - struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = dev->dev_private; - - if (adev->mode_info.rfbdev) - drm_fb_helper_add_one_connector(&adev->mode_info.rfbdev->helper, connector); - else - DRM_ERROR("adev->mode_info.rfbdev is NULL\n"); - drm_connector_register(connector); } diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c index ac8a78bfda032..f2dc371bd8e57 100644 --- a/drivers/gpu/drm/armada/armada_fbdev.c +++ b/drivers/gpu/drm/armada/armada_fbdev.c @@ -129,18 +129,12 @@ int armada_fbdev_init(struct drm_device *dev) drm_fb_helper_prepare(dev, fbh, &armada_fb_helper_funcs); - ret = drm_fb_helper_init(dev, fbh, 1); + ret = drm_fb_helper_init(dev, fbh); if (ret) { DRM_ERROR("failed to initialize drm fb helper\n"); goto err_fb_helper; } - ret = drm_fb_helper_single_add_all_connectors(fbh); - if (ret) { - DRM_ERROR("failed to add fb connectors\n"); - goto err_fb_setup; - } - ret = drm_fb_helper_initial_config(fbh, 32); if (ret) { DRM_ERROR("failed to set initial config\n"); diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index f5d8780776ae9..656d591b154b3 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -121,6 +121,7 @@ struct ast_private { unsigned int next_index; } cursor; + struct drm_encoder encoder; struct drm_plane primary_plane; struct drm_plane cursor_plane; @@ -238,13 +239,8 @@ struct ast_crtc { u8 offset_x, offset_y; }; -struct ast_encoder { - struct drm_encoder base; -}; - #define to_ast_crtc(x) container_of(x, struct ast_crtc, base) #define to_ast_connector(x) container_of(x, struct ast_connector, base) -#define to_ast_encoder(x) container_of(x, struct ast_encoder, base) struct ast_vbios_stdtable { u8 misc; diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 7810a84e7e9ea..cdd6c46d6557d 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "ast_drv.h" #include "ast_tables.h" @@ -957,28 +958,18 @@ static int ast_crtc_init(struct drm_device *dev) * Encoder */ -static void ast_encoder_destroy(struct drm_encoder *encoder) -{ - drm_encoder_cleanup(encoder); - kfree(encoder); -} - -static const struct drm_encoder_funcs ast_enc_funcs = { - .destroy = ast_encoder_destroy, -}; - static int ast_encoder_init(struct drm_device *dev) { - struct ast_encoder *ast_encoder; + struct ast_private *ast = dev->dev_private; + struct drm_encoder *encoder = &ast->encoder; + int ret; - ast_encoder = kzalloc(sizeof(struct ast_encoder), GFP_KERNEL); - if (!ast_encoder) - return -ENOMEM; + ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_DAC); + if (ret) + return ret; - drm_encoder_init(dev, &ast_encoder->base, &ast_enc_funcs, - DRM_MODE_ENCODER_DAC, NULL); + encoder->possible_crtcs = 1; - ast_encoder->base.possible_crtcs = 1; return 0; } diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c index 694c15bc7313b..2bc6e4f851716 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c @@ -719,14 +719,18 @@ static int anx6345_i2c_probe(struct i2c_client *client, /* 1.2V digital core power regulator */ anx6345->dvdd12 = devm_regulator_get(dev, "dvdd12"); if (IS_ERR(anx6345->dvdd12)) { - DRM_ERROR("dvdd12-supply not found\n"); + if (PTR_ERR(anx6345->dvdd12) != -EPROBE_DEFER) + DRM_ERROR("Failed to get dvdd12 supply (%ld)\n", + PTR_ERR(anx6345->dvdd12)); return PTR_ERR(anx6345->dvdd12); } /* 2.5V digital core power regulator */ anx6345->dvdd25 = devm_regulator_get(dev, "dvdd25"); if (IS_ERR(anx6345->dvdd25)) { - DRM_ERROR("dvdd25-supply not found\n"); + if (PTR_ERR(anx6345->dvdd25) != -EPROBE_DEFER) + DRM_ERROR("Failed to get dvdd25 supply (%ld)\n", + PTR_ERR(anx6345->dvdd25)); return PTR_ERR(anx6345->dvdd25); } diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c index 283e4a8dd923e..5ac1430fab049 100644 --- a/drivers/gpu/drm/bridge/tc358764.c +++ b/drivers/gpu/drm/bridge/tc358764.c @@ -375,7 +375,6 @@ static int tc358764_attach(struct drm_bridge *bridge, drm_connector_attach_encoder(&ctx->connector, bridge->encoder); drm_panel_attach(ctx->panel, &ctx->connector); ctx->connector.funcs->reset(&ctx->connector); - drm_fb_helper_add_one_connector(drm->fb_helper, &ctx->connector); drm_connector_register(&ctx->connector); return 0; @@ -384,10 +383,8 @@ static int tc358764_attach(struct drm_bridge *bridge, static void tc358764_detach(struct drm_bridge *bridge) { struct tc358764 *ctx = bridge_to_tc358764(bridge); - struct drm_device *drm = bridge->dev; drm_connector_unregister(&ctx->connector); - drm_fb_helper_remove_one_connector(drm->fb_helper, &ctx->connector); drm_panel_detach(ctx->panel); ctx->panel = NULL; drm_connector_put(&ctx->connector); diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index b031b45aa8efe..6b0c6ef8b9b39 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0 or MIT /* * Copyright 2018 Noralf Trønnes */ diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index a811247cecfef..61e7beada8323 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -736,6 +736,10 @@ static bool drm_dp_sideband_msg_build(struct drm_dp_sideband_msg_rx *msg, if (msg->curchunk_idx >= msg->curchunk_len) { /* do CRC */ crc4 = drm_dp_msg_data_crc4(msg->chunk, msg->curchunk_len - 1); + if (crc4 != msg->chunk[msg->curchunk_len - 1]) + print_hex_dump(KERN_DEBUG, "wrong crc", + DUMP_PREFIX_NONE, 16, 1, + msg->chunk, msg->curchunk_len, false); /* copy chunk into bigger msg */ memcpy(&msg->msg[msg->curlen], msg->chunk, msg->curchunk_len - 1); msg->curlen += msg->curchunk_len - 1; @@ -1035,7 +1039,8 @@ static bool drm_dp_sideband_parse_req(struct drm_dp_sideband_msg_rx *raw, } } -static int build_dpcd_write(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32 offset, u8 num_bytes, u8 *bytes) +static void build_dpcd_write(struct drm_dp_sideband_msg_tx *msg, + u8 port_num, u32 offset, u8 num_bytes, u8 *bytes) { struct drm_dp_sideband_msg_req_body req; @@ -1045,17 +1050,14 @@ static int build_dpcd_write(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32 req.u.dpcd_write.num_bytes = num_bytes; req.u.dpcd_write.bytes = bytes; drm_dp_encode_sideband_req(&req, msg); - - return 0; } -static int build_link_address(struct drm_dp_sideband_msg_tx *msg) +static void build_link_address(struct drm_dp_sideband_msg_tx *msg) { struct drm_dp_sideband_msg_req_body req; req.req_type = DP_LINK_ADDRESS; drm_dp_encode_sideband_req(&req, msg); - return 0; } static int build_clear_payload_id_table(struct drm_dp_sideband_msg_tx *msg) @@ -1067,7 +1069,8 @@ static int build_clear_payload_id_table(struct drm_dp_sideband_msg_tx *msg) return 0; } -static int build_enum_path_resources(struct drm_dp_sideband_msg_tx *msg, int port_num) +static int build_enum_path_resources(struct drm_dp_sideband_msg_tx *msg, + int port_num) { struct drm_dp_sideband_msg_req_body req; @@ -1078,10 +1081,11 @@ static int build_enum_path_resources(struct drm_dp_sideband_msg_tx *msg, int por return 0; } -static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_num, - u8 vcpi, uint16_t pbn, - u8 number_sdp_streams, - u8 *sdp_stream_sink) +static void build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, + int port_num, + u8 vcpi, uint16_t pbn, + u8 number_sdp_streams, + u8 *sdp_stream_sink) { struct drm_dp_sideband_msg_req_body req; memset(&req, 0, sizeof(req)); @@ -1094,11 +1098,10 @@ static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_n number_sdp_streams); drm_dp_encode_sideband_req(&req, msg); msg->path_msg = true; - return 0; } -static int build_power_updown_phy(struct drm_dp_sideband_msg_tx *msg, - int port_num, bool power_up) +static void build_power_updown_phy(struct drm_dp_sideband_msg_tx *msg, + int port_num, bool power_up) { struct drm_dp_sideband_msg_req_body req; @@ -1110,7 +1113,6 @@ static int build_power_updown_phy(struct drm_dp_sideband_msg_tx *msg, req.u.port_num.port_number = port_num; drm_dp_encode_sideband_req(&req, msg); msg->path_msg = true; - return 0; } static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr, @@ -2073,29 +2075,24 @@ ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux, offset, size, buffer); } -static void drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid) +static int drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid) { - int ret; + int ret = 0; memcpy(mstb->guid, guid, 16); if (!drm_dp_validate_guid(mstb->mgr, mstb->guid)) { if (mstb->port_parent) { - ret = drm_dp_send_dpcd_write( - mstb->mgr, - mstb->port_parent, - DP_GUID, - 16, - mstb->guid); + ret = drm_dp_send_dpcd_write(mstb->mgr, + mstb->port_parent, + DP_GUID, 16, mstb->guid); } else { - - ret = drm_dp_dpcd_write( - mstb->mgr->aux, - DP_GUID, - mstb->guid, - 16); + ret = drm_dp_dpcd_write(mstb->mgr->aux, + DP_GUID, mstb->guid, 16); } } + + return ret; } static void build_mst_prop_path(const struct drm_dp_mst_branch *mstb, @@ -2645,7 +2642,8 @@ static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr, return false; } -static int build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32 offset, u8 num_bytes) +static void build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, + u8 port_num, u32 offset, u8 num_bytes) { struct drm_dp_sideband_msg_req_body req; @@ -2654,8 +2652,6 @@ static int build_dpcd_read(struct drm_dp_sideband_msg_tx *msg, u8 port_num, u32 req.u.dpcd_read.dpcd_address = offset; req.u.dpcd_read.num_bytes = num_bytes; drm_dp_encode_sideband_req(&req, msg); - - return 0; } static int drm_dp_send_sideband_msg(struct drm_dp_mst_topology_mgr *mgr, @@ -2881,7 +2877,7 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_sideband_msg_tx *txmsg; struct drm_dp_link_address_ack_reply *reply; struct drm_dp_mst_port *port, *tmp; - int i, len, ret, port_mask = 0; + int i, ret, port_mask = 0; bool changed = false; txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); @@ -2889,7 +2885,7 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, return -ENOMEM; txmsg->dst = mstb; - len = build_link_address(txmsg); + build_link_address(txmsg); mstb->link_address_sent = true; drm_dp_queue_down_tx(mgr, txmsg); @@ -2910,7 +2906,9 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, DRM_DEBUG_KMS("link address reply: %d\n", reply->nports); drm_dp_dump_link_address(reply); - drm_dp_check_mstb_guid(mstb, reply->guid); + ret = drm_dp_check_mstb_guid(mstb, reply->guid); + if (ret) + goto out; for (i = 0; i < reply->nports; i++) { port_mask |= BIT(reply->ports[i].port_number); @@ -2951,14 +2949,14 @@ void drm_dp_send_clear_payload_id_table(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_branch *mstb) { struct drm_dp_sideband_msg_tx *txmsg; - int len, ret; + int ret; txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); if (!txmsg) return; txmsg->dst = mstb; - len = build_clear_payload_id_table(txmsg); + build_clear_payload_id_table(txmsg); drm_dp_queue_down_tx(mgr, txmsg); @@ -2976,7 +2974,6 @@ drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, { struct drm_dp_enum_path_resources_ack_reply *path_res; struct drm_dp_sideband_msg_tx *txmsg; - int len; int ret; txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); @@ -2984,7 +2981,7 @@ drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, return -ENOMEM; txmsg->dst = mstb; - len = build_enum_path_resources(txmsg, port->port_num); + build_enum_path_resources(txmsg, port->port_num); drm_dp_queue_down_tx(mgr, txmsg); @@ -3068,7 +3065,7 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, { struct drm_dp_sideband_msg_tx *txmsg; struct drm_dp_mst_branch *mstb; - int len, ret, port_num; + int ret, port_num; u8 sinks[DRM_DP_MAX_SDP_STREAMS]; int i; @@ -3093,9 +3090,9 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, sinks[i] = i; txmsg->dst = mstb; - len = build_allocate_payload(txmsg, port_num, - id, - pbn, port->num_sdp_streams, sinks); + build_allocate_payload(txmsg, port_num, + id, + pbn, port->num_sdp_streams, sinks); drm_dp_queue_down_tx(mgr, txmsg); @@ -3124,7 +3121,7 @@ int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, bool power_up) { struct drm_dp_sideband_msg_tx *txmsg; - int len, ret; + int ret; port = drm_dp_mst_topology_get_port_validated(mgr, port); if (!port) @@ -3137,7 +3134,7 @@ int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, } txmsg->dst = port->parent; - len = build_power_updown_phy(txmsg, port->port_num, power_up); + build_power_updown_phy(txmsg, port->port_num, power_up); drm_dp_queue_down_tx(mgr, txmsg); ret = drm_dp_mst_wait_tx_reply(port->parent, txmsg); @@ -3359,7 +3356,6 @@ static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int offset, int size, u8 *bytes) { - int len; int ret = 0; struct drm_dp_sideband_msg_tx *txmsg; struct drm_dp_mst_branch *mstb; @@ -3374,7 +3370,7 @@ static int drm_dp_send_dpcd_read(struct drm_dp_mst_topology_mgr *mgr, goto fail_put; } - len = build_dpcd_read(txmsg, port->port_num, offset, size); + build_dpcd_read(txmsg, port->port_num, offset, size); txmsg->dst = port->parent; drm_dp_queue_down_tx(mgr, txmsg); @@ -3412,7 +3408,6 @@ static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int offset, int size, u8 *bytes) { - int len; int ret; struct drm_dp_sideband_msg_tx *txmsg; struct drm_dp_mst_branch *mstb; @@ -3427,7 +3422,7 @@ static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr, goto fail_put; } - len = build_dpcd_write(txmsg, port->port_num, offset, size, bytes); + build_dpcd_write(txmsg, port->port_num, offset, size, bytes); txmsg->dst = mstb; drm_dp_queue_down_tx(mgr, txmsg); @@ -3673,7 +3668,12 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr, DRM_DEBUG_KMS("dpcd read failed - undocked during suspend?\n"); goto out_fail; } - drm_dp_check_mstb_guid(mgr->mst_primary, guid); + + ret = drm_dp_check_mstb_guid(mgr->mst_primary, guid); + if (ret) { + DRM_DEBUG_KMS("check mstb failed - undocked during suspend?\n"); + goto out_fail; + } /* * For the final step of resuming the topology, we need to bring the @@ -4615,15 +4615,34 @@ void drm_dp_mst_dump_topology(struct seq_file *m, int ret; ret = drm_dp_dpcd_read(mgr->aux, DP_DPCD_REV, buf, DP_RECEIVER_CAP_SIZE); + if (ret) { + seq_printf(m, "dpcd read failed\n"); + goto out; + } seq_printf(m, "dpcd: %*ph\n", DP_RECEIVER_CAP_SIZE, buf); + ret = drm_dp_dpcd_read(mgr->aux, DP_FAUX_CAP, buf, 2); + if (ret) { + seq_printf(m, "faux/mst read failed\n"); + goto out; + } seq_printf(m, "faux/mst: %*ph\n", 2, buf); + ret = drm_dp_dpcd_read(mgr->aux, DP_MSTM_CTRL, buf, 1); + if (ret) { + seq_printf(m, "mst ctrl read failed\n"); + goto out; + } seq_printf(m, "mst ctrl: %*ph\n", 1, buf); /* dump the standard OUI branch header */ ret = drm_dp_dpcd_read(mgr->aux, DP_BRANCH_OUI, buf, DP_BRANCH_OUI_HEADER_SIZE); + if (ret) { + seq_printf(m, "branch oui read failed\n"); + goto out; + } seq_printf(m, "branch oui: %*phN devid: ", 3, buf); + for (i = 0x3; i < 0x8 && buf[i]; i++) seq_printf(m, "%c", buf[i]); seq_printf(m, " revision: hw: %x.%x sw: %x.%x\n", @@ -4632,6 +4651,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m, seq_printf(m, "payload table: %*ph\n", DP_PAYLOAD_TABLE_SIZE, buf); } +out: mutex_unlock(&mgr->lock); } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 490a99de6ec16..a9771de4d17e6 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -450,7 +450,6 @@ EXPORT_SYMBOL(drm_fb_helper_prepare); * drm_fb_helper_init - initialize a &struct drm_fb_helper * @dev: drm device * @fb_helper: driver-allocated fbdev helper structure to initialize - * @max_conn_count: max connector count (not used) * * This allocates the structures for the fbdev helper with the given limits. * Note that this won't yet touch the hardware (through the driver interfaces) @@ -463,8 +462,7 @@ EXPORT_SYMBOL(drm_fb_helper_prepare); * Zero if everything went ok, nonzero otherwise. */ int drm_fb_helper_init(struct drm_device *dev, - struct drm_fb_helper *fb_helper, - int max_conn_count) + struct drm_fb_helper *fb_helper) { int ret; @@ -2125,7 +2123,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client) drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs); - ret = drm_fb_helper_init(dev, fb_helper, 0); + ret = drm_fb_helper_init(dev, fb_helper); if (ret) goto err; diff --git a/drivers/gpu/drm/drm_hdcp.c b/drivers/gpu/drm/drm_hdcp.c index 9191633a3c432..7f386adcf8725 100644 --- a/drivers/gpu/drm/drm_hdcp.c +++ b/drivers/gpu/drm/drm_hdcp.c @@ -23,14 +23,6 @@ #include "drm_internal.h" -static struct hdcp_srm { - u32 revoked_ksv_cnt; - u8 *revoked_ksv_list; - - /* Mutex to protect above struct member */ - struct mutex mutex; -} *srm_data; - static inline void drm_hdcp_print_ksv(const u8 *ksv) { DRM_DEBUG("\t%#02x, %#02x, %#02x, %#02x, %#02x\n", @@ -60,11 +52,11 @@ static u32 drm_hdcp_get_revoked_ksv_count(const u8 *buf, u32 vrls_length) return ksv_count; } -static u32 drm_hdcp_get_revoked_ksvs(const u8 *buf, u8 *revoked_ksv_list, +static u32 drm_hdcp_get_revoked_ksvs(const u8 *buf, u8 **revoked_ksv_list, u32 vrls_length) { - u32 parsed_bytes = 0, ksv_count = 0; u32 vrl_ksv_cnt, vrl_ksv_sz, vrl_idx = 0; + u32 parsed_bytes = 0, ksv_count = 0; do { vrl_ksv_cnt = *buf; @@ -74,10 +66,10 @@ static u32 drm_hdcp_get_revoked_ksvs(const u8 *buf, u8 *revoked_ksv_list, DRM_DEBUG("vrl: %d, Revoked KSVs: %d\n", vrl_idx++, vrl_ksv_cnt); - memcpy(revoked_ksv_list, buf, vrl_ksv_sz); + memcpy((*revoked_ksv_list) + (ksv_count * DRM_HDCP_KSV_LEN), + buf, vrl_ksv_sz); ksv_count += vrl_ksv_cnt; - revoked_ksv_list += vrl_ksv_sz; buf += vrl_ksv_sz; parsed_bytes += (vrl_ksv_sz + 1); @@ -91,7 +83,8 @@ static inline u32 get_vrl_length(const u8 *buf) return drm_hdcp_be24_to_cpu(buf); } -static int drm_hdcp_parse_hdcp1_srm(const u8 *buf, size_t count) +static int drm_hdcp_parse_hdcp1_srm(const u8 *buf, size_t count, + u8 **revoked_ksv_list, u32 *revoked_ksv_cnt) { struct hdcp_srm_header *header; u32 vrl_length, ksv_count; @@ -131,29 +124,28 @@ static int drm_hdcp_parse_hdcp1_srm(const u8 *buf, size_t count) ksv_count = drm_hdcp_get_revoked_ksv_count(buf, vrl_length); if (!ksv_count) { DRM_DEBUG("Revoked KSV count is 0\n"); - return count; + return 0; } - kfree(srm_data->revoked_ksv_list); - srm_data->revoked_ksv_list = kcalloc(ksv_count, DRM_HDCP_KSV_LEN, - GFP_KERNEL); - if (!srm_data->revoked_ksv_list) { + *revoked_ksv_list = kcalloc(ksv_count, DRM_HDCP_KSV_LEN, GFP_KERNEL); + if (!*revoked_ksv_list) { DRM_ERROR("Out of Memory\n"); return -ENOMEM; } - if (drm_hdcp_get_revoked_ksvs(buf, srm_data->revoked_ksv_list, + if (drm_hdcp_get_revoked_ksvs(buf, revoked_ksv_list, vrl_length) != ksv_count) { - srm_data->revoked_ksv_cnt = 0; - kfree(srm_data->revoked_ksv_list); + *revoked_ksv_cnt = 0; + kfree(*revoked_ksv_list); return -EINVAL; } - srm_data->revoked_ksv_cnt = ksv_count; - return count; + *revoked_ksv_cnt = ksv_count; + return 0; } -static int drm_hdcp_parse_hdcp2_srm(const u8 *buf, size_t count) +static int drm_hdcp_parse_hdcp2_srm(const u8 *buf, size_t count, + u8 **revoked_ksv_list, u32 *revoked_ksv_cnt) { struct hdcp_srm_header *header; u32 vrl_length, ksv_count, ksv_sz; @@ -195,13 +187,11 @@ static int drm_hdcp_parse_hdcp2_srm(const u8 *buf, size_t count) ksv_count = (*buf << 2) | DRM_HDCP_2_KSV_COUNT_2_LSBITS(*(buf + 1)); if (!ksv_count) { DRM_DEBUG("Revoked KSV count is 0\n"); - return count; + return 0; } - kfree(srm_data->revoked_ksv_list); - srm_data->revoked_ksv_list = kcalloc(ksv_count, DRM_HDCP_KSV_LEN, - GFP_KERNEL); - if (!srm_data->revoked_ksv_list) { + *revoked_ksv_list = kcalloc(ksv_count, DRM_HDCP_KSV_LEN, GFP_KERNEL); + if (!*revoked_ksv_list) { DRM_ERROR("Out of Memory\n"); return -ENOMEM; } @@ -210,10 +200,10 @@ static int drm_hdcp_parse_hdcp2_srm(const u8 *buf, size_t count) buf += DRM_HDCP_2_NO_OF_DEV_PLUS_RESERVED_SZ; DRM_DEBUG("Revoked KSVs: %d\n", ksv_count); - memcpy(srm_data->revoked_ksv_list, buf, ksv_sz); + memcpy(*revoked_ksv_list, buf, ksv_sz); - srm_data->revoked_ksv_cnt = ksv_count; - return count; + *revoked_ksv_cnt = ksv_count; + return 0; } static inline bool is_srm_version_hdcp1(const u8 *buf) @@ -226,22 +216,27 @@ static inline bool is_srm_version_hdcp2(const u8 *buf) return *buf == (u8)(DRM_HDCP_2_SRM_ID << 4 | DRM_HDCP_2_INDICATOR); } -static void drm_hdcp_srm_update(const u8 *buf, size_t count) +static int drm_hdcp_srm_update(const u8 *buf, size_t count, + u8 **revoked_ksv_list, u32 *revoked_ksv_cnt) { if (count < sizeof(struct hdcp_srm_header)) - return; + return -EINVAL; if (is_srm_version_hdcp1(buf)) - drm_hdcp_parse_hdcp1_srm(buf, count); + return drm_hdcp_parse_hdcp1_srm(buf, count, revoked_ksv_list, + revoked_ksv_cnt); else if (is_srm_version_hdcp2(buf)) - drm_hdcp_parse_hdcp2_srm(buf, count); + return drm_hdcp_parse_hdcp2_srm(buf, count, revoked_ksv_list, + revoked_ksv_cnt); + else + return -EINVAL; } -static void drm_hdcp_request_srm(struct drm_device *drm_dev) +static int drm_hdcp_request_srm(struct drm_device *drm_dev, + u8 **revoked_ksv_list, u32 *revoked_ksv_cnt) { char fw_name[36] = "display_hdcp_srm.bin"; const struct firmware *fw; - int ret; ret = request_firmware_direct(&fw, (const char *)fw_name, @@ -250,10 +245,12 @@ static void drm_hdcp_request_srm(struct drm_device *drm_dev) goto exit; if (fw->size && fw->data) - drm_hdcp_srm_update(fw->data, fw->size); + ret = drm_hdcp_srm_update(fw->data, fw->size, revoked_ksv_list, + revoked_ksv_cnt); exit: release_firmware(fw); + return ret; } /** @@ -279,71 +276,34 @@ static void drm_hdcp_request_srm(struct drm_device *drm_dev) * https://www.digital-cp.com/sites/default/files/specifications/HDCP%20on%20HDMI%20Specification%20Rev2_2_Final1.pdf * * Returns: - * TRUE on any of the KSV is revoked, else FALSE. + * Count of the revoked KSVs or -ve error number incase of the failure. */ -bool drm_hdcp_check_ksvs_revoked(struct drm_device *drm_dev, u8 *ksvs, - u32 ksv_count) +int drm_hdcp_check_ksvs_revoked(struct drm_device *drm_dev, u8 *ksvs, + u32 ksv_count) { - u32 rev_ksv_cnt, cnt, i, j; - u8 *rev_ksv_list; - - if (!srm_data) - return false; - - mutex_lock(&srm_data->mutex); - drm_hdcp_request_srm(drm_dev); - - rev_ksv_cnt = srm_data->revoked_ksv_cnt; - rev_ksv_list = srm_data->revoked_ksv_list; - - /* If the Revoked ksv list is empty */ - if (!rev_ksv_cnt || !rev_ksv_list) { - mutex_unlock(&srm_data->mutex); - return false; - } - - for (cnt = 0; cnt < ksv_count; cnt++) { - rev_ksv_list = srm_data->revoked_ksv_list; - for (i = 0; i < rev_ksv_cnt; i++) { - for (j = 0; j < DRM_HDCP_KSV_LEN; j++) - if (ksvs[j] != rev_ksv_list[j]) { - break; - } else if (j == (DRM_HDCP_KSV_LEN - 1)) { - DRM_DEBUG("Revoked KSV is "); - drm_hdcp_print_ksv(ksvs); - mutex_unlock(&srm_data->mutex); - return true; - } - /* Move the offset to next KSV in the revoked list */ - rev_ksv_list += DRM_HDCP_KSV_LEN; - } - - /* Iterate to next ksv_offset */ - ksvs += DRM_HDCP_KSV_LEN; - } - mutex_unlock(&srm_data->mutex); - return false; + u32 revoked_ksv_cnt = 0, i, j; + u8 *revoked_ksv_list = NULL; + int ret = 0; + + ret = drm_hdcp_request_srm(drm_dev, &revoked_ksv_list, + &revoked_ksv_cnt); + + /* revoked_ksv_cnt will be zero when above function failed */ + for (i = 0; i < revoked_ksv_cnt; i++) + for (j = 0; j < ksv_count; j++) + if (!memcmp(&ksvs[j * DRM_HDCP_KSV_LEN], + &revoked_ksv_list[i * DRM_HDCP_KSV_LEN], + DRM_HDCP_KSV_LEN)) { + DRM_DEBUG("Revoked KSV is "); + drm_hdcp_print_ksv(&ksvs[j * DRM_HDCP_KSV_LEN]); + ret++; + } + + kfree(revoked_ksv_list); + return ret; } EXPORT_SYMBOL_GPL(drm_hdcp_check_ksvs_revoked); -int drm_setup_hdcp_srm(struct class *drm_class) -{ - srm_data = kzalloc(sizeof(*srm_data), GFP_KERNEL); - if (!srm_data) - return -ENOMEM; - mutex_init(&srm_data->mutex); - - return 0; -} - -void drm_teardown_hdcp_srm(struct class *drm_class) -{ - if (srm_data) { - kfree(srm_data->revoked_ksv_list); - kfree(srm_data); - } -} - static struct drm_prop_enum_list drm_cp_enum_list[] = { { DRM_MODE_CONTENT_PROTECTION_UNDESIRED, "Undesired" }, { DRM_MODE_CONTENT_PROTECTION_DESIRED, "Desired" }, diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index aeec2e68d772b..5714a78365ac6 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -236,7 +236,3 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, const struct drm_framebuffer *fb); int drm_framebuffer_debugfs_init(struct drm_minor *minor); - -/* drm_hdcp.c */ -int drm_setup_hdcp_srm(struct class *drm_class); -void drm_teardown_hdcp_srm(struct class *drm_class); diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 2a6e346631466..47d5de9ca0a8d 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -366,6 +367,11 @@ next_hole(struct drm_mm *mm, struct drm_mm_node *node, enum drm_mm_insert_mode mode) { + /* Searching is slow; check if we ran out of time/patience */ + cond_resched(); + if (fatal_signal_pending(current)) + return NULL; + switch (mode) { default: case DRM_MM_INSERT_BEST: @@ -557,7 +563,7 @@ int drm_mm_insert_node_in_range(struct drm_mm * const mm, return 0; } - return -ENOSPC; + return signal_pending(current) ? -ERESTARTSYS : -ENOSPC; } EXPORT_SYMBOL(drm_mm_insert_node_in_range); diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index c6bb98729a265..81aa215619821 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -75,7 +75,6 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali return dmah; } - EXPORT_SYMBOL(drm_pci_alloc); /** @@ -167,6 +166,18 @@ int drm_irq_by_busid(struct drm_device *dev, void *data, return drm_pci_irq_by_busid(dev, p); } +void drm_pci_agp_destroy(struct drm_device *dev) +{ + if (dev->agp) { + arch_phys_wc_del(dev->agp->agp_mtrr); + drm_legacy_agp_clear(dev); + kfree(dev->agp); + dev->agp = NULL; + } +} + +#ifdef CONFIG_DRM_LEGACY + static void drm_pci_agp_init(struct drm_device *dev) { if (drm_core_check_feature(dev, DRIVER_USE_AGP)) { @@ -181,33 +192,9 @@ static void drm_pci_agp_init(struct drm_device *dev) } } -void drm_pci_agp_destroy(struct drm_device *dev) -{ - if (dev->agp) { - arch_phys_wc_del(dev->agp->agp_mtrr); - drm_legacy_agp_clear(dev); - kfree(dev->agp); - dev->agp = NULL; - } -} - -/** - * drm_get_pci_dev - Register a PCI device with the DRM subsystem - * @pdev: PCI device - * @ent: entry from the PCI ID table that matches @pdev - * @driver: DRM device driver - * - * Attempt to gets inter module "drm" information. If we are first - * then register the character device and inter module information. - * Try and register, if we fail to register, backout previous work. - * - * NOTE: This function is deprecated, please use drm_dev_alloc() and - * drm_dev_register() instead and remove your &drm_driver.load callback. - * - * Return: 0 on success or a negative error code on failure. - */ -int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, - struct drm_driver *driver) +static int drm_get_pci_dev(struct pci_dev *pdev, + const struct pci_device_id *ent, + struct drm_driver *driver) { struct drm_device *dev; int ret; @@ -250,9 +237,6 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, drm_dev_put(dev); return ret; } -EXPORT_SYMBOL(drm_get_pci_dev); - -#ifdef CONFIG_DRM_LEGACY /** * drm_legacy_pci_init - shadow-attach a legacy DRM PCI driver diff --git a/drivers/gpu/drm/drm_scatter.c b/drivers/gpu/drm/drm_scatter.c index d5c386154246e..ca520028b2cb1 100644 --- a/drivers/gpu/drm/drm_scatter.c +++ b/drivers/gpu/drm/drm_scatter.c @@ -99,6 +99,9 @@ int drm_legacy_sg_alloc(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_SG)) return -EOPNOTSUPP; + if (request->size > SIZE_MAX - PAGE_SIZE) + return -EINVAL; + if (dev->sg) return -EINVAL; diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index 8ff4504161d53..74946690aba4e 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -26,12 +26,51 @@ * entity. Some flexibility for code reuse is provided through a separately * allocated &drm_connector object and supporting optional &drm_bridge * encoder drivers. + * + * Many drivers require only a very simple encoder that fulfills the minimum + * requirements of the display pipeline and does not add additional + * functionality. The function drm_simple_encoder_init() provides an + * implementation of such an encoder. */ -static const struct drm_encoder_funcs drm_simple_kms_encoder_funcs = { +static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup = { .destroy = drm_encoder_cleanup, }; +/** + * drm_simple_encoder_init - Initialize a preallocated encoder with + * basic functionality. + * @dev: drm device + * @encoder: the encoder to initialize + * @encoder_type: user visible type of the encoder + * + * Initialises a preallocated encoder that has no further functionality. + * Settings for possible CRTC and clones are left to their initial values. + * The encoder will be cleaned up automatically as part of the mode-setting + * cleanup. + * + * The caller of drm_simple_encoder_init() is responsible for freeing + * the encoder's memory after the encoder has been cleaned up. At the + * moment this only works reliably if the encoder data structure is + * stored in the device structure. Free the encoder's memory as part of + * the device release function. + * + * FIXME: Later improvements to DRM's resource management may allow for + * an automated kfree() of the encoder's memory. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_simple_encoder_init(struct drm_device *dev, + struct drm_encoder *encoder, + int encoder_type) +{ + return drm_encoder_init(dev, encoder, + &drm_simple_encoder_funcs_cleanup, + encoder_type, NULL); +} +EXPORT_SYMBOL(drm_simple_encoder_init); + static enum drm_mode_status drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) @@ -288,8 +327,7 @@ int drm_simple_display_pipe_init(struct drm_device *dev, return ret; encoder->possible_crtcs = drm_crtc_mask(crtc); - ret = drm_encoder_init(dev, encoder, &drm_simple_kms_encoder_funcs, - DRM_MODE_ENCODER_NONE, NULL); + ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE); if (ret || !connector) return ret; diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index dd2bc85f43cc8..2e83c3d72af97 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -85,7 +85,6 @@ int drm_sysfs_init(void) } drm_class->devnode = drm_devnode; - drm_setup_hdcp_srm(drm_class); return 0; } @@ -98,7 +97,6 @@ void drm_sysfs_destroy(void) { if (IS_ERR_OR_NULL(drm_class)) return; - drm_teardown_hdcp_srm(drm_class); class_remove_file(drm_class, &class_attr_version.attr); class_destroy(drm_class); drm_class = NULL; diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 47fc4339ec7fa..da7b0b0c1090d 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -592,8 +592,7 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants); /** * drm_crtc_vblank_helper_get_vblank_timestamp_internal - precise vblank * timestamp helper - * @dev: DRM device - * @pipe: index of CRTC whose vblank timestamp to retrieve + * @crtc: CRTC whose vblank timestamp to retrieve * @max_error: Desired maximum allowable error in timestamps (nanosecs) * On return contains true maximum error of timestamp * @vblank_time: Pointer to time which should receive the timestamp diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 342d2a723a0e4..e080aa92338c0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1514,7 +1514,6 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder) return 0; connector->funcs->reset(connector); - drm_fb_helper_add_one_connector(drm->fb_helper, connector); drm_connector_register(connector); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 647a1fd1d815b..e6ceaf36fb044 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -200,21 +200,13 @@ int exynos_drm_fbdev_init(struct drm_device *dev) drm_fb_helper_prepare(dev, helper, &exynos_drm_fb_helper_funcs); - ret = drm_fb_helper_init(dev, helper, MAX_CONNECTOR); + ret = drm_fb_helper_init(dev, helper); if (ret < 0) { DRM_DEV_ERROR(dev->dev, "failed to initialize drm fb helper.\n"); goto err_init; } - ret = drm_fb_helper_single_add_all_connectors(helper); - if (ret < 0) { - DRM_DEV_ERROR(dev->dev, - "failed to register drm_fb_helper_connector.\n"); - goto err_setup; - - } - ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP); if (ret < 0) { DRM_DEV_ERROR(dev->dev, diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 1459076d19802..1d8f67e4795a6 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -513,14 +513,10 @@ int psb_fbdev_init(struct drm_device *dev) drm_fb_helper_prepare(dev, fb_helper, &psb_fb_helper_funcs); - ret = drm_fb_helper_init(dev, fb_helper, INTELFB_CONN_LIMIT); + ret = drm_fb_helper_init(dev, fb_helper); if (ret) goto free; - ret = drm_fb_helper_single_add_all_connectors(fb_helper); - if (ret) - goto fini; - /* disable all the possible outputs/crtcs before entering KMS mode */ drm_helper_disable_unused_functions(dev); diff --git a/drivers/gpu/drm/gma500/intel_bios.h b/drivers/gpu/drm/gma500/intel_bios.h index a1f9ce9465a51..0e6facf21e332 100644 --- a/drivers/gpu/drm/gma500/intel_bios.h +++ b/drivers/gpu/drm/gma500/intel_bios.h @@ -227,7 +227,7 @@ struct bdb_general_definitions { * number = (block_size - sizeof(bdb_general_definitions))/ * sizeof(child_device_config); */ - struct child_device_config devices[0]; + struct child_device_config devices[]; }; struct bdb_lvds_options { diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index d7bfa7c350e99..b15404a3b1cac 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -721,27 +721,15 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo static void intel_dp_register_mst_connector(struct drm_connector *connector) { - struct drm_i915_private *dev_priv = to_i915(connector->dev); - - if (dev_priv->fbdev) - drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper, - connector); - drm_connector_register(connector); } static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_connector *connector) { - struct drm_i915_private *dev_priv = to_i915(connector->dev); - DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); drm_connector_unregister(connector); - if (dev_priv->fbdev) - drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper, - connector); - drm_connector_put(connector); } diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index b4ff772252369..876264fc65601 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -453,7 +453,7 @@ int intel_fbdev_init(struct drm_device *dev) if (!intel_fbdev_init_bios(dev, ifbdev)) ifbdev->preferred_bpp = 32; - ret = drm_fb_helper_init(dev, &ifbdev->helper, 4); + ret = drm_fb_helper_init(dev, &ifbdev->helper); if (ret) { kfree(ifbdev); return ret; @@ -462,8 +462,6 @@ int intel_fbdev_init(struct drm_device *dev) dev_priv->fbdev = ifbdev; INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker); - drm_fb_helper_single_add_all_connectors(&ifbdev->helper); - return 0; } diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index aa32aad222c26..9691252d6233f 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -95,7 +95,6 @@ #define MATROX_DPMS_CLEARED (-1) #define to_mga_crtc(x) container_of(x, struct mga_crtc, base) -#define to_mga_encoder(x) container_of(x, struct mga_encoder, base) #define to_mga_connector(x) container_of(x, struct mga_connector, base) struct mga_crtc { @@ -110,12 +109,6 @@ struct mga_mode_info { struct mga_crtc *crtc; }; -struct mga_encoder { - struct drm_encoder base; - int last_dpms; -}; - - struct mga_i2c_chan { struct i2c_adapter adapter; struct drm_device *dev; @@ -185,6 +178,8 @@ struct mga_device { /* SE model number stored in reg 0x1e24 */ u32 unique_rev_id; + + struct drm_encoder encoder; }; static inline enum mga_type diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 62a8e9ccb16dc..d90e83959fca1 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "mgag200_drv.h" @@ -1449,76 +1450,6 @@ static void mga_crtc_init(struct mga_device *mdev) drm_crtc_helper_add(&mga_crtc->base, &mga_helper_funcs); } -/* - * The encoder comes after the CRTC in the output pipeline, but before - * the connector. It's responsible for ensuring that the digital - * stream is appropriately converted into the output format. Setup is - * very simple in this case - all we have to do is inform qemu of the - * colour depth in order to ensure that it displays appropriately - */ - -/* - * These functions are analagous to those in the CRTC code, but are intended - * to handle any encoder-specific limitations - */ -static void mga_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - -} - -static void mga_encoder_dpms(struct drm_encoder *encoder, int state) -{ - return; -} - -static void mga_encoder_prepare(struct drm_encoder *encoder) -{ -} - -static void mga_encoder_commit(struct drm_encoder *encoder) -{ -} - -static void mga_encoder_destroy(struct drm_encoder *encoder) -{ - struct mga_encoder *mga_encoder = to_mga_encoder(encoder); - drm_encoder_cleanup(encoder); - kfree(mga_encoder); -} - -static const struct drm_encoder_helper_funcs mga_encoder_helper_funcs = { - .dpms = mga_encoder_dpms, - .mode_set = mga_encoder_mode_set, - .prepare = mga_encoder_prepare, - .commit = mga_encoder_commit, -}; - -static const struct drm_encoder_funcs mga_encoder_encoder_funcs = { - .destroy = mga_encoder_destroy, -}; - -static struct drm_encoder *mga_encoder_init(struct drm_device *dev) -{ - struct drm_encoder *encoder; - struct mga_encoder *mga_encoder; - - mga_encoder = kzalloc(sizeof(struct mga_encoder), GFP_KERNEL); - if (!mga_encoder) - return NULL; - - encoder = &mga_encoder->base; - encoder->possible_crtcs = 0x1; - - drm_encoder_init(dev, encoder, &mga_encoder_encoder_funcs, - DRM_MODE_ENCODER_DAC, NULL); - drm_encoder_helper_add(encoder, &mga_encoder_helper_funcs); - - return encoder; -} - - static int mga_vga_get_modes(struct drm_connector *connector) { struct mga_connector *mga_connector = to_mga_connector(connector); @@ -1686,8 +1617,9 @@ static struct drm_connector *mga_vga_init(struct drm_device *dev) int mgag200_modeset_init(struct mga_device *mdev) { - struct drm_encoder *encoder; + struct drm_encoder *encoder = &mdev->encoder; struct drm_connector *connector; + int ret; mdev->mode_info.mode_config_initialized = true; @@ -1698,11 +1630,15 @@ int mgag200_modeset_init(struct mga_device *mdev) mga_crtc_init(mdev); - encoder = mga_encoder_init(mdev->dev); - if (!encoder) { - DRM_ERROR("mga_encoder_init failed\n"); - return -1; + ret = drm_simple_encoder_init(mdev->dev, encoder, + DRM_MODE_ENCODER_DAC); + if (ret) { + drm_err(mdev->dev, + "drm_simple_encoder_init() failed, error %d\n", + ret); + return ret; } + encoder->possible_crtcs = 0x1; connector = mga_vga_init(mdev->dev); if (!connector) { diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index db48867df47dd..47235f8c5922e 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -160,16 +160,12 @@ struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev) drm_fb_helper_prepare(dev, helper, &msm_fb_helper_funcs); - ret = drm_fb_helper_init(dev, helper, priv->num_connectors); + ret = drm_fb_helper_init(dev, helper); if (ret) { DRM_DEV_ERROR(dev->dev, "could not init fbdev: ret=%d\n", ret); goto fail; } - ret = drm_fb_helper_single_add_all_connectors(helper); - if (ret) - goto fini; - /* the fw fb could be anywhere in memory */ drm_fb_helper_remove_conflicting_framebuffers(NULL, "msm", false); diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index a3dc2ba19fb2b..4e164ad8003fe 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1260,23 +1260,16 @@ static void nv50_mstm_destroy_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_connector *connector) { - struct nouveau_drm *drm = nouveau_drm(connector->dev); struct nv50_mstc *mstc = nv50_mstc(connector); drm_connector_unregister(&mstc->connector); - drm_fb_helper_remove_one_connector(&drm->fbcon->helper, &mstc->connector); - drm_connector_put(&mstc->connector); } static void nv50_mstm_register_connector(struct drm_connector *connector) { - struct nouveau_drm *drm = nouveau_drm(connector->dev); - - drm_fb_helper_add_one_connector(&drm->fbcon->helper, connector); - drm_connector_register(connector); } diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 0c5cdda3c3365..24d543a01f435 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -558,14 +558,10 @@ nouveau_fbcon_init(struct drm_device *dev) drm_fb_helper_prepare(dev, &fbcon->helper, &nouveau_fbcon_helper_funcs); - ret = drm_fb_helper_init(dev, &fbcon->helper, 4); + ret = drm_fb_helper_init(dev, &fbcon->helper); if (ret) goto free; - ret = drm_fb_helper_single_add_all_connectors(&fbcon->helper); - if (ret) - goto fini; - if (preferred_bpp != 8 && preferred_bpp != 16 && preferred_bpp != 32) { if (drm->client.device.info.ram_size <= 32 * 1024 * 1024) preferred_bpp = 8; diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index b06e5cbfd03af..09a84919ef738 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -242,14 +242,10 @@ void omap_fbdev_init(struct drm_device *dev) drm_fb_helper_prepare(dev, helper, &omap_fb_helper_funcs); - ret = drm_fb_helper_init(dev, helper, priv->num_pipes); + ret = drm_fb_helper_init(dev, helper); if (ret) goto fail; - ret = drm_fb_helper_single_add_all_connectors(helper); - if (ret) - goto fini; - ret = drm_fb_helper_initial_config(helper, 32); if (ret) goto fini; diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index da3b84602cdd3..a1723c1b5fbf8 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -59,6 +59,16 @@ config DRM_PANEL_SIMPLE that it can be automatically turned off when the panel goes into a low power state. +config DRM_PANEL_ELIDA_KD35T133 + tristate "Elida KD35T133 panel driver" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for the Elida + KD35T133 controller for 320x480 LCD panels with MIPI-DSI + system interfaces. + config DRM_PANEL_FEIXIN_K101_IM2BA02 tristate "Feixin K101 IM2BA02 panel" depends on OF @@ -167,6 +177,16 @@ config DRM_PANEL_NEC_NL8048HL11 panel (found on the Zoom2/3/3630 SDP boards). To compile this driver as a module, choose M here. +config DRM_PANEL_NOVATEK_NT35510 + tristate "Novatek NT35510 RGB panel driver" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for the panels built + around the Novatek NT35510 display controller, such as some + Hydis panels. + config DRM_PANEL_NOVATEK_NT39016 tristate "Novatek NT39016 RGB/SPI panel" depends on OF && SPI diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index af1e2a3cc5fc3..96a883cd66305 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_PANEL_BOE_HIMAX8279D) += panel-boe-himax8279d.o obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o +obj-$(CONFIG_DRM_PANEL_ELIDA_KD35T133) += panel-elida-kd35t133.o obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o @@ -15,6 +16,7 @@ obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o +obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35510) += panel-novatek-nt35510.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c new file mode 100644 index 0000000000000..711ded453c44f --- /dev/null +++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Elida kd35t133 5.5" MIPI-DSI panel driver + * Copyright (C) 2020 Theobroma Systems Design und Consulting GmbH + * + * based on + * + * Rockteck jh057n00900 5.5" MIPI-DSI panel driver + * Copyright (C) Purism SPC 2019 + */ + +#include +#include +#include +#include +#include +#include + +#include