diff options
author | Dave Airlie <airlied@redhat.com> | 2024-11-11 12:10:48 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2024-11-11 12:10:49 +1000 |
commit | 56b70bf9ec460ad7d7d94dfb7a54a8829741e16e (patch) | |
tree | fdf41aa4701cc516c145df1b895c1b8b9ccc5759 | |
parent | 35a6e15aabc016a241379c09d6c367519709b95b (diff) | |
parent | baf4afc5831438b35de4b0e951b9cd58435a6d99 (diff) |
Merge tag 'drm-misc-next-2024-11-08' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next
drm-misc-next for v6.13:
UAPI Changes:
- Add 1X7X5 media-bus formats.
Cross-subsystem Changes:
- Maintainer updates for VKMS and IT6263.
- Add media-bus-fmt for MEDIA_BUS_FMT_RGB101010_1X7X5_*.
- Add IT6263 DT bindings and driver.
Core Changes:
- Add ABGR210101010 support to panic handler.
- Use ATOMIC64_INIT in drm_file.c
- Improve scheduler teardown documentation.
Driver Changes:
- Make mediatek compile on ARM again.
- Add missing drm/drm_bridge.h header include, already in drm-next.
- Small fixes and cleanups to vkms, bridge/it6505, panfrost, panthor.
- Add panic support to nouveau for nv50+.
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/344afe41-d27b-408a-8542-bfecfd3555f6@linux.intel.com
29 files changed, 1753 insertions, 347 deletions
diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml new file mode 100644 index 000000000000..0a10e10d80ff --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml @@ -0,0 +1,250 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/ite,it6263.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ITE IT6263 LVDS to HDMI converter + +maintainers: + - Liu Ying <victor.liu@nxp.com> + +description: | + The IT6263 is a high-performance single-chip De-SSC(De-Spread Spectrum) LVDS + to HDMI converter. Combined with LVDS receiver and HDMI 1.4a transmitter, + the IT6263 supports LVDS input and HDMI 1.4 output by conversion function. + The built-in LVDS receiver can support single-link and dual-link LVDS inputs, + and the built-in HDMI transmitter is fully compliant with HDMI 1.4a/3D, HDCP + 1.2 and backward compatible with DVI 1.0 specification. + + The IT6263 also encodes and transmits up to 8 channels of I2S digital audio, + with sampling rate up to 192KHz and sample size up to 24 bits. In addition, + an S/PDIF input port takes in compressed audio of up to 192KHz frame rate. + + The newly supported High-Bit Rate(HBR) audio by HDMI specifications v1.3 is + provided by the IT6263 in two interfaces: the four I2S input ports or the + S/PDIF input port. With both interfaces the highest possible HBR frame rate + is supported at up to 768KHz. + +allOf: + - $ref: /schemas/display/lvds-dual-ports.yaml# + +properties: + compatible: + const: ite,it6263 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + description: audio master clock + + clock-names: + const: mclk + + data-mapping: + enum: + - jeida-18 + - jeida-24 + - jeida-30 + - vesa-24 + - vesa-30 + + reset-gpios: + maxItems: 1 + + ivdd-supply: + description: 1.8V digital logic power + + ovdd-supply: + description: 3.3V I/O pin power + + txavcc18-supply: + description: 1.8V HDMI analog frontend power + + txavcc33-supply: + description: 3.3V HDMI analog frontend power + + pvcc1-supply: + description: 1.8V HDMI frontend core PLL power + + pvcc2-supply: + description: 1.8V HDMI frontend filter PLL power + + avcc-supply: + description: 3.3V LVDS frontend power + + anvdd-supply: + description: 1.8V LVDS frontend analog power + + apvdd-supply: + description: 1.8V LVDS frontend PLL power + + "#sound-dai-cells": + const: 0 + + ite,i2s-audio-fifo-sources: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 4 + items: + enum: [0, 1, 2, 3] + description: + Each array element indicates the pin number of an I2S serial data input + line which is connected to an audio FIFO, from audio FIFO0 to FIFO3. + + ite,rl-channel-swap-audio-sources: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 4 + uniqueItems: true + items: + enum: [0, 1, 2, 3] + description: + Each array element indicates an audio source whose right channel and left + channel are swapped by this converter. For I2S, the element is the pin + number of an I2S serial data input line. For S/PDIF, the element is always + 0. + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: true + + port@1: + oneOf: + - required: [dual-lvds-odd-pixels] + - required: [dual-lvds-even-pixels] + + port@2: + $ref: /schemas/graph.yaml#/properties/port + description: video port for the HDMI output + + port@3: + $ref: /schemas/graph.yaml#/properties/port + description: sound input port + + required: + - port@0 + - port@2 + +required: + - compatible + - reg + - data-mapping + - ivdd-supply + - ovdd-supply + - txavcc18-supply + - txavcc33-supply + - pvcc1-supply + - pvcc2-supply + - avcc-supply + - anvdd-supply + - apvdd-supply + +unevaluatedProperties: false + +examples: + - | + /* single-link LVDS input */ + #include <dt-bindings/gpio/gpio.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + hdmi@4c { + compatible = "ite,it6263"; + reg = <0x4c>; + data-mapping = "jeida-24"; + reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; + ivdd-supply = <®_buck5>; + ovdd-supply = <®_vext_3v3>; + txavcc18-supply = <®_buck5>; + txavcc33-supply = <®_vext_3v3>; + pvcc1-supply = <®_buck5>; + pvcc2-supply = <®_buck5>; + avcc-supply = <®_vext_3v3>; + anvdd-supply = <®_buck5>; + apvdd-supply = <®_buck5>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + it6263_lvds_link1: endpoint { + remote-endpoint = <&ldb_lvds_ch0>; + }; + }; + + port@2 { + reg = <2>; + + it6263_out: endpoint { + remote-endpoint = <&hdmi_in>; + }; + }; + }; + }; + }; + + - | + /* dual-link LVDS input */ + #include <dt-bindings/gpio/gpio.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + hdmi@4c { + compatible = "ite,it6263"; + reg = <0x4c>; + data-mapping = "jeida-24"; + reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; + ivdd-supply = <®_buck5>; + ovdd-supply = <®_vext_3v3>; + txavcc18-supply = <®_buck5>; + txavcc33-supply = <®_vext_3v3>; + pvcc1-supply = <®_buck5>; + pvcc2-supply = <®_buck5>; + avcc-supply = <®_vext_3v3>; + anvdd-supply = <®_buck5>; + apvdd-supply = <®_buck5>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dual-lvds-odd-pixels; + + it6263_lvds_link1_dual: endpoint { + remote-endpoint = <&ldb_lvds_ch0>; + }; + }; + + port@1 { + reg = <1>; + dual-lvds-even-pixels; + + it6263_lvds_link2_dual: endpoint { + remote-endpoint = <&ldb_lvds_ch1>; + }; + }; + + port@2 { + reg = <2>; + + it6263_out_dual: endpoint { + remote-endpoint = <&hdmi_in>; + }; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/lvds-data-mapping.yaml b/Documentation/devicetree/bindings/display/lvds-data-mapping.yaml index d68982fe2e9b..ab842594feb9 100644 --- a/Documentation/devicetree/bindings/display/lvds-data-mapping.yaml +++ b/Documentation/devicetree/bindings/display/lvds-data-mapping.yaml @@ -26,12 +26,17 @@ description: | Device compatible with those specifications have been marketed under the FPD-Link and FlatLink brands. + This bindings also supports 30-bit data mapping compatible with JEIDA and + VESA. + properties: data-mapping: enum: - jeida-18 - jeida-24 + - jeida-30 - vesa-24 + - vesa-30 description: | The color signals mapping order. @@ -60,6 +65,19 @@ properties: DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B7__><__B6__><__B5__><__B4__>< DATA3 ><_CTL3_><__B1__><__B0__><__G1__><__G0__><__R1__><__R0__>< + - "jeida-30" - 30-bit data mapping compatible with JEIDA and VESA. Data + are transferred as follows on 5 LVDS lanes. + + Slot 0 1 2 3 4 5 6 + ________________ _________________ + Clock \_______________________/ + ______ ______ ______ ______ ______ ______ ______ + DATA0 ><__G4__><__R9__><__R8__><__R7__><__R6__><__R5__><__R4__>< + DATA1 ><__B5__><__B4__><__G9__><__G8__><__G7__><__G6__><__G5__>< + DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B9__><__B8__><__B7__><__B6__>< + DATA3 ><_CTL3_><__B3__><__B2__><__G3__><__G2__><__R3__><__R2__>< + DATA4 ><_CTL3_><__B1__><__B0__><__G1__><__G0__><__R1__><__R0__>< + - "vesa-24" - 24-bit data mapping compatible with the [VESA] specification. Data are transferred as follows on 4 LVDS lanes. @@ -72,6 +90,19 @@ properties: DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B5__><__B4__><__B3__><__B2__>< DATA3 ><_CTL3_><__B7__><__B6__><__G7__><__G6__><__R7__><__R6__>< + - "vesa-30" - 30-bit data mapping compatible with VESA. Data are + transferred as follows on 5 LVDS lanes. + + Slot 0 1 2 3 4 5 6 + ________________ _________________ + Clock \_______________________/ + ______ ______ ______ ______ ______ ______ ______ + DATA0 ><__G0__><__R5__><__R4__><__R3__><__R2__><__R1__><__R0__>< + DATA1 ><__B1__><__B0__><__G5__><__G4__><__G3__><__G2__><__G1__>< + DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B5__><__B4__><__B3__><__B2__>< + DATA3 ><_CTL3_><__B7__><__B6__><__G7__><__G6__><__R7__><__R6__>< + DATA4 ><_CTL3_><__B9__><__B8__><__G9__><__G8__><__R9__><__R8__>< + Control signals are mapped as follows. CTL0: HSync diff --git a/Documentation/devicetree/bindings/display/lvds-dual-ports.yaml b/Documentation/devicetree/bindings/display/lvds-dual-ports.yaml new file mode 100644 index 000000000000..785701fe1590 --- /dev/null +++ b/Documentation/devicetree/bindings/display/lvds-dual-ports.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/lvds-dual-ports.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Dual-link LVDS Display Common Properties + +maintainers: + - Liu Ying <victor.liu@nxp.com> + +description: | + Common properties for LVDS displays with dual LVDS links. Extend LVDS display + common properties defined in lvds.yaml. + + Dual-link LVDS displays receive odd pixels and even pixels separately from + the dual LVDS links. One link receives odd pixels and the other receives + even pixels. Some of those displays may also use only one LVDS link to + receive all pixels, being odd and even agnostic. + +allOf: + - $ref: lvds.yaml# + +properties: + ports: + $ref: /schemas/graph.yaml#/properties/ports + + patternProperties: + '^port@[01]$': + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: | + port@0 represents the first LVDS input link. + port@1 represents the second LVDS input link. + + properties: + dual-lvds-odd-pixels: + type: boolean + description: LVDS input link for odd pixels + + dual-lvds-even-pixels: + type: boolean + description: LVDS input link for even pixels + + oneOf: + - required: [dual-lvds-odd-pixels] + - required: [dual-lvds-even-pixels] + - properties: + dual-lvds-odd-pixels: false + dual-lvds-even-pixels: false + + anyOf: + - required: + - port@0 + - required: + - port@1 + +required: + - ports + +additionalProperties: true + +... diff --git a/Documentation/devicetree/bindings/display/panel/advantech,idk-2121wr.yaml b/Documentation/devicetree/bindings/display/panel/advantech,idk-2121wr.yaml index 2e8dbdb5a3d5..05ca3b2385f8 100644 --- a/Documentation/devicetree/bindings/display/panel/advantech,idk-2121wr.yaml +++ b/Documentation/devicetree/bindings/display/panel/advantech,idk-2121wr.yaml @@ -20,6 +20,7 @@ description: | dual-lvds-odd-pixels or dual-lvds-even-pixels). allOf: + - $ref: /schemas/display/lvds-dual-ports.yaml# - $ref: panel-common.yaml# properties: @@ -44,22 +45,10 @@ properties: properties: port@0: - $ref: /schemas/graph.yaml#/$defs/port-base - unevaluatedProperties: false - description: The sink for odd pixels. - properties: - dual-lvds-odd-pixels: true - required: - dual-lvds-odd-pixels port@1: - $ref: /schemas/graph.yaml#/$defs/port-base - unevaluatedProperties: false - description: The sink for even pixels. - properties: - dual-lvds-even-pixels: true - required: - dual-lvds-even-pixels @@ -75,7 +64,6 @@ required: - height-mm - data-mapping - panel-timing - - ports examples: - |+ diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml index 10ed4b57232b..e80fc7006984 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml @@ -22,6 +22,7 @@ description: | If the panel is more advanced a dedicated binding file is required. allOf: + - $ref: /schemas/display/lvds-dual-ports.yaml# - $ref: panel-common.yaml# properties: @@ -55,28 +56,10 @@ properties: properties: port@0: - $ref: /schemas/graph.yaml#/$defs/port-base - unevaluatedProperties: false - description: The first sink port. - - properties: - dual-lvds-odd-pixels: - type: boolean - description: The first sink port for odd pixels. - required: - dual-lvds-odd-pixels port@1: - $ref: /schemas/graph.yaml#/$defs/port-base - unevaluatedProperties: false - description: The second sink port. - - properties: - dual-lvds-even-pixels: - type: boolean - description: The second sink port for even pixels. - required: - dual-lvds-even-pixels @@ -88,7 +71,6 @@ unevaluatedProperties: false required: - compatible - - ports - power-supply examples: diff --git a/Documentation/userspace-api/media/v4l/subdev-formats.rst b/Documentation/userspace-api/media/v4l/subdev-formats.rst index d2a6cd2e1eb2..2a94371448dc 100644 --- a/Documentation/userspace-api/media/v4l/subdev-formats.rst +++ b/Documentation/userspace-api/media/v4l/subdev-formats.rst @@ -2225,7 +2225,7 @@ The following table list existing packed 48bit wide RGB formats. \endgroup On LVDS buses, usually each sample is transferred serialized in seven -time slots per pixel clock, on three (18-bit) or four (24-bit) +time slots per pixel clock, on three (18-bit) or four (24-bit) or five (30-bit) differential data pairs at the same time. The remaining bits are used for control signals as defined by SPWG/PSWG/VESA or JEIDA standards. The 24-bit RGB format serialized in seven time slots on four lanes using @@ -2246,11 +2246,12 @@ JEIDA defined bit mapping will be named - Code - - - - :cspan:`3` Data organization + - :cspan:`4` Data organization * - - - Timeslot - Lane + - 4 - 3 - 2 - 1 @@ -2262,6 +2263,7 @@ JEIDA defined bit mapping will be named - 0 - - + - - d - b\ :sub:`1` - g\ :sub:`0` @@ -2270,6 +2272,7 @@ JEIDA defined bit mapping will be named - 1 - - + - - d - b\ :sub:`0` - r\ :sub:`5` @@ -2278,6 +2281,7 @@ JEIDA defined bit mapping will be named - 2 - - + - - d - g\ :sub:`5` - r\ :sub:`4` @@ -2286,6 +2290,7 @@ JEIDA defined bit mapping will be named - 3 - - + - - b\ :sub:`5` - g\ :sub:`4` - r\ :sub:`3` @@ -2294,6 +2299,7 @@ JEIDA defined bit mapping will be named - 4 - - + - - b\ :sub:`4` - g\ :sub:`3` - r\ :sub:`2` @@ -2302,6 +2308,7 @@ JEIDA defined bit mapping will be named - 5 - - + - - b\ :sub:`3` - g\ :sub:`2` - r\ :sub:`1` @@ -2310,6 +2317,7 @@ JEIDA defined bit mapping will be named - 6 - - + - - b\ :sub:`2` - g\ :sub:`1` - r\ :sub:`0` @@ -2319,6 +2327,7 @@ JEIDA defined bit mapping will be named - 0x1011 - 0 - + - - d - d - b\ :sub:`1` @@ -2327,6 +2336,7 @@ JEIDA defined bit mapping will be named - - 1 - + - - b\ :sub:`7` - d - b\ :sub:`0` @@ -2335,6 +2345,7 @@ JEIDA defined bit mapping will be named - - 2 - + - - b\ :sub:`6` - d - g\ :sub:`5` @@ -2343,6 +2354,7 @@ JEIDA defined bit mapping will be named - - 3 - + - - g\ :sub:`7` - b\ :sub:`5` - g\ :sub:`4` @@ -2351,6 +2363,7 @@ JEIDA defined bit mapping will be named - - 4 - + - - g\ :sub:`6` - b\ :sub:`4` - g\ :sub:`3` @@ -2359,6 +2372,7 @@ JEIDA defined bit mapping will be named - - 5 - + - - r\ :sub:`7` - b\ :sub:`3` - g\ :sub:`2` @@ -2367,6 +2381,7 @@ JEIDA defined bit mapping will be named - - 6 - + - - r\ :sub:`6` - b\ :sub:`2` - g\ :sub:`1` @@ -2377,6 +2392,7 @@ JEIDA defined bit mapping will be named - 0x1012 - 0 - + - - d - d - b\ :sub:`3` @@ -2385,6 +2401,7 @@ JEIDA defined bit mapping will be named - - 1 - + - - b\ :sub:`1` - d - b\ :sub:`2` @@ -2393,6 +2410,7 @@ JEIDA defined bit mapping will be named - - 2 - + - - b\ :sub:`0` - d - g\ :sub:`7` @@ -2401,6 +2419,7 @@ JEIDA defined bit mapping will be named - - 3 - + - - g\ :sub:`1` - b\ :sub:`7` - g\ :sub:`6` @@ -2409,6 +2428,7 @@ JEIDA defined bit mapping will be named - - 4 - + - - g\ :sub:`0` - b\ :sub:`6` - g\ :sub:`5` @@ -2417,6 +2437,7 @@ JEIDA defined bit mapping will be named - - 5 - + - - r\ :sub:`1` - b\ :sub:`5` - g\ :sub:`4` @@ -2425,10 +2446,141 @@ JEIDA defined bit mapping will be named - - 6 - + - + - r\ :sub:`0` + - b\ :sub:`4` + - g\ :sub:`3` + - r\ :sub:`2` + * .. _MEDIA-BUS-FMT-RGB101010-1X7X5-SPWG: + + - MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG + - 0x1026 + - 0 + - + - d + - d + - d + - b\ :sub:`1` + - g\ :sub:`0` + * - + - + - 1 + - + - b\ :sub:`9` + - b\ :sub:`7` + - d + - b\ :sub:`0` + - r\ :sub:`5` + * - + - + - 2 + - + - b\ :sub:`8` + - b\ :sub:`6` + - d + - g\ :sub:`5` + - r\ :sub:`4` + * - + - + - 3 + - + - g\ :sub:`9` + - g\ :sub:`7` + - b\ :sub:`5` + - g\ :sub:`4` + - r\ :sub:`3` + * - + - + - 4 + - + - g\ :sub:`8` + - g\ :sub:`6` + - b\ :sub:`4` + - g\ :sub:`3` + - r\ :sub:`2` + * - + - + - 5 + - + - r\ :sub:`9` + - r\ :sub:`7` + - b\ :sub:`3` + - g\ :sub:`2` + - r\ :sub:`1` + * - + - + - 6 + - + - r\ :sub:`8` + - r\ :sub:`6` + - b\ :sub:`2` + - g\ :sub:`1` - r\ :sub:`0` + * .. _MEDIA-BUS-FMT-RGB101010-1X7X5-JEIDA: + + - MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA + - 0x1027 + - 0 + - + - d + - d + - d + - b\ :sub:`5` + - g\ :sub:`4` + * - + - + - 1 + - + - b\ :sub:`1` + - b\ :sub:`3` + - d - b\ :sub:`4` + - r\ :sub:`9` + * - + - + - 2 + - + - b\ :sub:`0` + - b\ :sub:`2` + - d + - g\ :sub:`9` + - r\ :sub:`8` + * - + - + - 3 + - + - g\ :sub:`1` - g\ :sub:`3` + - b\ :sub:`9` + - g\ :sub:`8` + - r\ :sub:`7` + * - + - + - 4 + - + - g\ :sub:`0` + - g\ :sub:`2` + - b\ :sub:`8` + - g\ :sub:`7` + - r\ :sub:`6` + * - + - + - 5 + - + - r\ :sub:`1` + - r\ :sub:`3` + - b\ :sub:`7` + - g\ :sub:`6` + - r\ :sub:`5` + * - + - + - 6 + - + - r\ :sub:`0` - r\ :sub:`2` + - b\ :sub:`6` + - g\ :sub:`5` + - r\ :sub:`4` .. raw:: latex diff --git a/MAINTAINERS b/MAINTAINERS index 3779b3cc138e..f5dc00438ba3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7448,7 +7448,6 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git F: drivers/gpu/drm/udl/ DRM DRIVER FOR VIRTUAL KERNEL MODESETTING (VKMS) -M: MaĆra Canal <mairacanal@riseup.net> M: Louis Chauvet <louis.chauvet@bootlin.com> R: Haneen Mohammed <hamohammed.sa@gmail.com> R: Simona Vetter <simona@ffwll.ch> @@ -12135,6 +12134,14 @@ W: https://linuxtv.org Q: http://patchwork.linuxtv.org/project/linux-media/list/ F: drivers/media/tuners/it913x* +ITE IT6263 LVDS TO HDMI BRIDGE DRIVER +M: Liu Ying <victor.liu@nxp.com> +L: dri-devel@lists.freedesktop.org +S: Maintained +T: git https://gitlab.freedesktop.org/drm/misc/kernel.git +F: Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml +F: drivers/gpu/drm/bridge/ite-it6263.c + ITE IT66121 HDMI BRIDGE DRIVER M: Phong LE <ple@baylibre.com> M: Neil Armstrong <neil.armstrong@linaro.org> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 609f4d0ac93d..6b4664d91faa 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -90,6 +90,17 @@ config DRM_FSL_LDB help Support for i.MX8MP DPI-to-LVDS on-SoC encoder. +config DRM_ITE_IT6263 + tristate "ITE IT6263 LVDS/HDMI bridge" + depends on OF + select DRM_DISPLAY_HDMI_STATE_HELPER + select DRM_DISPLAY_HELPER + select DRM_BRIDGE_CONNECTOR + select DRM_KMS_HELPER + select REGMAP_I2C + help + ITE IT6263 LVDS to HDMI bridge chip driver. + config DRM_ITE_IT6505 tristate "ITE IT6505 DisplayPort bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 3daf803ce80b..97304b429a53 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o obj-$(CONFIG_DRM_FSL_LDB) += fsl-ldb.o +obj-$(CONFIG_DRM_ITE_IT6263) += ite-it6263.o obj-$(CONFIG_DRM_ITE_IT6505) += ite-it6505.o obj-$(CONFIG_DRM_LONTIUM_LT8912B) += lontium-lt8912b.o obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o diff --git a/drivers/gpu/drm/bridge/ite-it6263.c b/drivers/gpu/drm/bridge/ite-it6263.c new file mode 100644 index 000000000000..cbabd4e20d3e --- /dev/null +++ b/drivers/gpu/drm/bridge/ite-it6263.c @@ -0,0 +1,898 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2024 NXP + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/hdmi.h> +#include <linux/i2c.h> +#include <linux/media-bus-format.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +#include <drm/display/drm_hdmi_helper.h> +#include <drm/display/drm_hdmi_state_helper.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_atomic_state_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_bridge_connector.h> +#include <drm/drm_connector.h> +#include <drm/drm_crtc.h> +#include <drm/drm_edid.h> +#include <drm/drm_of.h> +#include <drm/drm_probe_helper.h> + +/* ----------------------------------------------------------------------------- + * LVDS registers + */ + +/* LVDS software reset registers */ +#define LVDS_REG_05 0x05 +#define REG_SOFT_P_RST BIT(1) + +/* LVDS system configuration registers */ +/* 0x0b */ +#define LVDS_REG_0B 0x0b +#define REG_SSC_PCLK_RF BIT(0) +#define REG_LVDS_IN_SWAP BIT(1) + +/* LVDS test pattern gen control registers */ +/* 0x2c */ +#define LVDS_REG_2C 0x2c +#define REG_COL_DEP GENMASK(1, 0) +#define BIT8 FIELD_PREP(REG_COL_DEP, 1) +#define OUT_MAP BIT(4) +#define JEIDA 0 +#define REG_DESSC_ENB BIT(6) +#define DMODE BIT(7) +#define DISO BIT(7) +#define SISO 0 + +#define LVDS_REG_3C 0x3c +#define LVDS_REG_3F 0x3f +#define LVDS_REG_47 0x47 +#define LVDS_REG_48 0x48 +#define LVDS_REG_4F 0x4f +#define LVDS_REG_52 0x52 + +/* ----------------------------------------------------------------------------- + * HDMI registers are separated into three banks: + * 1) HDMI register common bank: 0x00 ~ 0x2f + */ + +/* HDMI genernal registers */ +#define HDMI_REG_SW_RST 0x04 +#define SOFTREF_RST BIT(5) +#define SOFTA_RST BIT(4) +#define SOFTV_RST BIT(3) +#define AUD_RST BIT(2) +#define HDCP_RST BIT(0) +#define HDMI_RST_ALL (SOFTREF_RST | SOFTA_RST | SOFTV_RST | \ + AUD_RST | HDCP_RST) + +#define HDMI_REG_SYS_STATUS 0x0e +#define HPDETECT BIT(6) +#define TXVIDSTABLE BIT(4) + +#define HDMI_REG_BANK_CTRL 0x0f +#define REG_BANK_SEL BIT(0) + +/* HDMI System DDC control registers */ +#define HDMI_REG_DDC_MASTER_CTRL 0x10 +#define MASTER_SEL_HOST BIT(0) + +#define HDMI_REG_DDC_HEADER 0x11 + +#define HDMI_REG_DDC_REQOFF 0x12 +#define HDMI_REG_DDC_REQCOUNT 0x13 +#define HDMI_REG_DDC_EDIDSEG 0x14 + +#define HDMI_REG_DDC_CMD 0x15 +#define DDC_CMD_EDID_READ 0x3 +#define DDC_CMD_FIFO_CLR 0x9 + +#define HDMI_REG_DDC_STATUS 0x16 +#define DDC_DONE BIT(7) +#define DDC_NOACK BIT(5) +#define DDC_WAITBUS BIT(4) +#define DDC_ARBILOSE BIT(3) +#define DDC_ERROR (DDC_NOACK | DDC_WAITBUS | DDC_ARBILOSE) + +#define HDMI_DDC_FIFO_BYTES 32 +#define HDMI_REG_DDC_READFIFO 0x17 +#define HDMI_REG_LVDS_PORT 0x1d /* LVDS input control I2C addr */ +#define HDMI_REG_LVDS_PORT_EN 0x1e +#define LVDS_INPUT_CTRL_I2C_ADDR 0x33 + +/* ----------------------------------------------------------------------------- + * 2) HDMI register bank0: 0x30 ~ 0xff + */ + +/* HDMI AFE registers */ +#define HDMI_REG_AFE_DRV_CTRL 0x61 +#define AFE_DRV_PWD BIT(5) +#define AFE_DRV_RST BIT(4) + +#define HDMI_REG_AFE_XP_CTRL 0x62 +#define AFE_XP_GAINBIT BIT(7) +#define AFE_XP_ER0 BIT(4) +#define AFE_XP_RESETB BIT(3) + +#define HDMI_REG_AFE_ISW_CTRL 0x63 + +#define HDMI_REG_AFE_IP_CTRL 0x64 +#define AFE_IP_GAINBIT BIT(7) +#define AFE_IP_ER0 BIT(3) +#define AFE_IP_RESETB BIT(2) + +/* HDMI input data format registers */ +#define HDMI_REG_INPUT_MODE 0x70 +#define IN_RGB 0x00 + +/* HDMI general control registers */ +#define HDMI_REG_HDMI_MODE 0xc0 +#define TX_HDMI_MODE BIT(0) + +#define HDMI_REG_GCP 0xc1 +#define AVMUTE BIT(0) +#define HDMI_COLOR_DEPTH GENMASK(6, 4) +#define HDMI_COLOR_DEPTH_24 FIELD_PREP(HDMI_COLOR_DEPTH, 4) + +#define HDMI_REG_PKT_GENERAL_CTRL 0xc6 +#define HDMI_REG_AVI_INFOFRM_CTRL 0xcd +#define ENABLE_PKT BIT(0) +#define REPEAT_PKT BIT(1) + +/* ----------------------------------------------------------------------------- + * 3) HDMI register bank1: 0x130 ~ 0x1ff (HDMI packet registers) + */ + +/* AVI packet registers */ +#define HDMI_REG_AVI_DB1 0x158 +#define HDMI_REG_AVI_DB2 0x159 +#define HDMI_REG_AVI_DB3 0x15a +#define HDMI_REG_AVI_DB4 0x15b +#define HDMI_REG_AVI_DB5 0x15c +#define HDMI_REG_AVI_CSUM 0x15d +#define HDMI_REG_AVI_DB6 0x15e +#define HDMI_REG_AVI_DB7 0x15f +#define HDMI_REG_AVI_DB8 0x160 +#define HDMI_REG_AVI_DB9 0x161 +#define HDMI_REG_AVI_DB10 0x162 +#define HDMI_REG_AVI_DB11 0x163 +#define HDMI_REG_AVI_DB12 0x164 +#define HDMI_REG_AVI_DB13 0x165 + +#define HDMI_AVI_DB_CHUNK1_SIZE (HDMI_REG_AVI_DB5 - HDMI_REG_AVI_DB1 + 1) +#define HDMI_AVI_DB_CHUNK2_SIZE (HDMI_REG_AVI_DB13 - HDMI_REG_AVI_DB6 + 1) + +/* IT6263 data sheet Rev0.8: LVDS RX supports input clock rate up to 150MHz. */ +#define MAX_PIXEL_CLOCK_KHZ 150000 + +/* IT6263 programming guide Ver0.90: PCLK_HIGH for TMDS clock over 80MHz. */ +#define HIGH_PIXEL_CLOCK_KHZ 80000 + +/* + * IT6263 data sheet Rev0.8: HDMI TX supports link speeds of up to 2.25Gbps + * (link clock rate of 225MHz). + */ +#define MAX_HDMI_TMDS_CHAR_RATE_HZ 225000000 + +struct it6263 { + struct device *dev; + struct i2c_client *hdmi_i2c; + struct i2c_client *lvds_i2c; + struct regmap *hdmi_regmap; + struct regmap *lvds_regmap; + struct drm_bridge bridge; + struct drm_bridge *next_bridge; + int lvds_data_mapping; + bool lvds_dual_link; + bool lvds_link12_swap; +}; + +static inline struct it6263 *bridge_to_it6263(struct drm_bridge *bridge) +{ + return container_of(bridge, struct it6263, bridge); +} + +static bool it6263_hdmi_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case HDMI_REG_SW_RST: + case HDMI_REG_BANK_CTRL: + case HDMI_REG_DDC_MASTER_CTRL: + case HDMI_REG_DDC_HEADER: + case HDMI_REG_DDC_REQOFF: + case HDMI_REG_DDC_REQCOUNT: + case HDMI_REG_DDC_EDIDSEG: + case HDMI_REG_DDC_CMD: + case HDMI_REG_LVDS_PORT: + case HDMI_REG_LVDS_PORT_EN: + case HDMI_REG_AFE_DRV_CTRL: + case HDMI_REG_AFE_XP_CTRL: + case HDMI_REG_AFE_ISW_CTRL: + case HDMI_REG_AFE_IP_CTRL: + case HDMI_REG_INPUT_MODE: + case HDMI_REG_HDMI_MODE: + case HDMI_REG_GCP: + case HDMI_REG_PKT_GENERAL_CTRL: + case HDMI_REG_AVI_INFOFRM_CTRL: + case HDMI_REG_AVI_DB1: + case HDMI_REG_AVI_DB2: + case HDMI_REG_AVI_DB3: + case HDMI_REG_AVI_DB4: + case HDMI_REG_AVI_DB5: + case HDMI_REG_AVI_CSUM: + case HDMI_REG_AVI_DB6: + case HDMI_REG_AVI_DB7: + case HDMI_REG_AVI_DB8: + case HDMI_REG_AVI_DB9: + case HDMI_REG_AVI_DB10: + case HDMI_REG_AVI_DB11: + case HDMI_REG_AVI_DB12: + case HDMI_REG_AVI_DB13: + return true; + default: + return false; + } +} + +static bool it6263_hdmi_readable_reg(struct device *dev, unsigned int reg) +{ + if (it6263_hdmi_writeable_reg(dev, reg)) + return true; + + switch (reg) { + case HDMI_REG_SYS_STATUS: + case HDMI_REG_DDC_STATUS: + case HDMI_REG_DDC_READFIFO: + return true; + default: + return false; + } +} + +static bool it6263_hdmi_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case HDMI_REG_SW_RST: + case HDMI_REG_SYS_STATUS: + case HDMI_REG_DDC_STATUS: + case HDMI_REG_DDC_READFIFO: + return true; + default: + return false; + } +} + +static const struct regmap_range_cfg it6263_hdmi_range_cfg = { + .range_min = 0x00, + .range_max = HDMI_REG_AVI_DB13, + .selector_reg = HDMI_REG_BANK_CTRL, + .selector_mask = REG_BANK_SEL, + .selector_shift = 0, + .window_start = 0x00, + .window_len = 0x100, +}; + +static const struct regmap_config it6263_hdmi_regmap_config = { + .name = "it6263-hdmi", + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = it6263_hdmi_writeable_reg, + .readable_reg = it6263_hdmi_readable_reg, + .volatile_reg = it6263_hdmi_volatile_reg, + .max_register = HDMI_REG_AVI_DB13, + .ranges = &it6263_hdmi_range_cfg, + .num_ranges = 1, + .cache_type = REGCACHE_MAPLE, +}; + +static bool it6263_lvds_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case LVDS_REG_05: + case LVDS_REG_0B: + case LVDS_REG_2C: + case LVDS_REG_3C: + case LVDS_REG_3F: + case LVDS_REG_47: + case LVDS_REG_48: + case LVDS_REG_4F: + case LVDS_REG_52: + return true; + default: + return false; + } +} + +static bool it6263_lvds_readable_reg(struct device *dev, unsigned int reg) +{ + return it6263_lvds_writeable_reg(dev, reg); +} + +static bool it6263_lvds_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg == LVDS_REG_05; +} + +static const struct regmap_config it6263_lvds_regmap_config = { + .name = "it6263-lvds", + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = it6263_lvds_writeable_reg, + .readable_reg = it6263_lvds_readable_reg, + .volatile_reg = it6263_lvds_volatile_reg, + .max_register = LVDS_REG_52, + .cache_type = REGCACHE_MAPLE, +}; + +static const char * const it6263_supplies[] = { + "ivdd", "ovdd", "txavcc18", "txavcc33", "pvcc1", "pvcc2", + "avcc", "anvdd", "apvdd" +}; + +static int it6263_parse_dt(struct it6263 *it) +{ + struct device *dev = it->dev; + struct device_node *port0, *port1; + int ret = 0; + + it->lvds_data_mapping = drm_of_lvds_get_data_mapping(dev->of_node); + if (it->lvds_data_mapping < 0) { + dev_err(dev, "%pOF: invalid or missing %s DT property: %d\n", + dev->of_node, "data-mapping", it->lvds_data_mapping); + return it->lvds_data_mapping; + } + + it->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 2, 0); + if (IS_ERR(it->next_bridge)) + return dev_err_probe(dev, PTR_ERR(it->next_bridge), + "failed to get next bridge\n"); + + port0 = of_graph_get_port_by_id(dev->of_node, 0); + port1 = of_graph_get_port_by_id(dev->of_node, 1); + if (port0 && port1) { + int order; + + it->lvds_dual_link = true; + order = drm_of_lvds_get_dual_link_pixel_order_sink(port0, port1); + if (order < 0) { + dev_err(dev, + "failed to get dual link pixel order: %d\n", + order); + ret = order; + } else if (order == DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS) { + it->lvds_link12_swap = true; + } + } else if (port1) { + ret = -EINVAL; + dev_err(dev, "single input LVDS port1 is not supported\n"); + } else if (!port0) { + ret = -EINVAL; + dev_err(dev, "no input LVDS port\n"); + } + + of_node_put(port0); + of_node_put(port1); + + return ret; +} + +static inline void it6263_hw_reset(struct gpio_desc *reset_gpio) +{ + if (!reset_gpio) + return; + + gpiod_set_value_cansleep(reset_gpio, 0); + fsleep(1000); + gpiod_set_value_cansleep(reset_gpio, 1); + /* The chip maker says the low pulse should be at least 40ms. */ + fsleep(40000); + gpiod_set_value_cansleep(reset_gpio, 0); + /* addtional time to wait the high voltage to be stable */ + fsleep(5000); +} + +static inline int it6263_lvds_set_i2c_addr(struct it6263 *it) +{ + int ret; + + ret = regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT, + LVDS_INPUT_CTRL_I2C_ADDR << 1); + if (ret) + return ret; + + return regmap_write(it->hdmi_regmap, HDMI_REG_LVDS_PORT_EN, BIT(0)); +} + +static inline void it6263_lvds_reset(struct it6263 *it) +{ + /* AFE PLL reset */ + regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), 0x0); + fsleep(1000); + regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, BIT(0), BIT(0)); + + /* software pixel clock domain reset */ + regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST, + REG_SOFT_P_RST); + fsleep(1000); + regmap_write_bits(it->lvds_regmap, LVDS_REG_05, REG_SOFT_P_RST, 0x0); + fsleep(10000); +} + +static inline void it6263_lvds_set_interface(struct it6263 *it) +{ + /* color depth */ + regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_COL_DEP, BIT8); + /* output mapping */ + regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, OUT_MAP, JEIDA); + + if (it->lvds_dual_link) { + regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, DISO); + regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), BIT(1)); + } else { + regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, DMODE, SISO); + regmap_write_bits(it->lvds_regmap, LVDS_REG_52, BIT(1), 0); + } +} + +static inline void it6263_lvds_set_afe(struct it6263 *it) +{ + regmap_write(it->lvds_regmap, LVDS_REG_3C, 0xaa); + regmap_write(it->lvds_regmap, LVDS_REG_3F, 0x02); + regmap_write(it->lvds_regmap, LVDS_REG_47, 0xaa); + regmap_write(it->lvds_regmap, LVDS_REG_48, 0x02); + regmap_write(it->lvds_regmap, LVDS_REG_4F, 0x11); + + regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_SSC_PCLK_RF, + REG_SSC_PCLK_RF); + regmap_write_bits(it->lvds_regmap, LVDS_REG_3C, 0x07, 0); + regmap_write_bits(it->lvds_regmap, LVDS_REG_2C, REG_DESSC_ENB, + REG_DESSC_ENB); +} + +static inline void it6263_lvds_sys_cfg(struct it6263 *it) +{ + regmap_write_bits(it->lvds_regmap, LVDS_REG_0B, REG_LVDS_IN_SWAP, + it->lvds_link12_swap ? REG_LVDS_IN_SWAP : 0); +} + +static inline void it6263_lvds_config(struct it6263 *it) +{ + it6263_lvds_reset(it); + it6263_lvds_set_interface(it); + it6263_lvds_set_afe(it); + it6263_lvds_sys_cfg(it); +} + +static inline void it6263_hdmi_config(struct it6263 *it) +{ + regmap_write(it->hdmi_regmap, HDMI_REG_SW_RST, HDMI_RST_ALL); + regmap_write(it->hdmi_regmap, HDMI_REG_INPUT_MODE, IN_RGB); + regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, HDMI_COLOR_DEPTH, + HDMI_COLOR_DEPTH_24); +} + +static enum drm_connector_status it6263_detect(struct it6263 *it) +{ + unsigned int val; + + regmap_read(it->hdmi_regmap, HDMI_REG_SYS_STATUS, &val); + if (val & HPDETECT) + return connector_status_connected; + else + return connector_status_disconnected; +} + +static int it6263_read_edid(void *data, u8 *buf, unsigned int block, size_t len) +{ + struct it6263 *it = data; + struct regmap *regmap = it->hdmi_regmap; + unsigned int start = (block % 2) * EDID_LENGTH; + unsigned int segment = block >> 1; + unsigned int count, val; + int ret; + + regmap_write(regmap, HDMI_REG_DDC_MASTER_CTRL, MASTER_SEL_HOST); + regmap_write(regmap, HDMI_REG_DDC_HEADER, DDC_ADDR << 1); + regmap_write(regmap, HDMI_REG_DDC_EDIDSEG, segment); + + while (len) { + /* clear DDC FIFO */ + regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_FIFO_CLR); + + ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS, + val, val & DDC_DONE, + 2000, 10000); + if (ret) { + dev_err(it->dev, "failed to clear DDC FIFO:%d\n", ret); + return ret; + } + + count = len > HDMI_DDC_FIFO_BYTES ? HDMI_DDC_FIFO_BYTES : len; + + /* fire the read command */ + regmap_write(regmap, HDMI_REG_DDC_REQOFF, start); + regmap_write(regmap, HDMI_REG_DDC_REQCOUNT, count); + regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_EDID_READ); + + start += count; + len -= count; + + ret = regmap_read_poll_timeout(regmap, HDMI_REG_DDC_STATUS, val, + val & (DDC_DONE | DDC_ERROR), + 20000, 250000); + if (ret && !(val & DDC_ERROR)) { + dev_err(it->dev, "failed to read EDID:%d\n", ret); + return ret; + } + + if (val & DDC_ERROR) { + dev_err(it->dev, "DDC error\n"); + return -EIO; + } + + /* cache to buffer */ + for (; count > 0; count--) { + regmap_read(regmap, HDMI_REG_DDC_READFIFO, &val); + *(buf++) = val; + } + } + + return 0; +} + +static int it6263_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + return drm_atomic_helper_connector_hdmi_check(conn_state->connector, + conn_state->state); +} + +static void +it6263_bridge_atomic_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) +{ + struct it6263 *it = bridge_to_it6263(bridge); + + regmap_write_bits(it->hdmi_regmap, HDMI_REG_GCP, AVMUTE, AVMUTE); + regmap_write(it->hdmi_regmap, HDMI_REG_PKT_GENERAL_CTRL, 0); + regmap_write(it->hdmi_regmap, HDMI_REG_AFE_DRV_CTRL, + AFE_DRV_RST | AFE_DRV_PWD); +} + +static void +it6263_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) +{ + struct drm_atomic_state *state = old_bridge_state->base.state; + struct it6263 *it = bridge_to_it6263(bridge); + const struct drm_crtc_state *crtc_state; + struct regmap *regmap = it->hdmi_regmap; + const struct drm_display_mode *mode; + struct drm_connector *connector; + bool is_stable = false; + struct drm_crtc *crtc; + unsigned int val; + bool pclk_high; + int i, ret; + + connector = drm_atomic_get_new_connector_for_encoder(state, + bridge->encoder); + crtc = drm_atomic_get_new_connector_state(state, connector)->crtc; + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + mode = &crtc_state->adjusted_mode; + + regmap_write(regmap, HDMI_REG_HDMI_MODE, TX_HDMI_MODE); + + drm_atomic_helper_connector_hdmi_update_infoframes(connector, state); + + /* HDMI AFE setup */ + pclk_high = mode->clock > HIGH_PIXEL_CLOCK_KHZ; + regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, AFE_DRV_RST); + if (pclk_high) + regmap_write(regmap, HDMI_REG_AFE_XP_CTRL, + AFE_XP_GAINBIT | AFE_XP_RESETB); + else + regmap_write(regmap, HDMI_REG_AFE_XP_CTRL, + AFE_XP_ER0 | AFE_XP_RESETB); + regmap_write(regmap, HDMI_REG_AFE_ISW_CTRL, 0x10); + if (pclk_high) + regmap_write(regmap, HDMI_REG_AFE_IP_CTRL, + AFE_IP_GAINBIT | AFE_IP_RESETB); + else + regmap_write(regmap, HDMI_REG_AFE_IP_CTRL, + AFE_IP_ER0 | AFE_IP_RESETB); + + /* HDMI software video reset */ + regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, SOFTV_RST); + fsleep(1000); + regmap_write_bits(regmap, HDMI_REG_SW_RST, SOFTV_RST, 0); + + /* reconfigure LVDS and retry several times in case video is instable */ + for (i = 0; i < 3; i++) { + ret = regmap_read_poll_timeout(regmap, HDMI_REG_SYS_STATUS, val, + val & TXVIDSTABLE, + 20000, 500000); + if (!ret) { + is_stable = true; + break; + } + + it6263_lvds_config(it); + } + + if (!is_stable) + dev_warn(it->dev, "failed to wait for video stable\n"); + + /* HDMI AFE reset release and power up */ + regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, 0); + + regmap_write_bits(regmap, HDMI_REG_GCP, AVMUTE, 0); + + regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL, ENABLE_PKT | REPEAT_PKT); +} + +static enum drm_mode_status +it6263_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + unsigned long long rate; + + rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB); + if (rate == 0) + return MODE_NOCLOCK; + + return bridge->funcs->hdmi_tmds_char_rate_valid(bridge, mode, rate); +} + +static int it6263_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct it6263 *it = bridge_to_it6263(bridge); + struct drm_connector *connector; + int ret; + + ret = drm_bridge_attach(bridge->encoder, it->next_bridge, bridge, + flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret < 0) + return ret; + + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) + return 0; + + connector = drm_bridge_connector_init(bridge->dev, bridge->encoder); + if (IS_ERR(connector)) { + ret = PTR_ERR(connector); + dev_err(it->dev, "failed to initialize bridge connector: %d\n", + ret); + return ret; + } + + drm_connector_attach_encoder(connector, bridge->encoder); + + return 0; +} + +static enum drm_connector_status it6263_bridge_detect(struct drm_bridge *bridge) +{ + struct it6263 *it = bridge_to_it6263(bridge); + + return it6263_detect(it); +} + +static const struct drm_edid * +it6263_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) +{ + struct it6263 *it = bridge_to_it6263(bridge); + + return drm_edid_read_custom(connector, it6263_read_edid, it); +} + +static u32 * +it6263_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + struct it6263 *it = bridge_to_it6263(bridge); + u32 *input_fmts; + + *num_input_fmts = 0; + + if (it->lvds_data_mapping != MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA) + return NULL; + + input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL); + if (!input_fmts) + return NULL; + + input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA; + *num_input_fmts = 1; + + return input_fmts; +} + +static enum drm_mode_status +it6263_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge, + const struct drm_display_mode *mode, + unsigned long long tmds_rate) +{ + if (mode->clock > MAX_PIXEL_CLOCK_KHZ) + return MODE_CLOCK_HIGH; + + if (tmds_rate > MAX_HDMI_TMDS_CHAR_RATE_HZ) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static int it6263_hdmi_clear_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type) +{ + struct it6263 *it = bridge_to_it6263(bridge); + + if (type == HDMI_INFOFRAME_TYPE_AVI) + regmap_write(it->hdmi_regmap, HDMI_REG_AVI_INFOFRM_CTRL, 0); + else + dev_dbg(it->dev, "unsupported HDMI infoframe 0x%x\n", type); + + return 0; +} + +static int it6263_hdmi_write_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len) +{ + struct it6263 *it = bridge_to_it6263(bridge); + struct regmap *regmap = it->hdmi_regmap; + + if (type != HDMI_INFOFRAME_TYPE_AVI) { + dev_dbg(it->dev, "unsupported HDMI infoframe 0x%x\n", type); + return 0; + } + + /* write the first AVI infoframe data byte chunk(DB1-DB5) */ + regmap_bulk_write(regmap, HDMI_REG_AVI_DB1, + &buffer[HDMI_INFOFRAME_HEADER_SIZE], + HDMI_AVI_DB_CHUNK1_SIZE); + + /* write the second AVI infoframe data byte chunk(DB6-DB13) */ + regmap_bulk_write(regmap, HDMI_REG_AVI_DB6, + &buffer[HDMI_INFOFRAME_HEADER_SIZE + + HDMI_AVI_DB_CHUNK1_SIZE], + HDMI_AVI_DB_CHUNK2_SIZE); + + /* write checksum */ + regmap_write(regmap, HDMI_REG_AVI_CSUM, buffer[3]); + + regmap_write(regmap, HDMI_REG_AVI_INFOFRM_CTRL, ENABLE_PKT | REPEAT_PKT); + + return 0; +} + +static const struct drm_bridge_funcs it6263_bridge_funcs = { + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .attach = it6263_bridge_attach, + .mode_valid = it6263_bridge_mode_valid, + .atomic_disable = it6263_bridge_atomic_disable, + .atomic_enable = it6263_bridge_atomic_enable, + .atomic_check = it6263_bridge_atomic_check, + .detect = it6263_bridge_detect, + .edid_read = it6263_bridge_edid_read, + .atomic_get_input_bus_fmts = it6263_bridge_atomic_get_input_bus_fmts, + .hdmi_tmds_char_rate_valid = it6263_hdmi_tmds_char_rate_valid, + .hdmi_clear_infoframe = it6263_hdmi_clear_infoframe, + .hdmi_write_infoframe = it6263_hdmi_write_infoframe, +}; + +static int it6263_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct gpio_desc *reset_gpio; + struct it6263 *it; + int ret; + + it = devm_kzalloc(dev, sizeof(*it), GFP_KERNEL); + if (!it) + return -ENOMEM; + + it->dev = dev; + it->hdmi_i2c = client; + + it->hdmi_regmap = devm_regmap_init_i2c(client, + &it6263_hdmi_regmap_config); + if (IS_ERR(it->hdmi_regmap)) + return dev_err_probe(dev, PTR_ERR(it->hdmi_regmap), + "failed to init I2C regmap for HDMI\n"); + + reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(reset_gpio)) + return dev_err_probe(dev, PTR_ERR(reset_gpio), + "failed to get reset gpio\n"); + + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(it6263_supplies), + it6263_supplies); + if (ret) + return dev_err_probe(dev, ret, "failed to get power supplies\n"); + + ret = it6263_parse_dt(it); + if (ret) + return ret; + + it6263_hw_reset(reset_gpio); + + ret = it6263_lvds_set_i2c_addr(it); + if (ret) + return dev_err_probe(dev, ret, "failed to set I2C addr\n"); + + it->lvds_i2c = devm_i2c_new_dummy_device(dev, client->adapter, + LVDS_INPUT_CTRL_I2C_ADDR); + if (IS_ERR(it->lvds_i2c)) + dev_err_probe(it->dev, PTR_ERR(it->lvds_i2c), + "failed to allocate I2C device for LVDS\n"); + + it->lvds_regmap = devm_regmap_init_i2c(it->lvds_i2c, + &it6263_lvds_regmap_config); + if (IS_ERR(it->lvds_regmap)) + return dev_err_probe(dev, PTR_ERR(it->lvds_regmap), + "failed to init I2C regmap for LVDS\n"); + + it6263_lvds_config(it); + it6263_hdmi_config(it); + + i2c_set_clientdata(client, it); + + it->bridge.funcs = &it6263_bridge_funcs; + it->bridge.of_node = dev->of_node; + /* IT6263 chip doesn't support HPD interrupt. */ + it->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | + DRM_BRIDGE_OP_HDMI; + it->bridge.type = DRM_MODE_CONNECTOR_HDMIA; + it->bridge.vendor = "ITE"; + it->bridge.product = "IT6263"; + + return devm_drm_bridge_add(dev, &it->bridge); +} + +static const struct of_device_id it6263_of_match[] = { + { .compatible = "ite,it6263", }, + { } +}; +MODULE_DEVICE_TABLE(of, it6263_of_match); + +static const struct i2c_device_id it6263_i2c_ids[] = { + { "it6263", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, it6263_i2c_ids); + +static struct i2c_driver it6263_driver = { + .probe = it6263_probe, + .driver = { + .name = "it6263", + .of_match_table = it6263_of_match, + }, + .id_table = it6263_i2c_ids, +}; +module_i2c_driver(it6263_driver); + +MODULE_DESCRIPTION("ITE Tech. Inc. IT6263 LVDS/HDMI bridge"); +MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 7ff17aa14b01..008d86cc562a 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -2614,9 +2614,9 @@ static int it6505_poweron(struct it6505 *it6505) /* time interval between OVDD and SYSRSTN at least be 10ms */ if (pdata->gpiod_reset) { usleep_range(10000, 20000); - gpiod_set_value_cansleep(pdata->gpiod_reset, 0); - usleep_range(1000, 2000); gpiod_set_value_cansleep(pdata->gpiod_reset, 1); + usleep_range(1000, 2000); + gpiod_set_value_cansleep(pdata->gpiod_reset, 0); usleep_range(25000, 35000); } @@ -2647,7 +2647,7 @@ static int it6505_poweroff(struct it6505 *it6505) disable_irq_nosync(it6505->irq); if (pdata->gpiod_reset) - gpiod_set_value_cansleep(pdata->gpiod_reset, 0); + gpiod_set_value_cansleep(pdata->gpiod_reset, 1); if (pdata->pwr18) { err = regulator_disable(pdata->pwr18); @@ -3135,7 +3135,7 @@ static int it6505_init_pdata(struct it6505 *it6505) return PTR_ERR(pdata->ovdd); } - pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(pdata->gpiod_reset)) { dev_err(dev, "gpiod_reset gpio not found"); return PTR_ERR(pdata->gpiod_reset); diff --git a/drivers/gpu/drm/ci/xfails/requirements.txt b/drivers/gpu/drm/ci/xfails/requirements.txt deleted file mode 100644 index 5e6d48d98e4e..000000000000 --- a/drivers/gpu/drm/ci/xfails/requirements.txt +++ /dev/null @@ -1,17 +0,0 @@ -git+https://gitlab.freedesktop.org/gfx-ci/ci-collate@09e7142715c16f54344ddf97013331ba063b162b -termcolor==2.3.0 - -# ci-collate dependencies -certifi==2023.7.22 -charset-normalizer==3.2.0 -idna==3.4 -pip==23.3 -python-gitlab==3.15.0 -requests==2.31.0 -requests-toolbelt==1.0.0 -ruamel.yaml==0.17.32 -ruamel.yaml.clib==0.2.7 -setuptools==70.0.0 -tenacity==8.2.3 -urllib3==2.0.7 -wheel==0.41.1 diff --git a/drivers/gpu/drm/ci/xfails/update-xfails.py b/drivers/gpu/drm/ci/xfails/update-xfails.py deleted file mode 100755 index a446e98d72a1..000000000000 --- a/drivers/gpu/drm/ci/xfails/update-xfails.py +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -from collections import defaultdict -import difflib -import os -import re -from glcollate import Collate -from termcolor import colored -from urllib.parse import urlparse - - -def get_canonical_name(job_name): - return re.split(r" \d+/\d+", job_name)[0] - - -def get_xfails_file_path(job_name, suffix): - canonical_name = get_canonical_name(job_name) - name = canonical_name.replace(":", "-") - script_dir = os.path.dirname(os.path.abspath(__file__)) - return os.path.join(script_dir, f"{name}-{suffix}.txt") - - -def get_unit_test_name_and_results(unit_test): - if "Artifact results/failures.csv not found" in unit_test or '' == unit_test: - return None, None - unit_test_name, unit_test_result = unit_test.strip().split(",") - return unit_test_name, unit_test_result - - -def read_file(file_path): - try: - with open(file_path, "r") as file: - f = file.readlines() - if len(f): - f[-1] = f[-1].strip() + "\n" - return f - except FileNotFoundError: - return [] - - -def save_file(content, file_path): - # delete file is content is empty - if not content or not any(content): - if os.path.exists(file_path): - os.remove(file_path) - return - - with open(file_path, "w") as file: - file.writelines(content) - - -def is_test_present_on_file(file_content, unit_test_name): - return any(unit_test_name in line for line in file_content) - - -def is_unit_test_present_in_other_jobs(unit_test, job_ids): - return all(unit_test in job_ids[job_id] for job_id in job_ids) - - -def remove_unit_test_if_present(lines, unit_test_name): - if not is_test_present_on_file(lines, unit_test_name): - return - lines[:] = [line for line in lines if unit_test_name not in line] - - -def add_unit_test_if_not_present(lines, unit_test_name, file_name): - # core_getversion is mandatory - if "core_getversion" in unit_test_name: - print("WARNING: core_getversion should pass, not adding it to", os.path.basename(file_name)) - elif all(unit_test_name not in line for line in lines): - lines.append(unit_test_name + "\n") - - -def update_unit_test_result_in_fails_txt(fails_txt, unit_test): - unit_test_name, unit_test_result = get_unit_test_name_and_results(unit_test) - for i, line in enumerate(fails_txt): - if unit_test_name in line: - _, current_result = get_unit_test_name_and_results(line) - fails_txt[i] = unit_test + "\n" - return - - -def add_unit_test_or_update_result_to_fails_if_present(fails_txt, unit_test, fails_txt_path): - unit_test_name, _ = get_unit_test_name_and_results(unit_test) - if not is_test_present_on_file(fails_txt, unit_test_name): - add_unit_test_if_not_present(fails_txt, unit_test, fails_txt_path) - # if it is present but not with the same result - elif not is_test_present_on_file(fails_txt, unit_test): - update_unit_test_result_in_fails_txt(fails_txt, unit_test) - - -def split_unit_test_from_collate(xfails): - for job_name in xfails.keys(): - for job_id in xfails[job_name].copy().keys(): - if "not found" in xfails[job_name][job_id].content_as_str: - del xfails[job_name][job_id] - continue - xfails[job_name][job_id] = xfails[job_name][job_id].content_as_str.splitlines() - - -def get_xfails_from_pipeline_url(pipeline_url): - parsed_url = urlparse(pipeline_url) - path_components = parsed_url.path.strip("/").split("/") - - namespace = path_components[0] - project = path_components[1] - pipeline_id = path_components[-1] - - print("Collating from:", namespace, project, pipeline_id) - xfails = ( - Collate(namespace=namespace, project=project) - .from_pipeline(pipeline_id) - .get_artifact("results/failures.csv") - ) - - split_unit_test_from_collate(xfails) - return xfails - - -def get_xfails_from_pipeline_urls(pipelines_urls): - xfails = defaultdict(dict) - - for url in pipelines_urls: - new_xfails = get_xfails_from_pipeline_url(url) - for key in new_xfails: - xfails[key].update(new_xfails[key]) - - return xfails - - -def print_diff(old_content, new_content, file_name): - diff = difflib.unified_diff(old_content, new_content, lineterm="", fromfile=file_name, tofile=file_name) - diff = [colored(line, "green") if line.startswith("+") else - colored(line, "red") if line.startswith("-") else line for line in diff] - print("\n".join(diff[:3])) - print("".join(diff[3:])) - - -def main(pipelines_urls, only_flakes): - xfails = get_xfails_from_pipeline_urls(pipelines_urls) - - for job_name in xfails.keys(): - fails_txt_path = get_xfails_file_path(job_name, "fails") - flakes_txt_path = get_xfails_file_path(job_name, "flakes") - - fails_txt = read_file(fails_txt_path) - flakes_txt = read_file(flakes_txt_path) - - fails_txt_original = fails_txt.copy() - flakes_txt_original = flakes_txt.copy() - - for job_id in xfails[job_name].keys(): - for unit_test in xfails[job_name][job_id]: - unit_test_name, unit_test_result = get_unit_test_name_and_results(unit_test) - - if not unit_test_name: - continue - - if only_flakes: - remove_unit_test_if_present(fails_txt, unit_test_name) - add_unit_test_if_not_present(flakes_txt, unit_test_name, flakes_txt_path) - continue - - # drop it from flakes if it is present to analyze it again - remove_unit_test_if_present(flakes_txt, unit_test_name) - - if unit_test_result == "UnexpectedPass": - remove_unit_test_if_present(fails_txt, unit_test_name) - # flake result - if not is_unit_test_present_in_other_jobs(unit_test, xfails[job_name]): - add_unit_test_if_not_present(flakes_txt, unit_test_name, flakes_txt_path) - continue - - # flake result - if not is_unit_test_present_in_other_jobs(unit_test, xfails[job_name]): - remove_unit_test_if_present(fails_txt, unit_test_name) - add_unit_test_if_not_present(flakes_txt, unit_test_name, flakes_txt_path) - continue - - # consistent result - add_unit_test_or_update_result_to_fails_if_present(fails_txt, unit_test, - fails_txt_path) - - fails_txt.sort() - flakes_txt.sort() - - if fails_txt != fails_txt_original: - save_file(fails_txt, fails_txt_path) - print_diff(fails_txt_original, fails_txt, os.path.basename(fails_txt_path)) - if flakes_txt != flakes_txt_original: - save_file(flakes_txt, flakes_txt_path) - print_diff(flakes_txt_original, flakes_txt, os.path.basename(flakes_txt_path)) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Update xfails from a given pipeline.") - parser.add_argument("pipeline_urls", nargs="+", type=str, help="URLs to the pipelines to analyze the failures.") - parser.add_argument("--only-flakes", action="store_true", help="Treat every detected failure as a flake, edit *-flakes.txt only.") - - args = parser.parse_args() - - main(args.pipeline_urls, args.only_flakes) - print("Done.") diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 9011f8e16099..cb5f22f5bbb6 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -129,7 +129,7 @@ bool drm_dev_needs_global_mutex(struct drm_device *dev) */ struct drm_file *drm_file_alloc(struct drm_minor *minor) { - static atomic64_t ident = ATOMIC_INIT(0); + static atomic64_t ident = ATOMIC64_INIT(0); struct drm_device *dev = minor->dev; struct drm_file *file; int ret; diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 177b600895d3..5c2abc9eca9c 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -341,8 +341,23 @@ static int drm_of_lvds_get_remote_pixels_type( return pixels_type; } +static int __drm_of_lvds_get_dual_link_pixel_order(int p1_pt, int p2_pt) +{ + /* + * A valid dual-lVDS bus is found when one port is marked with + * "dual-lvds-even-pixels", and the other port is marked with + * "dual-lvds-odd-pixels", bail out if the markers are not right. + */ + if (p1_pt + p2_pt != DRM_OF_LVDS_EVEN + DRM_OF_LVDS_ODD) + return -EINVAL; + + return p1_pt == DRM_OF_LVDS_EVEN ? + DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS : + DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS; +} + /** - * drm_of_lvds_get_dual_link_pixel_order - Get LVDS dual-link pixel order + * drm_of_lvds_get_dual_link_pixel_order - Get LVDS dual-link source pixel order * @port1: First DT port node of the Dual-link LVDS source * @port2: Second DT port node of the Dual-link LVDS source * @@ -387,19 +402,58 @@ int drm_of_lvds_get_dual_link_pixel_order(const struct device_node *port1, if (remote_p2_pt < 0) return remote_p2_pt; - /* - * A valid dual-lVDS bus is found when one remote port is marked with - * "dual-lvds-even-pixels", and the other remote port is marked with - * "dual-lvds-odd-pixels", bail out if the markers are not right. - */ - if (remote_p1_pt + remote_p2_pt != DRM_OF_LVDS_EVEN + DRM_OF_LVDS_ODD) + return __drm_of_lvds_get_dual_link_pixel_order(remote_p1_pt, remote_p2_pt); +} +EXPORT_SYMBOL_GPL(drm_of_lvds_get_dual_link_pixel_order); + +/** + * drm_of_lvds_get_dual_link_pixel_order_sink - Get LVDS dual-link sink pixel order + * @port1: First DT port node of the Dual-link LVDS sink + * @port2: Second DT port node of the Dual-link LVDS sink + * + * An LVDS dual-link connection is made of two links, with even pixels + * transitting on one link, and odd pixels on the other link. This function + * returns, for two ports of an LVDS dual-link sink, which port shall transmit + * the even and odd pixels, based on the requirements of the sink. + * + * The pixel order is determined from the dual-lvds-even-pixels and + * dual-lvds-odd-pixels properties in the sink's DT port nodes. If those + * properties are not present, or if their usage is not valid, this function + * returns -EINVAL. + * + * If either port is not connected, this function returns -EPIPE. + * + * @port1 and @port2 are typically DT sibling nodes, but may have different + * parents when, for instance, two separate LVDS decoders receive the even and + * odd pixels. + * + * Return: + * * DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS - @port1 receives even pixels and @port2 + * receives odd pixels + * * DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS - @port1 receives odd pixels and @port2 + * receives even pixels + * * -EINVAL - @port1 or @port2 are NULL + * * -EPIPE - when @port1 or @port2 are not connected + */ +int drm_of_lvds_get_dual_link_pixel_order_sink(struct device_node *port1, + struct device_node *port2) +{ + int sink_p1_pt, sink_p2_pt; + + if (!port1 || !port2) return -EINVAL; - return remote_p1_pt == DRM_OF_LVDS_EVEN ? - DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS : - DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS; + sink_p1_pt = drm_of_lvds_get_port_pixels_type(port1); + if (!sink_p1_pt) + return -EPIPE; + + sink_p2_pt = drm_of_lvds_get_port_pixels_type(port2); + if (!sink_p2_pt) + return -EPIPE; + + return __drm_of_lvds_get_dual_link_pixel_order(sink_p1_pt, sink_p2_pt); } -EXPORT_SYMBOL_GPL(drm_of_lvds_get_dual_link_pixel_order); +EXPORT_SYMBOL_GPL(drm_of_lvds_get_dual_link_pixel_order_sink); /** * drm_of_lvds_get_data_mapping - Get LVDS data mapping @@ -410,7 +464,9 @@ EXPORT_SYMBOL_GPL(drm_of_lvds_get_dual_link_pixel_order); * Return: * * MEDIA_BUS_FMT_RGB666_1X7X3_SPWG - data-mapping is "jeida-18" * * MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA - data-mapping is "jeida-24" + * * MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA - data-mapping is "jeida-30" * * MEDIA_BUS_FMT_RGB888_1X7X4_SPWG - data-mapping is "vesa-24" + * * MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG - data-mapping is "vesa-30" * * -EINVAL - the "data-mapping" property is unsupported * * -ENODEV - the "data-mapping" property is missing */ @@ -427,8 +483,12 @@ int drm_of_lvds_get_data_mapping(const struct device_node *port) return MEDIA_BUS_FMT_RGB666_1X7X3_SPWG; if (!strcmp(mapping, "jeida-24")) return MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA; + if (!strcmp(mapping, "jeida-30")) + return MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA; if (!strcmp(mapping, "vesa-24")) return MEDIA_BUS_FMT_RGB888_1X7X4_SPWG; + if (!strcmp(mapping, "vesa-30")) + return MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG; return -EINVAL; } diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c index 74412b7bf936..0a9ecc1380d2 100644 --- a/drivers/gpu/drm/drm_panic.c +++ b/drivers/gpu/drm/drm_panic.c @@ -209,6 +209,14 @@ static u32 convert_xrgb8888_to_argb2101010(u32 pix) return GENMASK(31, 30) /* set alpha bits */ | pix | ((pix >> 8) & 0x00300C03); } +static u32 convert_xrgb8888_to_abgr2101010(u32 pix) +{ + pix = ((pix & 0x00FF0000) >> 14) | + ((pix & 0x0000FF00) << 4) | + ((pix & 0x000000FF) << 22); + return GENMASK(31, 30) /* set alpha bits */ | pix | ((pix >> 8) & 0x00300C03); +} + /* * convert_from_xrgb8888 - convert one pixel from xrgb8888 to the desired format * @color: input color, in xrgb8888 format @@ -242,6 +250,8 @@ static u32 convert_from_xrgb8888(u32 color, u32 format) return convert_xrgb8888_to_xrgb2101010(color); case DRM_FORMAT_ARGB2101010: return convert_xrgb8888_to_argb2101010(color); + case DRM_FORMAT_ABGR2101010: + return convert_xrgb8888_to_abgr2101010(color); default: WARN_ONCE(1, "Can't convert to %p4cc\n", &format); return 0; diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig index 2e0e7c4079b6..f496e6cfdfe0 100644 --- a/drivers/gpu/drm/mediatek/Kconfig +++ b/drivers/gpu/drm/mediatek/Kconfig @@ -2,7 +2,7 @@ config DRM_MEDIATEK tristate "DRM Support for Mediatek SoCs" depends on DRM - depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST + depends on ARCH_MEDIATEK || COMPILE_TEST depends on COMMON_CLK depends on HAVE_ARM_SMCCC || COMPILE_TEST depends on OF diff --git a/drivers/gpu/drm/nouveau/dispnv50/tile.h b/drivers/gpu/drm/nouveau/dispnv50/tile.h new file mode 100644 index 000000000000..e2be82830cf7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/dispnv50/tile.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NV50_TILE_H__ +#define __NV50_TILE_H__ + +#include <linux/types.h> +#include <linux/math.h> + +/* + * Tiling parameters for NV50+. + * GOB = Group of bytes, the main unit for tiling blocks. + * Tiling blocks are a power of 2 number of GOB. + * All GOBs and blocks have the same width: 64 bytes (so 16 pixels in 32bits). + * tile_mode is the log2 of the number of GOB per block. + */ + +#define NV_TILE_GOB_HEIGHT_TESLA 4 /* 4 x 64 bytes = 256 bytes for a GOB on Tesla*/ +#define NV_TILE_GOB_HEIGHT 8 /* 8 x 64 bytes = 512 bytes for a GOB on Fermi and later */ +#define NV_TILE_GOB_WIDTH_BYTES 64 + +/* Number of blocks to cover the width of the framebuffer */ +static inline u32 nouveau_get_width_in_blocks(u32 stride) +{ + return DIV_ROUND_UP(stride, NV_TILE_GOB_WIDTH_BYTES); +} + +/* Return the height in pixel of one GOB */ +static inline u32 nouveau_get_gob_height(u16 family) +{ + if (family == NV_DEVICE_INFO_V0_TESLA) + return NV_TILE_GOB_HEIGHT_TESLA; + else + return NV_TILE_GOB_HEIGHT; +} + +/* Number of blocks to cover the heigth of the framebuffer */ +static inline u32 nouveau_get_height_in_blocks(u32 height, u32 gobs_in_block, u16 family) +{ + return DIV_ROUND_UP(height, nouveau_get_gob_height(family) * gobs_in_block); +} + +/* Return the GOB size in bytes */ +static inline u32 nouveau_get_gob_size(u16 family) +{ + return nouveau_get_gob_height(family) * NV_TILE_GOB_WIDTH_BYTES; +} + +/* Return the number of GOB in a block */ +static inline int nouveau_get_gobs_in_block(u32 tile_mode, u16 chipset) +{ + if (chipset >= 0xc0) + return 1 << (tile_mode >> 4); + return 1 << tile_mode; +} + +/* Return true if tile_mode is invalid */ +static inline bool nouveau_check_tile_mode(u32 tile_mode, u16 chipset) +{ + if (chipset >= 0xc0) + return (tile_mode & 0xfffff0f); + return (tile_mode & 0xfffffff0); +} + +#endif diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c index 7a2cceaee6e9..f6be426dd525 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c @@ -30,14 +30,20 @@ #include <nvhw/class/cl507e.h> #include <nvhw/class/clc37e.h> +#include <linux/iosys-map.h> + #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> -#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_fourcc.h> +#include <drm/drm_framebuffer.h> +#include <drm/drm_gem_atomic_helper.h> +#include <drm/drm_panic.h> +#include <drm/ttm/ttm_bo.h> #include "nouveau_bo.h" #include "nouveau_gem.h" +#include "tile.h" static void nv50_wndw_ctxdma_del(struct nv50_wndw_ctxdma *ctxdma) @@ -577,6 +583,114 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) return 0; } +/* Only used by drm_panic get_scanout_buffer() and set_pixel(), so it is + * protected by the drm panic spinlock + */ +static u32 nv50_panic_blk_h; + +/* Return the framebuffer offset of the start of the block where pixel(x,y) is */ +static u32 +nv50_get_block_off(unsigned int x, unsigned int y, unsigned int pitch) +{ + u32 blk_x, blk_y, blk_columns; + + blk_columns = nouveau_get_width_in_blocks(pitch); + blk_x = (x * 4) / NV_TILE_GOB_WIDTH_BYTES; + blk_y = y / nv50_panic_blk_h; + + return ((blk_y * blk_columns) + blk_x) * NV_TILE_GOB_WIDTH_BYTES * nv50_panic_blk_h; +} + +/* Turing and later have 2 level of tiles inside the block */ +static void +nv50_set_pixel_swizzle(struct drm_scanout_buffer *sb, unsigned int x, + unsigned int y, u32 color) +{ + u32 blk_off, off, swizzle; + + blk_off = nv50_get_block_off(x, y, sb->pitch[0]); + + y = y % nv50_panic_blk_h; + + /* Inside the block, use the fast address swizzle to compute the offset + * For nvidia blocklinear, bit order is yn..y3 x3 y2 x2 y1 y0 x1 x0 + */ + swizzle = (x & 3) | (y & 3) << 2 | (x & 4) << 2 | (y & 4) << 3; + swizzle |= (x & 8) << 3 | (y >> 3) << 7; + off = blk_off + swizzle * 4; + + iosys_map_wr(&sb->map[0], off, u32, color); +} + +static void +nv50_set_pixel(struct drm_scanout_buffer *sb, unsigned int x, unsigned int y, + u32 color) +{ + u32 blk_off, off; + + blk_off = nv50_get_block_off(x, y, sb->width); + + x = x % (NV_TILE_GOB_WIDTH_BYTES / 4); + y = y % nv50_panic_blk_h; + off = blk_off + x * 4 + y * NV_TILE_GOB_WIDTH_BYTES; + + iosys_map_wr(&sb->map[0], off, u32, color); +} + +static int +nv50_wndw_get_scanout_buffer(struct drm_plane *plane, struct drm_scanout_buffer *sb) +{ + struct drm_framebuffer *fb; + struct nouveau_bo *nvbo; + struct nouveau_drm *drm = nouveau_drm(plane->dev); + u16 chipset = drm->client.device.info.chipset; + u8 family = drm->client.device.info.family; + u32 tile_mode; + u8 kind; + + if (!plane->state || !plane->state->fb) + return -EINVAL; + + fb = plane->state->fb; + nvbo = nouveau_gem_object(fb->obj[0]); + + /* Don't support compressed format, or multiplane yet. */ + if (nvbo->comp || fb->format->num_planes != 1) + return -EOPNOTSUPP; + + if (nouveau_bo_map(nvbo)) { + drm_warn(plane->dev, "nouveau bo map failed, panic won't be displayed\n"); + return -ENOMEM; + } + + if (nvbo->kmap.bo_kmap_type & TTM_BO_MAP_IOMEM_MASK) + iosys_map_set_vaddr_iomem(&sb->map[0], (void __iomem *)nvbo->kmap.virtual); + else + iosys_map_set_vaddr(&sb->map[0], nvbo->kmap.virtual); + + sb->height = fb->height; + sb->width = fb->width; + sb->pitch[0] = fb->pitches[0]; + sb->format = fb->format; + + nouveau_framebuffer_get_layout(fb, &tile_mode, &kind); + if (kind) { + /* If tiling is enabled, use set_pixel() to display correctly. + * Only handle 32bits format for now. + */ + if (fb->format->cpp[0] != 4) + return -EOPNOTSUPP; + nv50_panic_blk_h = nouveau_get_gob_height(family) * + nouveau_get_gobs_in_block(tile_mode, chipset); + + if (chipset >= 0x160) + sb->set_pixel = nv50_set_pixel_swizzle; + else + sb->set_pixel = nv50_set_pixel; + } + return 0; +} + static const struct drm_plane_helper_funcs nv50_wndw_helper = { .prepare_fb = nv50_wndw_prepare_fb, @@ -584,6 +698,14 @@ nv50_wndw_helper = { .atomic_check = nv50_wndw_atomic_check, }; +static const struct drm_plane_helper_funcs +nv50_wndw_primary_helper = { + .prepare_fb = nv50_wndw_prepare_fb, + .cleanup_fb = nv50_wndw_cleanup_fb, + .atomic_check = nv50_wndw_atomic_check, + .get_scanout_buffer = nv50_wndw_get_scanout_buffer, +}; + static void nv50_wndw_atomic_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) @@ -732,7 +854,10 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev, return ret; } - drm_plane_helper_add(&wndw->plane, &nv50_wndw_helper); + if (type == DRM_PLANE_TYPE_PRIMARY) + drm_plane_helper_add(&wndw->plane, &nv50_wndw_primary_helper); + else + drm_plane_helper_add(&wndw->plane, &nv50_wndw_helper); if (wndw->func->ilut) { ret = nv50_lut_init(disp, mmu, &wndw->ilut); diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 619a3efbe8c8..add006fc8d81 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -44,6 +44,7 @@ #include <nvif/if0011.h> #include <nvif/if0013.h> #include <dispnv50/crc.h> +#include <dispnv50/tile.h> int nouveau_display_vblank_enable(struct drm_crtc *crtc) @@ -220,69 +221,29 @@ nouveau_validate_decode_mod(struct nouveau_drm *drm, return 0; } -static inline uint32_t -nouveau_get_width_in_blocks(uint32_t stride) -{ - /* GOBs per block in the x direction is always one, and GOBs are - * 64 bytes wide - */ - static const uint32_t log_block_width = 6; - - return (stride + (1 << log_block_width) - 1) >> log_block_width; -} - -static inline uint32_t -nouveau_get_height_in_blocks(struct nouveau_drm *drm, - uint32_t height, - uint32_t log_block_height_in_gobs) -{ - uint32_t log_gob_height; - uint32_t log_block_height; - - BUG_ON(drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA); - - if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI) - log_gob_height = 2; - else - log_gob_height = 3; - - log_block_height = log_block_height_in_gobs + log_gob_height; - - return (height + (1 << log_block_height) - 1) >> log_block_height; -} - static int nouveau_check_bl_size(struct nouveau_drm *drm, struct nouveau_bo *nvbo, uint32_t offset, uint32_t stride, uint32_t h, uint32_t tile_mode) { - uint32_t gob_size, bw, bh; + uint32_t gob_size, bw, bh, gobs_in_block; uint64_t bl_size; BUG_ON(drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA); - if (drm->client.device.info.chipset >= 0xc0) { - if (tile_mode & 0xF) - return -EINVAL; - tile_mode >>= 4; - } - - if (tile_mode & 0xFFFFFFF0) + if (nouveau_check_tile_mode(tile_mode, drm->client.device.info.chipset)) return -EINVAL; - if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI) - gob_size = 256; - else - gob_size = 512; - + gobs_in_block = nouveau_get_gobs_in_block(tile_mode, drm->client.device.info.chipset); bw = nouveau_get_width_in_blocks(stride); - bh = nouveau_get_height_in_blocks(drm, h, tile_mode); + bh = nouveau_get_height_in_blocks(h, gobs_in_block, drm->client.device.info.family); + gob_size = nouveau_get_gob_size(drm->client.device.info.family); - bl_size = bw * bh * (1 << tile_mode) * gob_size; + bl_size = bw * bh * gobs_in_block * gob_size; - DRM_DEBUG_KMS("offset=%u stride=%u h=%u tile_mode=0x%02x bw=%u bh=%u gob_size=%u bl_size=%llu size=%zu\n", - offset, stride, h, tile_mode, bw, bh, gob_size, bl_size, - nvbo->bo.base.size); + DRM_DEBUG_KMS("offset=%u stride=%u h=%u gobs_in_block=%u bw=%u bh=%u gob_size=%u bl_size=%llu size=%zu\n", + offset, stride, h, gobs_in_block, bw, bh, gob_size, + bl_size, nvbo->bo.base.size); if (bl_size + offset > nvbo->bo.base.size) return -ERANGE; diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c index 2d30da38c2c3..3385fd3ef41a 100644 --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c @@ -38,7 +38,7 @@ static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, return PTR_ERR(opp); dev_pm_opp_put(opp); - err = dev_pm_opp_set_rate(dev, *freq); + err = dev_pm_opp_set_rate(dev, *freq); if (!err) ptdev->pfdevfreq.current_frequency = *freq; @@ -182,6 +182,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) * if any and will avoid a switch off by regulator_late_cleanup() */ ret = dev_pm_opp_set_opp(dev, opp); + dev_pm_opp_put(opp); if (ret) { DRM_DEV_ERROR(dev, "Couldn't set recommended OPP\n"); return ret; diff --git a/drivers/gpu/drm/panthor/panthor_devfreq.c b/drivers/gpu/drm/panthor/panthor_devfreq.c index 9d0f891b9b53..ecc7a52bd688 100644 --- a/drivers/gpu/drm/panthor/panthor_devfreq.c +++ b/drivers/gpu/drm/panthor/panthor_devfreq.c @@ -163,13 +163,6 @@ int panthor_devfreq_init(struct panthor_device *ptdev) cur_freq = clk_get_rate(ptdev->clks.core); - opp = devfreq_recommended_opp(dev, &cur_freq, 0); - if (IS_ERR(opp)) - return PTR_ERR(opp); - - panthor_devfreq_profile.initial_freq = cur_freq; - ptdev->current_frequency = cur_freq; - /* Regulator coupling only takes care of synchronizing/balancing voltage * updates, but the coupled regulator needs to be enabled manually. * @@ -200,18 +193,24 @@ int panthor_devfreq_init(struct panthor_device *ptdev) return ret; } + opp = devfreq_recommended_opp(dev, &cur_freq, 0); + if (IS_ERR(opp)) + return PTR_ERR(opp); + + panthor_devfreq_profile.initial_freq = cur_freq; + ptdev->current_frequency = cur_freq; + /* * Set the recommend OPP this will enable and configure the regulator * if any and will avoid a switch off by regulator_late_cleanup() */ ret = dev_pm_opp_set_opp(dev, opp); + dev_pm_opp_put(opp); if (ret) { DRM_DEV_ERROR(dev, "Couldn't set recommended OPP\n"); return ret; } - dev_pm_opp_put(opp); - /* Find the fastest defined rate */ opp = dev_pm_opp_find_freq_floor(dev, &freq); if (IS_ERR(opp)) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index eeaf71d43191..7ce25281c74c 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -1350,6 +1350,19 @@ EXPORT_SYMBOL(drm_sched_init); * @sched: scheduler instance * * Tears down and cleans up the scheduler. + * + * This stops submission of new jobs to the hardware through + * drm_sched_backend_ops.run_job(). Consequently, drm_sched_backend_ops.free_job() + * will not be called for all jobs still in drm_gpu_scheduler.pending_list. + * There is no solution for this currently. Thus, it is up to the driver to make + * sure that + * a) drm_sched_fini() is only called after for all submitted jobs + * drm_sched_backend_ops.free_job() has been called or that + * b) the jobs for which drm_sched_backend_ops.free_job() has not been called + * after drm_sched_fini() ran are freed manually. + * + * FIXME: Take care of the above problem and prevent this function from leaking + * the jobs in drm_gpu_scheduler.pending_list under any circumstances. */ void drm_sched_fini(struct drm_gpu_scheduler *sched) { @@ -1445,8 +1458,10 @@ EXPORT_SYMBOL(drm_sched_wqueue_ready); /** * drm_sched_wqueue_stop - stop scheduler submission - * * @sched: scheduler instance + * + * Stops the scheduler from pulling new jobs from entities. It also stops + * freeing jobs automatically through drm_sched_backend_ops.free_job(). */ void drm_sched_wqueue_stop(struct drm_gpu_scheduler *sched) { @@ -1458,8 +1473,12 @@ EXPORT_SYMBOL(drm_sched_wqueue_stop); /** * drm_sched_wqueue_start - start scheduler submission - * * @sched: scheduler instance + * + * Restarts the scheduler after drm_sched_wqueue_stop() has stopped it. + * + * This function is not necessary for 'conventional' startup. The scheduler is + * fully operational after drm_sched_init() succeeded. */ void drm_sched_wqueue_start(struct drm_gpu_scheduler *sched) { diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index 57a5769fc994..3f0977d746be 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -187,7 +187,7 @@ static void blend(struct vkms_writeback_job *wb, const struct pixel_argb_u16 background_color = { .a = 0xffff }; - size_t crtc_y_limit = crtc_state->base.crtc->mode.vdisplay; + size_t crtc_y_limit = crtc_state->base.mode.vdisplay; /* * The planes are composed line-by-line to avoid heavy memory usage. It is a necessary @@ -270,7 +270,7 @@ static int compose_active_planes(struct vkms_writeback_job *active_wb, if (WARN_ON(check_format_funcs(crtc_state, active_wb))) return -EINVAL; - line_width = crtc_state->base.crtc->mode.hdisplay; + line_width = crtc_state->base.mode.hdisplay; stage_buffer.n_pixels = line_width; output_buffer.n_pixels = line_width; diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c index a40295c18b48..bbf080d32d2c 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -64,8 +64,6 @@ static int vkms_enable_vblank(struct drm_crtc *crtc) struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); struct vkms_output *out = drm_crtc_to_vkms_output(crtc); - drm_calc_timestamping_constants(crtc, &crtc->mode); - hrtimer_init(&out->vblank_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); out->vblank_hrtimer.function = &vkms_vblank_simulate; out->period_ns = ktime_set(0, vblank->framedur_ns); diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c index 0a5a185aa0b0..25a99fde126c 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -92,7 +92,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index) DRM_MODE_CONNECTOR_VIRTUAL); if (ret) { DRM_ERROR("Failed to init connector\n"); - goto err_connector; + return ret; } drm_connector_helper_add(connector, &vkms_conn_helper_funcs); @@ -131,8 +131,5 @@ err_attach: err_encoder: drm_connector_cleanup(connector); -err_connector: - drm_crtc_cleanup(crtc); - return ret; } diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c index bc724cbd5e3a..999d5c01ea81 100644 --- a/drivers/gpu/drm/vkms/vkms_writeback.c +++ b/drivers/gpu/drm/vkms/vkms_writeback.c @@ -131,8 +131,8 @@ static void vkms_wb_atomic_commit(struct drm_connector *conn, struct drm_connector_state *conn_state = wb_conn->base.state; struct vkms_crtc_state *crtc_state = output->composer_state; struct drm_framebuffer *fb = connector_state->writeback_job->fb; - u16 crtc_height = crtc_state->base.crtc->mode.vdisplay; - u16 crtc_width = crtc_state->base.crtc->mode.hdisplay; + u16 crtc_height = crtc_state->base.mode.vdisplay; + u16 crtc_width = crtc_state->base.mode.hdisplay; struct vkms_writeback_job *active_wb; struct vkms_frame_info *wb_frame_info; u32 wb_format = fb->format->format; diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h index 02d1cdd7f798..7f0256dae3f1 100644 --- a/include/drm/drm_of.h +++ b/include/drm/drm_of.h @@ -52,6 +52,8 @@ int drm_of_find_panel_or_bridge(const struct device_node *np, struct drm_bridge **bridge); int drm_of_lvds_get_dual_link_pixel_order(const struct device_node *port1, const struct device_node *port2); +int drm_of_lvds_get_dual_link_pixel_order_sink(struct device_node *port1, + struct device_node *port2); int drm_of_lvds_get_data_mapping(const struct device_node *port); int drm_of_get_data_lanes_count(const struct device_node *endpoint, const unsigned int min, const unsigned int max); @@ -110,6 +112,13 @@ drm_of_lvds_get_dual_link_pixel_order(const struct device_node *port1, } static inline int +drm_of_lvds_get_dual_link_pixel_order_sink(struct device_node *port1, + struct device_node *port2) +{ + return -EINVAL; +} + +static inline int drm_of_lvds_get_data_mapping(const struct device_node *port) { return -EINVAL; diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index d4c1d991014b..ff62056feed5 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -34,7 +34,7 @@ #define MEDIA_BUS_FMT_FIXED 0x0001 -/* RGB - next is 0x1026 */ +/* RGB - next is 0x1028 */ #define MEDIA_BUS_FMT_RGB444_1X12 0x1016 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 @@ -68,6 +68,8 @@ #define MEDIA_BUS_FMT_ARGB8888_1X32 0x100d #define MEDIA_BUS_FMT_RGB888_1X32_PADHI 0x100f #define MEDIA_BUS_FMT_RGB101010_1X30 0x1018 +#define MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG 0x1026 +#define MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA 0x1027 #define MEDIA_BUS_FMT_RGB666_1X36_CPADLO 0x1020 #define MEDIA_BUS_FMT_RGB888_1X36_CPADLO 0x1021 #define MEDIA_BUS_FMT_RGB121212_1X36 0x1019 |