diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt new file mode 100644 index 000000000000..7f040edc16fe --- /dev/null +++ b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt @@ -0,0 +1,111 @@ +Amlogic specific extensions to the Synopsys Designware HDMI Controller +====================================================================== + +The Amlogic Meson Synopsys Designware Integration is composed of : +- A Synopsys DesignWare HDMI Controller IP +- A TOP control block controlling the Clocks and PHY +- A custom HDMI PHY in order to convert video to TMDS signal + ___________________________________ +| HDMI TOP |<= HPD +|___________________________________| +| | | +| Synopsys HDMI | HDMI PHY |=> TMDS +| Controller |________________| +|___________________________________|<=> DDC + +The HDMI TOP block only supports HPD sensing. +The Synopsys HDMI Controller interrupt is routed through the +TOP Block interrupt. +Communication to the TOP Block and the Synopsys HDMI Controller is done +via a pair of dedicated addr+read/write registers. +The HDMI PHY is configured by registers in the HHI register block. + +Pixel data arrives in 4:4:4 format from the VENC block and the VPU HDMI mux +selects either the ENCI encoder for the 576i or 480i formats or the ENCP +encoder for all the other formats including interlaced HD formats. + +The VENC uses a DVI encoder on top of the ENCI or ENCP encoders to generate +DVI timings for the HDMI controller. + +Amlogic Meson GXBB, GXL and GXM SoCs families embeds the Synopsys DesignWare +HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF +audio source interfaces. + +Required properties: +- compatible: value should be different for each SoC family as : + - GXBB (S905) : "amlogic,meson-gxbb-dw-hdmi" + - GXL (S905X, S905D) : "amlogic,meson-gxl-dw-hdmi" + - GXM (S912) : "amlogic,meson-gxm-dw-hdmi" + followed by the common "amlogic,meson-gx-dw-hdmi" +- reg: Physical base address and length of the controller's registers. +- interrupts: The HDMI interrupt number +- clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks, + and the Amlogic Meson venci clocks as described in + Documentation/devicetree/bindings/clock/clock-bindings.txt, + the clocks are soc specific, the clock-names should be "iahb", "isfr", "venci" +- resets, resets-names: must have the phandles to the HDMI apb, glue and phy + resets as described in : + Documentation/devicetree/bindings/reset/reset.txt, + the reset-names should be "hdmitx_apb", "hdmitx", "hdmitx_phy" + +Required nodes: + +The connections to the HDMI ports are modeled using the OF graph +bindings specified in Documentation/devicetree/bindings/graph.txt. + +The following table lists for each supported model the port number +corresponding to each HDMI output and input. + + Port 0 Port 1 +----------------------------------------- + S905 (GXBB) VENC Input TMDS Output + S905X (GXL) VENC Input TMDS Output + S905D (GXL) VENC Input TMDS Output + S912 (GXM) VENC Input TMDS Output + +Example: + +hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; +}; + +hdmi_tx: hdmi-tx@c883a000 { + compatible = "amlogic,meson-gxbb-dw-hdmi", "amlogic,meson-gx-dw-hdmi"; + reg = <0x0 0xc883a000 0x0 0x1c>; + interrupts = ; + resets = <&reset RESET_HDMITX_CAPB3>, + <&reset RESET_HDMI_SYSTEM_RESET>, + <&reset RESET_HDMI_TX>; + reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy"; + clocks = <&clkc CLKID_HDMI_PCLK>, + <&clkc CLKID_CLK81>, + <&clkc CLKID_GCLK_VENCI_INT0>; + clock-names = "isfr", "iahb", "venci"; + #address-cells = <1>; + #size-cells = <0>; + + /* VPU VENC Input */ + hdmi_tx_venc_port: port@0 { + reg = <0>; + + hdmi_tx_in: endpoint { + remote-endpoint = <&hdmi_tx_out>; + }; + }; + + /* TMDS Output */ + hdmi_tx_tmds_port: port@1 { + reg = <1>; + + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt index 1d722f5055ab..543b07435f4f 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt @@ -17,9 +17,12 @@ Required properties: Optional properties: - power-domains: a phandle to mipi dsi power domain node. +- resets: list of phandle + reset specifier pairs, as described in [3]. +- reset-names: string reset name, must be "apb". [1] Documentation/devicetree/bindings/clock/clock-bindings.txt [2] Documentation/devicetree/bindings/media/video-interfaces.txt +[3] Documentation/devicetree/bindings/reset/reset.txt Example: mipi_dsi: mipi@ff960000 { @@ -30,6 +33,8 @@ Example: interrupts = ; clocks = <&cru SCLK_MIPI_24M>, <&cru PCLK_MIPI_DSI0>; clock-names = "ref", "pclk"; + resets = <&cru SRST_MIPIDSI0>; + reset-names = "apb"; rockchip,grf = <&grf>; status = "okay"; diff --git a/Documentation/gpu/bridge/dw-hdmi.rst b/Documentation/gpu/bridge/dw-hdmi.rst new file mode 100644 index 000000000000..486faadf00af --- /dev/null +++ b/Documentation/gpu/bridge/dw-hdmi.rst @@ -0,0 +1,15 @@ +======================================================= + drm/bridge/dw-hdmi Synopsys DesignWare HDMI Controller +======================================================= + +Synopsys DesignWare HDMI Controller +=================================== + +This section covers everything related to the Synopsys DesignWare HDMI +Controller implemented as a DRM bridge. + +Supported Input Formats and Encodings +------------------------------------- + +.. kernel-doc:: include/drm/bridge/dw_hdmi.h + :doc: Supported input formats and encodings diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index a09c721f9e89..babfb6143bd9 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst @@ -255,56 +255,6 @@ File Operations .. kernel-doc:: drivers/gpu/drm/drm_file.c :export: -IOCTLs ------- - -struct drm_ioctl_desc \*ioctls; int num_ioctls; - Driver-specific ioctls descriptors table. - -Driver-specific ioctls numbers start at DRM_COMMAND_BASE. The ioctls -descriptors table is indexed by the ioctl number offset from the base -value. Drivers can use the DRM_IOCTL_DEF_DRV() macro to initialize -the table entries. - -:: - - DRM_IOCTL_DEF_DRV(ioctl, func, flags) - -``ioctl`` is the ioctl name. Drivers must define the DRM_##ioctl and -DRM_IOCTL_##ioctl macros to the ioctl number offset from -DRM_COMMAND_BASE and the ioctl number respectively. The first macro is -private to the device while the second must be exposed to userspace in a -public header. - -``func`` is a pointer to the ioctl handler function compatible with the -``drm_ioctl_t`` type. - -:: - - typedef int drm_ioctl_t(struct drm_device *dev, void *data, - struct drm_file *file_priv); - -``flags`` is a bitmask combination of the following values. It restricts -how the ioctl is allowed to be called. - -- DRM_AUTH - Only authenticated callers allowed - -- DRM_MASTER - The ioctl can only be called on the master file handle - -- DRM_ROOT_ONLY - Only callers with the SYSADMIN capability allowed - -- DRM_CONTROL_ALLOW - The ioctl can only be called on a control - device - -- DRM_UNLOCKED - The ioctl handler will be called without locking the - DRM global mutex. This is the enforced default for kms drivers (i.e. - using the DRIVER_MODESET flag) and hence shouldn't be used any more - for new drivers. - -.. kernel-doc:: drivers/gpu/drm/drm_ioctl.c - :export: - - Misc Utilities ============== diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 76356c86e358..858457567d3d 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -160,6 +160,20 @@ other hand, a driver requires shared state between clients which is visible to user-space and accessible beyond open-file boundaries, they cannot support render nodes. +IOCTL Support on Device Nodes +============================= + +.. kernel-doc:: drivers/gpu/drm/drm_ioctl.c + :doc: driver specific ioctls + +.. kernel-doc:: include/drm/drm_ioctl.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_ioctl.c + :export: + +.. kernel-doc:: drivers/gpu/drm/drm_ioc32.c + :export: Testing and validation ====================== @@ -219,6 +233,16 @@ Debugfs Support .. kernel-doc:: drivers/gpu/drm/drm_debugfs.c :export: +Sysfs Support +============= + +.. kernel-doc:: drivers/gpu/drm/drm_sysfs.c + :doc: overview + +.. kernel-doc:: drivers/gpu/drm/drm_sysfs.c + :export: + + VBlank event handling ===================== diff --git a/Documentation/gpu/index.rst b/Documentation/gpu/index.rst index e998ee0d0dd5..c572f092739e 100644 --- a/Documentation/gpu/index.rst +++ b/Documentation/gpu/index.rst @@ -11,10 +11,12 @@ Linux GPU Driver Developer's Guide drm-kms-helpers drm-uapi i915 + meson tinydrm vc4 vga-switcheroo vgaarbiter + bridge/dw-hdmi todo .. only:: subproject and html diff --git a/Documentation/gpu/meson.rst b/Documentation/gpu/meson.rst new file mode 100644 index 000000000000..479f6f51a13b --- /dev/null +++ b/Documentation/gpu/meson.rst @@ -0,0 +1,61 @@ +============================================= +drm/meson AmLogic Meson Video Processing Unit +============================================= + +.. kernel-doc:: drivers/gpu/drm/meson/meson_drv.c + :doc: Video Processing Unit + +Video Processing Unit +===================== + +The Amlogic Meson Display controller is composed of several components +that are going to be documented below: + +.. code:: + + DMC|---------------VPU (Video Processing Unit)----------------|------HHI------| + | vd1 _______ _____________ _________________ | | + D |-------| |----| | | | | HDMI PLL | + D | vd2 | VIU | | Video Post | | Video Encoders |<---|-----VCLK | + R |-------| |----| Processing | | | | | + | osd2 | | | |---| Enci ----------|----|-----VDAC------| + R |-------| CSC |----| Scalers | | Encp ----------|----|----HDMI-TX----| + A | osd1 | | | Blenders | | Encl ----------|----|---------------| + M |-------|______|----|____________| |________________| | | + ___|__________________________________________________________|_______________| + +Video Input Unit +================ + +.. kernel-doc:: drivers/gpu/drm/meson/meson_viu.c + :doc: Video Input Unit + +Video Post Processing +===================== + +.. kernel-doc:: drivers/gpu/drm/meson/meson_vpp.c + :doc: Video Post Processing + +Video Encoder +============= + +.. kernel-doc:: drivers/gpu/drm/meson/meson_venc.c + :doc: Video Encoder + +Video Canvas Management +======================= + +.. kernel-doc:: drivers/gpu/drm/meson/meson_canvas.c + :doc: Canvas + +Video Clocks +============ + +.. kernel-doc:: drivers/gpu/drm/meson/meson_vclk.c + :doc: Video Clocks + +HDMI Video Output +================= + +.. kernel-doc:: drivers/gpu/drm/meson/meson_dw_hdmi.c + :doc: HDMI Output diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index e255b36b34a3..1bdb7356a310 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -16,7 +16,7 @@ De-midlayer drivers With the recent ``drm_bus`` cleanup patches for 3.17 it is no longer required to have a ``drm_bus`` structure set up. Drivers can directly set up the ``drm_device`` structure instead of relying on bus methods in ``drm_usb.c`` -and ``drm_platform.c``. The goal is to get rid of the driver's ``->load`` / +and ``drm_pci.c``. The goal is to get rid of the driver's ``->load`` / ``->unload`` callbacks and open-code the load/unload sequence properly, using the new two-stage ``drm_device`` setup/teardown. @@ -175,7 +175,7 @@ fine-grained per-buffer object and per-context lockings scheme. Currently the following drivers still use ``struct_mutex``: ``msm``, ``omapdrm`` and ``udl``. -Contact: Daniel Vetter +Contact: Daniel Vetter, respective driver maintainers Switch to drm_connector_list_iter for any connector_list walking ---------------------------------------------------------------- @@ -217,6 +217,8 @@ plan is to switch to per-file driver API headers, which will also structure the kerneldoc better. This should also allow more fine-grained ``#include`` directives. +In the end no .c file should need to include ``drmP.h`` anymore. + Contact: Daniel Vetter Add missing kerneldoc for exported functions @@ -244,13 +246,8 @@ be hidden so that driver writers don't accidentally end up using it. And to prevent security issues in those legacy IOCTLs from being exploited on modern drivers. This has multiple possible subtasks: -* Make sure legacy IOCTLs can't be used on modern drivers. * Extract support code for legacy features into a ``drm-legacy.ko`` kernel module and compile it only when one of the legacy drivers is enabled. -* Extract legacy functions into their own headers and remove it that from the - monolithic ``drmP.h`` header. -* Remove any lingering cruft from the OS abstraction layer from modern - drivers. This is mostly done, the only thing left is to split up ``drm_irq.c`` into legacy cruft and the parts needed by modern KMS drivers. @@ -408,23 +405,3 @@ Contact: Noralf Trønnes, Daniel Vetter Outside DRM =========== - -Better kerneldoc ----------------- - -This is pretty much done, but there's some advanced topics: - -Come up with a way to hyperlink to struct members. Currently you can hyperlink -to the struct using ``#struct_name``, but not to a member within. Would need -buy-in from kerneldoc maintainers, and the big question is how to make it work -without totally unsightly -``drm_foo_bar_really_long_structure->even_longer_memeber`` all over the text -which breaks text flow. - -Figure out how to integrate the asciidoc support for ascii-diagrams. We have a -few of those (e.g. to describe mode timings), and asciidoc supports converting -some ascii-art dialect into pngs. Would be really pretty to make that work. - -Contact: Daniel Vetter, Jani Nikula - -Jani is working on this already, hopefully lands in 4.8. diff --git a/Documentation/media/uapi/v4l/subdev-formats.rst b/Documentation/media/uapi/v4l/subdev-formats.rst index d6152c907b8b..4032d97e022d 100644 --- a/Documentation/media/uapi/v4l/subdev-formats.rst +++ b/Documentation/media/uapi/v4l/subdev-formats.rst @@ -1258,6 +1258,319 @@ The following tables list existing packed RGB formats. - b\ :sub:`2` - b\ :sub:`1` - b\ :sub:`0` + * .. _MEDIA-BUS-FMT-RGB101010-1X30: + + - MEDIA_BUS_FMT_RGB101010_1X30 + - 0x1018 + - + - 0 + - 0 + - r\ :sub:`9` + - r\ :sub:`8` + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`9` + - g\ :sub:`8` + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`9` + - b\ :sub:`8` + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + +.. raw:: latex + + \endgroup + + +The following table list existing packed 36bit wide RGB formats. + +.. tabularcolumns:: |p{4.0cm}|p{0.7cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| + +.. _v4l2-mbus-pixelcode-rgb-36: + +.. raw:: latex + + \begingroup + \tiny + \setlength{\tabcolsep}{2pt} + +.. flat-table:: 36bit RGB formats + :header-rows: 2 + :stub-columns: 0 + :widths: 36 7 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + * - Identifier + - Code + - + - :cspan:`35` Data organization + * - + - + - Bit + - 35 + - 34 + - 33 + - 32 + - 31 + - 30 + - 29 + - 28 + - 27 + - 26 + - 25 + - 24 + - 23 + - 22 + - 21 + - 20 + - 19 + - 18 + - 17 + - 16 + - 15 + - 14 + - 13 + - 12 + - 11 + - 10 + - 9 + - 8 + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + * .. _MEDIA-BUS-FMT-RGB121212-1X36: + + - MEDIA_BUS_FMT_RGB121212_1X36 + - 0x1019 + - + - r\ :sub:`11` + - r\ :sub:`10` + - r\ :sub:`9` + - r\ :sub:`8` + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`11` + - g\ :sub:`10` + - g\ :sub:`9` + - g\ :sub:`8` + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`11` + - b\ :sub:`10` + - b\ :sub:`9` + - b\ :sub:`8` + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + +.. raw:: latex + + \endgroup + + +The following table list existing packed 48bit wide RGB formats. + +.. tabularcolumns:: |p{4.0cm}|p{0.7cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| + +.. _v4l2-mbus-pixelcode-rgb-48: + +.. raw:: latex + + \begingroup + \tiny + \setlength{\tabcolsep}{2pt} + +.. flat-table:: 48bit RGB formats + :header-rows: 3 + :stub-columns: 0 + :widths: 36 7 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + * - Identifier + - Code + - + - :cspan:`31` Data organization + * - + - + - Bit + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - 47 + - 46 + - 45 + - 44 + - 43 + - 42 + - 41 + - 40 + - 39 + - 38 + - 37 + - 36 + - 35 + - 34 + - 33 + - 32 + * - + - + - + - 31 + - 30 + - 29 + - 28 + - 27 + - 26 + - 25 + - 24 + - 23 + - 22 + - 21 + - 20 + - 19 + - 18 + - 17 + - 16 + - 15 + - 14 + - 13 + - 12 + - 11 + - 10 + - 9 + - 8 + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + * .. _MEDIA-BUS-FMT-RGB161616-1X48: + + - MEDIA_BUS_FMT_RGB161616_1X48 + - 0x101a + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - r\ :sub:`15` + - r\ :sub:`14` + - r\ :sub:`13` + - r\ :sub:`12` + - r\ :sub:`11` + - r\ :sub:`10` + - r\ :sub:`9` + - r\ :sub:`8` + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + * - + - + - + - g\ :sub:`15` + - g\ :sub:`14` + - g\ :sub:`13` + - g\ :sub:`12` + - g\ :sub:`11` + - g\ :sub:`10` + - g\ :sub:`9` + - g\ :sub:`8` + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`15` + - b\ :sub:`14` + - b\ :sub:`13` + - b\ :sub:`12` + - b\ :sub:`11` + - b\ :sub:`10` + - b\ :sub:`9` + - b\ :sub:`8` + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` .. raw:: latex @@ -2344,7 +2657,8 @@ The format code is made of the following information. - The number of bus samples per pixel. Pixels that are wider than the bus width must be transferred in multiple samples. Common values are - 1, 1.5 (encoded as 1_5) and 2. + 0.5 (encoded as 0_5; in this case two pixels are transferred per bus + sample), 1, 1.5 (encoded as 1_5) and 2. - The bus width. When the bus width is larger than the number of bits per pixel component, several components are packed in a single bus @@ -5962,6 +6276,78 @@ the following codes. - v\ :sub:`2` - v\ :sub:`1` - v\ :sub:`0` + * .. _MEDIA-BUS-FMT-UYYVYY8-0-5X24: + + - MEDIA_BUS_FMT_UYYVYY8_0_5X24 + - 0x2026 + - + - + - + - + - + - + - + - + - + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * - + - + - + - + - + - + - + - + - + - + - + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` * .. _MEDIA-BUS-FMT-UYVY12-1X24: - MEDIA_BUS_FMT_UYVY12_1X24 @@ -6287,6 +6673,78 @@ the following codes. - v\ :sub:`2` - v\ :sub:`1` - v\ :sub:`0` + * .. _MEDIA-BUS-FMT-UYYVYY10-0-5X30: + + - MEDIA_BUS_FMT_UYYVYY10_0_5X30 + - 0x2027 + - + - + - + - u\ :sub:`9` + - u\ :sub:`8` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * - + - + - + - + - + - v\ :sub:`9` + - v\ :sub:`8` + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` * .. _MEDIA-BUS-FMT-AYUV8-1X32: - MEDIA_BUS_FMT_AYUV8_1X32 @@ -6326,6 +6784,506 @@ the following codes. - v\ :sub:`0` +.. raw:: latex + + \endgroup + + +The following table list existing packed 36bit wide YUV formats. + +.. raw:: latex + + \begingroup + \tiny + \setlength{\tabcolsep}{2pt} + +.. tabularcolumns:: |p{4.0cm}|p{0.7cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| + +.. _v4l2-mbus-pixelcode-yuv8-36bit: + +.. flat-table:: 36bit YUV Formats + :header-rows: 2 + :stub-columns: 0 + :widths: 36 7 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + * - Identifier + - Code + - + - :cspan:`35` Data organization + * - + - + - Bit + - 35 + - 34 + - 33 + - 32 + - 31 + - 30 + - 29 + - 28 + - 27 + - 26 + - 25 + - 24 + - 23 + - 22 + - 21 + - 10 + - 19 + - 18 + - 17 + - 16 + - 15 + - 14 + - 13 + - 12 + - 11 + - 10 + - 9 + - 8 + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + * .. _MEDIA-BUS-FMT-UYYVYY12-0-5X36: + + - MEDIA_BUS_FMT_UYYVYY12_0_5X36 + - 0x2028 + - + - u\ :sub:`11` + - u\ :sub:`10` + - u\ :sub:`9` + - u\ :sub:`8` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * - + - + - + - v\ :sub:`11` + - v\ :sub:`10` + - v\ :sub:`9` + - v\ :sub:`8` + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * .. _MEDIA-BUS-FMT-YUV12-1X36: + + - MEDIA_BUS_FMT_YUV12_1X36 + - 0x2029 + - + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + - u\ :sub:`11` + - u\ :sub:`10` + - u\ :sub:`9` + - u\ :sub:`8` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + - v\ :sub:`11` + - v\ :sub:`10` + - v\ :sub:`9` + - v\ :sub:`8` + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + + +.. raw:: latex + + \endgroup + + +The following table list existing packed 48bit wide YUV formats. + +.. raw:: latex + + \begingroup + \tiny + \setlength{\tabcolsep}{2pt} + +.. tabularcolumns:: |p{4.0cm}|p{0.7cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| + +.. _v4l2-mbus-pixelcode-yuv8-48bit: + +.. flat-table:: 48bit YUV Formats + :header-rows: 3 + :stub-columns: 0 + :widths: 36 7 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + * - Identifier + - Code + - + - :cspan:`31` Data organization + * - + - + - Bit + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - 47 + - 46 + - 45 + - 44 + - 43 + - 42 + - 41 + - 40 + - 39 + - 38 + - 37 + - 36 + - 35 + - 34 + - 33 + - 32 + * - + - + - + - 31 + - 30 + - 29 + - 28 + - 27 + - 26 + - 25 + - 24 + - 23 + - 22 + - 21 + - 10 + - 19 + - 18 + - 17 + - 16 + - 15 + - 14 + - 13 + - 12 + - 11 + - 10 + - 9 + - 8 + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + * .. _MEDIA-BUS-FMT-YUV16-1X48: + + - MEDIA_BUS_FMT_YUV16_1X48 + - 0x202a + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - y\ :sub:`15` + - y\ :sub:`14` + - y\ :sub:`13` + - y\ :sub:`12` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`8` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * - + - + - + - u\ :sub:`15` + - u\ :sub:`14` + - u\ :sub:`13` + - u\ :sub:`12` + - u\ :sub:`11` + - u\ :sub:`10` + - u\ :sub:`9` + - u\ :sub:`8` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + - v\ :sub:`15` + - v\ :sub:`14` + - v\ :sub:`13` + - v\ :sub:`12` + - v\ :sub:`11` + - v\ :sub:`10` + - v\ :sub:`9` + - v\ :sub:`8` + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + * .. _MEDIA-BUS-FMT-UYYVYY16-0-5X48: + + - MEDIA_BUS_FMT_UYYVYY16_0_5X48 + - 0x202b + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - u\ :sub:`15` + - u\ :sub:`14` + - u\ :sub:`13` + - u\ :sub:`12` + - u\ :sub:`11` + - u\ :sub:`10` + - u\ :sub:`9` + - u\ :sub:`8` + - u\ :sub:`7` + - u\ :sub:`6` + - u\ :sub:`5` + - u\ :sub:`4` + - u\ :sub:`3` + - u\ :sub:`2` + - u\ :sub:`1` + - u\ :sub:`0` + * - + - + - + - y\ :sub:`15` + - y\ :sub:`14` + - y\ :sub:`13` + - y\ :sub:`12` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + - y\ :sub:`15` + - y\ :sub:`14` + - y\ :sub:`13` + - y\ :sub:`12` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`8` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + * - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - v\ :sub:`15` + - v\ :sub:`14` + - v\ :sub:`13` + - v\ :sub:`12` + - v\ :sub:`11` + - v\ :sub:`10` + - v\ :sub:`9` + - v\ :sub:`8` + - v\ :sub:`7` + - v\ :sub:`6` + - v\ :sub:`5` + - v\ :sub:`4` + - v\ :sub:`3` + - v\ :sub:`2` + - v\ :sub:`1` + - v\ :sub:`0` + * - + - + - + - y\ :sub:`15` + - y\ :sub:`14` + - y\ :sub:`13` + - y\ :sub:`12` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`9` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + - y\ :sub:`15` + - y\ :sub:`14` + - y\ :sub:`13` + - y\ :sub:`12` + - y\ :sub:`11` + - y\ :sub:`10` + - y\ :sub:`8` + - y\ :sub:`8` + - y\ :sub:`7` + - y\ :sub:`6` + - y\ :sub:`5` + - y\ :sub:`4` + - y\ :sub:`3` + - y\ :sub:`2` + - y\ :sub:`1` + - y\ :sub:`0` + + .. raw:: latex \endgroup diff --git a/MAINTAINERS b/MAINTAINERS index c2eb0373a02d..7df09152b2e0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4256,7 +4256,8 @@ W: http://linux-meson.com/ S: Supported F: drivers/gpu/drm/meson/ F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt -T: git git://anongit.freedesktop.org/drm/drm-meson +F: Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt +F: Documentation/gpu/meson.rst T: git git://anongit.freedesktop.org/drm/drm-misc DRM DRIVERS FOR EXYNOS diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 0007b792827b..f72aaacbe023 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1059,7 +1059,11 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) int ret; struct dma_buf *buf_obj; struct dma_buf_attachment *attach_obj; - int count = 0, attach_count; + struct reservation_object *robj; + struct reservation_object_list *fobj; + struct dma_fence *fence; + unsigned seq; + int count = 0, attach_count, shared_count, i; size_t size = 0; ret = mutex_lock_interruptible(&db_list.lock); @@ -1068,7 +1072,8 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) return ret; seq_puts(s, "\nDma-buf Objects:\n"); - seq_puts(s, "size\tflags\tmode\tcount\texp_name\n"); + seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\n", + "size", "flags", "mode", "count"); list_for_each_entry(buf_obj, &db_list.head, list_node) { ret = mutex_lock_interruptible(&buf_obj->lock); @@ -1085,6 +1090,34 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) file_count(buf_obj->file), buf_obj->exp_name); + robj = buf_obj->resv; + while (true) { + seq = read_seqcount_begin(&robj->seq); + rcu_read_lock(); + fobj = rcu_dereference(robj->fence); + shared_count = fobj ? fobj->shared_count : 0; + fence = rcu_dereference(robj->fence_excl); + if (!read_seqcount_retry(&robj->seq, seq)) + break; + rcu_read_unlock(); + } + + if (fence) + seq_printf(s, "\tExclusive fence: %s %s %ssignalled\n", + fence->ops->get_driver_name(fence), + fence->ops->get_timeline_name(fence), + dma_fence_is_signaled(fence) ? "" : "un"); + for (i = 0; i < shared_count; i++) { + fence = rcu_dereference(fobj->shared[i]); + if (!dma_fence_get_rcu(fence)) + continue; + seq_printf(s, "\tShared fence: %s %s %ssignalled\n", + fence->ops->get_driver_name(fence), + fence->ops->get_timeline_name(fence), + dma_fence_is_signaled(fence) ? "" : "un"); + } + rcu_read_unlock(); + seq_puts(s, "\tAttached Devices:\n"); attach_count = 0; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 2b78d58c9c35..ba98d35340a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -2618,7 +2618,8 @@ static void dce_v10_0_cursor_reset(struct drm_crtc *crtc) } static int dce_v10_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size) + u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); int i; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index fec2a69f3ae2..e59bc42df18c 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -2638,7 +2638,8 @@ static void dce_v11_0_cursor_reset(struct drm_crtc *crtc) } static int dce_v11_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size) + u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); int i; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index 6604bcf783b7..307269bda4fa 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -1985,7 +1985,8 @@ static void dce_v6_0_cursor_reset(struct drm_crtc *crtc) } static int dce_v6_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size) + u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); int i; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index e10c82f7a37a..6df7a28e8aac 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -2469,7 +2469,8 @@ static void dce_v8_0_cursor_reset(struct drm_crtc *crtc) } static int dce_v8_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size) + u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); int i; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c index 5c51f9a97811..81a24b6b4846 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c @@ -165,7 +165,8 @@ static void dce_virtual_bandwidth_update(struct amdgpu_device *adev) } static int dce_virtual_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, - u16 *green, u16 *blue, uint32_t size) + u16 *green, u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); int i; diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index 0e74880b5e94..0f49c4b12772 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -392,30 +392,14 @@ static int compare_dev(struct device *dev, void *data) static int hdlcd_probe(struct platform_device *pdev) { - struct device_node *port, *ep; + struct device_node *port; struct component_match *match = NULL; - if (!pdev->dev.of_node) - return -ENODEV; - /* there is only one output port inside each device, find it */ - ep = of_graph_get_next_endpoint(pdev->dev.of_node, NULL); - if (!ep) + port = of_graph_get_remote_node(pdev->dev.of_node, 0, 0); + if (!port) return -ENODEV; - if (!of_device_is_available(ep)) { - of_node_put(ep); - return -ENODEV; - } - - /* add the remote encoder port as component */ - port = of_graph_get_remote_port_parent(ep); - of_node_put(ep); - if (!port || !of_device_is_available(port)) { - of_node_put(port); - return -EAGAIN; - } - drm_of_component_match_add(&pdev->dev, &match, compare_dev, port); of_node_put(port); diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index ea2546f766c2..898c2b58e73d 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -283,7 +283,6 @@ static int malidp_bind(struct device *dev) { struct resource *res; struct drm_device *drm; - struct device_node *ep; struct malidp_drm *malidp; struct malidp_hw_device *hwdev; struct platform_device *pdev = to_platform_device(dev); @@ -398,12 +397,7 @@ static int malidp_bind(struct device *dev) goto init_fail; /* Set the CRTC's port so that the encoder component can find it */ - ep = of_graph_get_next_endpoint(dev->of_node, NULL); - if (!ep) { - ret = -EINVAL; - goto port_fail; - } - malidp->crtc.port = of_get_next_parent(ep); + malidp->crtc.port = of_graph_get_port_by_id(dev->of_node, 0); ret = component_bind_all(dev, drm); if (ret) { @@ -458,7 +452,6 @@ irq_init_fail: bind_fail: of_node_put(malidp->crtc.port); malidp->crtc.port = NULL; -port_fail: malidp_fini(drm); init_fail: drm->dev_private = NULL; @@ -516,30 +509,17 @@ static int malidp_compare_dev(struct device *dev, void *data) static int malidp_platform_probe(struct platform_device *pdev) { - struct device_node *port, *ep; + struct device_node *port; struct component_match *match = NULL; if (!pdev->dev.of_node) return -ENODEV; /* there is only one output port inside each device, find it */ - ep = of_graph_get_next_endpoint(pdev->dev.of_node, NULL); - if (!ep) + port = of_graph_get_remote_node(pdev->dev.of_node, 0, 0); + if (!port) return -ENODEV; - if (!of_device_is_available(ep)) { - of_node_put(ep); - return -ENODEV; - } - - /* add the remote encoder port as component */ - port = of_graph_get_remote_port_parent(ep); - of_node_put(ep); - if (!port || !of_device_is_available(port)) { - of_node_put(port); - return -EAGAIN; - } - drm_of_component_match_add(&pdev->dev, &match, malidp_compare_dev, port); of_node_put(port); diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 47b78e52691c..aaef0a652f10 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -645,7 +645,8 @@ static void ast_crtc_reset(struct drm_crtc *crtc) } static int ast_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size) + u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct ast_crtc *ast_crtc = to_ast_crtc(crtc); int i; diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c index e7799b6ee829..f987b4572d4a 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include "atmel_hlcdc_dc.h" @@ -152,29 +152,11 @@ static const struct drm_connector_funcs atmel_hlcdc_panel_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static int atmel_hlcdc_check_endpoint(struct drm_device *dev, - const struct of_endpoint *ep) -{ - struct device_node *np; - void *obj; - - np = of_graph_get_remote_port_parent(ep->local_node); - - obj = of_drm_find_panel(np); - if (!obj) - obj = of_drm_find_bridge(np); - - of_node_put(np); - - return obj ? 0 : -EPROBE_DEFER; -} - static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, - const struct of_endpoint *ep) + const struct device_node *np) { struct atmel_hlcdc_dc *dc = dev->dev_private; struct atmel_hlcdc_rgb_output *output; - struct device_node *np; struct drm_panel *panel; struct drm_bridge *bridge; int ret; @@ -195,13 +177,11 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, output->encoder.possible_crtcs = 0x1; - np = of_graph_get_remote_port_parent(ep->local_node); + ret = drm_of_find_panel_or_bridge(np, 0, 0, &panel, &bridge); + if (ret) + return ret; - ret = -EPROBE_DEFER; - - panel = of_drm_find_panel(np); if (panel) { - of_node_put(np); output->connector.dpms = DRM_MODE_DPMS_OFF; output->connector.polled = DRM_CONNECTOR_POLL_CONNECT; drm_connector_helper_add(&output->connector, @@ -226,9 +206,6 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, return 0; } - bridge = of_drm_find_bridge(np); - of_node_put(np); - if (bridge) { ret = drm_bridge_attach(&output->encoder, bridge, NULL); if (!ret) @@ -243,31 +220,23 @@ err_encoder_cleanup: int atmel_hlcdc_create_outputs(struct drm_device *dev) { - struct device_node *ep_np = NULL; - struct of_endpoint ep; - int ret; + struct device_node *remote; + int ret, endpoint = 0; - for_each_endpoint_of_node(dev->dev->of_node, ep_np) { - ret = of_graph_parse_endpoint(ep_np, &ep); - if (!ret) - ret = atmel_hlcdc_check_endpoint(dev, &ep); + while (true) { + /* Loop thru possible multiple connections to the output */ + remote = of_graph_get_remote_node(dev->dev->of_node, 0, + endpoint++); + if (!remote) + break; - if (ret) { - of_node_put(ep_np); + ret = atmel_hlcdc_attach_endpoint(dev, remote); + of_node_put(remote); + if (ret) return ret; - } } - for_each_endpoint_of_node(dev->dev->of_node, ep_np) { - ret = of_graph_parse_endpoint(ep_np, &ep); - if (!ret) - ret = atmel_hlcdc_attach_endpoint(dev, &ep); - - if (ret) { - of_node_put(ep_np); - return ret; - } - } - - return 0; + if (!endpoint) + return -ENODEV; + return ret; } diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c index 8b210373cfa2..ac804f81e2f6 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7533.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c @@ -232,7 +232,6 @@ void adv7533_detach_dsi(struct adv7511 *adv) int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv) { u32 num_lanes; - struct device_node *endpoint; of_property_read_u32(np, "adi,dsi-lanes", &num_lanes); @@ -241,17 +240,10 @@ int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv) adv->num_dsi_lanes = num_lanes; - endpoint = of_graph_get_next_endpoint(np, NULL); - if (!endpoint) + adv->host_node = of_graph_get_remote_node(np, 0, 0); + if (!adv->host_node) return -ENODEV; - adv->host_node = of_graph_get_remote_port_parent(endpoint); - if (!adv->host_node) { - of_node_put(endpoint); - return -ENODEV; - } - - of_node_put(endpoint); of_node_put(adv->host_node); adv->use_timing_gen = !of_property_read_bool(np, diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index c26997afd3cf..4c758ed51939 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1439,13 +1439,19 @@ void analogix_dp_unbind(struct device *dev, struct device *master, struct analogix_dp_device *dp = dev_get_drvdata(dev); analogix_dp_bridge_disable(dp->bridge); + dp->connector.funcs->destroy(&dp->connector); + dp->encoder->funcs->destroy(dp->encoder); if (dp->plat_data->panel) { if (drm_panel_unprepare(dp->plat_data->panel)) DRM_ERROR("failed to turnoff the panel\n"); + if (drm_panel_detach(dp->plat_data->panel)) + DRM_ERROR("failed to detach the panel\n"); } + drm_dp_aux_unregister(&dp->aux); pm_runtime_disable(dev); + clk_disable_unprepare(dp->clock); } EXPORT_SYMBOL_GPL(analogix_dp_unbind); diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c index 63e113bd21d2..831a606c4706 100644 --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c @@ -154,21 +154,12 @@ static const struct drm_bridge_funcs dumb_vga_bridge_funcs = { static struct i2c_adapter *dumb_vga_retrieve_ddc(struct device *dev) { - struct device_node *end_node, *phandle, *remote; + struct device_node *phandle, *remote; struct i2c_adapter *ddc; - end_node = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1); - if (!end_node) { - dev_err(dev, "Missing connector endpoint\n"); - return ERR_PTR(-ENODEV); - } - - remote = of_graph_get_remote_port_parent(end_node); - of_node_put(end_node); - if (!remote) { - dev_err(dev, "Enable to parse remote node\n"); + remote = of_graph_get_remote_node(dev->of_node, 1, -1); + if (!remote) return ERR_PTR(-EINVAL); - } phandle = of_parse_phandle(remote, "ddc-i2c-bus", 0); of_node_put(remote); diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c index cfc606a13a6d..11f11086a68f 100644 --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -279,10 +279,6 @@ static int ge_b850v3_lvds_init(struct device *dev) return -ENOMEM; } - ge_b850v3_lvds_ptr->bridge.funcs = &ge_b850v3_lvds_funcs; - ge_b850v3_lvds_ptr->bridge.of_node = dev->of_node; - drm_bridge_add(&ge_b850v3_lvds_ptr->bridge); - success: mutex_unlock(&ge_b850v3_lvds_dev_mutex); return 0; @@ -317,6 +313,11 @@ static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c, ge_b850v3_lvds_ptr->stdp4028_i2c = stdp4028_i2c; i2c_set_clientdata(stdp4028_i2c, ge_b850v3_lvds_ptr); + /* drm bridge initialization */ + ge_b850v3_lvds_ptr->bridge.funcs = &ge_b850v3_lvds_funcs; + ge_b850v3_lvds_ptr->bridge.of_node = dev->of_node; + drm_bridge_add(&ge_b850v3_lvds_ptr->bridge); + /* Clear pending interrupts since power up. */ i2c_smbus_write_word_data(stdp4028_i2c, STDP4028_DPTX_IRQ_STS_REG, diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index 27f98c518dde..351704390d02 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -20,8 +20,8 @@ #include #include #include -#include +#include #include #include "drm_crtc.h" @@ -292,7 +292,6 @@ static int ptn3460_probe(struct i2c_client *client, { struct device *dev = &client->dev; struct ptn3460_bridge *ptn_bridge; - struct device_node *endpoint, *panel_node; int ret; ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL); @@ -300,16 +299,9 @@ static int ptn3460_probe(struct i2c_client *client, return -ENOMEM; } - endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); - if (endpoint) { - panel_node = of_graph_get_remote_port_parent(endpoint); - if (panel_node) { - ptn_bridge->panel = of_drm_find_panel(panel_node); - of_node_put(panel_node); - if (!ptn_bridge->panel) - return -EPROBE_DEFER; - } - } + ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &ptn_bridge->panel, NULL); + if (ret) + return ret; ptn_bridge->client = client; diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c index ac8cc5b50d9f..1dcec3b97e67 100644 --- a/drivers/gpu/drm/bridge/parade-ps8622.c +++ b/drivers/gpu/drm/bridge/parade-ps8622.c @@ -22,10 +22,10 @@ #include #include #include -#include #include #include +#include #include #include "drmP.h" @@ -536,7 +536,6 @@ static int ps8622_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; - struct device_node *endpoint, *panel_node; struct ps8622_bridge *ps8622; int ret; @@ -544,16 +543,9 @@ static int ps8622_probe(struct i2c_client *client, if (!ps8622) return -ENOMEM; - endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); - if (endpoint) { - panel_node = of_graph_get_remote_port_parent(endpoint); - if (panel_node) { - ps8622->panel = of_drm_find_panel(panel_node); - of_node_put(panel_node); - if (!ps8622->panel) - return -EPROBE_DEFER; - } - } + ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &ps8622->panel, NULL); + if (ret) + return ret; ps8622->client = client; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 32f02e92e0b9..3bc856cc6daa 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -30,18 +30,15 @@ #include #include +#include +#include + #include "dw-hdmi.h" #include "dw-hdmi-audio.h" #define DDC_SEGMENT_ADDR 0x30 #define HDMI_EDID_LEN 512 -#define RGB 0 -#define YCBCR444 1 -#define YCBCR422_16BITS 2 -#define YCBCR422_8BITS 3 -#define XVYCC444 4 - enum hdmi_datamap { RGB444_8B = 0x01, RGB444_10B = 0x03, @@ -95,10 +92,10 @@ struct hdmi_vmode { }; struct hdmi_data_info { - unsigned int enc_in_format; - unsigned int enc_out_format; - unsigned int enc_color_depth; - unsigned int colorimetry; + unsigned int enc_in_bus_format; + unsigned int enc_out_bus_format; + unsigned int enc_in_encoding; + unsigned int enc_out_encoding; unsigned int pix_repet_factor; unsigned int hdcp_enable; struct hdmi_vmode video_mode; @@ -567,6 +564,78 @@ void dw_hdmi_audio_disable(struct dw_hdmi *hdmi) } EXPORT_SYMBOL_GPL(dw_hdmi_audio_disable); +static bool hdmi_bus_fmt_is_rgb(unsigned int bus_format) +{ + switch (bus_format) { + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_RGB101010_1X30: + case MEDIA_BUS_FMT_RGB121212_1X36: + case MEDIA_BUS_FMT_RGB161616_1X48: + return true; + + default: + return false; + } +} + +static bool hdmi_bus_fmt_is_yuv444(unsigned int bus_format) +{ + switch (bus_format) { + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_YUV12_1X36: + case MEDIA_BUS_FMT_YUV16_1X48: + return true; + + default: + return false; + } +} + +static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format) +{ + switch (bus_format) { + case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_UYVY10_1X20: + case MEDIA_BUS_FMT_UYVY12_1X24: + return true; + + default: + return false; + } +} + +static int hdmi_bus_fmt_color_depth(unsigned int bus_format) +{ + switch (bus_format) { + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + return 8; + + case MEDIA_BUS_FMT_RGB101010_1X30: + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_UYVY10_1X20: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + return 10; + + case MEDIA_BUS_FMT_RGB121212_1X36: + case MEDIA_BUS_FMT_YUV12_1X36: + case MEDIA_BUS_FMT_UYVY12_1X24: + case MEDIA_BUS_FMT_UYYVYY12_0_5X36: + return 12; + + case MEDIA_BUS_FMT_RGB161616_1X48: + case MEDIA_BUS_FMT_YUV16_1X48: + case MEDIA_BUS_FMT_UYYVYY16_0_5X48: + return 16; + + default: + return 0; + } +} + /* * this submodule is responsible for the video data synchronization. * for example, for RGB 4:4:4 input, the data map is defined as @@ -579,37 +648,49 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi) int color_format = 0; u8 val; - if (hdmi->hdmi_data.enc_in_format == RGB) { - if (hdmi->hdmi_data.enc_color_depth == 8) - color_format = 0x01; - else if (hdmi->hdmi_data.enc_color_depth == 10) - color_format = 0x03; - else if (hdmi->hdmi_data.enc_color_depth == 12) - color_format = 0x05; - else if (hdmi->hdmi_data.enc_color_depth == 16) - color_format = 0x07; - else - return; - } else if (hdmi->hdmi_data.enc_in_format == YCBCR444) { - if (hdmi->hdmi_data.enc_color_depth == 8) - color_format = 0x09; - else if (hdmi->hdmi_data.enc_color_depth == 10) - color_format = 0x0B; - else if (hdmi->hdmi_data.enc_color_depth == 12) - color_format = 0x0D; - else if (hdmi->hdmi_data.enc_color_depth == 16) - color_format = 0x0F; - else - return; - } else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) { - if (hdmi->hdmi_data.enc_color_depth == 8) - color_format = 0x16; - else if (hdmi->hdmi_data.enc_color_depth == 10) - color_format = 0x14; - else if (hdmi->hdmi_data.enc_color_depth == 12) - color_format = 0x12; - else - return; + switch (hdmi->hdmi_data.enc_in_bus_format) { + case MEDIA_BUS_FMT_RGB888_1X24: + color_format = 0x01; + break; + case MEDIA_BUS_FMT_RGB101010_1X30: + color_format = 0x03; + break; + case MEDIA_BUS_FMT_RGB121212_1X36: + color_format = 0x05; + break; + case MEDIA_BUS_FMT_RGB161616_1X48: + color_format = 0x07; + break; + + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + color_format = 0x09; + break; + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + color_format = 0x0B; + break; + case MEDIA_BUS_FMT_YUV12_1X36: + case MEDIA_BUS_FMT_UYYVYY12_0_5X36: + color_format = 0x0D; + break; + case MEDIA_BUS_FMT_YUV16_1X48: + case MEDIA_BUS_FMT_UYYVYY16_0_5X48: + color_format = 0x0F; + break; + + case MEDIA_BUS_FMT_UYVY8_1X16: + color_format = 0x16; + break; + case MEDIA_BUS_FMT_UYVY10_1X20: + color_format = 0x14; + break; + case MEDIA_BUS_FMT_UYVY12_1X24: + color_format = 0x12; + break; + + default: + return; } val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE | @@ -632,26 +713,30 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi) static int is_color_space_conversion(struct dw_hdmi *hdmi) { - return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format; + return hdmi->hdmi_data.enc_in_bus_format != hdmi->hdmi_data.enc_out_bus_format; } static int is_color_space_decimation(struct dw_hdmi *hdmi) { - if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS) + if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) return 0; - if (hdmi->hdmi_data.enc_in_format == RGB || - hdmi->hdmi_data.enc_in_format == YCBCR444) + + if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_in_bus_format) || + hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_in_bus_format)) return 1; + return 0; } static int is_color_space_interpolation(struct dw_hdmi *hdmi) { - if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS) + if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_in_bus_format)) return 0; - if (hdmi->hdmi_data.enc_out_format == RGB || - hdmi->hdmi_data.enc_out_format == YCBCR444) + + if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) || + hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) return 1; + return 0; } @@ -662,15 +747,16 @@ static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi) u32 csc_scale = 1; if (is_color_space_conversion(hdmi)) { - if (hdmi->hdmi_data.enc_out_format == RGB) { - if (hdmi->hdmi_data.colorimetry == - HDMI_COLORIMETRY_ITU_601) + if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) { + if (hdmi->hdmi_data.enc_out_encoding == + V4L2_YCBCR_ENC_601) csc_coeff = &csc_coeff_rgb_out_eitu601; else csc_coeff = &csc_coeff_rgb_out_eitu709; - } else if (hdmi->hdmi_data.enc_in_format == RGB) { - if (hdmi->hdmi_data.colorimetry == - HDMI_COLORIMETRY_ITU_601) + } else if (hdmi_bus_fmt_is_rgb( + hdmi->hdmi_data.enc_in_bus_format)) { + if (hdmi->hdmi_data.enc_out_encoding == + V4L2_YCBCR_ENC_601) csc_coeff = &csc_coeff_rgb_in_eitu601; else csc_coeff = &csc_coeff_rgb_in_eitu709; @@ -708,16 +794,23 @@ static void hdmi_video_csc(struct dw_hdmi *hdmi) else if (is_color_space_decimation(hdmi)) decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3; - if (hdmi->hdmi_data.enc_color_depth == 8) + switch (hdmi_bus_fmt_color_depth(hdmi->hdmi_data.enc_out_bus_format)) { + case 8: color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP; - else if (hdmi->hdmi_data.enc_color_depth == 10) + break; + case 10: color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP; - else if (hdmi->hdmi_data.enc_color_depth == 12) + break; + case 12: color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP; - else if (hdmi->hdmi_data.enc_color_depth == 16) + break; + case 16: color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP; - else + break; + + default: return; + } /* Configure the CSC registers */ hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG); @@ -740,32 +833,43 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi) struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data; u8 val, vp_conf; - if (hdmi_data->enc_out_format == RGB || - hdmi_data->enc_out_format == YCBCR444) { - if (!hdmi_data->enc_color_depth) { - output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; - } else if (hdmi_data->enc_color_depth == 8) { + if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) || + hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) { + switch (hdmi_bus_fmt_color_depth( + hdmi->hdmi_data.enc_out_bus_format)) { + case 8: color_depth = 4; output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; - } else if (hdmi_data->enc_color_depth == 10) { + break; + case 10: color_depth = 5; - } else if (hdmi_data->enc_color_depth == 12) { + break; + case 12: color_depth = 6; - } else if (hdmi_data->enc_color_depth == 16) { + break; + case 16: color_depth = 7; - } else { + break; + default: + output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; + } + } else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) { + switch (hdmi_bus_fmt_color_depth( + hdmi->hdmi_data.enc_out_bus_format)) { + case 0: + case 8: + remap_size = HDMI_VP_REMAP_YCC422_16bit; + break; + case 10: + remap_size = HDMI_VP_REMAP_YCC422_20bit; + break; + case 12: + remap_size = HDMI_VP_REMAP_YCC422_24bit; + break; + + default: return; } - } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) { - if (!hdmi_data->enc_color_depth || - hdmi_data->enc_color_depth == 8) - remap_size = HDMI_VP_REMAP_YCC422_16bit; - else if (hdmi_data->enc_color_depth == 10) - remap_size = HDMI_VP_REMAP_YCC422_20bit; - else if (hdmi_data->enc_color_depth == 12) - remap_size = HDMI_VP_REMAP_YCC422_24bit; - else - return; output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422; } else { return; @@ -1111,10 +1215,46 @@ static enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi, connector_status_connected : connector_status_disconnected; } +static void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data, + bool force, bool disabled, bool rxsense) +{ + u8 old_mask = hdmi->phy_mask; + + if (force || disabled || !rxsense) + hdmi->phy_mask |= HDMI_PHY_RX_SENSE; + else + hdmi->phy_mask &= ~HDMI_PHY_RX_SENSE; + + if (old_mask != hdmi->phy_mask) + hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); +} + +static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data) +{ + /* + * Configure the PHY RX SENSE and HPD interrupts polarities and clear + * any pending interrupt. + */ + hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0); + hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, + HDMI_IH_PHY_STAT0); + + /* Enable cable hot plug irq. */ + hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); + + /* Clear and unmute interrupts. */ + hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, + HDMI_IH_PHY_STAT0); + hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE), + HDMI_IH_MUTE_PHY_STAT0); +} + static const struct dw_hdmi_phy_ops dw_hdmi_synopsys_phy_ops = { .init = dw_hdmi_phy_init, .disable = dw_hdmi_phy_disable, .read_hpd = dw_hdmi_phy_read_hpd, + .update_hpd = dw_hdmi_phy_update_hpd, + .setup_hpd = dw_hdmi_phy_setup_hpd, }; /* ----------------------------------------------------------------------------- @@ -1148,28 +1288,36 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) /* Initialise info frame from DRM mode */ drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); - if (hdmi->hdmi_data.enc_out_format == YCBCR444) + if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) frame.colorspace = HDMI_COLORSPACE_YUV444; - else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS) + else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) frame.colorspace = HDMI_COLORSPACE_YUV422; else frame.colorspace = HDMI_COLORSPACE_RGB; /* Set up colorimetry */ - if (hdmi->hdmi_data.enc_out_format == XVYCC444) { - frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; - if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601) - frame.extended_colorimetry = + switch (hdmi->hdmi_data.enc_out_encoding) { + case V4L2_YCBCR_ENC_601: + if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV601) + frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; + else + frame.colorimetry = HDMI_COLORIMETRY_ITU_601; + frame.extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; - else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/ - frame.extended_colorimetry = + break; + case V4L2_YCBCR_ENC_709: + if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV709) + frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; + else + frame.colorimetry = HDMI_COLORIMETRY_ITU_709; + frame.extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_709; - } else if (hdmi->hdmi_data.enc_out_format != RGB) { - frame.colorimetry = hdmi->hdmi_data.colorimetry; - frame.extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; - } else { /* Carries no data */ - frame.colorimetry = HDMI_COLORIMETRY_NONE; - frame.extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; + break; + default: /* Carries no data */ + frame.colorimetry = HDMI_COLORIMETRY_ITU_601; + frame.extended_colorimetry = + HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; + break; } frame.scan_mode = HDMI_SCAN_MODE_NONE; @@ -1498,19 +1646,30 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) (hdmi->vic == 21) || (hdmi->vic == 22) || (hdmi->vic == 2) || (hdmi->vic == 3) || (hdmi->vic == 17) || (hdmi->vic == 18)) - hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601; + hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_601; else - hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709; + hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_709; hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0; - /* TODO: Get input format from IPU (via FB driver interface) */ - hdmi->hdmi_data.enc_in_format = RGB; + /* TOFIX: Get input format from plat data or fallback to RGB888 */ + if (hdmi->plat_data->input_bus_format) + hdmi->hdmi_data.enc_in_bus_format = + hdmi->plat_data->input_bus_format; + else + hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24; - hdmi->hdmi_data.enc_out_format = RGB; + /* TOFIX: Get input encoding from plat data or fallback to none */ + if (hdmi->plat_data->input_bus_encoding) + hdmi->hdmi_data.enc_in_encoding = + hdmi->plat_data->input_bus_encoding; + else + hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT; + + /* TOFIX: Default to RGB888 output format */ + hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24; - hdmi->hdmi_data.enc_color_depth = 8; hdmi->hdmi_data.pix_repet_factor = 0; hdmi->hdmi_data.hdcp_enable = 0; hdmi->hdmi_data.video_mode.mdataenablepolarity = true; @@ -1558,8 +1717,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) return 0; } -/* Wait until we are registered to enable interrupts */ -static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi) +static void dw_hdmi_setup_i2c(struct dw_hdmi *hdmi) { hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL, HDMI_PHY_I2CM_INT_ADDR); @@ -1567,15 +1725,6 @@ static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi) hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL | HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL, HDMI_PHY_I2CM_CTLINT_ADDR); - - /* enable cable hot plug irq */ - hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); - - /* Clear Hotplug interrupts */ - hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, - HDMI_IH_PHY_STAT0); - - return 0; } static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi) @@ -1682,15 +1831,10 @@ static void dw_hdmi_update_power(struct dw_hdmi *hdmi) */ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) { - u8 old_mask = hdmi->phy_mask; - - if (hdmi->force || hdmi->disabled || !hdmi->rxsense) - hdmi->phy_mask |= HDMI_PHY_RX_SENSE; - else - hdmi->phy_mask &= ~HDMI_PHY_RX_SENSE; - - if (old_mask != hdmi->phy_mask) - hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); + if (hdmi->phy.ops->update_hpd) + hdmi->phy.ops->update_hpd(hdmi, hdmi->phy.data, + hdmi->force, hdmi->disabled, + hdmi->rxsense); } static enum drm_connector_status @@ -1882,6 +2026,41 @@ static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id) return ret; } +void __dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense) +{ + mutex_lock(&hdmi->mutex); + + if (!hdmi->force) { + /* + * If the RX sense status indicates we're disconnected, + * clear the software rxsense status. + */ + if (!rx_sense) + hdmi->rxsense = false; + + /* + * Only set the software rxsense status when both + * rxsense and hpd indicates we're connected. + * This avoids what seems to be bad behaviour in + * at least iMX6S versions of the phy. + */ + if (hpd) + hdmi->rxsense = true; + + dw_hdmi_update_power(hdmi); + dw_hdmi_update_phy_mask(hdmi); + } + mutex_unlock(&hdmi->mutex); +} + +void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense) +{ + struct dw_hdmi *hdmi = dev_get_drvdata(dev); + + __dw_hdmi_setup_rx_sense(hdmi, hpd, rx_sense); +} +EXPORT_SYMBOL_GPL(dw_hdmi_setup_rx_sense); + static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) { struct dw_hdmi *hdmi = dev_id; @@ -1914,30 +2093,10 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) * ask the source to re-read the EDID. */ if (intr_stat & - (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) { - mutex_lock(&hdmi->mutex); - if (!hdmi->force) { - /* - * If the RX sense status indicates we're disconnected, - * clear the software rxsense status. - */ - if (!(phy_stat & HDMI_PHY_RX_SENSE)) - hdmi->rxsense = false; - - /* - * Only set the software rxsense status when both - * rxsense and hpd indicates we're connected. - * This avoids what seems to be bad behaviour in - * at least iMX6S versions of the phy. - */ - if (phy_stat & HDMI_PHY_HPD) - hdmi->rxsense = true; - - dw_hdmi_update_power(hdmi); - dw_hdmi_update_phy_mask(hdmi); - } - mutex_unlock(&hdmi->mutex); - } + (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) + __dw_hdmi_setup_rx_sense(hdmi, + phy_stat & HDMI_PHY_HPD, + phy_stat & HDMI_PHY_RX_SENSE); if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { dev_dbg(hdmi->dev, "EVENT=%s\n", @@ -2204,29 +2363,15 @@ __dw_hdmi_probe(struct platform_device *pdev, hdmi->ddc = NULL; } - /* - * Configure registers related to HDMI interrupt - * generation before registering IRQ. - */ - hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0); - - /* Clear Hotplug interrupts */ - hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, - HDMI_IH_PHY_STAT0); - hdmi->bridge.driver_private = hdmi; hdmi->bridge.funcs = &dw_hdmi_bridge_funcs; #ifdef CONFIG_OF hdmi->bridge.of_node = pdev->dev.of_node; #endif - ret = dw_hdmi_fb_registered(hdmi); - if (ret) - goto err_iahb; - - /* Unmute interrupts */ - hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE), - HDMI_IH_MUTE_PHY_STAT0); + dw_hdmi_setup_i2c(hdmi); + if (hdmi->phy.ops->setup_hpd) + hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data); memset(&pdevinfo, 0, sizeof(pdevinfo)); pdevinfo.parent = dev; diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index de9ffb49e9f6..5c26488e7a2d 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1244,7 +1244,6 @@ static const struct regmap_config tc_regmap_config = { static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; - struct device_node *ep; struct tc_data *tc; int ret; @@ -1255,29 +1254,9 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) tc->dev = dev; /* port@2 is the output port */ - ep = of_graph_get_endpoint_by_regs(dev->of_node, 2, -1); - if (ep) { - struct device_node *remote; - - remote = of_graph_get_remote_port_parent(ep); - if (!remote) { - dev_warn(dev, "endpoint %s not connected\n", - ep->full_name); - of_node_put(ep); - return -ENODEV; - } - of_node_put(ep); - tc->panel = of_drm_find_panel(remote); - if (tc->panel) { - dev_dbg(dev, "found panel %s\n", remote->full_name); - } else { - dev_dbg(dev, "waiting for panel %s\n", - remote->full_name); - of_node_put(remote); - return -EPROBE_DEFER; - } - of_node_put(remote); - } + ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &tc->panel, NULL); + if (ret) + return ret; /* Shut down GPIO is optional */ tc->sd_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH); diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index 7d519b46aee4..eee4efda829e 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -165,18 +165,13 @@ static irqreturn_t tfp410_hpd_irq_thread(int irq, void *arg) static int tfp410_get_connector_properties(struct tfp410 *dvi) { - struct device_node *ep = NULL, *connector_node = NULL; - struct device_node *ddc_phandle = NULL; + struct device_node *connector_node, *ddc_phandle; int ret = 0; /* port@1 is the connector node */ - ep = of_graph_get_endpoint_by_regs(dvi->dev->of_node, 1, -1); - if (!ep) - goto fail; - - connector_node = of_graph_get_remote_port_parent(ep); + connector_node = of_graph_get_remote_node(dvi->dev->of_node, 1, -1); if (!connector_node) - goto fail; + return -ENODEV; dvi->hpd = fwnode_get_named_gpiod(&connector_node->fwnode, "hpd-gpios", 0, GPIOD_IN, "hpd"); @@ -199,10 +194,10 @@ static int tfp410_get_connector_properties(struct tfp410 *dvi) else ret = -EPROBE_DEFER; -fail: - of_node_put(ep); - of_node_put(connector_node); of_node_put(ddc_phandle); + +fail: + of_node_put(connector_node); return ret; } diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c index ed43ab10ac99..53f6f0f84206 100644 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -327,7 +327,8 @@ static void cirrus_crtc_commit(struct drm_crtc *crtc) * but it's a requirement that we provide the function */ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t size) + u16 *blue, uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc); int i; diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 9b892af7811a..f32506a7c1d6 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1516,19 +1516,9 @@ EXPORT_SYMBOL(drm_atomic_add_affected_planes); void drm_atomic_legacy_backoff(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; - unsigned crtc_mask = 0; - struct drm_crtc *crtc; int ret; bool global = false; - drm_for_each_crtc(crtc, dev) { - if (crtc->acquire_ctx != state->acquire_ctx) - continue; - - crtc_mask |= drm_crtc_mask(crtc); - crtc->acquire_ctx = NULL; - } - if (WARN_ON(dev->mode_config.acquire_ctx == state->acquire_ctx)) { global = true; @@ -1542,10 +1532,6 @@ retry: if (ret) goto retry; - drm_for_each_crtc(crtc, dev) - if (drm_crtc_mask(crtc) & crtc_mask) - crtc->acquire_ctx = state->acquire_ctx; - if (global) dev->mode_config.acquire_ctx = state->acquire_ctx; } @@ -1690,6 +1676,44 @@ static void drm_atomic_print_state(const struct drm_atomic_state *state) drm_atomic_connector_print_state(&p, connector_state); } +static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p, + bool take_locks) +{ + struct drm_mode_config *config = &dev->mode_config; + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + + if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) + return; + + list_for_each_entry(plane, &config->plane_list, head) { + if (take_locks) + drm_modeset_lock(&plane->mutex, NULL); + drm_atomic_plane_print_state(p, plane->state); + if (take_locks) + drm_modeset_unlock(&plane->mutex); + } + + list_for_each_entry(crtc, &config->crtc_list, head) { + if (take_locks) + drm_modeset_lock(&crtc->mutex, NULL); + drm_atomic_crtc_print_state(p, crtc->state); + if (take_locks) + drm_modeset_unlock(&crtc->mutex); + } + + drm_connector_list_iter_begin(dev, &conn_iter); + if (take_locks) + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + drm_for_each_connector_iter(connector, &conn_iter) + drm_atomic_connector_print_state(p, connector->state); + if (take_locks) + drm_modeset_unlock(&dev->mode_config.connection_mutex); + drm_connector_list_iter_end(&conn_iter); +} + /** * drm_state_dump - dump entire device atomic state * @dev: the drm device @@ -1707,25 +1731,7 @@ static void drm_atomic_print_state(const struct drm_atomic_state *state) */ void drm_state_dump(struct drm_device *dev, struct drm_printer *p) { - struct drm_mode_config *config = &dev->mode_config; - struct drm_plane *plane; - struct drm_crtc *crtc; - struct drm_connector *connector; - struct drm_connector_list_iter conn_iter; - - if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) - return; - - list_for_each_entry(plane, &config->plane_list, head) - drm_atomic_plane_print_state(p, plane->state); - - list_for_each_entry(crtc, &config->crtc_list, head) - drm_atomic_crtc_print_state(p, crtc->state); - - drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) - drm_atomic_connector_print_state(p, connector->state); - drm_connector_list_iter_end(&conn_iter); + __drm_state_dump(dev, p, false); } EXPORT_SYMBOL(drm_state_dump); @@ -1736,9 +1742,7 @@ static int drm_state_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; struct drm_printer p = drm_seq_file_printer(m); - drm_modeset_lock_all(dev); - drm_state_dump(dev, &p); - drm_modeset_unlock_all(dev); + __drm_state_dump(dev, &p, true); return 0; } @@ -2077,94 +2081,6 @@ static void complete_crtc_signaling(struct drm_device *dev, kfree(fence_state); } -int drm_atomic_remove_fb(struct drm_framebuffer *fb) -{ - struct drm_modeset_acquire_ctx ctx; - struct drm_device *dev = fb->dev; - struct drm_atomic_state *state; - struct drm_plane *plane; - struct drm_connector *conn; - struct drm_connector_state *conn_state; - int i, ret = 0; - unsigned plane_mask; - - state = drm_atomic_state_alloc(dev); - if (!state) - return -ENOMEM; - - drm_modeset_acquire_init(&ctx, 0); - state->acquire_ctx = &ctx; - -retry: - plane_mask = 0; - ret = drm_modeset_lock_all_ctx(dev, &ctx); - if (ret) - goto unlock; - - drm_for_each_plane(plane, dev) { - struct drm_plane_state *plane_state; - - if (plane->state->fb != fb) - continue; - - plane_state = drm_atomic_get_plane_state(state, plane); - if (IS_ERR(plane_state)) { - ret = PTR_ERR(plane_state); - goto unlock; - } - - if (plane_state->crtc->primary == plane) { - struct drm_crtc_state *crtc_state; - - crtc_state = drm_atomic_get_existing_crtc_state(state, plane_state->crtc); - - ret = drm_atomic_add_affected_connectors(state, plane_state->crtc); - if (ret) - goto unlock; - - crtc_state->active = false; - ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); - if (ret) - goto unlock; - } - - drm_atomic_set_fb_for_plane(plane_state, NULL); - ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); - if (ret) - goto unlock; - - plane_mask |= BIT(drm_plane_index(plane)); - - plane->old_fb = plane->fb; - } - - for_each_connector_in_state(state, conn, conn_state, i) { - ret = drm_atomic_set_crtc_for_connector(conn_state, NULL); - - if (ret) - goto unlock; - } - - if (plane_mask) - ret = drm_atomic_commit(state); - -unlock: - if (plane_mask) - drm_atomic_clean_old_fb(dev, plane_mask, ret); - - if (ret == -EDEADLK) { - drm_modeset_backoff(&ctx); - goto retry; - } - - drm_atomic_state_put(state); - - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); - - return ret; -} - int drm_mode_atomic_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index c3994b4d5f32..8be9719284b0 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -459,10 +459,20 @@ mode_fixup(struct drm_atomic_state *state) * * Check the state object to see if the requested state is physically possible. * This does all the crtc and connector related computations for an atomic - * update and adds any additional connectors needed for full modesets and calls - * down into &drm_crtc_helper_funcs.mode_fixup and - * &drm_encoder_helper_funcs.mode_fixup or - * &drm_encoder_helper_funcs.atomic_check functions of the driver backend. + * update and adds any additional connectors needed for full modesets. It calls + * the various per-object callbacks in the follow order: + * + * 1. &drm_connector_helper_funcs.atomic_best_encoder for determining the new encoder. + * 2. &drm_connector_helper_funcs.atomic_check to validate the connector state. + * 3. If it's determined a modeset is needed then all connectors on the affected crtc + * crtc are added and &drm_connector_helper_funcs.atomic_check is run on them. + * 4. &drm_bridge_funcs.mode_fixup is called on all encoder bridges. + * 5. &drm_encoder_helper_funcs.atomic_check is called to validate any encoder state. + * This function is only called when the encoder will be part of a configured crtc, + * it must not be used for implementing connector property validation. + * If this function is NULL, &drm_atomic_encoder_helper_funcs.mode_fixup is called + * instead. + * 6. &drm_crtc_helper_funcs.mode_fixup is called last, to fix up the mode with crtc constraints. * * &drm_crtc_state.mode_changed is set when the input mode is changed. * &drm_crtc_state.connectors_changed is set when a connector is added or @@ -492,8 +502,12 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, struct drm_connector *connector; struct drm_connector_state *old_connector_state, *new_connector_state; int i, ret; + unsigned connectors_mask = 0; for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + bool has_connectors = + !!new_crtc_state->connector_mask; + if (!drm_mode_equal(&old_crtc_state->mode, &new_crtc_state->mode)) { DRM_DEBUG_ATOMIC("[CRTC:%d:%s] mode changed\n", crtc->base.id, crtc->name); @@ -515,13 +529,28 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, new_crtc_state->mode_changed = true; new_crtc_state->connectors_changed = true; } + + if (old_crtc_state->active != new_crtc_state->active) { + DRM_DEBUG_ATOMIC("[CRTC:%d:%s] active changed\n", + crtc->base.id, crtc->name); + new_crtc_state->active_changed = true; + } + + if (new_crtc_state->enable != has_connectors) { + DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enabled/connectors mismatch\n", + crtc->base.id, crtc->name); + + return -EINVAL; + } } - ret = handle_conflicting_encoders(state, state->legacy_set_config); + ret = handle_conflicting_encoders(state, false); if (ret) return ret; for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) { + const struct drm_connector_helper_funcs *funcs = connector->helper_private; + /* * This only sets crtc->connectors_changed for routing changes, * drivers must set crtc->connectors_changed themselves when @@ -539,6 +568,13 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, new_connector_state->link_status) new_crtc_state->connectors_changed = true; } + + if (funcs->atomic_check) + ret = funcs->atomic_check(connector, new_connector_state); + if (ret) + return ret; + + connectors_mask += BIT(i); } /* @@ -548,20 +584,6 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, * crtc only changed its mode but has the same set of connectors. */ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { - bool has_connectors = - !!new_crtc_state->connector_mask; - - /* - * We must set ->active_changed after walking connectors for - * otherwise an update that only changes active would result in - * a full modeset because update_connector_routing force that. - */ - if (old_crtc_state->active != new_crtc_state->active) { - DRM_DEBUG_ATOMIC("[CRTC:%d:%s] active changed\n", - crtc->base.id, crtc->name); - new_crtc_state->active_changed = true; - } - if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) continue; @@ -577,13 +599,22 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, ret = drm_atomic_add_affected_planes(state, crtc); if (ret != 0) return ret; + } - if (new_crtc_state->enable != has_connectors) { - DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enabled/connectors mismatch\n", - crtc->base.id, crtc->name); + /* + * Iterate over all connectors again, to make sure atomic_check() + * has been called on them when a modeset is forced. + */ + for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) { + const struct drm_connector_helper_funcs *funcs = connector->helper_private; - return -EINVAL; - } + if (connectors_mask & BIT(i)) + continue; + + if (funcs->atomic_check) + ret = funcs->atomic_check(connector, new_connector_state); + if (ret) + return ret; } return mode_fixup(state); @@ -2289,12 +2320,15 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set, if (!state) return -ENOMEM; - state->legacy_set_config = true; state->acquire_ctx = ctx; ret = __drm_atomic_helper_set_config(set, state); if (ret != 0) goto fail; + ret = handle_conflicting_encoders(state, true); + if (ret) + return ret; + ret = drm_atomic_commit(state); fail: @@ -2622,14 +2656,22 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_duplicated_state); int drm_atomic_helper_resume(struct drm_device *dev, struct drm_atomic_state *state) { - struct drm_mode_config *config = &dev->mode_config; + struct drm_modeset_acquire_ctx ctx; int err; drm_mode_config_reset(dev); - drm_modeset_lock_all(dev); - err = drm_atomic_helper_commit_duplicated_state(state, config->acquire_ctx); - drm_modeset_unlock_all(dev); + drm_modeset_acquire_init(&ctx, 0); + while (1) { + err = drm_atomic_helper_commit_duplicated_state(state, &ctx); + if (err != -EDEADLK) + break; + + drm_modeset_backoff(&ctx); + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); return err; } @@ -2975,7 +3017,7 @@ int drm_atomic_helper_connector_dpms(struct drm_connector *connector, if (!state) return -ENOMEM; - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); + state->acquire_ctx = crtc->dev->mode_config.acquire_ctx; retry: crtc_state = drm_atomic_get_crtc_state(state, crtc); if (IS_ERR(crtc_state)) { @@ -3471,6 +3513,7 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); * @green: green correction table * @blue: green correction table * @size: size of the tables + * @ctx: lock acquire context * * Implements support for legacy gamma correction table for drivers * that support color management through the DEGAMMA_LUT/GAMMA_LUT @@ -3478,7 +3521,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); */ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, - uint32_t size) + uint32_t size, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev = crtc->dev; struct drm_mode_config *config = &dev->mode_config; @@ -3509,8 +3553,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, blob_data[i].blue = blue[i]; } - state->acquire_ctx = crtc->dev->mode_config.acquire_ctx; -retry: + state->acquire_ctx = ctx; crtc_state = drm_atomic_get_crtc_state(state, crtc); if (IS_ERR(crtc_state)) { ret = PTR_ERR(crtc_state); @@ -3534,18 +3577,10 @@ retry: goto fail; ret = drm_atomic_commit(state); -fail: - if (ret == -EDEADLK) - goto backoff; +fail: drm_atomic_state_put(state); drm_property_blob_put(blob); return ret; - -backoff: - drm_atomic_state_clear(state); - drm_atomic_legacy_backoff(state); - - goto retry; } EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set); diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index cc23b9a505c0..533f3a3e6877 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -218,28 +218,28 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, struct drm_crtc *crtc; void *r_base, *g_base, *b_base; int size; + struct drm_modeset_acquire_ctx ctx; int ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - drm_modeset_lock_all(dev); crtc = drm_crtc_find(dev, crtc_lut->crtc_id); - if (!crtc) { - ret = -ENOENT; - goto out; - } + if (!crtc) + return -ENOENT; - if (crtc->funcs->gamma_set == NULL) { - ret = -ENOSYS; - goto out; - } + if (crtc->funcs->gamma_set == NULL) + return -ENOSYS; /* memcpy into gamma store */ - if (crtc_lut->gamma_size != crtc->gamma_size) { - ret = -EINVAL; + if (crtc_lut->gamma_size != crtc->gamma_size) + return -EINVAL; + + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock_all_ctx(dev, &ctx); + if (ret) goto out; - } size = crtc_lut->gamma_size * (sizeof(uint16_t)); r_base = crtc->gamma_store; @@ -260,10 +260,17 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, goto out; } - ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); + ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, + crtc->gamma_size, &ctx); out: - drm_modeset_unlock_all(dev); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + return ret; } @@ -295,19 +302,15 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - drm_modeset_lock_all(dev); crtc = drm_crtc_find(dev, crtc_lut->crtc_id); - if (!crtc) { - ret = -ENOENT; - goto out; - } + if (!crtc) + return -ENOENT; /* memcpy into gamma store */ - if (crtc_lut->gamma_size != crtc->gamma_size) { - ret = -EINVAL; - goto out; - } + if (crtc_lut->gamma_size != crtc->gamma_size) + return -EINVAL; + drm_modeset_lock(&crtc->mutex, NULL); size = crtc_lut->gamma_size * (sizeof(uint16_t)); r_base = crtc->gamma_store; if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { @@ -327,6 +330,6 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, goto out; } out: - drm_modeset_unlock_all(dev); + drm_modeset_unlock(&crtc->mutex); return ret; } diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index d69e180fc563..5af25ce5bf7c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -576,6 +576,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, } DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); + mutex_lock(&crtc->dev->mode_config.mutex); drm_modeset_acquire_init(&ctx, 0); retry: ret = drm_modeset_lock_all_ctx(crtc->dev, &ctx); @@ -721,6 +722,7 @@ out: } drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); + mutex_unlock(&crtc->dev->mode_config.mutex); return ret; } diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 8c04275cf226..d077c5490041 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -182,7 +182,6 @@ int drm_atomic_get_property(struct drm_mode_object *obj, struct drm_property *property, uint64_t *val); int drm_mode_atomic_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_atomic_remove_fb(struct drm_framebuffer *fb); /* drm_plane.c */ diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index e65becd964a1..a0ea3241c651 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -109,6 +109,42 @@ static DEFINE_MUTEX(kernel_fb_helper_lock); for (({ lockdep_assert_held(&(fbh)->dev->mode_config.mutex); }), \ i__ = 0; i__ < (fbh)->connector_count; i__++) +int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, + struct drm_connector *connector) +{ + struct drm_fb_helper_connector *fb_conn; + struct drm_fb_helper_connector **temp; + unsigned int count; + + if (!drm_fbdev_emulation) + return 0; + + WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); + + count = fb_helper->connector_count + 1; + + if (count > fb_helper->connector_info_alloc_count) { + size_t size = count * sizeof(fb_conn); + + temp = krealloc(fb_helper->connector_info, size, GFP_KERNEL); + if (!temp) + return -ENOMEM; + + fb_helper->connector_info_alloc_count = count; + fb_helper->connector_info = temp; + } + + fb_conn = kzalloc(sizeof(*fb_conn), GFP_KERNEL); + if (!fb_conn) + return -ENOMEM; + + drm_connector_get(connector); + fb_conn->connector = connector; + fb_helper->connector_info[fb_helper->connector_count++] = fb_conn; + return 0; +} +EXPORT_SYMBOL(drm_fb_helper_add_one_connector); + /** * drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev * emulation helper @@ -162,36 +198,6 @@ out: } EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); -int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector) -{ - struct drm_fb_helper_connector **temp; - struct drm_fb_helper_connector *fb_helper_connector; - - if (!drm_fbdev_emulation) - return 0; - - WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); - if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) { - temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector *) * (fb_helper->connector_count + 1), GFP_KERNEL); - if (!temp) - return -ENOMEM; - - fb_helper->connector_info_alloc_count = fb_helper->connector_count + 1; - fb_helper->connector_info = temp; - } - - - fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); - if (!fb_helper_connector) - return -ENOMEM; - - drm_connector_get(connector); - fb_helper_connector->connector = connector; - fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; - return 0; -} -EXPORT_SYMBOL(drm_fb_helper_add_one_connector); - int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector) { @@ -213,9 +219,9 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, fb_helper_connector = fb_helper->connector_info[i]; drm_connector_put(fb_helper_connector->connector); - for (j = i + 1; j < fb_helper->connector_count; j++) { + for (j = i + 1; j < fb_helper->connector_count; j++) fb_helper->connector_info[j - 1] = fb_helper->connector_info[j]; - } + fb_helper->connector_count--; kfree(fb_helper_connector); @@ -250,7 +256,8 @@ static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc) g_base = r_base + crtc->gamma_size; b_base = g_base + crtc->gamma_size; - crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); + crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, + crtc->gamma_size, NULL); } /** @@ -275,6 +282,9 @@ int drm_fb_helper_debug_enter(struct fb_info *info) if (funcs->mode_set_base_atomic == NULL) continue; + if (drm_drv_uses_atomic_modeset(mode_set->crtc->dev)) + continue; + drm_fb_helper_save_lut_atomic(mode_set->crtc, helper); funcs->mode_set_base_atomic(mode_set->crtc, mode_set->fb, @@ -316,6 +326,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info) for (i = 0; i < helper->crtc_count; i++) { struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set; + crtc = mode_set->crtc; funcs = crtc->helper_private; fb = drm_mode_config_fb(crtc); @@ -331,6 +342,9 @@ int drm_fb_helper_debug_leave(struct fb_info *info) if (funcs->mode_set_base_atomic == NULL) continue; + if (drm_drv_uses_atomic_modeset(crtc->dev)) + continue; + drm_fb_helper_restore_lut_atomic(mode_set->crtc); funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x, crtc->y, LEAVE_ATOMIC_MODE_SET); @@ -346,7 +360,7 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper) struct drm_plane *plane; struct drm_atomic_state *state; int i, ret; - unsigned plane_mask; + unsigned int plane_mask; state = drm_atomic_state_alloc(dev); if (!state) @@ -378,7 +392,7 @@ retry: goto fail; } - for(i = 0; i < fb_helper->crtc_count; i++) { + for (i = 0; i < fb_helper->crtc_count; i++) { struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; ret = __drm_atomic_helper_set_config(mode_set, state); @@ -404,17 +418,12 @@ backoff: goto retry; } -static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) +static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper) { struct drm_device *dev = fb_helper->dev; struct drm_plane *plane; int i; - drm_warn_on_modeset_not_all_locked(dev); - - if (drm_drv_uses_atomic_modeset(dev)) - return restore_fbdev_mode_atomic(fb_helper); - drm_for_each_plane(plane, dev) { if (plane->type != DRM_PLANE_TYPE_PRIMARY) drm_plane_force_disable(plane); @@ -448,6 +457,18 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) return 0; } +static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) +{ + struct drm_device *dev = fb_helper->dev; + + drm_warn_on_modeset_not_all_locked(dev); + + if (drm_drv_uses_atomic_modeset(dev)) + return restore_fbdev_mode_atomic(fb_helper); + else + return restore_fbdev_mode_legacy(fb_helper); +} + /** * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration * @fb_helper: fbcon to restore @@ -488,8 +509,10 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) struct drm_crtc *crtc; int bound = 0, crtcs_bound = 0; - /* Sometimes user space wants everything disabled, so don't steal the - * display if there's a master. */ + /* + * Sometimes user space wants everything disabled, so don't steal the + * display if there's a master. + */ if (READ_ONCE(dev->master)) return false; @@ -537,6 +560,7 @@ static bool drm_fb_helper_force_kernel_mode(void) static void drm_fb_helper_restore_work_fn(struct work_struct *ignored) { bool ret; + ret = drm_fb_helper_force_kernel_mode(); if (ret == true) DRM_ERROR("Failed to restore crtc configuration\n"); @@ -870,9 +894,8 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) mutex_lock(&kernel_fb_helper_lock); if (!list_empty(&fb_helper->kernel_fb_list)) { list_del(&fb_helper->kernel_fb_list); - if (list_empty(&kernel_fb_helper_list)) { + if (list_empty(&kernel_fb_helper_list)) unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); - } } mutex_unlock(&kernel_fb_helper_lock); @@ -1165,6 +1188,7 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, (blue << info->var.blue.offset); if (info->var.transp.length > 0) { u32 mask = (1 << info->var.transp.length) - 1; + mask <<= info->var.transp.offset; value |= mask; } @@ -1447,7 +1471,7 @@ static int pan_display_atomic(struct fb_var_screeninfo *var, struct drm_atomic_state *state; struct drm_plane *plane; int i, ret; - unsigned plane_mask; + unsigned int plane_mask; state = drm_atomic_state_alloc(dev); if (!state) @@ -1456,7 +1480,7 @@ static int pan_display_atomic(struct fb_var_screeninfo *var, state->acquire_ctx = dev->mode_config.acquire_ctx; retry: plane_mask = 0; - for(i = 0; i < fb_helper->crtc_count; i++) { + for (i = 0; i < fb_helper->crtc_count; i++) { struct drm_mode_set *mode_set; mode_set = &fb_helper->crtc_info[i].mode_set; @@ -1496,34 +1520,14 @@ backoff: goto retry; } -/** - * drm_fb_helper_pan_display - implementation for &fb_ops.fb_pan_display - * @var: updated screen information - * @info: fbdev registered by the helper - */ -int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, +static int pan_display_legacy(struct fb_var_screeninfo *var, struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; - struct drm_device *dev = fb_helper->dev; struct drm_mode_set *modeset; int ret = 0; int i; - if (oops_in_progress) - return -EBUSY; - - drm_modeset_lock_all(dev); - if (!drm_fb_helper_is_bound(fb_helper)) { - drm_modeset_unlock_all(dev); - return -EBUSY; - } - - if (drm_drv_uses_atomic_modeset(dev)) { - ret = pan_display_atomic(var, info); - goto unlock; - } - for (i = 0; i < fb_helper->crtc_count; i++) { modeset = &fb_helper->crtc_info[i].mode_set; @@ -1538,8 +1542,37 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, } } } -unlock: + + return ret; +} + +/** + * drm_fb_helper_pan_display - implementation for &fb_ops.fb_pan_display + * @var: updated screen information + * @info: fbdev registered by the helper + */ +int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct drm_fb_helper *fb_helper = info->par; + struct drm_device *dev = fb_helper->dev; + int ret; + + if (oops_in_progress) + return -EBUSY; + + drm_modeset_lock_all(dev); + if (!drm_fb_helper_is_bound(fb_helper)) { + drm_modeset_unlock_all(dev); + return -EBUSY; + } + + if (drm_drv_uses_atomic_modeset(dev)) + ret = pan_display_atomic(var, info); + else + ret = pan_display_legacy(var, info); drm_modeset_unlock_all(dev); + return ret; } EXPORT_SYMBOL(drm_fb_helper_pan_display); @@ -1561,11 +1594,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); sizes.surface_depth = 24; sizes.surface_bpp = 32; - sizes.fb_width = (unsigned)-1; - sizes.fb_height = (unsigned)-1; + sizes.fb_width = (u32)-1; + sizes.fb_height = (u32)-1; - /* if driver picks 8 or 16 by default use that - for both depth/bpp */ + /* if driver picks 8 or 16 by default use that for both depth/bpp */ if (preferred_bpp != sizes.surface_bpp) sizes.surface_depth = sizes.surface_bpp = preferred_bpp; @@ -1630,6 +1662,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, for (j = 0; j < mode_set->num_connectors; j++) { struct drm_connector *connector = mode_set->connectors[j]; + if (connector->has_tile) { lasth = (connector->tile_h_loc == (connector->num_h_tile - 1)); lastv = (connector->tile_v_loc == (connector->num_v_tile - 1)); @@ -1645,8 +1678,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, } if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { - /* hmm everyone went away - assume VGA cable just fell out - and will come back later. */ + /* + * hmm everyone went away - assume VGA cable just fell out + * and will come back later. + */ DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n"); sizes.fb_width = sizes.surface_width = 1024; sizes.fb_height = sizes.surface_height = 768; @@ -1703,7 +1738,6 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, info->fix.accel = FB_ACCEL_NONE; info->fix.line_length = pitch; - return; } EXPORT_SYMBOL(drm_fb_helper_fill_fix); @@ -1725,6 +1759,7 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe uint32_t fb_width, uint32_t fb_height) { struct drm_framebuffer *fb = fb_helper->fb; + info->pseudo_palette = fb_helper->pseudo_palette; info->var.xres_virtual = fb->width; info->var.yres_virtual = fb->height; @@ -2057,13 +2092,15 @@ retry: continue; } else { - if (fb_helper_conn->connector->tile_h_loc != tile_pass -1 && + if (fb_helper_conn->connector->tile_h_loc != tile_pass - 1 && fb_helper_conn->connector->tile_v_loc != tile_pass - 1) /* if this tile_pass doesn't cover any of the tiles - keep going */ continue; - /* find the tile offsets for this pass - need - to find all tiles left and above */ + /* + * find the tile offsets for this pass - need to find + * all tiles left and above + */ drm_get_tile_offsets(fb_helper, modes, offsets, i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc); } @@ -2147,8 +2184,10 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, if (!encoder) goto out; - /* select a crtc for this connector and then attempt to configure - remaining connectors */ + /* + * select a crtc for this connector and then attempt to configure + * remaining connectors + */ for (c = 0; c < fb_helper->crtc_count; c++) { crtc = &fb_helper->crtc_info[c]; diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index e8f9c13a0afd..fc8ef42203ec 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "drm_crtc_internal.h" @@ -755,6 +756,117 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) } EXPORT_SYMBOL(drm_framebuffer_cleanup); +static int atomic_remove_fb(struct drm_framebuffer *fb) +{ + struct drm_modeset_acquire_ctx ctx; + struct drm_device *dev = fb->dev; + struct drm_atomic_state *state; + struct drm_plane *plane; + struct drm_connector *conn; + struct drm_connector_state *conn_state; + int i, ret = 0; + unsigned plane_mask; + + state = drm_atomic_state_alloc(dev); + if (!state) + return -ENOMEM; + + drm_modeset_acquire_init(&ctx, 0); + state->acquire_ctx = &ctx; + +retry: + plane_mask = 0; + ret = drm_modeset_lock_all_ctx(dev, &ctx); + if (ret) + goto unlock; + + drm_for_each_plane(plane, dev) { + struct drm_plane_state *plane_state; + + if (plane->state->fb != fb) + continue; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + goto unlock; + } + + if (plane_state->crtc->primary == plane) { + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_existing_crtc_state(state, plane_state->crtc); + + ret = drm_atomic_add_affected_connectors(state, plane_state->crtc); + if (ret) + goto unlock; + + crtc_state->active = false; + ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); + if (ret) + goto unlock; + } + + drm_atomic_set_fb_for_plane(plane_state, NULL); + ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); + if (ret) + goto unlock; + + plane_mask |= BIT(drm_plane_index(plane)); + + plane->old_fb = plane->fb; + } + + for_each_connector_in_state(state, conn, conn_state, i) { + ret = drm_atomic_set_crtc_for_connector(conn_state, NULL); + + if (ret) + goto unlock; + } + + if (plane_mask) + ret = drm_atomic_commit(state); + +unlock: + if (plane_mask) + drm_atomic_clean_old_fb(dev, plane_mask, ret); + + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + drm_atomic_state_put(state); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; +} + +static void legacy_remove_fb(struct drm_framebuffer *fb) +{ + struct drm_device *dev = fb->dev; + struct drm_crtc *crtc; + struct drm_plane *plane; + + drm_modeset_lock_all(dev); + /* remove from any CRTC */ + drm_for_each_crtc(crtc, dev) { + if (crtc->primary->fb == fb) { + /* should turn off the crtc */ + if (drm_crtc_force_disable(crtc)) + DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); + } + } + + drm_for_each_plane(plane, dev) { + if (plane->fb == fb) + drm_plane_force_disable(plane); + } + drm_modeset_unlock_all(dev); +} + /** * drm_framebuffer_remove - remove and unreference a framebuffer object * @fb: framebuffer to remove @@ -770,8 +882,6 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup); void drm_framebuffer_remove(struct drm_framebuffer *fb) { struct drm_device *dev; - struct drm_crtc *crtc; - struct drm_plane *plane; if (!fb) return; @@ -797,29 +907,12 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) */ if (drm_framebuffer_read_refcount(fb) > 1) { if (drm_drv_uses_atomic_modeset(dev)) { - int ret = drm_atomic_remove_fb(fb); + int ret = atomic_remove_fb(fb); WARN(ret, "atomic remove_fb failed with %i\n", ret); - goto out; - } - - drm_modeset_lock_all(dev); - /* remove from any CRTC */ - drm_for_each_crtc(crtc, dev) { - if (crtc->primary->fb == fb) { - /* should turn off the crtc */ - if (drm_crtc_force_disable(crtc)) - DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); - } - } - - drm_for_each_plane(plane, dev) { - if (plane->fb == fb) - drm_plane_force_disable(plane); - } - drm_modeset_unlock_all(dev); + } else + legacy_remove_fb(fb); } -out: drm_framebuffer_put(fb); } EXPORT_SYMBOL(drm_framebuffer_remove); diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index b134482f4022..ae386783e3ea 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -1,4 +1,4 @@ -/** +/* * \file drm_ioc32.c * * 32-bit ioctl compatibility routines for the DRM. @@ -72,15 +72,15 @@ #define DRM_IOCTL_MODE_ADDFB232 DRM_IOWR(0xb8, drm_mode_fb_cmd232_t) typedef struct drm_version_32 { - int version_major; /**< Major version */ - int version_minor; /**< Minor version */ - int version_patchlevel; /**< Patch level */ - u32 name_len; /**< Length of name buffer */ - u32 name; /**< Name of driver */ - u32 date_len; /**< Length of date buffer */ - u32 date; /**< User-space buffer to hold date */ - u32 desc_len; /**< Length of desc buffer */ - u32 desc; /**< User-space buffer to hold desc */ + int version_major; /* Major version */ + int version_minor; /* Minor version */ + int version_patchlevel; /* Patch level */ + u32 name_len; /* Length of name buffer */ + u32 name; /* Name of driver */ + u32 date_len; /* Length of date buffer */ + u32 date; /* User-space buffer to hold date */ + u32 desc_len; /* Length of desc buffer */ + u32 desc; /* User-space buffer to hold desc */ } drm_version32_t; static int compat_drm_version(struct file *file, unsigned int cmd, @@ -126,8 +126,8 @@ static int compat_drm_version(struct file *file, unsigned int cmd, } typedef struct drm_unique32 { - u32 unique_len; /**< Length of unique */ - u32 unique; /**< Unique name for driver instantiation */ + u32 unique_len; /* Length of unique */ + u32 unique; /* Unique name for driver instantiation */ } drm_unique32_t; static int compat_drm_getunique(struct file *file, unsigned int cmd, @@ -180,12 +180,12 @@ static int compat_drm_setunique(struct file *file, unsigned int cmd, } typedef struct drm_map32 { - u32 offset; /**< Requested physical address (0 for SAREA)*/ - u32 size; /**< Requested physical size (bytes) */ - enum drm_map_type type; /**< Type of memory to map */ - enum drm_map_flags flags; /**< Flags */ - u32 handle; /**< User-space: "Handle" to pass to mmap() */ - int mtrr; /**< MTRR slot used */ + u32 offset; /* Requested physical address (0 for SAREA) */ + u32 size; /* Requested physical size (bytes) */ + enum drm_map_type type; /* Type of memory to map */ + enum drm_map_flags flags; /* Flags */ + u32 handle; /* User-space: "Handle" to pass to mmap() */ + int mtrr; /* MTRR slot used */ } drm_map32_t; static int compat_drm_getmap(struct file *file, unsigned int cmd, @@ -286,12 +286,12 @@ static int compat_drm_rmmap(struct file *file, unsigned int cmd, } typedef struct drm_client32 { - int idx; /**< Which client desired? */ - int auth; /**< Is client authenticated? */ - u32 pid; /**< Process ID */ - u32 uid; /**< User ID */ - u32 magic; /**< Magic */ - u32 iocs; /**< Ioctl count */ + int idx; /* Which client desired? */ + int auth; /* Is client authenticated? */ + u32 pid; /* Process ID */ + u32 uid; /* User ID */ + u32 magic; /* Magic */ + u32 iocs; /* Ioctl count */ } drm_client32_t; static int compat_drm_getclient(struct file *file, unsigned int cmd, @@ -366,12 +366,12 @@ static int compat_drm_getstats(struct file *file, unsigned int cmd, } typedef struct drm_buf_desc32 { - int count; /**< Number of buffers of this size */ - int size; /**< Size in bytes */ - int low_mark; /**< Low water mark */ - int high_mark; /**< High water mark */ + int count; /* Number of buffers of this size */ + int size; /* Size in bytes */ + int low_mark; /* Low water mark */ + int high_mark; /* High water mark */ int flags; - u32 agp_start; /**< Start address in the AGP aperture */ + u32 agp_start; /* Start address in the AGP aperture */ } drm_buf_desc32_t; static int compat_drm_addbufs(struct file *file, unsigned int cmd, @@ -1111,13 +1111,18 @@ static drm_ioctl_compat_t *drm_compat_ioctls[] = { }; /** - * Called whenever a 32-bit process running under a 64-bit kernel - * performs an ioctl on /dev/drm. + * drm_compat_ioctl - 32bit IOCTL compatibility handler for DRM drivers + * @filp: file this ioctl is called on + * @cmd: ioctl cmd number + * @arg: user argument * - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument. - * \return zero on success or negative number on failure. + * Compatibility handler for 32 bit userspace running on 64 kernels. All actual + * IOCTL handling is forwarded to drm_ioctl(), while marshalling structures as + * appropriate. Note that this only handles DRM core IOCTLs, if the driver has + * botched IOCTL itself, it must handle those by wrapping this function. + * + * Returns: + * Zero on success, negative error code on failure. */ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -1141,5 +1146,4 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return ret; } - EXPORT_SYMBOL(drm_compat_ioctl); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 7d6deaa91281..865e3ee4d743 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -286,6 +286,9 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_ case DRM_CAP_ADDFB2_MODIFIERS: req->value = dev->mode_config.allow_fb_modifiers; break; + case DRM_CAP_CRTC_IN_VBLANK_EVENT: + req->value = 1; + break; default: return -EINVAL; } @@ -646,14 +649,60 @@ static const struct drm_ioctl_desc drm_ioctls[] = { #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) +/** + * DOC: driver specific ioctls + * + * First things first, driver private IOCTLs should only be needed for drivers + * supporting rendering. Kernel modesetting is all standardized, and extended + * through properties. There are a few exceptions in some existing drivers, + * which define IOCTL for use by the display DRM master, but they all predate + * properties. + * + * Now if you do have a render driver you always have to support it through + * driver private properties. There's a few steps needed to wire all the things + * up. + * + * First you need to define the structure for your IOCTL in your driver private + * UAPI header in ``include/uapi/drm/my_driver_drm.h``:: + * + * struct my_driver_operation { + * u32 some_thing; + * u32 another_thing; + * }; + * + * Please make sure that you follow all the best practices from + * ``Documentation/ioctl/botching-up-ioctls.txt``. Note that drm_ioctl() + * automatically zero-extends structures, hence make sure you can add more stuff + * at the end, i.e. don't put a variable sized array there. + * + * Then you need to define your IOCTL number, using one of DRM_IO(), DRM_IOR(), + * DRM_IOW() or DRM_IOWR(). It must start with the DRM_IOCTL\_ prefix:: + * + * ##define DRM_IOCTL_MY_DRIVER_OPERATION \ + * DRM_IOW(DRM_COMMAND_BASE, struct my_driver_operation) + * + * DRM driver private IOCTL must be in the range from DRM_COMMAND_BASE to + * DRM_COMMAND_END. Finally you need an array of &struct drm_ioctl_desc to wire + * up the handlers and set the access rights: + * + * static const struct drm_ioctl_desc my_driver_ioctls[] = { + * DRM_IOCTL_DEF_DRV(MY_DRIVER_OPERATION, my_driver_operation, + * DRM_AUTH|DRM_RENDER_ALLOW), + * }; + * + * And then assign this to the &drm_driver.ioctls field in your driver + * structure. + */ + /** * drm_ioctl - ioctl callback implementation for DRM drivers * @filp: file this ioctl is called on * @cmd: ioctl cmd number * @arg: user argument * - * Looks up the ioctl function in the ::ioctls table, checking for root - * previleges if so required, and dispatches to the respective function. + * Looks up the ioctl function in the DRM core and the driver dispatch table, + * stored in &drm_driver.ioctls. It checks for necessary permission by calling + * drm_ioctl_permit(), and dispatches to the respective function. * * Returns: * Zero on success, negative error code on failure. diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index dac1b2593cb1..8c866cac62dd 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1026,6 +1026,7 @@ void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, e->pipe = pipe; e->event.sequence = drm_vblank_count(dev, pipe); + e->event.crtc_id = crtc->base.id; list_add_tail(&e->base.link, &dev->vblank_event_list); } EXPORT_SYMBOL(drm_crtc_arm_vblank_event); @@ -1056,6 +1057,7 @@ void drm_crtc_send_vblank_event(struct drm_crtc *crtc, now = get_drm_timestamp(); } e->pipe = pipe; + e->event.crtc_id = crtc->base.id; send_vblank_event(dev, e, seq, &now); } EXPORT_SYMBOL(drm_crtc_send_vblank_event); diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index bf60f2645e55..64ef09a6cccb 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -148,108 +148,6 @@ void drm_modeset_unlock_all(struct drm_device *dev) } EXPORT_SYMBOL(drm_modeset_unlock_all); -/** - * drm_modeset_lock_crtc - lock crtc with hidden acquire ctx for a plane update - * @crtc: DRM CRTC - * @plane: DRM plane to be updated on @crtc - * - * This function locks the given crtc and plane (which should be either the - * primary or cursor plane) using a hidden acquire context. This is necessary so - * that drivers internally using the atomic interfaces can grab further locks - * with the lock acquire context. - * - * Note that @plane can be NULL, e.g. when the cursor support hasn't yet been - * converted to universal planes yet. - */ -void drm_modeset_lock_crtc(struct drm_crtc *crtc, - struct drm_plane *plane) -{ - struct drm_modeset_acquire_ctx *ctx; - int ret; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (WARN_ON(!ctx)) - return; - - drm_modeset_acquire_init(ctx, 0); - -retry: - ret = drm_modeset_lock(&crtc->mutex, ctx); - if (ret) - goto fail; - - if (plane) { - ret = drm_modeset_lock(&plane->mutex, ctx); - if (ret) - goto fail; - - if (plane->crtc) { - ret = drm_modeset_lock(&plane->crtc->mutex, ctx); - if (ret) - goto fail; - } - } - - WARN_ON(crtc->acquire_ctx); - - /* now we hold the locks, so now that it is safe, stash the - * ctx for drm_modeset_unlock_crtc(): - */ - crtc->acquire_ctx = ctx; - - return; - -fail: - if (ret == -EDEADLK) { - drm_modeset_backoff(ctx); - goto retry; - } -} -EXPORT_SYMBOL(drm_modeset_lock_crtc); - -/** - * drm_modeset_legacy_acquire_ctx - find acquire ctx for legacy ioctls - * @crtc: drm crtc - * - * Legacy ioctl operations like cursor updates or page flips only have per-crtc - * locking, and store the acquire ctx in the corresponding crtc. All other - * legacy operations take all locks and use a global acquire context. This - * function grabs the right one. - */ -struct drm_modeset_acquire_ctx * -drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc) -{ - if (crtc->acquire_ctx) - return crtc->acquire_ctx; - - WARN_ON(!crtc->dev->mode_config.acquire_ctx); - - return crtc->dev->mode_config.acquire_ctx; -} -EXPORT_SYMBOL(drm_modeset_legacy_acquire_ctx); - -/** - * drm_modeset_unlock_crtc - drop crtc lock - * @crtc: drm crtc - * - * This drops the crtc lock acquire with drm_modeset_lock_crtc() and all other - * locks acquired through the hidden context. - */ -void drm_modeset_unlock_crtc(struct drm_crtc *crtc) -{ - struct drm_modeset_acquire_ctx *ctx = crtc->acquire_ctx; - - if (WARN_ON(!ctx)) - return; - - crtc->acquire_ctx = NULL; - drm_modeset_drop_locks(ctx); - drm_modeset_acquire_fini(ctx); - - kfree(ctx); -} -EXPORT_SYMBOL(drm_modeset_unlock_crtc); - /** * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked * @dev: device diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index b5f2f0fece99..2120f33bdf4a 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -3,8 +3,10 @@ #include #include #include +#include #include #include +#include #include static void drm_release_of(struct device *dev, void *data) @@ -208,3 +210,53 @@ int drm_of_encoder_active_endpoint(struct device_node *node, return -EINVAL; } EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint); + +/* + * drm_of_find_panel_or_bridge - return connected panel or bridge device + * @np: device tree node containing encoder output ports + * @panel: pointer to hold returned drm_panel + * @bridge: pointer to hold returned drm_bridge + * + * Given a DT node's port and endpoint number, find the connected node and + * return either the associated struct drm_panel or drm_bridge device. Either + * @panel or @bridge must not be NULL. + * + * Returns zero if successful, or one of the standard error codes if it fails. + */ +int drm_of_find_panel_or_bridge(const struct device_node *np, + int port, int endpoint, + struct drm_panel **panel, + struct drm_bridge **bridge) +{ + int ret = -EPROBE_DEFER; + struct device_node *remote; + + if (!panel && !bridge) + return -EINVAL; + + remote = of_graph_get_remote_node(np, port, endpoint); + if (!remote) + return -ENODEV; + + if (panel) { + *panel = of_drm_find_panel(remote); + if (*panel) + ret = 0; + } + + /* No panel found yet, check for a bridge next. */ + if (bridge) { + if (ret) { + *bridge = of_drm_find_bridge(remote); + if (*bridge) + ret = 0; + } else { + *bridge = NULL; + } + + } + + of_node_put(remote); + return ret; +} +EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge); diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index bc71aa2b7872..fedd4d60d9cd 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -620,7 +620,8 @@ int drm_mode_setplane(struct drm_device *dev, void *data, static int drm_mode_cursor_universal(struct drm_crtc *crtc, struct drm_mode_cursor2 *req, - struct drm_file *file_priv) + struct drm_file *file_priv, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev = crtc->dev; struct drm_framebuffer *fb = NULL; @@ -634,21 +635,11 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, int32_t crtc_x, crtc_y; uint32_t crtc_w = 0, crtc_h = 0; uint32_t src_w = 0, src_h = 0; - struct drm_modeset_acquire_ctx ctx; int ret = 0; BUG_ON(!crtc->cursor); WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); - drm_modeset_acquire_init(&ctx, 0); -retry: - ret = drm_modeset_lock(&crtc->mutex, &ctx); - if (ret) - goto fail; - ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx); - if (ret) - goto fail; - /* * Obtain fb we'll be using (either new or existing) and take an extra * reference to it if fb != null. setplane will take care of dropping @@ -693,7 +684,7 @@ retry: */ ret = __setplane_internal(crtc->cursor, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - 0, 0, src_w, src_h, &ctx); + 0, 0, src_w, src_h, ctx); /* Update successful; save new cursor position, if necessary */ if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { @@ -701,15 +692,6 @@ retry: crtc->cursor_y = req->y; } -fail: - if (ret == -EDEADLK) { - drm_modeset_backoff(&ctx); - goto retry; - } - - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); - return ret; } @@ -718,6 +700,7 @@ static int drm_mode_cursor_common(struct drm_device *dev, struct drm_file *file_priv) { struct drm_crtc *crtc; + struct drm_modeset_acquire_ctx ctx; int ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) @@ -732,14 +715,24 @@ static int drm_mode_cursor_common(struct drm_device *dev, return -ENOENT; } + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock(&crtc->mutex, &ctx); + if (ret) + goto out; /* * If this crtc has a universal cursor plane, call that plane's update * handler rather than using legacy cursor handlers. */ - if (crtc->cursor) - return drm_mode_cursor_universal(crtc, req, file_priv); + if (crtc->cursor) { + ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx); + if (ret) + goto out; + + ret = drm_mode_cursor_universal(crtc, req, file_priv, &ctx); + goto out; + } - drm_modeset_lock_crtc(crtc, crtc->cursor); if (req->flags & DRM_MODE_CURSOR_BO) { if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { ret = -ENXIO; @@ -763,7 +756,13 @@ static int drm_mode_cursor_common(struct drm_device *dev, } } out: - drm_modeset_unlock_crtc(crtc); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); return ret; diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 85005d57bde6..1b0c14ab3fff 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -44,7 +44,7 @@ * * This library provides some helper code for output probing. It provides an * implementation of the core &drm_connector_funcs.fill_modes interface with - * drm_helper_probe_single_connector_modes. + * drm_helper_probe_single_connector_modes(). * * It also provides support for polling connectors with a work item and for * generic hotplug interrupt handling where the driver doesn't or cannot keep @@ -169,13 +169,74 @@ void drm_kms_helper_poll_enable(struct drm_device *dev) EXPORT_SYMBOL(drm_kms_helper_poll_enable); static enum drm_connector_status -drm_connector_detect(struct drm_connector *connector, bool force) +drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force) { - return connector->funcs->detect ? - connector->funcs->detect(connector, force) : - connector_status_connected; + const struct drm_connector_helper_funcs *funcs = connector->helper_private; + struct drm_modeset_acquire_ctx ctx; + int ret; + + drm_modeset_acquire_init(&ctx, 0); + +retry: + ret = drm_modeset_lock(&connector->dev->mode_config.connection_mutex, &ctx); + if (!ret) { + if (funcs->detect_ctx) + ret = funcs->detect_ctx(connector, &ctx, force); + else if (connector->funcs->detect) + ret = connector->funcs->detect(connector, force); + else + ret = connector_status_connected; + } + + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + if (WARN_ON(ret < 0)) + ret = connector_status_unknown; + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; } +/** + * drm_helper_probe_detect - probe connector status + * @connector: connector to probe + * @ctx: acquire_ctx, or NULL to let this function handle locking. + * @force: Whether destructive probe operations should be performed. + * + * This function calls the detect callbacks of the connector. + * This function returns &drm_connector_status, or + * if @ctx is set, it might also return -EDEADLK. + */ +int +drm_helper_probe_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) +{ + const struct drm_connector_helper_funcs *funcs = connector->helper_private; + struct drm_device *dev = connector->dev; + int ret; + + if (!ctx) + return drm_helper_probe_detect_ctx(connector, force); + + ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx); + if (ret) + return ret; + + if (funcs->detect_ctx) + return funcs->detect_ctx(connector, ctx, force); + else if (connector->funcs->detect) + return connector->funcs->detect(connector, force); + else + return connector_status_connected; +} +EXPORT_SYMBOL(drm_helper_probe_detect); + /** * drm_helper_probe_single_connector_modes - get complete set of display modes * @connector: connector to probe @@ -239,15 +300,27 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, struct drm_display_mode *mode; const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; - int count = 0; + int count = 0, ret; int mode_flags = 0; bool verbose_prune = true; enum drm_connector_status old_status; + struct drm_modeset_acquire_ctx ctx; WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + drm_modeset_acquire_init(&ctx, 0); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); + +retry: + ret = drm_modeset_lock(&dev->mode_config.connection_mutex, &ctx); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } else + WARN_ON(ret < 0); + /* set all old modes to the stale state */ list_for_each_entry(mode, &connector->modes, head) mode->status = MODE_STALE; @@ -263,7 +336,15 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, if (connector->funcs->force) connector->funcs->force(connector); } else { - connector->status = drm_connector_detect(connector, true); + ret = drm_helper_probe_detect(connector, &ctx, true); + + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } else if (WARN(ret < 0, "Invalid return value %i for connector detection\n", ret)) + ret = connector_status_unknown; + + connector->status = ret; } /* @@ -355,6 +436,9 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, prune: drm_mode_prune_invalid(dev, &connector->modes, verbose_prune); + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + if (list_empty(&connector->modes)) return 0; @@ -440,7 +524,7 @@ static void output_poll_execute(struct work_struct *work) repoll = true; - connector->status = drm_connector_detect(connector, false); + connector->status = drm_helper_probe_detect(connector, NULL, false); if (old_status != connector->status) { const char *old, *new; @@ -588,7 +672,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) old_status = connector->status; - connector->status = drm_connector_detect(connector, false); + connector->status = drm_helper_probe_detect(connector, NULL, false); DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", connector->base.id, connector->name, diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c index b17959c3e099..3feef0659940 100644 --- a/drivers/gpu/drm/drm_property.c +++ b/drivers/gpu/drm/drm_property.c @@ -442,8 +442,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, struct drm_property *property; int enum_count = 0; int value_count = 0; - int ret = 0, i; - int copied; + int i, copied; struct drm_property_enum *prop_enum; struct drm_mode_property_enum __user *enum_ptr; uint64_t __user *values_ptr; @@ -451,55 +450,43 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - drm_modeset_lock_all(dev); property = drm_property_find(dev, out_resp->prop_id); - if (!property) { - ret = -ENOENT; - goto done; - } - - if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || - drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { - list_for_each_entry(prop_enum, &property->enum_list, head) - enum_count++; - } - - value_count = property->num_values; + if (!property) + return -ENOENT; strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); out_resp->name[DRM_PROP_NAME_LEN-1] = 0; out_resp->flags = property->flags; - if ((out_resp->count_values >= value_count) && value_count) { - values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; - for (i = 0; i < value_count; i++) { - if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { - ret = -EFAULT; - goto done; - } + value_count = property->num_values; + values_ptr = u64_to_user_ptr(out_resp->values_ptr); + + for (i = 0; i < value_count; i++) { + if (i < out_resp->count_values && + put_user(property->values[i], values_ptr + i)) { + return -EFAULT; } } out_resp->count_values = value_count; + copied = 0; + enum_ptr = u64_to_user_ptr(out_resp->enum_blob_ptr); + if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || - drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { - if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { - copied = 0; - enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; - list_for_each_entry(prop_enum, &property->enum_list, head) { + drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { + list_for_each_entry(prop_enum, &property->enum_list, head) { + enum_count++; + if (out_resp->count_enum_blobs <= enum_count) + continue; - if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { - ret = -EFAULT; - goto done; - } + if (copy_to_user(&enum_ptr[copied].value, + &prop_enum->value, sizeof(uint64_t))) + return -EFAULT; - if (copy_to_user(&enum_ptr[copied].name, - &prop_enum->name, DRM_PROP_NAME_LEN)) { - ret = -EFAULT; - goto done; - } - copied++; - } + if (copy_to_user(&enum_ptr[copied].name, + &prop_enum->name, DRM_PROP_NAME_LEN)) + return -EFAULT; + copied++; } out_resp->count_enum_blobs = enum_count; } @@ -514,9 +501,8 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, */ if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) out_resp->count_enum_blobs = 0; -done: - drm_modeset_unlock_all(dev); - return ret; + + return 0; } static void drm_property_free_blob(struct kref *kref) diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 513288b5c2f6..1c5b5ce1fd7f 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -25,6 +25,20 @@ #define to_drm_minor(d) dev_get_drvdata(d) #define to_drm_connector(d) dev_get_drvdata(d) +/** + * DOC: overview + * + * DRM provides very little additional support to drivers for sysfs + * interactions, beyond just all the standard stuff. Drivers who want to expose + * additional sysfs properties and property groups can attach them at either + * &drm_device.dev or &drm_connector.kdev. + * + * Registration is automatically handled when calling drm_dev_register(), or + * drm_connector_register() in case of hot-plugged connectors. Unregistration is + * also automatically handled by drm_dev_unregister() and + * drm_connector_unregister(). + */ + static struct device_type drm_sysfs_device_minor = { .name = "drm_minor" }; @@ -250,15 +264,6 @@ static const struct attribute_group *connector_dev_groups[] = { NULL }; -/** - * drm_sysfs_connector_add - add a connector to sysfs - * @connector: connector to add - * - * Create a connector device in sysfs, along with its associated connector - * properties (so far, connection status, dpms, mode list and edid) and - * generate a hotplug event so userspace knows there's a new connector - * available. - */ int drm_sysfs_connector_add(struct drm_connector *connector) { struct drm_device *dev = connector->dev; @@ -285,19 +290,6 @@ int drm_sysfs_connector_add(struct drm_connector *connector) return 0; } -/** - * drm_sysfs_connector_remove - remove an connector device from sysfs - * @connector: connector to remove - * - * Remove @connector and its associated attributes from sysfs. Note that - * the device model core will take care of sending the "remove" uevent - * at this time, so we don't need to do it. - * - * Note: - * This routine should only be called if the connector was previously - * successfully registered. If @connector hasn't been registered yet, - * you'll likely see a panic somewhere deep in sysfs code when called. - */ void drm_sysfs_connector_remove(struct drm_connector *connector) { if (!connector->kdev) @@ -333,20 +325,6 @@ static void drm_sysfs_release(struct device *dev) kfree(dev); } -/** - * drm_sysfs_minor_alloc() - Allocate sysfs device for given minor - * @minor: minor to allocate sysfs device for - * - * This allocates a new sysfs device for @minor and returns it. The device is - * not registered nor linked. The caller has to use device_add() and - * device_del() to register and unregister it. - * - * Note that dev_get_drvdata() on the new device will return the minor. - * However, the device does not hold a ref-count to the minor nor to the - * underlying drm_device. This is unproblematic as long as you access the - * private data only in sysfs callbacks. device_del() disables those - * synchronously, so they cannot be called after you cleanup a minor. - */ struct device *drm_sysfs_minor_alloc(struct drm_minor *minor) { const char *minor_str; @@ -384,15 +362,13 @@ err_free: } /** - * drm_class_device_register - Register a struct device in the drm class. + * drm_class_device_register - register new device with the DRM sysfs class + * @dev: device to register * - * @dev: pointer to struct device to register. - * - * @dev should have all relevant members pre-filled with the exception - * of the class member. In particular, the device_type member must - * be set. + * Registers a new &struct device within the DRM sysfs class. Essentially only + * used by ttm to have a place for its global settings. Drivers should never use + * this. */ - int drm_class_device_register(struct device *dev) { if (!drm_class || IS_ERR(drm_class)) @@ -403,6 +379,14 @@ int drm_class_device_register(struct device *dev) } EXPORT_SYMBOL_GPL(drm_class_device_register); +/** + * drm_class_device_unregister - unregister device with the DRM sysfs class + * @dev: device to unregister + * + * Unregisters a &struct device from the DRM sysfs class. Essentially only used + * by ttm to have a place for its global settings. Drivers should never use + * this. + */ void drm_class_device_unregister(struct device *dev) { return device_unregister(dev); diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index b445b50a5dc4..385537b726a6 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -211,8 +212,11 @@ static const struct component_ops exynos_dp_ops = { static int exynos_dp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = NULL, *endpoint = NULL; + struct device_node *np; struct exynos_dp_device *dp; + struct drm_panel *panel; + struct drm_bridge *bridge; + int ret; dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), GFP_KERNEL); @@ -236,28 +240,13 @@ static int exynos_dp_probe(struct platform_device *pdev) goto out; } - endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); - if (endpoint) { - np = of_graph_get_remote_port_parent(endpoint); - if (np) { - /* The remote port can be either a panel or a bridge */ - dp->plat_data.panel = of_drm_find_panel(np); - if (!dp->plat_data.panel) { - dp->ptn_bridge = of_drm_find_bridge(np); - if (!dp->ptn_bridge) { - of_node_put(np); - return -EPROBE_DEFER; - } - } - of_node_put(np); - } else { - DRM_ERROR("no remote endpoint device node found.\n"); - return -EINVAL; - } - } else { - DRM_ERROR("no port endpoint subnode found.\n"); - return -EINVAL; - } + ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, &bridge); + if (ret) + return ret; + + /* The remote port can be either a panel or a bridge */ + dp->plat_data.panel = panel; + dp->ptn_bridge = bridge; out: return component_add(&pdev->dev, &exynos_dp_ops); diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 3aab71a485ba..63abcd280fa0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -163,27 +163,13 @@ enum { FIMD_PORT_WRB, }; -static struct device_node *exynos_dpi_of_find_panel_node(struct device *dev) -{ - struct device_node *np, *ep; - - ep = of_graph_get_endpoint_by_regs(dev->of_node, FIMD_PORT_RGB, 0); - if (!ep) - return NULL; - - np = of_graph_get_remote_port_parent(ep); - of_node_put(ep); - - return np; -} - static int exynos_dpi_parse_dt(struct exynos_dpi *ctx) { struct device *dev = ctx->dev; struct device_node *dn = dev->of_node; struct device_node *np; - ctx->panel_node = exynos_dpi_of_find_panel_node(dev); + ctx->panel_node = of_graph_get_remote_node(dn, FIMD_PORT_RGB, 0); np = of_get_child_by_name(dn, "display-timings"); if (np) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 6d4da2f0932d..fc4fda738906 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1659,17 +1659,10 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi) of_node_put(ep); - ep = of_graph_get_next_endpoint(node, NULL); - if (!ep) { - ret = -EINVAL; - goto end; - } + dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_OUT, 0); + if (!dsi->bridge_node) + return -EINVAL; - dsi->bridge_node = of_graph_get_remote_port_parent(ep); - if (!dsi->bridge_node) { - ret = -EINVAL; - goto end; - } end: of_node_put(ep); diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c index 2ef43d403eaa..e45720543a45 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_mic.c +++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c @@ -229,29 +229,6 @@ static void mic_set_reg_on(struct exynos_mic *mic, bool enable) writel(reg, mic->reg + MIC_OP); } -static struct device_node *get_remote_node(struct device_node *from, int reg) -{ - struct device_node *endpoint = NULL, *remote_node = NULL; - - endpoint = of_graph_get_endpoint_by_regs(from, reg, -1); - if (!endpoint) { - DRM_ERROR("mic: Failed to find remote port from %s", - from->full_name); - goto exit; - } - - remote_node = of_graph_get_remote_port_parent(endpoint); - if (!remote_node) { - DRM_ERROR("mic: Failed to find remote port parent from %s", - from->full_name); - goto exit; - } - -exit: - of_node_put(endpoint); - return remote_node; -} - static int parse_dt(struct exynos_mic *mic) { int ret = 0, i, j; @@ -263,7 +240,7 @@ static int parse_dt(struct exynos_mic *mic) * The first node must be for decon and the second one must be for dsi. */ for (i = 0, j = 0; i < NUM_ENDPOINTS; i++) { - remote_node = get_remote_node(mic->dev->of_node, i); + remote_node = of_graph_get_remote_node(mic->dev->of_node, i, 0); if (!remote_node) { ret = -EPIPE; goto exit; diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c index c3651456c963..dcbf3c06e1d8 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "fsl_dcu_drm_drv.h" @@ -141,32 +142,11 @@ err_cleanup: return ret; } -static int fsl_dcu_attach_endpoint(struct fsl_dcu_drm_device *fsl_dev, - const struct of_endpoint *ep) -{ - struct drm_bridge *bridge; - struct device_node *np; - - np = of_graph_get_remote_port_parent(ep->local_node); - - fsl_dev->connector.panel = of_drm_find_panel(np); - if (fsl_dev->connector.panel) { - of_node_put(np); - return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel); - } - - bridge = of_drm_find_bridge(np); - of_node_put(np); - if (!bridge) - return -ENODEV; - - return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL); -} - int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev) { - struct of_endpoint ep; - struct device_node *ep_node, *panel_node; + struct device_node *panel_node; + struct drm_panel *panel; + struct drm_bridge *bridge; int ret; /* This is for backward compatibility */ @@ -179,14 +159,14 @@ int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev) return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel); } - ep_node = of_graph_get_next_endpoint(fsl_dev->np, NULL); - if (!ep_node) - return -ENODEV; - - ret = of_graph_parse_endpoint(ep_node, &ep); - of_node_put(ep_node); + ret = drm_of_find_panel_or_bridge(fsl_dev->np, 0, 0, &panel, &bridge); if (ret) - return -ENODEV; + return ret; - return fsl_dcu_attach_endpoint(fsl_dev, &ep); + if (panel) { + fsl_dev->connector.panel = panel; + return fsl_dcu_attach_panel(fsl_dev, panel); + } + + return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL); } diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index 93ff46535c04..e7fd356acf2e 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -177,7 +177,8 @@ void gma_crtc_load_lut(struct drm_crtc *crtc) } int gma_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, - u32 size) + u32 size, + struct drm_modeset_acquire_ctx *ctx) { struct gma_crtc *gma_crtc = to_gma_crtc(crtc); int i; diff --git a/drivers/gpu/drm/gma500/gma_display.h b/drivers/gpu/drm/gma500/gma_display.h index 166e608923db..239c374b6169 100644 --- a/drivers/gpu/drm/gma500/gma_display.h +++ b/drivers/gpu/drm/gma500/gma_display.h @@ -73,7 +73,8 @@ extern int gma_crtc_cursor_set(struct drm_crtc *crtc, extern int gma_crtc_cursor_move(struct drm_crtc *crtc, int x, int y); extern void gma_crtc_load_lut(struct drm_crtc *crtc); extern int gma_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, u32 size); + u16 *blue, u32 size, + struct drm_modeset_acquire_ctx *ctx); extern void gma_crtc_dpms(struct drm_crtc *crtc, int mode); extern void gma_crtc_prepare(struct drm_crtc *crtc); extern void gma_crtc_commit(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c index 1737e98bc10a..5abc69c9630f 100644 --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c @@ -17,7 +17,6 @@ #include #include -#include #include #include @@ -754,34 +753,16 @@ static int dsi_parse_dt(struct platform_device *pdev, struct dw_dsi *dsi) { struct dsi_hw_ctx *ctx = dsi->ctx; struct device_node *np = pdev->dev.of_node; - struct device_node *endpoint, *bridge_node; - struct drm_bridge *bridge; struct resource *res; + int ret; /* * Get the endpoint node. In our case, dsi has one output port1 * to which the external HDMI bridge is connected. */ - endpoint = of_graph_get_endpoint_by_regs(np, 1, -1); - if (!endpoint) { - DRM_ERROR("no valid endpoint node\n"); - return -ENODEV; - } - of_node_put(endpoint); - - bridge_node = of_graph_get_remote_port_parent(endpoint); - if (!bridge_node) { - DRM_ERROR("no valid bridge node\n"); - return -ENODEV; - } - of_node_put(bridge_node); - - bridge = of_drm_find_bridge(bridge_node); - if (!bridge) { - DRM_INFO("wait for external HDMI bridge driver.\n"); - return -EPROBE_DEFER; - } - dsi->bridge = bridge; + ret = drm_of_find_panel_or_bridge(np, 0, 0, NULL, &dsi->bridge); + if (ret) + return ret; ctx->pclk = devm_clk_get(&pdev->dev, "pclk"); if (IS_ERR(ctx->pclk)) { diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index df4f50713e54..9c903672f582 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c @@ -230,34 +230,6 @@ static const struct component_master_ops kirin_drm_ops = { .unbind = kirin_drm_unbind, }; -static struct device_node *kirin_get_remote_node(struct device_node *np) -{ - struct device_node *endpoint, *remote; - - /* get the first endpoint, in our case only one remote node - * is connected to display controller. - */ - endpoint = of_graph_get_next_endpoint(np, NULL); - if (!endpoint) { - DRM_ERROR("no valid endpoint node\n"); - return ERR_PTR(-ENODEV); - } - - remote = of_graph_get_remote_port_parent(endpoint); - of_node_put(endpoint); - if (!remote) { - DRM_ERROR("no valid remote node\n"); - return ERR_PTR(-ENODEV); - } - - if (!of_device_is_available(remote)) { - DRM_ERROR("not available for remote node\n"); - return ERR_PTR(-ENODEV); - } - - return remote; -} - static int kirin_drm_platform_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -271,7 +243,7 @@ static int kirin_drm_platform_probe(struct platform_device *pdev) return -EINVAL; } - remote = kirin_get_remote_node(np); + remote = of_graph_get_remote_node(np, 0, 0); if (IS_ERR(remote)) return PTR_ERR(remote); diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 8c82607294c6..2797bf37c3ac 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -669,15 +669,16 @@ static const struct dmi_system_id intel_spurious_crt_detect[] = { { } }; -static enum drm_connector_status -intel_crt_detect(struct drm_connector *connector, bool force) +static int +intel_crt_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) { struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_crt *crt = intel_attached_crt(connector); struct intel_encoder *intel_encoder = &crt->base; - enum drm_connector_status status; + int status, ret; struct intel_load_detect_pipe tmp; - struct drm_modeset_acquire_ctx ctx; DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n", connector->base.id, connector->name, @@ -721,10 +722,9 @@ intel_crt_detect(struct drm_connector *connector, bool force) goto out; } - drm_modeset_acquire_init(&ctx, 0); - /* for pre-945g platforms use load detect */ - if (intel_get_load_detect_pipe(connector, NULL, &tmp, &ctx)) { + ret = intel_get_load_detect_pipe(connector, NULL, &tmp, ctx); + if (ret > 0) { if (intel_crt_detect_ddc(connector)) status = connector_status_connected; else if (INTEL_GEN(dev_priv) < 4) @@ -734,12 +734,11 @@ intel_crt_detect(struct drm_connector *connector, bool force) status = connector_status_disconnected; else status = connector_status_unknown; - intel_release_load_detect_pipe(connector, &tmp, &ctx); - } else + intel_release_load_detect_pipe(connector, &tmp, ctx); + } else if (ret == 0) status = connector_status_unknown; - - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); + else if (ret < 0) + status = ret; out: intel_display_power_put(dev_priv, intel_encoder->power_domain); @@ -811,7 +810,6 @@ void intel_crt_reset(struct drm_encoder *encoder) static const struct drm_connector_funcs intel_crt_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, - .detect = intel_crt_detect, .fill_modes = drm_helper_probe_single_connector_modes, .late_register = intel_connector_register, .early_unregister = intel_connector_unregister, @@ -823,6 +821,7 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = { }; static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = { + .detect_ctx = intel_crt_detect, .mode_valid = intel_crt_mode_valid, .get_modes = intel_crt_get_modes, }; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 81baa5a9780c..881dec88df6e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3412,17 +3412,6 @@ static void skylake_disable_primary_plane(struct drm_plane *primary, spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } -/* Assume fb object is pinned & idle & fenced and just update base pointers */ -static int -intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, - int x, int y, enum mode_set_atomic state) -{ - /* Support for kgdboc is disabled, this needs a major rework. */ - DRM_ERROR("legacy panic handler not supported any more.\n"); - - return -ENODEV; -} - static void intel_complete_page_flips(struct drm_i915_private *dev_priv) { struct intel_crtc *crtc; @@ -9503,10 +9492,10 @@ static int intel_modeset_setup_plane_state(struct drm_atomic_state *state, return 0; } -bool intel_get_load_detect_pipe(struct drm_connector *connector, - struct drm_display_mode *mode, - struct intel_load_detect_pipe *old, - struct drm_modeset_acquire_ctx *ctx) +int intel_get_load_detect_pipe(struct drm_connector *connector, + struct drm_display_mode *mode, + struct intel_load_detect_pipe *old, + struct drm_modeset_acquire_ctx *ctx) { struct intel_crtc *intel_crtc; struct intel_encoder *intel_encoder = @@ -9529,10 +9518,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, old->restore_state = NULL; -retry: - ret = drm_modeset_lock(&config->connection_mutex, ctx); - if (ret) - goto fail; + WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); /* * Algorithm gets a little messy: @@ -9682,10 +9668,8 @@ fail: restore_state = NULL; } - if (ret == -EDEADLK) { - drm_modeset_backoff(ctx); - goto retry; - } + if (ret == -EDEADLK) + return ret; return false; } @@ -10727,7 +10711,7 @@ out_hang: state = drm_atomic_state_alloc(dev); if (!state) return -ENOMEM; - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); + state->acquire_ctx = dev->mode_config.acquire_ctx; retry: plane_state = drm_atomic_get_plane_state(state, primary); @@ -11017,7 +11001,6 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, } static const struct drm_crtc_helper_funcs intel_helper_funcs = { - .mode_set_base_atomic = intel_pipe_set_base_atomic, .atomic_begin = intel_begin_crtc_commit, .atomic_flush = intel_finish_crtc_commit, .atomic_check = intel_crtc_atomic_check, @@ -13090,7 +13073,7 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) return; } - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); + state->acquire_ctx = crtc->dev->mode_config.acquire_ctx; retry: crtc_state = drm_atomic_get_crtc_state(state, crtc); @@ -13113,50 +13096,8 @@ out: drm_atomic_state_put(state); } -/* - * FIXME: Remove this once i915 is fully DRIVER_ATOMIC by calling - * drm_atomic_helper_legacy_gamma_set() directly. - */ -static int intel_atomic_legacy_gamma_set(struct drm_crtc *crtc, - u16 *red, u16 *green, u16 *blue, - uint32_t size) -{ - struct drm_device *dev = crtc->dev; - struct drm_mode_config *config = &dev->mode_config; - struct drm_crtc_state *state; - int ret; - - ret = drm_atomic_helper_legacy_gamma_set(crtc, red, green, blue, size); - if (ret) - return ret; - - /* - * Make sure we update the legacy properties so this works when - * atomic is not enabled. - */ - - state = crtc->state; - - drm_object_property_set_value(&crtc->base, - config->degamma_lut_property, - (state->degamma_lut) ? - state->degamma_lut->base.id : 0); - - drm_object_property_set_value(&crtc->base, - config->ctm_property, - (state->ctm) ? - state->ctm->base.id : 0); - - drm_object_property_set_value(&crtc->base, - config->gamma_lut_property, - (state->gamma_lut) ? - state->gamma_lut->base.id : 0); - - return 0; -} - static const struct drm_crtc_funcs intel_crtc_funcs = { - .gamma_set = intel_atomic_legacy_gamma_set, + .gamma_set = drm_atomic_helper_legacy_gamma_set, .set_config = drm_atomic_helper_set_config, .set_property = drm_atomic_helper_crtc_set_property, .destroy = intel_crtc_destroy, @@ -15107,6 +15048,7 @@ static void intel_enable_pipe_a(struct drm_device *dev) struct drm_connector *crt = NULL; struct intel_load_detect_pipe load_detect_temp; struct drm_modeset_acquire_ctx *ctx = dev->mode_config.acquire_ctx; + int ret; /* We can't just switch on the pipe A, we need to set things up with a * proper mode and output configuration. As a gross hack, enable pipe A @@ -15123,7 +15065,10 @@ static void intel_enable_pipe_a(struct drm_device *dev) if (!crt) return; - if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, ctx)) + ret = intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, ctx); + WARN(ret < 0, "All modeset mutexes are locked, but intel_get_load_detect_pipe failed\n"); + + if (ret > 0) intel_release_load_detect_pipe(crt, &load_detect_temp, ctx); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index fd96a6cf7326..6e04cb54e3ff 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4566,7 +4566,7 @@ intel_dp_unset_edid(struct intel_dp *intel_dp) intel_dp->has_audio = false; } -static enum drm_connector_status +static int intel_dp_long_pulse(struct intel_connector *intel_connector) { struct drm_connector *connector = &intel_connector->base; @@ -4577,6 +4577,8 @@ intel_dp_long_pulse(struct intel_connector *intel_connector) enum drm_connector_status status; u8 sink_irq_vector = 0; + WARN_ON(!drm_modeset_is_locked(&connector->dev->mode_config.connection_mutex)); + intel_display_power_get(to_i915(dev), intel_dp->aux_power_domain); /* Can't disconnect eDP, but you can close the lid... */ @@ -4635,14 +4637,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector) status = connector_status_disconnected; goto out; } else if (connector->status == connector_status_connected) { - /* - * If display was connected already and is still connected - * check links status, there has been known issues of - * link loss triggerring long pulse!!!! - */ - drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); intel_dp_check_link_status(intel_dp); - drm_modeset_unlock(&dev->mode_config.connection_mutex); goto out; } @@ -4682,11 +4677,13 @@ out: return status; } -static enum drm_connector_status -intel_dp_detect(struct drm_connector *connector, bool force) +static int +intel_dp_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) { struct intel_dp *intel_dp = intel_attached_dp(connector); - enum drm_connector_status status = connector->status; + int status = connector->status; DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); @@ -5014,7 +5011,6 @@ void intel_dp_encoder_reset(struct drm_encoder *encoder) static const struct drm_connector_funcs intel_dp_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, - .detect = intel_dp_detect, .force = intel_dp_force, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = intel_dp_set_property, @@ -5027,6 +5023,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = { }; static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = { + .detect_ctx = intel_dp_detect, .get_modes = intel_dp_get_modes, .mode_valid = intel_dp_mode_valid, }; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 313fad059bfa..aaee3949a422 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1358,10 +1358,10 @@ int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp); void vlv_wait_port_ready(struct drm_i915_private *dev_priv, struct intel_digital_port *dport, unsigned int expected_mask); -bool intel_get_load_detect_pipe(struct drm_connector *connector, - struct drm_display_mode *mode, - struct intel_load_detect_pipe *old, - struct drm_modeset_acquire_ctx *ctx); +int intel_get_load_detect_pipe(struct drm_connector *connector, + struct drm_display_mode *mode, + struct intel_load_detect_pipe *old, + struct drm_modeset_acquire_ctx *ctx); void intel_release_load_detect_pipe(struct drm_connector *connector, struct intel_load_detect_pipe *old, struct drm_modeset_acquire_ctx *ctx); diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index 7d210097eefa..f1200272a699 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -243,7 +243,8 @@ static bool intel_hpd_irq_event(struct drm_device *dev, WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); old_status = connector->status; - connector->status = connector->funcs->detect(connector, false); + connector->status = drm_helper_probe_detect(connector, NULL, false); + if (old_status == connector->status) return false; diff --git a/drivers/gpu/drm/i915/intel_pipe_crc.c b/drivers/gpu/drm/i915/intel_pipe_crc.c index 9fd9c70baeed..206ee4f0150e 100644 --- a/drivers/gpu/drm/i915/intel_pipe_crc.c +++ b/drivers/gpu/drm/i915/intel_pipe_crc.c @@ -522,7 +522,7 @@ static void hsw_trans_edp_pipe_A_crc_wa(struct drm_i915_private *dev_priv, goto unlock; } - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(&crtc->base); + state->acquire_ctx = crtc->base.dev->mode_config.acquire_ctx; pipe_config = intel_atomic_get_crtc_state(state, crtc); if (IS_ERR(pipe_config)) { ret = PTR_ERR(pipe_config); diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 6ed1a3ce47b7..e077c2a9e694 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1315,8 +1315,10 @@ static void intel_tv_find_better_format(struct drm_connector *connector) * Currently this always returns CONNECTOR_STATUS_UNKNOWN, as we need to be sure * we have a pipe programmed in order to probe the TV. */ -static enum drm_connector_status -intel_tv_detect(struct drm_connector *connector, bool force) +static int +intel_tv_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) { struct drm_display_mode mode; struct intel_tv *intel_tv = intel_attached_tv(connector); @@ -1331,21 +1333,20 @@ intel_tv_detect(struct drm_connector *connector, bool force) if (force) { struct intel_load_detect_pipe tmp; - struct drm_modeset_acquire_ctx ctx; + int ret; - drm_modeset_acquire_init(&ctx, 0); + ret = intel_get_load_detect_pipe(connector, &mode, &tmp, ctx); + if (ret < 0) + return ret; - if (intel_get_load_detect_pipe(connector, &mode, &tmp, &ctx)) { + if (ret > 0) { type = intel_tv_detect_type(intel_tv, connector); - intel_release_load_detect_pipe(connector, &tmp, &ctx); + intel_release_load_detect_pipe(connector, &tmp, ctx); status = type < 0 ? connector_status_disconnected : connector_status_connected; } else status = connector_status_unknown; - - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); } else return connector->status; @@ -1516,7 +1517,6 @@ out: static const struct drm_connector_funcs intel_tv_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, - .detect = intel_tv_detect, .late_register = intel_connector_register, .early_unregister = intel_connector_unregister, .destroy = intel_tv_destroy, @@ -1528,6 +1528,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = { }; static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = { + .detect_ctx = intel_tv_detect, .mode_valid = intel_tv_mode_valid, .get_modes = intel_tv_get_modes, }; diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 88cd11d30134..8fb801fab039 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -647,7 +647,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) for_each_child_of_node(np, child) { struct imx_ldb_channel *channel; - struct device_node *ep; int bus_format; ret = of_property_read_u32(child, "reg", &i); @@ -671,27 +670,11 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) * The output port is port@4 with an external 4-port mux or * port@2 with the internal 2-port mux. */ - ep = of_graph_get_endpoint_by_regs(child, - imx_ldb->lvds_mux ? 4 : 2, - -1); - if (ep) { - struct device_node *remote; - - remote = of_graph_get_remote_port_parent(ep); - of_node_put(ep); - if (remote) { - channel->panel = of_drm_find_panel(remote); - channel->bridge = of_drm_find_bridge(remote); - } else - return -EPROBE_DEFER; - of_node_put(remote); - - if (!channel->panel && !channel->bridge) { - dev_err(dev, "panel/bridge not found: %s\n", - remote->full_name); - return -EPROBE_DEFER; - } - } + ret = drm_of_find_panel_or_bridge(child, + imx_ldb->lvds_mux ? 4 : 2, 0, + &channel->panel, &channel->bridge); + if (ret) + return ret; /* panel ddc only if there is no bridge */ if (!channel->bridge) { diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index d5c06fd89f90..636031a30e17 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -19,10 +19,10 @@ #include #include #include +#include #include #include #include