Merge tag 'drm-misc-next-2017-04-07' of git://anongit.freedesktop.org/git/drm-misc into drm-next
Last drm-misc-next pull req for 4.12 Core changes: - fb_helper checkpatch cleanup and simplified _add_one_connector() (Thierry) - drm_ioctl and drm_sysfs improved/gained documentation (Daniel) - [ABI] Repurpose reserved field in drm_event_vblank for crtc_id (Ander) - Plumb acquire ctx through legacy paths to avoid lock_all and legacy_backoff (Daniel) - Add connector_atomic_check to check conn constraints on modeset (Maarten) - Add drm_of_find_panel_or_bridge to remove boilerplate in drivers (Rob) Driver changes: - meson moved to drm-misc (Neil) - Added support for Amlogic GX SoCs in dw-hdmi (Neil) - Rockchip unbind actually cleans up the things bind initializes (Jeffy) - A couple misc fixes in virtio, dw-hdmi NOTE: this also includes a backmerge of drm-next as well rc5 (we needed vmwgfx as well as the new synopsys media formats) * tag 'drm-misc-next-2017-04-07' of git://anongit.freedesktop.org/git/drm-misc: (77 commits) Revert "drm: Don't allow interruptions when opening debugfs/crc" drm: Only take cursor locks when the cursor plane exists drm/vmwgfx: Fix fbdev emulation using legacy functions drm/rockchip: Shutdown all crtcs when unbinding drm drm/rockchip: Reorder drm bind/unbind sequence drm/rockchip: analogix_dp: Disable clock when unbinding drm/rockchip: vop: Unprepare clocks when unbinding drm/rockchip: vop: Enable pm domain before vop_initial drm/rockchip: cdn-dp: Don't unregister audio dev when unbinding drm/rockchip: cdn-dp: Don't try to release firmware when not loaded drm: bridge: analogix: Destroy connector & encoder when unbinding drm: bridge: analogix: Disable clock when unbinding drm: bridge: analogix: Unregister dp aux when unbinding drm: bridge: analogix: Detach panel when unbinding analogix dp drm: Don't allow interruptions when opening debugfs/crc drm/virtio: don't leak bo on drm_gem_object_init failure drm: bridge: dw-hdmi: fix input format/encoding from plat_data drm: omap: use common OF graph helpers drm: convert drivers to use drm_of_find_panel_or_bridge drm: convert drivers to use of_graph_get_remote_node ...
This commit is contained in:
commit
df45eaca51
@ -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 = <GIC_SPI 57 IRQ_TYPE_EDGE_RISING>;
|
||||
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>;
|
||||
};
|
||||
};
|
||||
};
|
@ -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 = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
|
||||
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";
|
||||
|
||||
|
15
Documentation/gpu/bridge/dw-hdmi.rst
Normal file
15
Documentation/gpu/bridge/dw-hdmi.rst
Normal file
@ -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
|
@ -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
|
||||
==============
|
||||
|
||||
|
@ -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
|
||||
=====================
|
||||
|
||||
|
@ -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
|
||||
|
61
Documentation/gpu/meson.rst
Normal file
61
Documentation/gpu/meson.rst
Normal file
@ -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
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_of.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -20,8 +20,8 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#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;
|
||||
|
||||
|
@ -22,10 +22,10 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#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;
|
||||
|
||||
|
@ -30,18 +30,15 @@
|
||||
#include <drm/drm_encoder_slave.h>
|
||||
#include <drm/bridge/dw_hdmi.h>
|
||||
|
||||
#include <uapi/linux/media-bus-format.h>
|
||||
#include <uapi/linux/videodev2.h>
|
||||
|
||||
#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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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];
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_auth.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
|
||||
#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);
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -3,8 +3,10 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_of.h>
|
||||
|
||||
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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#include <drm/bridge/analogix_dp.h>
|
||||
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
@ -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)) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -19,10 +19,10 @@
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <video/of_display_timing.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
#include "imx-drm.h"
|
||||
|
||||
@ -208,7 +208,6 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct drm_device *drm = data;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *ep;
|
||||
const u8 *edidp;
|
||||
struct imx_parallel_display *imxpd;
|
||||
int ret;
|
||||
@ -237,36 +236,9 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
|
||||
imxpd->bus_format = bus_format;
|
||||
|
||||
/* port@1 is the output port */
|
||||
ep = of_graph_get_endpoint_by_regs(np, 1, -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);
|
||||
|
||||
imxpd->panel = of_drm_find_panel(remote);
|
||||
if (imxpd->panel) {
|
||||
dev_dbg(dev, "found panel %s\n", remote->full_name);
|
||||
} else {
|
||||
imxpd->bridge = of_drm_find_bridge(remote);
|
||||
if (imxpd->bridge)
|
||||
dev_dbg(dev, "found bridge %s\n",
|
||||
remote->full_name);
|
||||
}
|
||||
if (!imxpd->panel && !imxpd->bridge) {
|
||||
dev_dbg(dev, "waiting for panel or bridge %s\n",
|
||||
remote->full_name);
|
||||
of_node_put(remote);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
of_node_put(remote);
|
||||
}
|
||||
ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel, &imxpd->bridge);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
imxpd->dev = dev;
|
||||
|
||||
|
@ -661,7 +661,7 @@ static int mtk_dpi_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mtk_dpi *dpi;
|
||||
struct resource *mem;
|
||||
struct device_node *ep, *bridge_node = NULL;
|
||||
struct device_node *bridge_node;
|
||||
int comp_id;
|
||||
int ret;
|
||||
|
||||
@ -706,15 +706,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ep = of_graph_get_next_endpoint(dev->of_node, NULL);
|
||||
if (ep) {
|
||||
bridge_node = of_graph_get_remote_port_parent(ep);
|
||||
of_node_put(ep);
|
||||
}
|
||||
if (!bridge_node) {
|
||||
dev_err(dev, "Failed to find bridge node\n");
|
||||
bridge_node = of_graph_get_remote_node(dev->of_node, 0, 0);
|
||||
if (!bridge_node)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_info(dev, "Found bridge node: %s\n", bridge_node->full_name);
|
||||
|
||||
|
@ -16,12 +16,12 @@
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <video/mipi_display.h>
|
||||
@ -1097,7 +1097,6 @@ static int mtk_dsi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mtk_dsi *dsi;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *remote_node, *endpoint;
|
||||
struct resource *regs;
|
||||
int irq_num;
|
||||
int comp_id;
|
||||
@ -1110,22 +1109,10 @@ static int mtk_dsi_probe(struct platform_device *pdev)
|
||||
dsi->host.ops = &mtk_dsi_ops;
|
||||
dsi->host.dev = dev;
|
||||
|
||||
endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
|
||||
if (endpoint) {
|
||||
remote_node = of_graph_get_remote_port_parent(endpoint);
|
||||
if (!remote_node) {
|
||||
dev_err(dev, "No panel connected\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dsi->bridge = of_drm_find_bridge(remote_node);
|
||||
dsi->panel = of_drm_find_panel(remote_node);
|
||||
of_node_put(remote_node);
|
||||
if (!dsi->bridge && !dsi->panel) {
|
||||
dev_info(dev, "Waiting for bridge or panel driver\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
}
|
||||
ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
|
||||
&dsi->panel, &dsi->bridge);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dsi->engine_clk = devm_clk_get(dev, "engine");
|
||||
if (IS_ERR(dsi->engine_clk)) {
|
||||
|
@ -1434,7 +1434,7 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *cec_np, *port, *ep, *remote, *i2c_np;
|
||||
struct device_node *cec_np, *remote, *i2c_np;
|
||||
struct platform_device *cec_pdev;
|
||||
struct regmap *regmap;
|
||||
struct resource *mem;
|
||||
@ -1486,29 +1486,9 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
|
||||
if (IS_ERR(hdmi->regs))
|
||||
return PTR_ERR(hdmi->regs);
|
||||
|
||||
port = of_graph_get_port_by_id(np, 1);
|
||||
if (!port) {
|
||||
dev_err(dev, "Missing output port node\n");
|
||||
remote = of_graph_get_remote_node(np, 1, 0);
|
||||
if (!remote)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ep = of_get_child_by_name(port, "endpoint");
|
||||
if (!ep) {
|
||||
dev_err(dev, "Missing endpoint node in port %s\n",
|
||||
port->full_name);
|
||||
of_node_put(port);
|
||||
return -EINVAL;
|
||||
}
|
||||
of_node_put(port);
|
||||
|
||||
remote = of_graph_get_remote_port_parent(ep);
|
||||
if (!remote) {
|
||||
dev_err(dev, "Missing connector/bridge node for endpoint %s\n",
|
||||
ep->full_name);
|
||||
of_node_put(ep);
|
||||
return -EINVAL;
|
||||
}
|
||||
of_node_put(ep);
|
||||
|
||||
if (!of_device_is_compatible(remote, "hdmi-connector")) {
|
||||
hdmi->next_bridge = of_drm_find_bridge(remote);
|
||||
|
@ -7,3 +7,9 @@ config DRM_MESON
|
||||
select DRM_GEM_CMA_HELPER
|
||||
select VIDEOMODE_HELPERS
|
||||
select REGMAP_MMIO
|
||||
|
||||
config DRM_MESON_DW_HDMI
|
||||
tristate "HDMI Synopsys Controller support for Amlogic Meson Display"
|
||||
depends on DRM_MESON
|
||||
default y if DRM_MESON
|
||||
select DRM_DW_HDMI
|
||||
|
@ -2,3 +2,4 @@ meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o
|
||||
meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o
|
||||
|
||||
obj-$(CONFIG_DRM_MESON) += meson-drm.o
|
||||
obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o
|
||||
|
@ -24,7 +24,9 @@
|
||||
#include "meson_canvas.h"
|
||||
#include "meson_registers.h"
|
||||
|
||||
/*
|
||||
/**
|
||||
* DOC: Canvas
|
||||
*
|
||||
* CANVAS is a memory zone where physical memory frames information
|
||||
* are stored for the VIU to scanout.
|
||||
*/
|
||||
|
@ -82,11 +82,18 @@ static const struct drm_crtc_funcs meson_crtc_funcs = {
|
||||
static void meson_crtc_enable(struct drm_crtc *crtc)
|
||||
{
|
||||
struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
|
||||
struct drm_plane *plane = meson_crtc->priv->primary_plane;
|
||||
struct drm_crtc_state *crtc_state = crtc->state;
|
||||
struct meson_drm *priv = meson_crtc->priv;
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
||||
if (!crtc_state) {
|
||||
DRM_ERROR("Invalid crtc_state\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enable VPP Postblend */
|
||||
writel(plane->state->crtc_w,
|
||||
writel(crtc_state->mode.hdisplay,
|
||||
priv->io_base + _REG(VPP_POSTBLEND_H_SIZE));
|
||||
|
||||
writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE,
|
||||
@ -101,6 +108,7 @@ static void meson_crtc_disable(struct drm_crtc *crtc)
|
||||
struct meson_drm *priv = meson_crtc->priv;
|
||||
|
||||
priv->viu.osd1_enabled = false;
|
||||
priv->viu.osd1_commit = false;
|
||||
|
||||
/* Disable VPP Postblend */
|
||||
writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0,
|
||||
@ -137,8 +145,7 @@ static void meson_crtc_atomic_flush(struct drm_crtc *crtc,
|
||||
struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
|
||||
struct meson_drm *priv = meson_crtc->priv;
|
||||
|
||||
if (priv->viu.osd1_enabled)
|
||||
priv->viu.osd1_commit = true;
|
||||
priv->viu.osd1_commit = true;
|
||||
}
|
||||
|
||||
static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = {
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
@ -51,13 +52,14 @@
|
||||
#define DRIVER_NAME "meson"
|
||||
#define DRIVER_DESC "Amlogic Meson DRM driver"
|
||||
|
||||
/*
|
||||
* Video Processing Unit
|
||||
/**
|
||||
* DOC: Video Processing Unit
|
||||
*
|
||||
* VPU Handles the Global Video Processing, it includes management of the
|
||||
* clocks gates, blocks reset lines and power domains.
|
||||
*
|
||||
* What is missing :
|
||||
*
|
||||
* - Full reset of entire video processing HW blocks
|
||||
* - Scaling and setup of the VPU clock
|
||||
* - Bus clock gates
|
||||
@ -150,9 +152,9 @@ static struct regmap_config meson_regmap_config = {
|
||||
.max_register = 0x1000,
|
||||
};
|
||||
|
||||
static int meson_drv_probe(struct platform_device *pdev)
|
||||
static int meson_drv_bind(struct device *dev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct meson_drm *priv;
|
||||
struct drm_device *drm;
|
||||
struct resource *res;
|
||||
@ -215,6 +217,15 @@ static int meson_drv_probe(struct platform_device *pdev)
|
||||
|
||||
drm_vblank_init(drm, 1);
|
||||
drm_mode_config_init(drm);
|
||||
drm->mode_config.max_width = 3840;
|
||||
drm->mode_config.max_height = 2160;
|
||||
drm->mode_config.funcs = &meson_mode_config_funcs;
|
||||
|
||||
/* Hardware Initialization */
|
||||
|
||||
meson_venc_init(priv);
|
||||
meson_vpp_init(priv);
|
||||
meson_viu_init(priv);
|
||||
|
||||
/* Encoder Initialization */
|
||||
|
||||
@ -222,11 +233,11 @@ static int meson_drv_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto free_drm;
|
||||
|
||||
/* Hardware Initialization */
|
||||
|
||||
meson_venc_init(priv);
|
||||
meson_vpp_init(priv);
|
||||
meson_viu_init(priv);
|
||||
ret = component_bind_all(drm->dev, drm);
|
||||
if (ret) {
|
||||
dev_err(drm->dev, "Couldn't bind all components\n");
|
||||
goto free_drm;
|
||||
}
|
||||
|
||||
ret = meson_plane_create(priv);
|
||||
if (ret)
|
||||
@ -241,9 +252,6 @@ static int meson_drv_probe(struct platform_device *pdev)
|
||||
goto free_drm;
|
||||
|
||||
drm_mode_config_reset(drm);
|
||||
drm->mode_config.max_width = 8192;
|
||||
drm->mode_config.max_height = 8192;
|
||||
drm->mode_config.funcs = &meson_mode_config_funcs;
|
||||
|
||||
priv->fbdev = drm_fbdev_cma_init(drm, 32,
|
||||
drm->mode_config.num_connector);
|
||||
@ -268,9 +276,9 @@ free_drm:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int meson_drv_remove(struct platform_device *pdev)
|
||||
static void meson_drv_unbind(struct device *dev)
|
||||
{
|
||||
struct drm_device *drm = dev_get_drvdata(&pdev->dev);
|
||||
struct drm_device *drm = dev_get_drvdata(dev);
|
||||
struct meson_drm *priv = drm->dev_private;
|
||||
|
||||
drm_dev_unregister(drm);
|
||||
@ -280,9 +288,88 @@ static int meson_drv_remove(struct platform_device *pdev)
|
||||
drm_vblank_cleanup(drm);
|
||||
drm_dev_unref(drm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct component_master_ops meson_drv_master_ops = {
|
||||
.bind = meson_drv_bind,
|
||||
.unbind = meson_drv_unbind,
|
||||
};
|
||||
|
||||
static int compare_of(struct device *dev, void *data)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("Comparing of node %s with %s\n",
|
||||
of_node_full_name(dev->of_node),
|
||||
of_node_full_name(data));
|
||||
|
||||
return dev->of_node == data;
|
||||
}
|
||||
|
||||
/* Possible connectors nodes to ignore */
|
||||
static const struct of_device_id connectors_match[] = {
|
||||
{ .compatible = "composite-video-connector" },
|
||||
{ .compatible = "svideo-connector" },
|
||||
{ .compatible = "hdmi-connector" },
|
||||
{ .compatible = "dvi-connector" },
|
||||
{}
|
||||
};
|
||||
|
||||
static int meson_probe_remote(struct platform_device *pdev,
|
||||
struct component_match **match,
|
||||
struct device_node *parent,
|
||||
struct device_node *remote)
|
||||
{
|
||||
struct device_node *ep, *remote_node;
|
||||
int count = 1;
|
||||
|
||||
/* If node is a connector, return and do not add to match table */
|
||||
if (of_match_node(connectors_match, remote))
|
||||
return 1;
|
||||
|
||||
component_match_add(&pdev->dev, match, compare_of, remote);
|
||||
|
||||
for_each_endpoint_of_node(remote, ep) {
|
||||
remote_node = of_graph_get_remote_port_parent(ep);
|
||||
if (!remote_node ||
|
||||
remote_node == parent || /* Ignore parent endpoint */
|
||||
!of_device_is_available(remote_node))
|
||||
continue;
|
||||
|
||||
count += meson_probe_remote(pdev, match, remote, remote_node);
|
||||
|
||||
of_node_put(remote_node);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int meson_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct component_match *match = NULL;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *ep, *remote;
|
||||
int count = 0;
|
||||
|
||||
for_each_endpoint_of_node(np, ep) {
|
||||
remote = of_graph_get_remote_port_parent(ep);
|
||||
if (!remote || !of_device_is_available(remote))
|
||||
continue;
|
||||
|
||||
count += meson_probe_remote(pdev, &match, np, remote);
|
||||
}
|
||||
|
||||
/* If some endpoints were found, initialize the nodes */
|
||||
if (count) {
|
||||
dev_info(&pdev->dev, "Queued %d outputs on vpu\n", count);
|
||||
|
||||
return component_master_add_with_match(&pdev->dev,
|
||||
&meson_drv_master_ops,
|
||||
match);
|
||||
}
|
||||
|
||||
/* If no output endpoints were available, simply bail out */
|
||||
return 0;
|
||||
};
|
||||
|
||||
static const struct of_device_id dt_match[] = {
|
||||
{ .compatible = "amlogic,meson-gxbb-vpu" },
|
||||
{ .compatible = "amlogic,meson-gxl-vpu" },
|
||||
@ -293,7 +380,6 @@ MODULE_DEVICE_TABLE(of, dt_match);
|
||||
|
||||
static struct platform_driver meson_drm_platform_driver = {
|
||||
.probe = meson_drv_probe,
|
||||
.remove = meson_drv_remove,
|
||||
.driver = {
|
||||
.name = "meson-drm",
|
||||
.of_match_table = dt_match,
|
||||
|
@ -47,6 +47,9 @@ struct meson_drm {
|
||||
|
||||
struct {
|
||||
unsigned int current_mode;
|
||||
bool hdmi_repeat;
|
||||
bool venc_repeat;
|
||||
bool hdmi_use_enci;
|
||||
} venc;
|
||||
};
|
||||
|
||||
|
919
drivers/gpu/drm/meson/meson_dw_hdmi.c
Normal file
919
drivers/gpu/drm/meson/meson_dw_hdmi.c
Normal file
@ -0,0 +1,919 @@
|
||||
/*
|
||||
* Copyright (C) 2016 BayLibre, SAS
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
* Copyright (C) 2015 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/bridge/dw_hdmi.h>
|
||||
|
||||
#include <uapi/linux/media-bus-format.h>
|
||||
#include <uapi/linux/videodev2.h>
|
||||
|
||||
#include "meson_drv.h"
|
||||
#include "meson_venc.h"
|
||||
#include "meson_vclk.h"
|
||||
#include "meson_dw_hdmi.h"
|
||||
#include "meson_registers.h"
|
||||
|
||||
#define DRIVER_NAME "meson-dw-hdmi"
|
||||
#define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver"
|
||||
|
||||
/**
|
||||
* DOC: HDMI Output
|
||||
*
|
||||
* HDMI Output is composed of :
|
||||
*
|
||||
* - A Synopsys DesignWare HDMI Controller IP
|
||||
* - A TOP control block controlling the Clocks and PHY
|
||||
* - A custom HDMI PHY in order convert video to TMDS signal
|
||||
*
|
||||
* .. code::
|
||||
*
|
||||
* ___________________________________
|
||||
* | 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 a pair of 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.
|
||||
*
|
||||
* GXBB, GXL and GXM embeds the Synopsys DesignWare
|
||||
* HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF
|
||||
* audio source interfaces.
|
||||
*
|
||||
* We handle the following features :
|
||||
*
|
||||
* - HPD Rise & Fall interrupt
|
||||
* - HDMI Controller Interrupt
|
||||
* - HDMI PHY Init for 480i to 1080p60
|
||||
* - VENC & HDMI Clock setup for 480i to 1080p60
|
||||
* - VENC Mode setup for 480i to 1080p60
|
||||
*
|
||||
* What is missing :
|
||||
*
|
||||
* - PHY, Clock and Mode setup for 2k && 4k modes
|
||||
* - SDDC Scrambling mode for HDMI 2.0a
|
||||
* - HDCP Setup
|
||||
* - CEC Management
|
||||
*/
|
||||
|
||||
/* TOP Block Communication Channel */
|
||||
#define HDMITX_TOP_ADDR_REG 0x0
|
||||
#define HDMITX_TOP_DATA_REG 0x4
|
||||
#define HDMITX_TOP_CTRL_REG 0x8
|
||||
|
||||
/* Controller Communication Channel */
|
||||
#define HDMITX_DWC_ADDR_REG 0x10
|
||||
#define HDMITX_DWC_DATA_REG 0x14
|
||||
#define HDMITX_DWC_CTRL_REG 0x18
|
||||
|
||||
/* HHI Registers */
|
||||
#define HHI_MEM_PD_REG0 0x100 /* 0x40 */
|
||||
#define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 */
|
||||
#define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 */
|
||||
#define HHI_HDMI_PHY_CNTL1 0x3a4 /* 0xe9 */
|
||||
#define HHI_HDMI_PHY_CNTL2 0x3a8 /* 0xea */
|
||||
#define HHI_HDMI_PHY_CNTL3 0x3ac /* 0xeb */
|
||||
|
||||
static DEFINE_SPINLOCK(reg_lock);
|
||||
|
||||
enum meson_venc_source {
|
||||
MESON_VENC_SOURCE_NONE = 0,
|
||||
MESON_VENC_SOURCE_ENCI = 1,
|
||||
MESON_VENC_SOURCE_ENCP = 2,
|
||||
};
|
||||
|
||||
struct meson_dw_hdmi {
|
||||
struct drm_encoder encoder;
|
||||
struct dw_hdmi_plat_data dw_plat_data;
|
||||
struct meson_drm *priv;
|
||||
struct device *dev;
|
||||
void __iomem *hdmitx;
|
||||
struct reset_control *hdmitx_apb;
|
||||
struct reset_control *hdmitx_ctrl;
|
||||
struct reset_control *hdmitx_phy;
|
||||
struct clk *hdmi_pclk;
|
||||
struct clk *venci_clk;
|
||||
u32 irq_stat;
|
||||
};
|
||||
#define encoder_to_meson_dw_hdmi(x) \
|
||||
container_of(x, struct meson_dw_hdmi, encoder)
|
||||
|
||||
static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi,
|
||||
const char *compat)
|
||||
{
|
||||
return of_device_is_compatible(dw_hdmi->dev->of_node, compat);
|
||||
}
|
||||
|
||||
/* PHY (via TOP bridge) and Controller dedicated register interface */
|
||||
|
||||
static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int data;
|
||||
|
||||
spin_lock_irqsave(®_lock, flags);
|
||||
|
||||
/* ADDR must be written twice */
|
||||
writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
|
||||
writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
|
||||
|
||||
/* Read needs a second DATA read */
|
||||
data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
|
||||
data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
|
||||
|
||||
spin_unlock_irqrestore(®_lock, flags);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr, unsigned int data)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(®_lock, flags);
|
||||
|
||||
/* ADDR must be written twice */
|
||||
writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
|
||||
writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
|
||||
|
||||
/* Write needs single DATA write */
|
||||
writel(data, dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
|
||||
|
||||
spin_unlock_irqrestore(®_lock, flags);
|
||||
}
|
||||
|
||||
/* Helper to change specific bits in PHY registers */
|
||||
static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr,
|
||||
unsigned int mask,
|
||||
unsigned int val)
|
||||
{
|
||||
unsigned int data = dw_hdmi_top_read(dw_hdmi, addr);
|
||||
|
||||
data &= ~mask;
|
||||
data |= val;
|
||||
|
||||
dw_hdmi_top_write(dw_hdmi, addr, data);
|
||||
}
|
||||
|
||||
static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int data;
|
||||
|
||||
spin_lock_irqsave(®_lock, flags);
|
||||
|
||||
/* ADDR must be written twice */
|
||||
writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
|
||||
writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
|
||||
|
||||
/* Read needs a second DATA read */
|
||||
data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
|
||||
data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
|
||||
|
||||
spin_unlock_irqrestore(®_lock, flags);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr, unsigned int data)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(®_lock, flags);
|
||||
|
||||
/* ADDR must be written twice */
|
||||
writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
|
||||
writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
|
||||
|
||||
/* Write needs single DATA write */
|
||||
writel(data, dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
|
||||
|
||||
spin_unlock_irqrestore(®_lock, flags);
|
||||
}
|
||||
|
||||
/* Helper to change specific bits in controller registers */
|
||||
static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr,
|
||||
unsigned int mask,
|
||||
unsigned int val)
|
||||
{
|
||||
unsigned int data = dw_hdmi_dwc_read(dw_hdmi, addr);
|
||||
|
||||
data &= ~mask;
|
||||
data |= val;
|
||||
|
||||
dw_hdmi_dwc_write(dw_hdmi, addr, data);
|
||||
}
|
||||
|
||||
/* Bridge */
|
||||
|
||||
/* Setup PHY bandwidth modes */
|
||||
static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
unsigned int pixel_clock = mode->clock;
|
||||
|
||||
if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
|
||||
dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) {
|
||||
if (pixel_clock >= 371250) {
|
||||
/* 5.94Gbps, 3.7125Gbps */
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x333d3282);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2136315b);
|
||||
} else if (pixel_clock >= 297000) {
|
||||
/* 2.97Gbps */
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303382);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2036315b);
|
||||
} else if (pixel_clock >= 148500) {
|
||||
/* 1.485Gbps */
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303362);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2016315b);
|
||||
} else {
|
||||
/* 742.5Mbps, and below */
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33604142);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x0016315b);
|
||||
}
|
||||
} else if (dw_hdmi_is_compatible(dw_hdmi,
|
||||
"amlogic,meson-gxbb-dw-hdmi")) {
|
||||
if (pixel_clock >= 371250) {
|
||||
/* 5.94Gbps, 3.7125Gbps */
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33353245);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2100115b);
|
||||
} else if (pixel_clock >= 297000) {
|
||||
/* 2.97Gbps */
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33634283);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0xb000115b);
|
||||
} else {
|
||||
/* 1.485Gbps, and below */
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi)
|
||||
{
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
|
||||
/* Enable and software reset */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xf);
|
||||
|
||||
mdelay(2);
|
||||
|
||||
/* Enable and unreset */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xe);
|
||||
|
||||
mdelay(2);
|
||||
}
|
||||
|
||||
static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
int vic = drm_match_cea_mode(mode);
|
||||
unsigned int vclk_freq;
|
||||
unsigned int venc_freq;
|
||||
unsigned int hdmi_freq;
|
||||
|
||||
vclk_freq = mode->clock;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
vclk_freq *= 2;
|
||||
|
||||
venc_freq = vclk_freq;
|
||||
hdmi_freq = vclk_freq;
|
||||
|
||||
if (meson_venc_hdmi_venc_repeat(vic))
|
||||
venc_freq *= 2;
|
||||
|
||||
vclk_freq = max(venc_freq, hdmi_freq);
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
venc_freq /= 2;
|
||||
|
||||
DRM_DEBUG_DRIVER("vclk:%d venc=%d hdmi=%d enci=%d\n",
|
||||
vclk_freq, venc_freq, hdmi_freq,
|
||||
priv->venc.hdmi_use_enci);
|
||||
|
||||
meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, vclk_freq,
|
||||
venc_freq, hdmi_freq, priv->venc.hdmi_use_enci);
|
||||
}
|
||||
|
||||
static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
unsigned int wr_clk =
|
||||
readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING));
|
||||
|
||||
DRM_DEBUG_DRIVER("%d:\"%s\"\n", mode->base.id, mode->name);
|
||||
|
||||
/* Enable clocks */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
|
||||
|
||||
/* Bring HDMITX MEM output of power down */
|
||||
regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
|
||||
|
||||
/* Bring out of reset */
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0);
|
||||
|
||||
/* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */
|
||||
dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
|
||||
0x3, 0x3);
|
||||
dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
|
||||
0x3 << 4, 0x3 << 4);
|
||||
|
||||
/* Enable normal output to PHY */
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
|
||||
|
||||
/* TMDS pattern setup (TOFIX pattern for 4k2k scrambling) */
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0x001f001f);
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 0x001f001f);
|
||||
|
||||
/* Load TMDS pattern */
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
|
||||
msleep(20);
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2);
|
||||
|
||||
/* Setup PHY parameters */
|
||||
meson_hdmi_phy_setup_mode(dw_hdmi, mode);
|
||||
|
||||
/* Setup PHY */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
|
||||
0xffff << 16, 0x0390 << 16);
|
||||
|
||||
/* BIT_INVERT */
|
||||
if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
|
||||
dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
|
||||
BIT(17), 0);
|
||||
else
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
|
||||
BIT(17), BIT(17));
|
||||
|
||||
/* Disable clock, fifo, fifo_wr */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0);
|
||||
|
||||
msleep(100);
|
||||
|
||||
/* Reset PHY 3 times in a row */
|
||||
dw_hdmi_phy_reset(dw_hdmi);
|
||||
dw_hdmi_phy_reset(dw_hdmi);
|
||||
dw_hdmi_phy_reset(dw_hdmi);
|
||||
|
||||
/* Temporary Disable VENC video stream */
|
||||
if (priv->venc.hdmi_use_enci)
|
||||
writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
|
||||
else
|
||||
writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
|
||||
|
||||
/* Temporary Disable HDMI video stream to HDMI-TX */
|
||||
writel_bits_relaxed(0x3, 0,
|
||||
priv->io_base + _REG(VPU_HDMI_SETTING));
|
||||
writel_bits_relaxed(0xf << 8, 0,
|
||||
priv->io_base + _REG(VPU_HDMI_SETTING));
|
||||
|
||||
/* Re-Enable VENC video stream */
|
||||
if (priv->venc.hdmi_use_enci)
|
||||
writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
|
||||
else
|
||||
writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
|
||||
|
||||
/* Push back HDMI clock settings */
|
||||
writel_bits_relaxed(0xf << 8, wr_clk & (0xf << 8),
|
||||
priv->io_base + _REG(VPU_HDMI_SETTING));
|
||||
|
||||
/* Enable and Select HDMI video source for HDMI-TX */
|
||||
if (priv->venc.hdmi_use_enci)
|
||||
writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCI,
|
||||
priv->io_base + _REG(VPU_HDMI_SETTING));
|
||||
else
|
||||
writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCP,
|
||||
priv->io_base + _REG(VPU_HDMI_SETTING));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi,
|
||||
void *data)
|
||||
{
|
||||
struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0);
|
||||
}
|
||||
|
||||
static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi,
|
||||
void *data)
|
||||
{
|
||||
struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
|
||||
|
||||
return !!dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_STAT0) ?
|
||||
connector_status_connected : connector_status_disconnected;
|
||||
}
|
||||
|
||||
static void dw_hdmi_setup_hpd(struct dw_hdmi *hdmi,
|
||||
void *data)
|
||||
{
|
||||
struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
|
||||
|
||||
/* Setup HPD Filter */
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER,
|
||||
(0xa << 12) | 0xa0);
|
||||
|
||||
/* Clear interrupts */
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
|
||||
HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL);
|
||||
|
||||
/* Unmask interrupts */
|
||||
dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_INTR_MASKN,
|
||||
HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL,
|
||||
HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL);
|
||||
}
|
||||
|
||||
static const struct dw_hdmi_phy_ops meson_dw_hdmi_phy_ops = {
|
||||
.init = dw_hdmi_phy_init,
|
||||
.disable = dw_hdmi_phy_disable,
|
||||
.read_hpd = dw_hdmi_read_hpd,
|
||||
.setup_hpd = dw_hdmi_setup_hpd,
|
||||
};
|
||||
|
||||
static irqreturn_t dw_hdmi_top_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct meson_dw_hdmi *dw_hdmi = dev_id;
|
||||
u32 stat;
|
||||
|
||||
stat = dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_INTR_STAT);
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat);
|
||||
|
||||
/* HPD Events, handle in the threaded interrupt handler */
|
||||
if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) {
|
||||
dw_hdmi->irq_stat = stat;
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
/* HDMI Controller Interrupt */
|
||||
if (stat & 1)
|
||||
return IRQ_NONE;
|
||||
|
||||
/* TOFIX Handle HDCP Interrupts */
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Threaded interrupt handler to manage HPD events */
|
||||
static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct meson_dw_hdmi *dw_hdmi = dev_id;
|
||||
u32 stat = dw_hdmi->irq_stat;
|
||||
|
||||
/* HPD Events */
|
||||
if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) {
|
||||
bool hpd_connected = false;
|
||||
|
||||
if (stat & HDMITX_TOP_INTR_HPD_RISE)
|
||||
hpd_connected = true;
|
||||
|
||||
dw_hdmi_setup_rx_sense(dw_hdmi->dev, hpd_connected,
|
||||
hpd_connected);
|
||||
|
||||
drm_helper_hpd_irq_event(dw_hdmi->encoder.dev);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* TOFIX Enable support for non-vic modes */
|
||||
static enum drm_mode_status dw_hdmi_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
unsigned int vclk_freq;
|
||||
unsigned int venc_freq;
|
||||
unsigned int hdmi_freq;
|
||||
int vic = drm_match_cea_mode(mode);
|
||||
|
||||
DRM_DEBUG_DRIVER("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
|
||||
mode->base.id, mode->name, mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start,
|
||||
mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start,
|
||||
mode->vsync_end, mode->vtotal, mode->type, mode->flags);
|
||||
|
||||
/* For now, only accept VIC modes */
|
||||
if (!vic)
|
||||
return MODE_BAD;
|
||||
|
||||
/* For now, filter by supported VIC modes */
|
||||
if (!meson_venc_hdmi_supported_vic(vic))
|
||||
return MODE_BAD;
|
||||
|
||||
vclk_freq = mode->clock;
|
||||
|
||||
/* 480i/576i needs global pixel doubling */
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
vclk_freq *= 2;
|
||||
|
||||
venc_freq = vclk_freq;
|
||||
hdmi_freq = vclk_freq;
|
||||
|
||||
/* VENC double pixels for 1080i and 720p modes */
|
||||
if (meson_venc_hdmi_venc_repeat(vic))
|
||||
venc_freq *= 2;
|
||||
|
||||
vclk_freq = max(venc_freq, hdmi_freq);
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
venc_freq /= 2;
|
||||
|
||||
dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
|
||||
vclk_freq, venc_freq, hdmi_freq);
|
||||
|
||||
/* Finally filter by configurable vclk frequencies */
|
||||
switch (vclk_freq) {
|
||||
case 54000:
|
||||
case 74250:
|
||||
case 148500:
|
||||
case 297000:
|
||||
case 594000:
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
return MODE_CLOCK_RANGE;
|
||||
}
|
||||
|
||||
/* Encoder */
|
||||
|
||||
static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder)
|
||||
{
|
||||
drm_encoder_cleanup(encoder);
|
||||
}
|
||||
|
||||
static const struct drm_encoder_funcs meson_venc_hdmi_encoder_funcs = {
|
||||
.destroy = meson_venc_hdmi_encoder_destroy,
|
||||
};
|
||||
|
||||
static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
||||
writel_bits_relaxed(0x3, 0,
|
||||
priv->io_base + _REG(VPU_HDMI_SETTING));
|
||||
|
||||
writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
|
||||
writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
|
||||
}
|
||||
|
||||
static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP");
|
||||
|
||||
if (priv->venc.hdmi_use_enci)
|
||||
writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
|
||||
else
|
||||
writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
|
||||
}
|
||||
|
||||
static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
int vic = drm_match_cea_mode(mode);
|
||||
|
||||
DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n",
|
||||
mode->base.id, mode->name, vic);
|
||||
|
||||
/* Should have been filtered */
|
||||
if (!vic)
|
||||
return;
|
||||
|
||||
/* VENC + VENC-DVI Mode setup */
|
||||
meson_venc_hdmi_mode_set(priv, vic, mode);
|
||||
|
||||
/* VCLK Set clock */
|
||||
dw_hdmi_set_vclk(dw_hdmi, mode);
|
||||
|
||||
/* Setup YUV444 to HDMI-TX, no 10bit diphering */
|
||||
writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs
|
||||
meson_venc_hdmi_encoder_helper_funcs = {
|
||||
.atomic_check = meson_venc_hdmi_encoder_atomic_check,
|
||||
.disable = meson_venc_hdmi_encoder_disable,
|
||||
.enable = meson_venc_hdmi_encoder_enable,
|
||||
.mode_set = meson_venc_hdmi_encoder_mode_set,
|
||||
};
|
||||
|
||||
/* DW HDMI Regmap */
|
||||
|
||||
static int meson_dw_hdmi_reg_read(void *context, unsigned int reg,
|
||||
unsigned int *result)
|
||||
{
|
||||
*result = dw_hdmi_dwc_read(context, reg);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int meson_dw_hdmi_reg_write(void *context, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
dw_hdmi_dwc_write(context, reg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config meson_dw_hdmi_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 8,
|
||||
.reg_read = meson_dw_hdmi_reg_read,
|
||||
.reg_write = meson_dw_hdmi_reg_write,
|
||||
.max_register = 0x10000,
|
||||
};
|
||||
|
||||
static bool meson_hdmi_connector_is_available(struct device *dev)
|
||||
{
|
||||
struct device_node *ep, *remote;
|
||||
|
||||
/* HDMI Connector is on the second port, first endpoint */
|
||||
ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0);
|
||||
if (!ep)
|
||||
return false;
|
||||
|
||||
/* If the endpoint node exists, consider it enabled */
|
||||
remote = of_graph_get_remote_port(ep);
|
||||
if (remote) {
|
||||
of_node_put(ep);
|
||||
return true;
|
||||
}
|
||||
|
||||
of_node_put(ep);
|
||||
of_node_put(remote);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct meson_dw_hdmi *meson_dw_hdmi;
|
||||
struct drm_device *drm = data;
|
||||
struct meson_drm *priv = drm->dev_private;
|
||||
struct dw_hdmi_plat_data *dw_plat_data;
|
||||
struct drm_encoder *encoder;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
||||
if (!meson_hdmi_connector_is_available(dev)) {
|
||||
dev_info(drm->dev, "HDMI Output connector not available\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi),
|
||||
GFP_KERNEL);
|
||||
if (!meson_dw_hdmi)
|
||||
return -ENOMEM;
|
||||
|
||||
meson_dw_hdmi->priv = priv;
|
||||
meson_dw_hdmi->dev = dev;
|
||||
dw_plat_data = &meson_dw_hdmi->dw_plat_data;
|
||||
encoder = &meson_dw_hdmi->encoder;
|
||||
|
||||
meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev,
|
||||
"hdmitx_apb");
|
||||
if (IS_ERR(meson_dw_hdmi->hdmitx_apb)) {
|
||||
dev_err(dev, "Failed to get hdmitx_apb reset\n");
|
||||
return PTR_ERR(meson_dw_hdmi->hdmitx_apb);
|
||||
}
|
||||
|
||||
meson_dw_hdmi->hdmitx_ctrl = devm_reset_control_get_exclusive(dev,
|
||||
"hdmitx");
|
||||
if (IS_ERR(meson_dw_hdmi->hdmitx_ctrl)) {
|
||||
dev_err(dev, "Failed to get hdmitx reset\n");
|
||||
return PTR_ERR(meson_dw_hdmi->hdmitx_ctrl);
|
||||
}
|
||||
|
||||
meson_dw_hdmi->hdmitx_phy = devm_reset_control_get_exclusive(dev,
|
||||
"hdmitx_phy");
|
||||
if (IS_ERR(meson_dw_hdmi->hdmitx_phy)) {
|
||||
dev_err(dev, "Failed to get hdmitx_phy reset\n");
|
||||
return PTR_ERR(meson_dw_hdmi->hdmitx_phy);
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
meson_dw_hdmi->hdmitx = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(meson_dw_hdmi->hdmitx))
|
||||
return PTR_ERR(meson_dw_hdmi->hdmitx);
|
||||
|
||||
meson_dw_hdmi->hdmi_pclk = devm_clk_get(dev, "isfr");
|
||||
if (IS_ERR(meson_dw_hdmi->hdmi_pclk)) {
|
||||
dev_err(dev, "Unable to get HDMI pclk\n");
|
||||
return PTR_ERR(meson_dw_hdmi->hdmi_pclk);
|
||||
}
|
||||
clk_prepare_enable(meson_dw_hdmi->hdmi_pclk);
|
||||
|
||||
meson_dw_hdmi->venci_clk = devm_clk_get(dev, "venci");
|
||||
if (IS_ERR(meson_dw_hdmi->venci_clk)) {
|
||||
dev_err(dev, "Unable to get venci clk\n");
|
||||
return PTR_ERR(meson_dw_hdmi->venci_clk);
|
||||
}
|
||||
clk_prepare_enable(meson_dw_hdmi->venci_clk);
|
||||
|
||||
dw_plat_data->regm = devm_regmap_init(dev, NULL, meson_dw_hdmi,
|
||||
&meson_dw_hdmi_regmap_config);
|
||||
if (IS_ERR(dw_plat_data->regm))
|
||||
return PTR_ERR(dw_plat_data->regm);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "Failed to get hdmi top irq\n");
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, dw_hdmi_top_irq,
|
||||
dw_hdmi_top_thread_irq, IRQF_SHARED,
|
||||
"dw_hdmi_top_irq", meson_dw_hdmi);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to request hdmi top irq\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Encoder */
|
||||
|
||||
drm_encoder_helper_add(encoder, &meson_venc_hdmi_encoder_helper_funcs);
|
||||
|
||||
ret = drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS, "meson_hdmi");
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "Failed to init HDMI encoder\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
encoder->possible_crtcs = BIT(0);
|
||||
|
||||
DRM_DEBUG_DRIVER("encoder initialized\n");
|
||||
|
||||
/* Enable clocks */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
|
||||
|
||||
/* Bring HDMITX MEM output of power down */
|
||||
regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
|
||||
|
||||
/* Reset HDMITX APB & TX & PHY */
|
||||
reset_control_reset(meson_dw_hdmi->hdmitx_apb);
|
||||
reset_control_reset(meson_dw_hdmi->hdmitx_ctrl);
|
||||
reset_control_reset(meson_dw_hdmi->hdmitx_phy);
|
||||
|
||||
/* Enable APB3 fail on error */
|
||||
writel_bits_relaxed(BIT(15), BIT(15),
|
||||
meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG);
|
||||
writel_bits_relaxed(BIT(15), BIT(15),
|
||||
meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG);
|
||||
|
||||
/* Bring out of reset */
|
||||
dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_SW_RESET, 0);
|
||||
|
||||
msleep(20);
|
||||
|
||||
dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_CLK_CNTL, 0xff);
|
||||
|
||||
/* Enable HDMI-TX Interrupt */
|
||||
dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
|
||||
HDMITX_TOP_INTR_CORE);
|
||||
|
||||
dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN,
|
||||
HDMITX_TOP_INTR_CORE);
|
||||
|
||||
/* Bridge / Connector */
|
||||
|
||||
dw_plat_data->mode_valid = dw_hdmi_mode_valid;
|
||||
dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops;
|
||||
dw_plat_data->phy_name = "meson_dw_hdmi_phy";
|
||||
dw_plat_data->phy_data = meson_dw_hdmi;
|
||||
dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
|
||||
dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
|
||||
|
||||
ret = dw_hdmi_bind(pdev, encoder, &meson_dw_hdmi->dw_plat_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
DRM_DEBUG_DRIVER("HDMI controller initialized\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void meson_dw_hdmi_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
dw_hdmi_unbind(dev);
|
||||
}
|
||||
|
||||
static const struct component_ops meson_dw_hdmi_ops = {
|
||||
.bind = meson_dw_hdmi_bind,
|
||||
.unbind = meson_dw_hdmi_unbind,
|
||||
};
|
||||
|
||||
static int meson_dw_hdmi_probe(struct platform_device *pdev)
|
||||
{
|
||||
return component_add(&pdev->dev, &meson_dw_hdmi_ops);
|
||||
}
|
||||
|
||||
static int meson_dw_hdmi_remove(struct platform_device *pdev)
|
||||
{
|
||||
component_del(&pdev->dev, &meson_dw_hdmi_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id meson_dw_hdmi_of_table[] = {
|
||||
{ .compatible = "amlogic,meson-gxbb-dw-hdmi" },
|
||||
{ .compatible = "amlogic,meson-gxl-dw-hdmi" },
|
||||
{ .compatible = "amlogic,meson-gxm-dw-hdmi" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table);
|
||||
|
||||
static struct platform_driver meson_dw_hdmi_platform_driver = {
|
||||
.probe = meson_dw_hdmi_probe,
|
||||
.remove = meson_dw_hdmi_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = meson_dw_hdmi_of_table,
|
||||
},
|
||||
};
|
||||
module_platform_driver(meson_dw_hdmi_platform_driver);
|
||||
|
||||
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
146
drivers/gpu/drm/meson/meson_dw_hdmi.h
Normal file
146
drivers/gpu/drm/meson/meson_dw_hdmi.h
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (C) 2016 BayLibre, SAS
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
* Copyright (C) 2015 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __MESON_DW_HDMI_H
|
||||
#define __MESON_DW_HDMI_H
|
||||
|
||||
/*
|
||||
* Bit 7 RW Reserved. Default 1.
|
||||
* Bit 6 RW Reserved. Default 1.
|
||||
* Bit 5 RW Reserved. Default 1.
|
||||
* Bit 4 RW sw_reset_phyif: PHY interface. 1=Apply reset; 0=Release from reset.
|
||||
* Default 1.
|
||||
* Bit 3 RW sw_reset_intr: interrupt module. 1=Apply reset;
|
||||
* 0=Release from reset.
|
||||
* Default 1.
|
||||
* Bit 2 RW sw_reset_mem: KSV/REVOC mem. 1=Apply reset; 0=Release from reset.
|
||||
* Default 1.
|
||||
* Bit 1 RW sw_reset_rnd: random number interface to HDCP. 1=Apply reset;
|
||||
* 0=Release from reset. Default 1.
|
||||
* Bit 0 RW sw_reset_core: connects to IP's ~irstz. 1=Apply reset;
|
||||
* 0=Release from reset. Default 1.
|
||||
*/
|
||||
#define HDMITX_TOP_SW_RESET (0x000)
|
||||
|
||||
/*
|
||||
* Bit 12 RW i2s_ws_inv:1=Invert i2s_ws; 0=No invert. Default 0.
|
||||
* Bit 11 RW i2s_clk_inv: 1=Invert i2s_clk; 0=No invert. Default 0.
|
||||
* Bit 10 RW spdif_clk_inv: 1=Invert spdif_clk; 0=No invert. Default 0.
|
||||
* Bit 9 RW tmds_clk_inv: 1=Invert tmds_clk; 0=No invert. Default 0.
|
||||
* Bit 8 RW pixel_clk_inv: 1=Invert pixel_clk; 0=No invert. Default 0.
|
||||
* Bit 4 RW cec_clk_en: 1=enable cec_clk; 0=disable. Default 0.
|
||||
* Bit 3 RW i2s_clk_en: 1=enable i2s_clk; 0=disable. Default 0.
|
||||
* Bit 2 RW spdif_clk_en: 1=enable spdif_clk; 0=disable. Default 0.
|
||||
* Bit 1 RW tmds_clk_en: 1=enable tmds_clk; 0=disable. Default 0.
|
||||
* Bit 0 RW pixel_clk_en: 1=enable pixel_clk; 0=disable. Default 0.
|
||||
*/
|
||||
#define HDMITX_TOP_CLK_CNTL (0x001)
|
||||
|
||||
/*
|
||||
* Bit 11: 0 RW hpd_valid_width: filter out width <= M*1024. Default 0.
|
||||
* Bit 15:12 RW hpd_glitch_width: filter out glitch <= N. Default 0.
|
||||
*/
|
||||
#define HDMITX_TOP_HPD_FILTER (0x002)
|
||||
|
||||
/*
|
||||
* intr_maskn: MASK_N, one bit per interrupt source.
|
||||
* 1=Enable interrupt source; 0=Disable interrupt source. Default 0.
|
||||
* [ 4] hdcp22_rndnum_err
|
||||
* [ 3] nonce_rfrsh_rise
|
||||
* [ 2] hpd_fall_intr
|
||||
* [ 1] hpd_rise_intr
|
||||
* [ 0] core_intr
|
||||
*/
|
||||
#define HDMITX_TOP_INTR_MASKN (0x003)
|
||||
|
||||
/*
|
||||
* Bit 30: 0 RW intr_stat: For each bit, write 1 to manually set the interrupt
|
||||
* bit, read back the interrupt status.
|
||||
* Bit 31 R IP interrupt status
|
||||
* Bit 2 RW hpd_fall
|
||||
* Bit 1 RW hpd_rise
|
||||
* Bit 0 RW IP interrupt
|
||||
*/
|
||||
#define HDMITX_TOP_INTR_STAT (0x004)
|
||||
|
||||
/*
|
||||
* [4] hdcp22_rndnum_err
|
||||
* [3] nonce_rfrsh_rise
|
||||
* [2] hpd_fall
|
||||
* [1] hpd_rise
|
||||
* [0] core_intr_rise
|
||||
*/
|
||||
#define HDMITX_TOP_INTR_STAT_CLR (0x005)
|
||||
|
||||
#define HDMITX_TOP_INTR_CORE BIT(0)
|
||||
#define HDMITX_TOP_INTR_HPD_RISE BIT(1)
|
||||
#define HDMITX_TOP_INTR_HPD_FALL BIT(2)
|
||||
|
||||
/* Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data;
|
||||
* 3'b010=Output PRBS data; 3'b100=Output shift pattern. Default 0.
|
||||
* Bit 11: 9 RW shift_pttn_repeat: 0=New pattern every clk cycle; 1=New pattern
|
||||
* every 2 clk cycles; ...; 7=New pattern every 8 clk cycles. Default 0.
|
||||
* Bit 8 RW shift_pttn_en: 1= Enable shift pattern generator; 0=Disable.
|
||||
* Default 0.
|
||||
* Bit 4: 3 RW prbs_pttn_mode: 0=PRBS11; 1=PRBS15; 2=PRBS7; 3=PRBS31. Default 0.
|
||||
* Bit 2: 1 RW prbs_pttn_width: 0=idle; 1=output 8-bit pattern;
|
||||
* 2=Output 1-bit pattern; 3=output 10-bit pattern. Default 0.
|
||||
* Bit 0 RW prbs_pttn_en: 1=Enable PRBS generator; 0=Disable. Default 0.
|
||||
*/
|
||||
#define HDMITX_TOP_BIST_CNTL (0x006)
|
||||
|
||||
/* Bit 29:20 RW shift_pttn_data[59:50]. Default 0. */
|
||||
/* Bit 19:10 RW shift_pttn_data[69:60]. Default 0. */
|
||||
/* Bit 9: 0 RW shift_pttn_data[79:70]. Default 0. */
|
||||
#define HDMITX_TOP_SHIFT_PTTN_012 (0x007)
|
||||
|
||||
/* Bit 29:20 RW shift_pttn_data[29:20]. Default 0. */
|
||||
/* Bit 19:10 RW shift_pttn_data[39:30]. Default 0. */
|
||||
/* Bit 9: 0 RW shift_pttn_data[49:40]. Default 0. */
|
||||
#define HDMITX_TOP_SHIFT_PTTN_345 (0x008)
|
||||
|
||||
/* Bit 19:10 RW shift_pttn_data[ 9: 0]. Default 0. */
|
||||
/* Bit 9: 0 RW shift_pttn_data[19:10]. Default 0. */
|
||||
#define HDMITX_TOP_SHIFT_PTTN_67 (0x009)
|
||||
|
||||
/* Bit 25:16 RW tmds_clk_pttn[19:10]. Default 0. */
|
||||
/* Bit 9: 0 RW tmds_clk_pttn[ 9: 0]. Default 0. */
|
||||
#define HDMITX_TOP_TMDS_CLK_PTTN_01 (0x00A)
|
||||
|
||||
/* Bit 25:16 RW tmds_clk_pttn[39:30]. Default 0. */
|
||||
/* Bit 9: 0 RW tmds_clk_pttn[29:20]. Default 0. */
|
||||
#define HDMITX_TOP_TMDS_CLK_PTTN_23 (0x00B)
|
||||
|
||||
/* Bit 1 RW shift_tmds_clk_pttn:1=Enable shifting clk pattern,
|
||||
* used when TMDS CLK rate = TMDS character rate /4. Default 0.
|
||||
* Bit 0 R Reserved. Default 0.
|
||||
* [ 1] shift_tmds_clk_pttn
|
||||
* [ 0] load_tmds_clk_pttn
|
||||
*/
|
||||
#define HDMITX_TOP_TMDS_CLK_PTTN_CNTL (0x00C)
|
||||
|
||||
/* Bit 0 RW revocmem_wr_fail: Read back 1 to indicate Host write REVOC MEM
|
||||
* failure, write 1 to clear the failure flag. Default 0.
|
||||
*/
|
||||
#define HDMITX_TOP_REVOCMEM_STAT (0x00D)
|
||||
|
||||
/* Bit 0 R filtered HPD status. */
|
||||
#define HDMITX_TOP_STAT0 (0x00E)
|
||||
|
||||
#endif /* __MESON_DW_HDMI_H */
|
@ -1319,6 +1319,7 @@
|
||||
#define VPU_MISC_CTRL 0x2740
|
||||
#define VPU_ISP_GCLK_CTRL0 0x2741
|
||||
#define VPU_ISP_GCLK_CTRL1 0x2742
|
||||
#define VPU_HDMI_FMT_CTRL 0x2743
|
||||
#define VPU_VDIN_ASYNC_HOLD_CTRL 0x2743
|
||||
#define VPU_VDISP_ASYNC_HOLD_CTRL 0x2744
|
||||
#define VPU_VPUARB2_ASYNC_HOLD_CTRL 0x2745
|
||||
|
@ -23,13 +23,38 @@
|
||||
#include "meson_drv.h"
|
||||
#include "meson_vclk.h"
|
||||
|
||||
/*
|
||||
/**
|
||||
* DOC: Video Clocks
|
||||
*
|
||||
* VCLK is the "Pixel Clock" frequency generator from a dedicated PLL.
|
||||
* We handle the following encodings :
|
||||
*
|
||||
* - CVBS 27MHz generator via the VCLK2 to the VENCI and VDAC blocks
|
||||
* - HDMI Pixel Clocks generation
|
||||
*
|
||||
* What is missing :
|
||||
* - HDMI Pixel Clocks generation
|
||||
*
|
||||
* - Genenate Pixel clocks for 2K/4K 10bit formats
|
||||
*
|
||||
* Clock generator scheme :
|
||||
*
|
||||
* .. code::
|
||||
*
|
||||
* __________ _________ _____
|
||||
* | | | | | |--ENCI
|
||||
* | HDMI PLL |-| PLL_DIV |--- VCLK--| |--ENCL
|
||||
* |__________| |_________| \ | MUX |--ENCP
|
||||
* --VCLK2-| |--VDAC
|
||||
* |_____|--HDMI-TX
|
||||
*
|
||||
* Final clocks can take input for either VCLK or VCLK2, but
|
||||
* VCLK is the preferred path for HDMI clocking and VCLK2 is the
|
||||
* preferred path for CVBS VDAC clocking.
|
||||
*
|
||||
* VCLK and VCLK2 have fixed divided clocks paths for /1, /2, /4, /6 or /12.
|
||||
*
|
||||
* The PLL_DIV can achieve an additional fractional dividing like
|
||||
* 1.5, 3.5, 3.75... to generate special 2K and 4K 10bit clocks.
|
||||
*/
|
||||
|
||||
/* HHI Registers */
|
||||
@ -50,11 +75,34 @@
|
||||
#define VCLK2_SOFT_RESET BIT(15)
|
||||
#define VCLK2_DIV1_EN BIT(0)
|
||||
#define HHI_VID_CLK_DIV 0x164 /* 0x59 offset in data sheet */
|
||||
#define VCLK_DIV_MASK 0xff
|
||||
#define VCLK_DIV_EN BIT(16)
|
||||
#define VCLK_DIV_RESET BIT(17)
|
||||
#define CTS_ENCP_SEL_MASK (0xf << 24)
|
||||
#define CTS_ENCP_SEL_SHIFT 24
|
||||
#define CTS_ENCI_SEL_MASK (0xf << 28)
|
||||
#define CTS_ENCI_SEL_SHIFT 28
|
||||
#define HHI_VID_CLK_CNTL 0x17c /* 0x5f offset in data sheet */
|
||||
#define VCLK_EN BIT(19)
|
||||
#define VCLK_SEL_MASK (0x7 << 16)
|
||||
#define VCLK_SEL_SHIFT 16
|
||||
#define VCLK_SOFT_RESET BIT(15)
|
||||
#define VCLK_DIV1_EN BIT(0)
|
||||
#define VCLK_DIV2_EN BIT(1)
|
||||
#define VCLK_DIV4_EN BIT(2)
|
||||
#define VCLK_DIV6_EN BIT(3)
|
||||
#define VCLK_DIV12_EN BIT(4)
|
||||
#define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in data sheet */
|
||||
#define CTS_ENCI_EN BIT(0)
|
||||
#define CTS_ENCP_EN BIT(2)
|
||||
#define CTS_VDAC_EN BIT(4)
|
||||
#define HDMI_TX_PIXEL_EN BIT(5)
|
||||
#define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 offset in data sheet */
|
||||
#define HDMI_TX_PIXEL_SEL_MASK (0xf << 16)
|
||||
#define HDMI_TX_PIXEL_SEL_SHIFT 16
|
||||
#define CTS_HDMI_SYS_SEL_MASK (0x7 << 9)
|
||||
#define CTS_HDMI_SYS_DIV_MASK (0x7f)
|
||||
#define CTS_HDMI_SYS_EN BIT(8)
|
||||
|
||||
#define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */
|
||||
#define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */
|
||||
@ -69,6 +117,126 @@
|
||||
#define HDMI_PLL_RESET BIT(28)
|
||||
#define HDMI_PLL_LOCK BIT(31)
|
||||
|
||||
/* VID PLL Dividers */
|
||||
enum {
|
||||
VID_PLL_DIV_1 = 0,
|
||||
VID_PLL_DIV_2,
|
||||
VID_PLL_DIV_2p5,
|
||||
VID_PLL_DIV_3,
|
||||
VID_PLL_DIV_3p5,
|
||||
VID_PLL_DIV_3p75,
|
||||
VID_PLL_DIV_4,
|
||||
VID_PLL_DIV_5,
|
||||
VID_PLL_DIV_6,
|
||||
VID_PLL_DIV_6p25,
|
||||
VID_PLL_DIV_7,
|
||||
VID_PLL_DIV_7p5,
|
||||
VID_PLL_DIV_12,
|
||||
VID_PLL_DIV_14,
|
||||
VID_PLL_DIV_15,
|
||||
};
|
||||
|
||||
void meson_vid_pll_set(struct meson_drm *priv, unsigned int div)
|
||||
{
|
||||
unsigned int shift_val = 0;
|
||||
unsigned int shift_sel = 0;
|
||||
|
||||
/* Disable vid_pll output clock */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_EN, 0);
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_PRESET, 0);
|
||||
|
||||
switch (div) {
|
||||
case VID_PLL_DIV_2:
|
||||
shift_val = 0x0aaa;
|
||||
shift_sel = 0;
|
||||
break;
|
||||
case VID_PLL_DIV_2p5:
|
||||
shift_val = 0x5294;
|
||||
shift_sel = 2;
|
||||
break;
|
||||
case VID_PLL_DIV_3:
|
||||
shift_val = 0x0db6;
|
||||
shift_sel = 0;
|
||||
break;
|
||||
case VID_PLL_DIV_3p5:
|
||||
shift_val = 0x36cc;
|
||||
shift_sel = 1;
|
||||
break;
|
||||
case VID_PLL_DIV_3p75:
|
||||
shift_val = 0x6666;
|
||||
shift_sel = 2;
|
||||
break;
|
||||
case VID_PLL_DIV_4:
|
||||
shift_val = 0x0ccc;
|
||||
shift_sel = 0;
|
||||
break;
|
||||
case VID_PLL_DIV_5:
|
||||
shift_val = 0x739c;
|
||||
shift_sel = 2;
|
||||
break;
|
||||
case VID_PLL_DIV_6:
|
||||
shift_val = 0x0e38;
|
||||
shift_sel = 0;
|
||||
break;
|
||||
case VID_PLL_DIV_6p25:
|
||||
shift_val = 0x0000;
|
||||
shift_sel = 3;
|
||||
break;
|
||||
case VID_PLL_DIV_7:
|
||||
shift_val = 0x3c78;
|
||||
shift_sel = 1;
|
||||
break;
|
||||
case VID_PLL_DIV_7p5:
|
||||
shift_val = 0x78f0;
|
||||
shift_sel = 2;
|
||||
break;
|
||||
case VID_PLL_DIV_12:
|
||||
shift_val = 0x0fc0;
|
||||
shift_sel = 0;
|
||||
break;
|
||||
case VID_PLL_DIV_14:
|
||||
shift_val = 0x3f80;
|
||||
shift_sel = 1;
|
||||
break;
|
||||
case VID_PLL_DIV_15:
|
||||
shift_val = 0x7f80;
|
||||
shift_sel = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (div == VID_PLL_DIV_1)
|
||||
/* Enable vid_pll bypass to HDMI pll */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
|
||||
VID_PLL_BYPASS, VID_PLL_BYPASS);
|
||||
else {
|
||||
/* Disable Bypass */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
|
||||
VID_PLL_BYPASS, 0);
|
||||
/* Clear sel */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
|
||||
3 << 16, 0);
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
|
||||
VID_PLL_PRESET, 0);
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
|
||||
0x7fff, 0);
|
||||
|
||||
/* Setup sel and val */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
|
||||
3 << 16, shift_sel << 16);
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
|
||||
VID_PLL_PRESET, VID_PLL_PRESET);
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
|
||||
0x7fff, shift_val);
|
||||
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
|
||||
VID_PLL_PRESET, 0);
|
||||
}
|
||||
|
||||
/* Enable the vid_pll output clock */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
|
||||
VID_PLL_EN, VID_PLL_EN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup VCLK2 for 27MHz, and enable clocks for ENCI and VDAC
|
||||
*
|
||||
@ -110,15 +278,8 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
|
||||
/* Disable VCLK2 */
|
||||
regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 0);
|
||||
|
||||
/* Disable vid_pll output clock */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_EN, 0);
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_PRESET, 0);
|
||||
/* Enable vid_pll bypass to HDMI pll */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
|
||||
VID_PLL_BYPASS, VID_PLL_BYPASS);
|
||||
/* Enable the vid_pll output clock */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
|
||||
VID_PLL_EN, VID_PLL_EN);
|
||||
/* Setup vid_pll to /1 */
|
||||
meson_vid_pll_set(priv, VID_PLL_DIV_1);
|
||||
|
||||
/* Setup the VCLK2 divider value to achieve 27MHz */
|
||||
regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV,
|
||||
@ -159,9 +320,454 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
|
||||
CTS_VDAC_EN, CTS_VDAC_EN);
|
||||
}
|
||||
|
||||
void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
|
||||
unsigned int freq)
|
||||
|
||||
/* PLL O1 O2 O3 VP DV EN TX */
|
||||
/* 4320 /4 /4 /1 /5 /1 => /2 /2 */
|
||||
#define MESON_VCLK_HDMI_ENCI_54000 1
|
||||
/* 4320 /4 /4 /1 /5 /1 => /1 /2 */
|
||||
#define MESON_VCLK_HDMI_DDR_54000 2
|
||||
/* 2970 /4 /1 /1 /5 /1 => /1 /2 */
|
||||
#define MESON_VCLK_HDMI_DDR_148500 3
|
||||
/* 2970 /2 /2 /2 /5 /1 => /1 /1 */
|
||||
#define MESON_VCLK_HDMI_74250 4
|
||||
/* 2970 /1 /2 /2 /5 /1 => /1 /1 */
|
||||
#define MESON_VCLK_HDMI_148500 5
|
||||
/* 2970 /1 /1 /1 /5 /2 => /1 /1 */
|
||||
#define MESON_VCLK_HDMI_297000 6
|
||||
/* 5940 /1 /1 /2 /5 /1 => /1 /1 */
|
||||
#define MESON_VCLK_HDMI_594000 7
|
||||
|
||||
struct meson_vclk_params {
|
||||
unsigned int pll_base_freq;
|
||||
unsigned int pll_od1;
|
||||
unsigned int pll_od2;
|
||||
unsigned int pll_od3;
|
||||
unsigned int vid_pll_div;
|
||||
unsigned int vclk_div;
|
||||
} params[] = {
|
||||
[MESON_VCLK_HDMI_ENCI_54000] = {
|
||||
.pll_base_freq = 4320000,
|
||||
.pll_od1 = 4,
|
||||
.pll_od2 = 4,
|
||||
.pll_od3 = 1,
|
||||
.vid_pll_div = VID_PLL_DIV_5,
|
||||
.vclk_div = 1,
|
||||
},
|
||||
[MESON_VCLK_HDMI_DDR_54000] = {
|
||||
.pll_base_freq = 4320000,
|
||||
.pll_od1 = 4,
|
||||
.pll_od2 = 4,
|
||||
.pll_od3 = 1,
|
||||
.vid_pll_div = VID_PLL_DIV_5,
|
||||
.vclk_div = 1,
|
||||
},
|
||||
[MESON_VCLK_HDMI_DDR_148500] = {
|
||||
.pll_base_freq = 2970000,
|
||||
.pll_od1 = 4,
|
||||
.pll_od2 = 1,
|
||||
.pll_od3 = 1,
|
||||
.vid_pll_div = VID_PLL_DIV_5,
|
||||
.vclk_div = 1,
|
||||
},
|
||||
[MESON_VCLK_HDMI_74250] = {
|
||||
.pll_base_freq = 2970000,
|
||||
.pll_od1 = 2,
|
||||
.pll_od2 = 2,
|
||||
.pll_od3 = 2,
|
||||
.vid_pll_div = VID_PLL_DIV_5,
|
||||
.vclk_div = 1,
|
||||
},
|
||||
[MESON_VCLK_HDMI_148500] = {
|
||||
.pll_base_freq = 2970000,
|
||||
.pll_od1 = 1,
|
||||
.pll_od2 = 2,
|
||||
.pll_od3 = 2,
|
||||
.vid_pll_div = VID_PLL_DIV_5,
|
||||
.vclk_div = 1,
|
||||
},
|
||||
[MESON_VCLK_HDMI_297000] = {
|
||||
.pll_base_freq = 2970000,
|
||||
.pll_od1 = 1,
|
||||
.pll_od2 = 1,
|
||||
.pll_od3 = 1,
|
||||
.vid_pll_div = VID_PLL_DIV_5,
|
||||
.vclk_div = 2,
|
||||
},
|
||||
[MESON_VCLK_HDMI_594000] = {
|
||||
.pll_base_freq = 5940000,
|
||||
.pll_od1 = 1,
|
||||
.pll_od2 = 1,
|
||||
.pll_od3 = 2,
|
||||
.vid_pll_div = VID_PLL_DIV_5,
|
||||
.vclk_div = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static inline unsigned int pll_od_to_reg(unsigned int od)
|
||||
{
|
||||
if (target == MESON_VCLK_TARGET_CVBS && freq == MESON_VCLK_CVBS)
|
||||
meson_venci_cvbs_clock_config(priv);
|
||||
switch (od) {
|
||||
case 1:
|
||||
return 0;
|
||||
case 2:
|
||||
return 1;
|
||||
case 4:
|
||||
return 2;
|
||||
case 8:
|
||||
return 3;
|
||||
}
|
||||
|
||||
/* Invalid */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void meson_hdmi_pll_set(struct meson_drm *priv,
|
||||
unsigned int base,
|
||||
unsigned int od1,
|
||||
unsigned int od2,
|
||||
unsigned int od3)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
|
||||
switch (base) {
|
||||
case 2970000:
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
|
||||
|
||||
/* Enable and unreset */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
0x7 << 28, 0x4 << 28);
|
||||
|
||||
/* Poll for lock bit */
|
||||
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
val, (val & HDMI_PLL_LOCK), 10, 0);
|
||||
|
||||
/* div_frac */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
|
||||
0xFFFF, 0x4e00);
|
||||
break;
|
||||
|
||||
case 4320000:
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800025a);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
|
||||
|
||||
/* unreset */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
BIT(28), 0);
|
||||
|
||||
/* Poll for lock bit */
|
||||
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
val, (val & HDMI_PLL_LOCK), 10, 0);
|
||||
break;
|
||||
|
||||
case 5940000:
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800027b);
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
|
||||
0xFFFF, 0x4c00);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
|
||||
|
||||
/* unreset */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
BIT(28), 0);
|
||||
|
||||
/* Poll for lock bit */
|
||||
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
val, (val & HDMI_PLL_LOCK), 10, 0);
|
||||
break;
|
||||
};
|
||||
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
|
||||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
|
||||
switch (base) {
|
||||
case 2970000:
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb300);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
|
||||
break;
|
||||
|
||||
case 4320000:
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002b4);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
|
||||
break;
|
||||
|
||||
case 5940000:
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002f7);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb200);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
|
||||
break;
|
||||
|
||||
};
|
||||
|
||||
/* Reset PLL */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
HDMI_PLL_RESET, HDMI_PLL_RESET);
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
HDMI_PLL_RESET, 0);
|
||||
|
||||
/* Poll for lock bit */
|
||||
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
|
||||
(val & HDMI_PLL_LOCK), 10, 0);
|
||||
};
|
||||
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
|
||||
3 << 16, pll_od_to_reg(od1) << 16);
|
||||
else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
|
||||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
|
||||
3 << 21, pll_od_to_reg(od1) << 21);
|
||||
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
|
||||
3 << 22, pll_od_to_reg(od2) << 22);
|
||||
else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
|
||||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
|
||||
3 << 23, pll_od_to_reg(od2) << 23);
|
||||
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
|
||||
3 << 18, pll_od_to_reg(od3) << 18);
|
||||
else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
|
||||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
|
||||
3 << 19, pll_od_to_reg(od3) << 19);
|
||||
}
|
||||
|
||||
void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
|
||||
unsigned int vclk_freq, unsigned int venc_freq,
|
||||
unsigned int dac_freq, bool hdmi_use_enci)
|
||||
{
|
||||
unsigned int freq;
|
||||
unsigned int hdmi_tx_div;
|
||||
unsigned int venc_div;
|
||||
|
||||
if (target == MESON_VCLK_TARGET_CVBS) {
|
||||
meson_venci_cvbs_clock_config(priv);
|
||||
return;
|
||||
}
|
||||
|
||||
hdmi_tx_div = vclk_freq / dac_freq;
|
||||
|
||||
if (hdmi_tx_div == 0) {
|
||||
pr_err("Fatal Error, invalid HDMI-TX freq %d\n",
|
||||
dac_freq);
|
||||
return;
|
||||
}
|
||||
|
||||
venc_div = vclk_freq / venc_freq;
|
||||
|
||||
if (venc_div == 0) {
|
||||
pr_err("Fatal Error, invalid HDMI venc freq %d\n",
|
||||
venc_freq);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (vclk_freq) {
|
||||
case 54000:
|
||||
if (hdmi_use_enci)
|
||||
freq = MESON_VCLK_HDMI_ENCI_54000;
|
||||
else
|
||||
freq = MESON_VCLK_HDMI_DDR_54000;
|
||||
break;
|
||||
case 74250:
|
||||
freq = MESON_VCLK_HDMI_74250;
|
||||
break;
|
||||
case 148500:
|
||||
if (dac_freq != 148500)
|
||||
freq = MESON_VCLK_HDMI_DDR_148500;
|
||||
else
|
||||
freq = MESON_VCLK_HDMI_148500;
|
||||
break;
|
||||
case 297000:
|
||||
freq = MESON_VCLK_HDMI_297000;
|
||||
break;
|
||||
case 594000:
|
||||
freq = MESON_VCLK_HDMI_594000;
|
||||
break;
|
||||
default:
|
||||
pr_err("Fatal Error, invalid HDMI vclk freq %d\n",
|
||||
vclk_freq);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set HDMI-TX sys clock */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
|
||||
CTS_HDMI_SYS_SEL_MASK, 0);
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
|
||||
CTS_HDMI_SYS_DIV_MASK, 0);
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
|
||||
CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN);
|
||||
|
||||
/* Set HDMI PLL rate */
|
||||
meson_hdmi_pll_set(priv, params[freq].pll_base_freq,
|
||||
params[freq].pll_od1,
|
||||
params[freq].pll_od2,
|
||||
params[freq].pll_od3);
|
||||
|
||||
/* Setup vid_pll divider */
|
||||
meson_vid_pll_set(priv, params[freq].vid_pll_div);
|
||||
|
||||
/* Set VCLK div */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
|
||||
VCLK_SEL_MASK, 0);
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
|
||||
VCLK_DIV_MASK, params[freq].vclk_div - 1);
|
||||
|
||||
/* Set HDMI-TX source */
|
||||
switch (hdmi_tx_div) {
|
||||
case 1:
|
||||
/* enable vclk_div1 gate */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
|
||||
VCLK_DIV1_EN, VCLK_DIV1_EN);
|
||||
|
||||
/* select vclk_div1 for HDMI-TX */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
|
||||
HDMI_TX_PIXEL_SEL_MASK, 0);
|
||||
break;
|
||||
case 2:
|
||||
/* enable vclk_div2 gate */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
|
||||
VCLK_DIV2_EN, VCLK_DIV2_EN);
|
||||
|
||||
/* select vclk_div2 for HDMI-TX */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
|
||||
HDMI_TX_PIXEL_SEL_MASK, 1 << HDMI_TX_PIXEL_SEL_SHIFT);
|
||||
break;
|
||||
case 4:
|
||||
/* enable vclk_div4 gate */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
|
||||
VCLK_DIV4_EN, VCLK_DIV4_EN);
|
||||
|
||||
/* select vclk_div4 for HDMI-TX */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
|
||||
HDMI_TX_PIXEL_SEL_MASK, 2 << HDMI_TX_PIXEL_SEL_SHIFT);
|
||||
break;
|
||||
case 6:
|
||||
/* enable vclk_div6 gate */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
|
||||
VCLK_DIV6_EN, VCLK_DIV6_EN);
|
||||
|
||||
/* select vclk_div6 for HDMI-TX */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
|
||||
HDMI_TX_PIXEL_SEL_MASK, 3 << HDMI_TX_PIXEL_SEL_SHIFT);
|
||||
break;
|
||||
case 12:
|
||||
/* enable vclk_div12 gate */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
|
||||
VCLK_DIV12_EN, VCLK_DIV12_EN);
|
||||
|
||||
/* select vclk_div12 for HDMI-TX */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
|
||||
HDMI_TX_PIXEL_SEL_MASK, 4 << HDMI_TX_PIXEL_SEL_SHIFT);
|
||||
break;
|
||||
}
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
|
||||
HDMI_TX_PIXEL_EN, HDMI_TX_PIXEL_EN);
|
||||
|
||||
/* Set ENCI/ENCP Source */
|
||||
switch (venc_div) {
|
||||
case 1:
|
||||
/* enable vclk_div1 gate */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
|
||||
VCLK_DIV1_EN, VCLK_DIV1_EN);
|
||||
|
||||
if (hdmi_use_enci)
|
||||
/* select vclk_div1 for enci */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
|
||||
CTS_ENCI_SEL_MASK, 0);
|
||||
else
|
||||
/* select vclk_div1 for encp */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
|
||||
CTS_ENCP_SEL_MASK, 0);
|
||||
break;
|
||||
case 2:
|
||||
/* enable vclk_div2 gate */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
|
||||
VCLK_DIV2_EN, VCLK_DIV2_EN);
|
||||
|
||||
if (hdmi_use_enci)
|
||||
/* select vclk_div2 for enci */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
|
||||
CTS_ENCI_SEL_MASK, 1 << CTS_ENCI_SEL_SHIFT);
|
||||
else
|
||||
/* select vclk_div2 for encp */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
|
||||
CTS_ENCP_SEL_MASK, 1 << CTS_ENCP_SEL_SHIFT);
|
||||
break;
|
||||
case 4:
|
||||
/* enable vclk_div4 gate */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
|
||||
VCLK_DIV4_EN, VCLK_DIV4_EN);
|
||||
|
||||
if (hdmi_use_enci)
|
||||
/* select vclk_div4 for enci */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
|
||||
CTS_ENCI_SEL_MASK, 2 << CTS_ENCI_SEL_SHIFT);
|
||||
else
|
||||
/* select vclk_div4 for encp */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
|
||||
CTS_ENCP_SEL_MASK, 2 << CTS_ENCP_SEL_SHIFT);
|
||||
break;
|
||||
case 6:
|
||||
/* enable vclk_div6 gate */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
|
||||
VCLK_DIV6_EN, VCLK_DIV6_EN);
|
||||
|
||||
if (hdmi_use_enci)
|
||||
/* select vclk_div6 for enci */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
|
||||
CTS_ENCI_SEL_MASK, 3 << CTS_ENCI_SEL_SHIFT);
|
||||
else
|
||||
/* select vclk_div6 for encp */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
|
||||
CTS_ENCP_SEL_MASK, 3 << CTS_ENCP_SEL_SHIFT);
|
||||
break;
|
||||
case 12:
|
||||
/* enable vclk_div12 gate */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
|
||||
VCLK_DIV12_EN, VCLK_DIV12_EN);
|
||||
|
||||
if (hdmi_use_enci)
|
||||
/* select vclk_div12 for enci */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
|
||||
CTS_ENCI_SEL_MASK, 4 << CTS_ENCI_SEL_SHIFT);
|
||||
else
|
||||
/* select vclk_div12 for encp */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
|
||||
CTS_ENCP_SEL_MASK, 4 << CTS_ENCP_SEL_SHIFT);
|
||||
break;
|
||||
}
|
||||
|
||||
if (hdmi_use_enci)
|
||||
/* Enable ENCI clock gate */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
|
||||
CTS_ENCI_EN, CTS_ENCI_EN);
|
||||
else
|
||||
/* Enable ENCP clock gate */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
|
||||
CTS_ENCP_EN, CTS_ENCP_EN);
|
||||
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, VCLK_EN, VCLK_EN);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(meson_vclk_setup);
|
||||
|
@ -23,12 +23,14 @@
|
||||
|
||||
enum {
|
||||
MESON_VCLK_TARGET_CVBS = 0,
|
||||
MESON_VCLK_TARGET_HDMI = 1,
|
||||
};
|
||||
|
||||
/* 27MHz is the CVBS Pixel Clock */
|
||||
#define MESON_VCLK_CVBS 27000
|
||||
#define MESON_VCLK_CVBS 27000
|
||||
|
||||
void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
|
||||
unsigned int freq);
|
||||
unsigned int vclk_freq, unsigned int venc_freq,
|
||||
unsigned int dac_freq, bool hdmi_use_enci);
|
||||
|
||||
#endif /* __MESON_VCLK_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,6 +30,7 @@ enum {
|
||||
MESON_VENC_MODE_NONE = 0,
|
||||
MESON_VENC_MODE_CVBS_PAL,
|
||||
MESON_VENC_MODE_CVBS_NTSC,
|
||||
MESON_VENC_MODE_HDMI,
|
||||
};
|
||||
|
||||
struct meson_cvbs_enci_mode {
|
||||
@ -56,12 +57,18 @@ struct meson_cvbs_enci_mode {
|
||||
unsigned int analog_sync_adj;
|
||||
};
|
||||
|
||||
/* HDMI Clock parameters */
|
||||
bool meson_venc_hdmi_supported_vic(int vic);
|
||||
bool meson_venc_hdmi_venc_repeat(int vic);
|
||||
|
||||
/* CVBS Timings and Parameters */
|
||||
extern struct meson_cvbs_enci_mode meson_cvbs_enci_pal;
|
||||
extern struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc;
|
||||
|
||||
void meson_venci_cvbs_mode_set(struct meson_drm *priv,
|
||||
struct meson_cvbs_enci_mode *mode);
|
||||
void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
|
||||
struct drm_display_mode *mode);
|
||||
unsigned int meson_venci_get_field(struct meson_drm *priv);
|
||||
|
||||
void meson_venc_enable_vsync(struct meson_drm *priv);
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
#include "meson_venc_cvbs.h"
|
||||
#include "meson_venc.h"
|
||||
#include "meson_vclk.h"
|
||||
#include "meson_registers.h"
|
||||
|
||||
/* HHI VDAC Registers */
|
||||
@ -194,14 +195,20 @@ static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder,
|
||||
{
|
||||
struct meson_venc_cvbs *meson_venc_cvbs =
|
||||
encoder_to_meson_venc_cvbs(encoder);
|
||||
struct meson_drm *priv = meson_venc_cvbs->priv;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
|
||||
struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
|
||||
|
||||
if (drm_mode_equal(mode, &meson_mode->mode)) {
|
||||
meson_venci_cvbs_mode_set(meson_venc_cvbs->priv,
|
||||
meson_venci_cvbs_mode_set(priv,
|
||||
meson_mode->enci);
|
||||
|
||||
/* Setup 27MHz vclk2 for ENCI and VDAC */
|
||||
meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS,
|
||||
MESON_VCLK_CVBS, MESON_VCLK_CVBS,
|
||||
MESON_VCLK_CVBS, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -217,25 +224,14 @@ static const struct drm_encoder_helper_funcs
|
||||
|
||||
static bool meson_venc_cvbs_connector_is_available(struct meson_drm *priv)
|
||||
{
|
||||
struct device_node *ep, *remote;
|
||||
struct device_node *remote;
|
||||
|
||||
/* CVBS VDAC output is on the first port, first endpoint */
|
||||
ep = of_graph_get_endpoint_by_regs(priv->dev->of_node, 0, 0);
|
||||
if (!ep)
|
||||
remote = of_graph_get_remote_node(priv->dev->of_node, 0, 0);
|
||||
if (!remote)
|
||||
return false;
|
||||
|
||||
|
||||
/* If the endpoint node exists, consider it enabled */
|
||||
remote = of_graph_get_remote_port(ep);
|
||||
if (remote) {
|
||||
of_node_put(ep);
|
||||
return true;
|
||||
}
|
||||
|
||||
of_node_put(ep);
|
||||
of_node_put(remote);
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int meson_venc_cvbs_create(struct meson_drm *priv)
|
||||
@ -248,7 +244,7 @@ int meson_venc_cvbs_create(struct meson_drm *priv)
|
||||
|
||||
if (!meson_venc_cvbs_connector_is_available(priv)) {
|
||||
dev_info(drm->dev, "CVBS Output connector not available\n");
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
meson_venc_cvbs = devm_kzalloc(priv->dev, sizeof(*meson_venc_cvbs),
|
||||
|
@ -28,9 +28,12 @@
|
||||
#include "meson_canvas.h"
|
||||
#include "meson_registers.h"
|
||||
|
||||
/*
|
||||
/**
|
||||
* DOC: Video Input Unit
|
||||
*
|
||||
* VIU Handles the Pixel scanout and the basic Colorspace conversions
|
||||
* We handle the following features :
|
||||
*
|
||||
* - OSD1 RGB565/RGB888/xRGB8888 scanout
|
||||
* - RGB conversion to x/cb/cr
|
||||
* - Progressive or Interlace buffer scanout
|
||||
@ -38,6 +41,7 @@
|
||||
* - HDR OSD matrix for GXL/GXM
|
||||
*
|
||||
* What is missing :
|
||||
*
|
||||
* - BGR888/xBGR8888/BGRx8888/BGRx8888 modes
|
||||
* - YUV4:2:2 Y0CbY1Cr scanout
|
||||
* - Conversion to YUV 4:4:4 from 4:2:2 input
|
||||
|
@ -25,16 +25,20 @@
|
||||
#include "meson_vpp.h"
|
||||
#include "meson_registers.h"
|
||||
|
||||
/*
|
||||
/**
|
||||
* DOC: Video Post Processing
|
||||
*
|
||||
* VPP Handles all the Post Processing after the Scanout from the VIU
|
||||
* We handle the following post processings :
|
||||
* - Postblend : Blends the OSD1 only
|
||||
*
|
||||
* - Postblend, Blends the OSD1 only
|
||||
* We exclude OSD2, VS1, VS1 and Preblend output
|
||||
* - Vertical OSD Scaler for OSD1 only, we disable vertical scaler and
|
||||
* use it only for interlace scanout
|
||||
* - Intermediate FIFO with default Amlogic values
|
||||
*
|
||||
* What is missing :
|
||||
*
|
||||
* - Preblend for video overlay pre-scaling
|
||||
* - OSD2 support for cursor framebuffer
|
||||
* - Video pre-scaling before postblend
|
||||
|
@ -23,6 +23,8 @@
|
||||
|
||||
/* Mux VIU/VPP to ENCI */
|
||||
#define MESON_VIU_VPP_MUX_ENCI 0x5
|
||||
/* Mux VIU/VPP to ENCP */
|
||||
#define MESON_VIU_VPP_MUX_ENCP 0xA
|
||||
|
||||
void meson_vpp_setup_mux(struct meson_drm *priv, unsigned int mux);
|
||||
|
||||
|
@ -1393,7 +1393,8 @@ static void mga_crtc_commit(struct drm_crtc *crtc)
|
||||
* but it's a requirement that we provide the function
|
||||
*/
|
||||
static int mga_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 mga_crtc *mga_crtc = to_mga_crtc(crtc);
|
||||
int i;
|
||||
|
@ -1635,7 +1635,7 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
|
||||
}
|
||||
|
||||
/* Get panel node from the output port's endpoint data */
|
||||
device_node = of_graph_get_remote_port_parent(endpoint);
|
||||
device_node = of_graph_get_remote_node(np, 1, 0);
|
||||
if (!device_node) {
|
||||
dev_dbg(dev, "%s: no valid device\n", __func__);
|
||||
goto err;
|
||||
|
@ -225,32 +225,6 @@ int mdp4_enable(struct mdp4_kms *mdp4_kms)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct device_node *mdp4_detect_lcdc_panel(struct drm_device *dev)
|
||||
{
|
||||
struct device_node *endpoint, *panel_node;
|
||||
struct device_node *np = dev->dev->of_node;
|
||||
|
||||
/*
|
||||
* LVDS/LCDC is the first port described in the list of ports in the
|
||||
* MDP4 DT node.
|
||||
*/
|
||||
endpoint = of_graph_get_endpoint_by_regs(np, 0, -1);
|
||||
if (!endpoint) {
|
||||
DBG("no LVDS remote endpoint\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
panel_node = of_graph_get_remote_port_parent(endpoint);
|
||||
if (!panel_node) {
|
||||
DBG("no valid panel node in LVDS endpoint\n");
|
||||
of_node_put(endpoint);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
of_node_put(endpoint);
|
||||
|
||||
return panel_node;
|
||||
}
|
||||
|
||||
static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
|
||||
int intf_type)
|
||||
@ -269,7 +243,7 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
|
||||
* bail out early if there is no panel node (no need to
|
||||
* initialize LCDC encoder and LVDS connector)
|
||||
*/
|
||||
panel_node = mdp4_detect_lcdc_panel(dev);
|
||||
panel_node = of_graph_get_remote_node(dev->dev->of_node, 0, 0);
|
||||
if (!panel_node)
|
||||
return 0;
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
@ -82,20 +83,15 @@ static const struct drm_connector_funcs mxsfb_panel_connector_funcs = {
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
static int mxsfb_attach_endpoint(struct drm_device *drm,
|
||||
const struct of_endpoint *ep)
|
||||
int mxsfb_create_output(struct drm_device *drm)
|
||||
{
|
||||
struct mxsfb_drm_private *mxsfb = drm->dev_private;
|
||||
struct device_node *np;
|
||||
struct drm_panel *panel;
|
||||
int ret = -EPROBE_DEFER;
|
||||
int ret;
|
||||
|
||||
np = of_graph_get_remote_port_parent(ep->local_node);
|
||||
panel = of_drm_find_panel(np);
|
||||
of_node_put(np);
|
||||
|
||||
if (!panel)
|
||||
return -EPROBE_DEFER;
|
||||
ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, &panel, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mxsfb->connector.dpms = DRM_MODE_DPMS_OFF;
|
||||
mxsfb->connector.polled = 0;
|
||||
@ -109,27 +105,3 @@ static int mxsfb_attach_endpoint(struct drm_device *drm,
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mxsfb_create_output(struct drm_device *drm)
|
||||
{
|
||||
struct mxsfb_drm_private *mxsfb = drm->dev_private;
|
||||
struct device_node *ep_np = NULL;
|
||||
struct of_endpoint ep;
|
||||
int ret;
|
||||
|
||||
for_each_endpoint_of_node(drm->dev->of_node, ep_np) {
|
||||
ret = of_graph_parse_endpoint(ep_np, &ep);
|
||||
if (!ret)
|
||||
ret = mxsfb_attach_endpoint(drm, &ep);
|
||||
|
||||
if (ret) {
|
||||
of_node_put(ep_np);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mxsfb->panel)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -788,7 +788,8 @@ nv_crtc_disable(struct drm_crtc *crtc)
|
||||
|
||||
static int
|
||||
nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
|
||||
uint32_t size)
|
||||
uint32_t size,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
||||
int i;
|
||||
|
@ -2210,25 +2210,16 @@ nv50_head_lut_load(struct drm_crtc *crtc)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_head_mode_set_base_atomic(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb, int x, int y,
|
||||
enum mode_set_atomic state)
|
||||
{
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_crtc_helper_funcs
|
||||
nv50_head_help = {
|
||||
.mode_set_base_atomic = nv50_head_mode_set_base_atomic,
|
||||
.load_lut = nv50_head_lut_load,
|
||||
.atomic_check = nv50_head_atomic_check,
|
||||
};
|
||||
|
||||
static int
|
||||
nv50_head_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
|
||||
uint32_t size)
|
||||
uint32_t size,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
||||
u32 i;
|
||||
|
@ -877,7 +877,7 @@ int dpi_init_port(struct platform_device *pdev, struct device_node *port)
|
||||
if (!dpi)
|
||||
return -ENOMEM;
|
||||
|
||||
ep = omapdss_of_get_next_endpoint(port, NULL);
|
||||
ep = of_get_next_child(port, NULL);
|
||||
if (!ep)
|
||||
return 0;
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/component.h>
|
||||
|
||||
@ -5090,7 +5091,7 @@ static int dsi_probe_of(struct platform_device *pdev)
|
||||
struct device_node *ep;
|
||||
struct omap_dsi_pin_config pin_cfg;
|
||||
|
||||
ep = omapdss_of_get_first_endpoint(node);
|
||||
ep = of_graph_get_endpoint_by_regs(node, 0, 0);
|
||||
if (!ep)
|
||||
return 0;
|
||||
|
||||
|
@ -16,76 +16,11 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include "omapdss.h"
|
||||
|
||||
struct device_node *
|
||||
omapdss_of_get_next_port(const struct device_node *parent,
|
||||
struct device_node *prev)
|
||||
{
|
||||
struct device_node *port = NULL;
|
||||
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
if (!prev) {
|
||||
struct device_node *ports;
|
||||
/*
|
||||
* It's the first call, we have to find a port subnode
|
||||
* within this node or within an optional 'ports' node.
|
||||
*/
|
||||
ports = of_get_child_by_name(parent, "ports");
|
||||
if (ports)
|
||||
parent = ports;
|
||||
|
||||
port = of_get_child_by_name(parent, "port");
|
||||
|
||||
/* release the 'ports' node */
|
||||
of_node_put(ports);
|
||||
} else {
|
||||
struct device_node *ports;
|
||||
|
||||
ports = of_get_parent(prev);
|
||||
if (!ports)
|
||||
return NULL;
|
||||
|
||||
do {
|
||||
port = of_get_next_child(ports, prev);
|
||||
if (!port) {
|
||||
of_node_put(ports);
|
||||
return NULL;
|
||||
}
|
||||
prev = port;
|
||||
} while (of_node_cmp(port->name, "port") != 0);
|
||||
|
||||
of_node_put(ports);
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_of_get_next_port);
|
||||
|
||||
struct device_node *
|
||||
omapdss_of_get_next_endpoint(const struct device_node *parent,
|
||||
struct device_node *prev)
|
||||
{
|
||||
struct device_node *ep = NULL;
|
||||
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
do {
|
||||
ep = of_get_next_child(parent, prev);
|
||||
if (!ep)
|
||||
return NULL;
|
||||
prev = ep;
|
||||
} while (of_node_cmp(ep->name, "endpoint") != 0);
|
||||
|
||||
return ep;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint);
|
||||
|
||||
struct device_node *dss_of_port_get_parent_device(struct device_node *port)
|
||||
{
|
||||
struct device_node *np;
|
||||
@ -124,37 +59,6 @@ u32 dss_of_port_get_port_number(struct device_node *port)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dss_of_port_get_port_number);
|
||||
|
||||
static struct device_node *omapdss_of_get_remote_port(const struct device_node *node)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
||||
np = of_parse_phandle(node, "remote-endpoint", 0);
|
||||
if (!np)
|
||||
return NULL;
|
||||
|
||||
np = of_get_next_parent(np);
|
||||
|
||||
return np;
|
||||
}
|
||||
|
||||
struct device_node *
|
||||
omapdss_of_get_first_endpoint(const struct device_node *parent)
|
||||
{
|
||||
struct device_node *port, *ep;
|
||||
|
||||
port = omapdss_of_get_next_port(parent, NULL);
|
||||
|
||||
if (!port)
|
||||
return NULL;
|
||||
|
||||
ep = omapdss_of_get_next_endpoint(port, NULL);
|
||||
|
||||
of_node_put(port);
|
||||
|
||||
return ep;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_of_get_first_endpoint);
|
||||
|
||||
struct omap_dss_device *
|
||||
omapdss_of_find_source_for_first_ep(struct device_node *node)
|
||||
{
|
||||
@ -162,11 +66,11 @@ omapdss_of_find_source_for_first_ep(struct device_node *node)
|
||||
struct device_node *src_port;
|
||||
struct omap_dss_device *src;
|
||||
|
||||
ep = omapdss_of_get_first_endpoint(node);
|
||||
ep = of_graph_get_endpoint_by_regs(node, 0, 0);
|
||||
if (!ep)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
src_port = omapdss_of_get_remote_port(ep);
|
||||
src_port = of_graph_get_remote_port(ep);
|
||||
if (!src_port) {
|
||||
of_node_put(ep);
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/component.h>
|
||||
@ -1035,32 +1036,14 @@ static int dss_init_ports(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *parent = pdev->dev.of_node;
|
||||
struct device_node *port;
|
||||
int r;
|
||||
int i;
|
||||
|
||||
if (parent == NULL)
|
||||
return 0;
|
||||
|
||||
port = omapdss_of_get_next_port(parent, NULL);
|
||||
if (!port)
|
||||
return 0;
|
||||
|
||||
if (dss.feat->num_ports == 0)
|
||||
return 0;
|
||||
|
||||
do {
|
||||
enum omap_display_type port_type;
|
||||
u32 reg;
|
||||
|
||||
r = of_property_read_u32(port, "reg", ®);
|
||||
if (r)
|
||||
reg = 0;
|
||||
|
||||
if (reg >= dss.feat->num_ports)
|
||||
for (i = 0; i < dss.feat->num_ports; i++) {
|
||||
port = of_graph_get_port_by_id(parent, i);
|
||||
if (!port)
|
||||
continue;
|
||||
|
||||
port_type = dss.feat->ports[reg];
|
||||
|
||||
switch (port_type) {
|
||||
switch (dss.feat->ports[i]) {
|
||||
case OMAP_DISPLAY_TYPE_DPI:
|
||||
dpi_init_port(pdev, port);
|
||||
break;
|
||||
@ -1070,7 +1053,7 @@ static int dss_init_ports(struct platform_device *pdev)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1079,32 +1062,14 @@ static void dss_uninit_ports(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *parent = pdev->dev.of_node;
|
||||
struct device_node *port;
|
||||
int i;
|
||||
|
||||
if (parent == NULL)
|
||||
return;
|
||||
|
||||
port = omapdss_of_get_next_port(parent, NULL);
|
||||
if (!port)
|
||||
return;
|
||||
|
||||
if (dss.feat->num_ports == 0)
|
||||
return;
|
||||
|
||||
do {
|
||||
enum omap_display_type port_type;
|
||||
u32 reg;
|
||||
int r;
|
||||
|
||||
r = of_property_read_u32(port, "reg", ®);
|
||||
if (r)
|
||||
reg = 0;
|
||||
|
||||
if (reg >= dss.feat->num_ports)
|
||||
for (i = 0; i < dss.feat->num_ports; i++) {
|
||||
port = of_graph_get_port_by_id(parent, i);
|
||||
if (!port)
|
||||
continue;
|
||||
|
||||
port_type = dss.feat->ports[reg];
|
||||
|
||||
switch (port_type) {
|
||||
switch (dss.feat->ports[i]) {
|
||||
case OMAP_DISPLAY_TYPE_DPI:
|
||||
dpi_uninit_port(port);
|
||||
break;
|
||||
@ -1114,7 +1079,7 @@ static void dss_uninit_ports(struct platform_device *pdev)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int dss_video_pll_probe(struct platform_device *pdev)
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <sound/omap-hdmi-audio.h>
|
||||
|
||||
#include "omapdss.h"
|
||||
@ -546,7 +547,7 @@ static int hdmi_probe_of(struct platform_device *pdev)
|
||||
struct device_node *ep;
|
||||
int r;
|
||||
|
||||
ep = omapdss_of_get_first_endpoint(node);
|
||||
ep = of_graph_get_endpoint_by_regs(node, 0, 0);
|
||||
if (!ep)
|
||||
return 0;
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <sound/omap-hdmi-audio.h>
|
||||
|
||||
#include "omapdss.h"
|
||||
@ -572,7 +573,7 @@ static int hdmi_probe_of(struct platform_device *pdev)
|
||||
struct device_node *ep;
|
||||
int r;
|
||||
|
||||
ep = omapdss_of_get_first_endpoint(node);
|
||||
ep = of_graph_get_endpoint_by_regs(node, 0, 0);
|
||||
if (!ep)
|
||||
return 0;
|
||||
|
||||
|
@ -830,17 +830,6 @@ static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev)
|
||||
return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE;
|
||||
}
|
||||
|
||||
struct device_node *
|
||||
omapdss_of_get_next_port(const struct device_node *parent,
|
||||
struct device_node *prev);
|
||||
|
||||
struct device_node *
|
||||
omapdss_of_get_next_endpoint(const struct device_node *parent,
|
||||
struct device_node *prev);
|
||||
|
||||
struct device_node *
|
||||
omapdss_of_get_first_endpoint(const struct device_node *parent);
|
||||
|
||||
struct omap_dss_device *
|
||||
omapdss_of_find_source_for_first_ep(struct device_node *node);
|
||||
|
||||
|
@ -414,7 +414,7 @@ int sdi_init_port(struct platform_device *pdev, struct device_node *port)
|
||||
u32 datapairs;
|
||||
int r;
|
||||
|
||||
ep = omapdss_of_get_next_endpoint(port, NULL);
|
||||
ep = of_get_next_child(port, NULL);
|
||||
if (!ep)
|
||||
return 0;
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/component.h>
|
||||
|
||||
#include "omapdss.h"
|
||||
@ -818,7 +819,7 @@ static int venc_probe_of(struct platform_device *pdev)
|
||||
u32 channels;
|
||||
int r;
|
||||
|
||||
ep = omapdss_of_get_first_endpoint(node);
|
||||
ep = of_graph_get_endpoint_by_regs(node, 0, 0);
|
||||
if (!ep)
|
||||
return 0;
|
||||
|
||||
|
@ -232,7 +232,8 @@ void radeon_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
|
||||
}
|
||||
|
||||
static int radeon_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 radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
|
||||
int i;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user