drm-misc-next for v4.18:
UAPI Changes: - Add support for a generic plane alpha property to sun4i, rcar-du and atmel-hclcdc. (Maxime) Core Changes: - Stop looking at legacy plane->fb and crtc members in atomic drivers. (Ville) - mode_valid return type fixes. (Luc) - Handle zpos normalization in the core. (Peter) Driver Changes: - Implement CTM, plane alpha and generic async cursor support in vc4. (Stefan) - Various fixes for HPD and aux chan in drm_bridge/analogix_dp. (Lin, Zain, Douglas) - Add support for MIPI DSI to sun4i. (Maxime) -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAlrhqA0ACgkQ/lWMcqZw E8PcQQ//ZfZE5SgklBEuqil4X30z0y/ikFy3rEPhJOYpCGYjwDpOXoHjbgeIqFYD NWiYmeq8OfFBDQz8EkqalVJkqH10w2rcOJszM2t86FlSUWTmVxTqWjuVIIySkv67 UNJZo9+ppvwPahvO8aZqs90fJOGS2dqslgRa5v91S1IT+AZMZ7UNBlbhjCsmCPod TKypdZ4rOzlI7E3NR2CVSngPgLbUvTLnGDx0xKCej3Pp4MSW2g4kDNzHOPY82uLZ P2GyacmNN1yKTL9qfvqOoEWr8lu2bJuQ3mSzuYn6bBl8lHLPVEjdSMrtA3SGhM1v 4gTNRmnN1nCv+q3umLNSPLqKN6OHO1nstqbcTf753+g6gtJBGotCK2aWmTSKW8FC DtezLQIaFVf+Vyhr2XIgHfuDetk+f6E1u0/01yqxpGDP2WpQCzadbgIqCdJviMZS W9i/as2nJssg3ekoCbkA1leteAc088HPzFHVyqt4zKNTdCmUwtx/HdCoF2uXjsFV fTj7+sFkLHMQWdR3WqKQHqnxoknD1mfBbR7SCjvNXfhjQPGZQZgdyoJXvOhuKAnO cTygEZhCxlM1G0afStY18It/uZlNpxVz393nTiFtPp4RHmPO3jyIApTDPyqgXGCu 5L6MTBOrAntlOQ7kSWqrm9dbiv8ZDvPAhm7eer5txH7kQK2ywJo= =9LYY -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2018-04-26' of git://anongit.freedesktop.org/drm/drm-misc into drm-next drm-misc-next for v4.18: UAPI Changes: - Add support for a generic plane alpha property to sun4i, rcar-du and atmel-hclcdc. (Maxime) Core Changes: - Stop looking at legacy plane->fb and crtc members in atomic drivers. (Ville) - mode_valid return type fixes. (Luc) - Handle zpos normalization in the core. (Peter) Driver Changes: - Implement CTM, plane alpha and generic async cursor support in vc4. (Stefan) - Various fixes for HPD and aux chan in drm_bridge/analogix_dp. (Lin, Zain, Douglas) - Add support for MIPI DSI to sun4i. (Maxime) Signed-off-by: Dave Airlie <airlied@redhat.com> # gpg: Signature made Thu 26 Apr 2018 08:21:01 PM AEST # gpg: using RSA key FE558C72A67013C3 # gpg: Can't check signature: public key not found Link: https://patchwork.freedesktop.org/patch/msgid/b33da7eb-efc9-ae6f-6f69-b7acd6df6797@mblankhorst.nl
This commit is contained in:
commit
0ab390262c
@ -14,7 +14,13 @@ Required properties:
|
||||
"adi,adv7513"
|
||||
"adi,adv7533"
|
||||
|
||||
- reg: I2C slave address
|
||||
- reg: I2C slave addresses
|
||||
The ADV7511 internal registers are split into four pages exposed through
|
||||
different I2C addresses, creating four register maps. Each map has it own
|
||||
I2C address and acts as a standard slave device on the I2C bus. The main
|
||||
address is mandatory, others are optional and revert to defaults if not
|
||||
specified.
|
||||
|
||||
|
||||
The ADV7511 supports a large number of input data formats that differ by their
|
||||
color depth, color format, clock mode, bit justification and random
|
||||
@ -70,6 +76,9 @@ Optional properties:
|
||||
rather than generate its own timings for HDMI output.
|
||||
- clocks: from common clock binding: reference to the CEC clock.
|
||||
- clock-names: from common clock binding: must be "cec".
|
||||
- reg-names : Names of maps with programmable addresses.
|
||||
It can contain any map needing a non-default address.
|
||||
Possible maps names are : "main", "edid", "cec", "packet"
|
||||
|
||||
Required nodes:
|
||||
|
||||
@ -88,7 +97,12 @@ Example
|
||||
|
||||
adv7511w: hdmi@39 {
|
||||
compatible = "adi,adv7511w";
|
||||
reg = <39>;
|
||||
/*
|
||||
* The EDID page will be accessible on address 0x66 on the I2C
|
||||
* bus. All other maps continue to use their default addresses.
|
||||
*/
|
||||
reg = <0x39>, <0x66>;
|
||||
reg-names = "main", "edid";
|
||||
interrupt-parent = <&gpio3>;
|
||||
interrupts = <29 IRQ_TYPE_EDGE_FALLING>;
|
||||
clocks = <&cec_clock>;
|
||||
|
133
Documentation/devicetree/bindings/display/bridge/cdns,dsi.txt
Normal file
133
Documentation/devicetree/bindings/display/bridge/cdns,dsi.txt
Normal file
@ -0,0 +1,133 @@
|
||||
Cadence DSI bridge
|
||||
==================
|
||||
|
||||
The Cadence DSI bridge is a DPI to DSI bridge supporting up to 4 DSI lanes.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be set to "cdns,dsi".
|
||||
- reg: physical base address and length of the controller's registers.
|
||||
- interrupts: interrupt line connected to the DSI bridge.
|
||||
- clocks: DSI bridge clocks.
|
||||
- clock-names: must contain "dsi_p_clk" and "dsi_sys_clk".
|
||||
- phys: phandle link to the MIPI D-PHY controller.
|
||||
- phy-names: must contain "dphy".
|
||||
- #address-cells: must be set to 1.
|
||||
- #size-cells: must be set to 0.
|
||||
|
||||
Optional properties:
|
||||
- resets: DSI reset lines.
|
||||
- reset-names: can contain "dsi_p_rst".
|
||||
|
||||
Required subnodes:
|
||||
- ports: Ports as described in Documentation/devicetree/bindings/graph.txt.
|
||||
2 ports are available:
|
||||
* port 0: this port is only needed if some of your DSI devices are
|
||||
controlled through an external bus like I2C or SPI. Can have at
|
||||
most 4 endpoints. The endpoint number is directly encoding the
|
||||
DSI virtual channel used by this device.
|
||||
* port 1: represents the DPI input.
|
||||
Other ports will be added later to support the new kind of inputs.
|
||||
|
||||
- one subnode per DSI device connected on the DSI bus. Each DSI device should
|
||||
contain a reg property encoding its virtual channel.
|
||||
|
||||
Cadence DPHY
|
||||
============
|
||||
|
||||
Cadence DPHY block.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be set to "cdns,dphy".
|
||||
- reg: physical base address and length of the DPHY registers.
|
||||
- clocks: DPHY reference clocks.
|
||||
- clock-names: must contain "psm" and "pll_ref".
|
||||
- #phy-cells: must be set to 0.
|
||||
|
||||
|
||||
Example:
|
||||
dphy0: dphy@fd0e0000{
|
||||
compatible = "cdns,dphy";
|
||||
reg = <0x0 0xfd0e0000 0x0 0x1000>;
|
||||
clocks = <&psm_clk>, <&pll_ref_clk>;
|
||||
clock-names = "psm", "pll_ref";
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
dsi0: dsi@fd0c0000 {
|
||||
compatible = "cdns,dsi";
|
||||
reg = <0x0 0xfd0c0000 0x0 0x1000>;
|
||||
clocks = <&pclk>, <&sysclk>;
|
||||
clock-names = "dsi_p_clk", "dsi_sys_clk";
|
||||
interrupts = <1>;
|
||||
phys = <&dphy0>;
|
||||
phy-names = "dphy";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
dsi0_dpi_input: endpoint {
|
||||
remote-endpoint = <&xxx_dpi_output>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
panel: dsi-dev@0 {
|
||||
compatible = "<vendor,panel>";
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
or
|
||||
|
||||
dsi0: dsi@fd0c0000 {
|
||||
compatible = "cdns,dsi";
|
||||
reg = <0x0 0xfd0c0000 0x0 0x1000>;
|
||||
clocks = <&pclk>, <&sysclk>;
|
||||
clock-names = "dsi_p_clk", "dsi_sys_clk";
|
||||
interrupts = <1>;
|
||||
phys = <&dphy1>;
|
||||
phy-names = "dphy";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dsi0_output: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&dsi_panel_input>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
dsi0_dpi_input: endpoint {
|
||||
remote-endpoint = <&xxx_dpi_output>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
i2c@xxx {
|
||||
panel: panel@59 {
|
||||
compatible = "<vendor,panel>";
|
||||
reg = <0x59>;
|
||||
|
||||
port {
|
||||
dsi_panel_input: endpoint {
|
||||
remote-endpoint = <&dsi0_output>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,60 @@
|
||||
Thine Electronics THC63LVD1024 LVDS decoder
|
||||
-------------------------------------------
|
||||
|
||||
The THC63LVD1024 is a dual link LVDS receiver designed to convert LVDS streams
|
||||
to parallel data outputs. The chip supports single/dual input/output modes,
|
||||
handling up to two LVDS input streams and up to two digital CMOS/TTL outputs.
|
||||
|
||||
Single or dual operation mode, output data mapping and DDR output modes are
|
||||
configured through input signals and the chip does not expose any control bus.
|
||||
|
||||
Required properties:
|
||||
- compatible: Shall be "thine,thc63lvd1024"
|
||||
- vcc-supply: Power supply for TTL output, TTL CLOCKOUT signal, LVDS input,
|
||||
PPL and digital circuitry
|
||||
|
||||
Optional properties:
|
||||
- powerdown-gpios: Power down GPIO signal, pin name "/PDWN". Active low
|
||||
- oe-gpios: Output enable GPIO signal, pin name "OE". Active high
|
||||
|
||||
The THC63LVD1024 video port connections are modeled according
|
||||
to OF graph bindings specified by Documentation/devicetree/bindings/graph.txt
|
||||
|
||||
Required video port nodes:
|
||||
- port@0: First LVDS input port
|
||||
- port@2: First digital CMOS/TTL parallel output
|
||||
|
||||
Optional video port nodes:
|
||||
- port@1: Second LVDS input port
|
||||
- port@3: Second digital CMOS/TTL parallel output
|
||||
|
||||
Example:
|
||||
--------
|
||||
|
||||
thc63lvd1024: lvds-decoder {
|
||||
compatible = "thine,thc63lvd1024";
|
||||
|
||||
vcc-supply = <®_lvds_vcc>;
|
||||
powerdown-gpios = <&gpio4 15 GPIO_ACTIVE_LOW>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
lvds_dec_in_0: endpoint {
|
||||
remote-endpoint = <&lvds_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@2{
|
||||
reg = <2>;
|
||||
|
||||
lvds_dec_out_2: endpoint {
|
||||
remote-endpoint = <&adv7511_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,93 @@
|
||||
Allwinner A31 DSI Encoder
|
||||
=========================
|
||||
|
||||
The DSI pipeline consists of two separate blocks: the DSI controller
|
||||
itself, and its associated D-PHY.
|
||||
|
||||
DSI Encoder
|
||||
-----------
|
||||
|
||||
The DSI Encoder generates the DSI signal from the TCON's.
|
||||
|
||||
Required properties:
|
||||
- compatible: value must be one of:
|
||||
* allwinner,sun6i-a31-mipi-dsi
|
||||
- reg: base address and size of memory-mapped region
|
||||
- interrupts: interrupt associated to this IP
|
||||
- clocks: phandles to the clocks feeding the DSI encoder
|
||||
* bus: the DSI interface clock
|
||||
* mod: the DSI module clock
|
||||
- clock-names: the clock names mentioned above
|
||||
- phys: phandle to the D-PHY
|
||||
- phy-names: must be "dphy"
|
||||
- resets: phandle to the reset controller driving the encoder
|
||||
|
||||
- ports: A ports node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt. The
|
||||
first port should be the input endpoint, usually coming from the
|
||||
associated TCON.
|
||||
|
||||
Any MIPI-DSI device attached to this should be described according to
|
||||
the bindings defined in ../mipi-dsi-bus.txt
|
||||
|
||||
D-PHY
|
||||
-----
|
||||
|
||||
Required properties:
|
||||
- compatible: value must be one of:
|
||||
* allwinner,sun6i-a31-mipi-dphy
|
||||
- reg: base address and size of memory-mapped region
|
||||
- clocks: phandles to the clocks feeding the DSI encoder
|
||||
* bus: the DSI interface clock
|
||||
* mod: the DSI module clock
|
||||
- clock-names: the clock names mentioned above
|
||||
- resets: phandle to the reset controller driving the encoder
|
||||
|
||||
Example:
|
||||
|
||||
dsi0: dsi@1ca0000 {
|
||||
compatible = "allwinner,sun6i-a31-mipi-dsi";
|
||||
reg = <0x01ca0000 0x1000>;
|
||||
interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&ccu CLK_BUS_MIPI_DSI>,
|
||||
<&ccu CLK_DSI_SCLK>;
|
||||
clock-names = "bus", "mod";
|
||||
resets = <&ccu RST_BUS_MIPI_DSI>;
|
||||
phys = <&dphy0>;
|
||||
phy-names = "dphy";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
panel@0 {
|
||||
compatible = "bananapi,lhr050h41", "ilitek,ili9881c";
|
||||
reg = <0>;
|
||||
power-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* PB07 */
|
||||
reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_LOW>; /* PL05 */
|
||||
backlight = <&pwm_bl>;
|
||||
};
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
dsi0_in_tcon0: endpoint {
|
||||
remote-endpoint = <&tcon0_out_dsi0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dphy0: d-phy@1ca1000 {
|
||||
compatible = "allwinner,sun6i-a31-mipi-dphy";
|
||||
reg = <0x01ca1000 0x1000>;
|
||||
clocks = <&ccu CLK_BUS_MIPI_DSI>,
|
||||
<&ccu CLK_DSI_DPHY>;
|
||||
clock-names = "bus", "mod";
|
||||
resets = <&ccu RST_BUS_MIPI_DSI>;
|
||||
#phy-cells = <0>;
|
||||
};
|
@ -12,6 +12,7 @@ GPU Driver Documentation
|
||||
tve200
|
||||
vc4
|
||||
bridge/dw-hdmi
|
||||
xen-front
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
|
@ -98,5 +98,4 @@ radeon,DVI-I,“coherent”,RANGE,"Min=0, Max=1",Connector,TBD
|
||||
,,"""underscan vborder""",RANGE,"Min=0, Max=128",Connector,TBD
|
||||
,Audio,“audio”,ENUM,"{ ""off"", ""on"", ""auto"" }",Connector,TBD
|
||||
,FMT Dithering,“dither”,ENUM,"{ ""off"", ""on"" }",Connector,TBD
|
||||
rcar-du,Generic,"""alpha""",RANGE,"Min=0, Max=255",Plane,TBD
|
||||
,,"""colorkey""",RANGE,"Min=0, Max=0x01ffffff",Plane,TBD
|
||||
|
|
@ -212,6 +212,24 @@ probably use drm_fb_helper_fbdev_teardown().
|
||||
|
||||
Contact: Maintainer of the driver you plan to convert
|
||||
|
||||
Clean up mmap forwarding
|
||||
------------------------
|
||||
|
||||
A lot of drivers forward gem mmap calls to dma-buf mmap for imported buffers.
|
||||
And also a lot of them forward dma-buf mmap to the gem mmap implementations.
|
||||
Would be great to refactor this all into a set of small common helpers.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Put a reservation_object into drm_gem_object
|
||||
--------------------------------------------
|
||||
|
||||
This would remove the need for the ->gem_prime_res_obj callback. It would also
|
||||
allow us to implement generic helpers for waiting for a bo, allowing for quite a
|
||||
bit of refactoring in the various wait ioctl implementations.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
idr_init_base()
|
||||
---------------
|
||||
|
||||
|
31
Documentation/gpu/xen-front.rst
Normal file
31
Documentation/gpu/xen-front.rst
Normal file
@ -0,0 +1,31 @@
|
||||
====================================================
|
||||
drm/xen-front Xen para-virtualized frontend driver
|
||||
====================================================
|
||||
|
||||
This frontend driver implements Xen para-virtualized display
|
||||
according to the display protocol described at
|
||||
include/xen/interface/io/displif.h
|
||||
|
||||
Driver modes of operation in terms of display buffers used
|
||||
==========================================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/xen/xen_drm_front.h
|
||||
:doc: Driver modes of operation in terms of display buffers used
|
||||
|
||||
Buffers allocated by the frontend driver
|
||||
----------------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/xen/xen_drm_front.h
|
||||
:doc: Buffers allocated by the frontend driver
|
||||
|
||||
Buffers allocated by the backend
|
||||
--------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/xen/xen_drm_front.h
|
||||
:doc: Buffers allocated by the backend
|
||||
|
||||
Driver limitations
|
||||
==================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/xen/xen_drm_front.h
|
||||
:doc: Driver limitations
|
@ -4830,6 +4830,15 @@ S: Maintained
|
||||
F: drivers/gpu/drm/tinydrm/
|
||||
F: include/drm/tinydrm/
|
||||
|
||||
DRM DRIVERS FOR XEN
|
||||
M: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
L: xen-devel@lists.xen.org
|
||||
S: Supported
|
||||
F: drivers/gpu/drm/xen/
|
||||
F: Documentation/gpu/xen-front.rst
|
||||
|
||||
DRM TTM SUBSYSTEM
|
||||
M: Christian Koenig <christian.koenig@amd.com>
|
||||
M: Roger He <Hongbo.He@amd.com>
|
||||
|
@ -289,6 +289,8 @@ source "drivers/gpu/drm/pl111/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/tve200/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/xen/Kconfig"
|
||||
|
||||
# Keep legacy drivers last
|
||||
|
||||
menuconfig DRM_LEGACY
|
||||
|
@ -103,3 +103,4 @@ obj-$(CONFIG_DRM_MXSFB) += mxsfb/
|
||||
obj-$(CONFIG_DRM_TINYDRM) += tinydrm/
|
||||
obj-$(CONFIG_DRM_PL111) += pl111/
|
||||
obj-$(CONFIG_DRM_TVE200) += tve200/
|
||||
obj-$(CONFIG_DRM_XEN) += xen/
|
||||
|
@ -799,7 +799,7 @@ static int ast_get_modes(struct drm_connector *connector)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ast_mode_valid(struct drm_connector *connector,
|
||||
static enum drm_mode_status ast_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct ast_private *ast = connector->dev->dev_private;
|
||||
|
@ -299,7 +299,6 @@ struct atmel_hlcdc_layer {
|
||||
struct atmel_hlcdc_plane {
|
||||
struct drm_plane base;
|
||||
struct atmel_hlcdc_layer layer;
|
||||
struct atmel_hlcdc_plane_properties *properties;
|
||||
};
|
||||
|
||||
static inline struct atmel_hlcdc_plane *
|
||||
@ -345,18 +344,6 @@ struct atmel_hlcdc_dc_desc {
|
||||
int nlayers;
|
||||
};
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Plane properties.
|
||||
*
|
||||
* This structure stores plane property definitions.
|
||||
*
|
||||
* @alpha: alpha blending (or transparency) property
|
||||
* @rotation: rotation property
|
||||
*/
|
||||
struct atmel_hlcdc_plane_properties {
|
||||
struct drm_property *alpha;
|
||||
};
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Display Controller.
|
||||
*
|
||||
|
@ -31,7 +31,6 @@
|
||||
* @src_y: y buffer position
|
||||
* @src_w: buffer width
|
||||
* @src_h: buffer height
|
||||
* @alpha: alpha blending of the plane
|
||||
* @disc_x: x discard position
|
||||
* @disc_y: y discard position
|
||||
* @disc_w: discard width
|
||||
@ -54,8 +53,6 @@ struct atmel_hlcdc_plane_state {
|
||||
uint32_t src_w;
|
||||
uint32_t src_h;
|
||||
|
||||
u8 alpha;
|
||||
|
||||
int disc_x;
|
||||
int disc_y;
|
||||
int disc_w;
|
||||
@ -385,7 +382,7 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
|
||||
cfg |= ATMEL_HLCDC_LAYER_LAEN;
|
||||
else
|
||||
cfg |= ATMEL_HLCDC_LAYER_GAEN |
|
||||
ATMEL_HLCDC_LAYER_GA(state->alpha);
|
||||
ATMEL_HLCDC_LAYER_GA(state->base.alpha >> 8);
|
||||
}
|
||||
|
||||
if (state->disc_h && state->disc_w)
|
||||
@ -553,7 +550,7 @@ atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
|
||||
|
||||
if (!ovl_s->fb ||
|
||||
ovl_s->fb->format->has_alpha ||
|
||||
ovl_state->alpha != 255)
|
||||
ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
|
||||
continue;
|
||||
|
||||
/* TODO: implement a smarter hidden area detection */
|
||||
@ -829,51 +826,18 @@ static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
|
||||
drm_plane_cleanup(p);
|
||||
}
|
||||
|
||||
static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
|
||||
struct drm_plane_state *s,
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
{
|
||||
struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
|
||||
struct atmel_hlcdc_plane_properties *props = plane->properties;
|
||||
struct atmel_hlcdc_plane_state *state =
|
||||
drm_plane_state_to_atmel_hlcdc_plane_state(s);
|
||||
|
||||
if (property == props->alpha)
|
||||
state->alpha = val;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
|
||||
const struct drm_plane_state *s,
|
||||
struct drm_property *property,
|
||||
uint64_t *val)
|
||||
{
|
||||
struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
|
||||
struct atmel_hlcdc_plane_properties *props = plane->properties;
|
||||
const struct atmel_hlcdc_plane_state *state =
|
||||
container_of(s, const struct atmel_hlcdc_plane_state, base);
|
||||
|
||||
if (property == props->alpha)
|
||||
*val = state->alpha;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
|
||||
struct atmel_hlcdc_plane_properties *props)
|
||||
static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
|
||||
{
|
||||
const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
|
||||
|
||||
if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
|
||||
desc->type == ATMEL_HLCDC_CURSOR_LAYER)
|
||||
drm_object_attach_property(&plane->base.base,
|
||||
props->alpha, 255);
|
||||
desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
|
||||
int ret;
|
||||
|
||||
ret = drm_plane_create_alpha_property(&plane->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (desc->layout.xstride && desc->layout.pstride) {
|
||||
int ret;
|
||||
@ -988,8 +952,8 @@ static void atmel_hlcdc_plane_reset(struct drm_plane *p)
|
||||
return;
|
||||
}
|
||||
|
||||
state->alpha = 255;
|
||||
p->state = &state->base;
|
||||
p->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
|
||||
p->state->plane = p;
|
||||
}
|
||||
}
|
||||
@ -1042,13 +1006,10 @@ static const struct drm_plane_funcs layer_plane_funcs = {
|
||||
.reset = atmel_hlcdc_plane_reset,
|
||||
.atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
|
||||
.atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
|
||||
.atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
|
||||
.atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
|
||||
};
|
||||
|
||||
static int atmel_hlcdc_plane_create(struct drm_device *dev,
|
||||
const struct atmel_hlcdc_layer_desc *desc,
|
||||
struct atmel_hlcdc_plane_properties *props)
|
||||
const struct atmel_hlcdc_layer_desc *desc)
|
||||
{
|
||||
struct atmel_hlcdc_dc *dc = dev->dev_private;
|
||||
struct atmel_hlcdc_plane *plane;
|
||||
@ -1060,7 +1021,6 @@ static int atmel_hlcdc_plane_create(struct drm_device *dev,
|
||||
return -ENOMEM;
|
||||
|
||||
atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
|
||||
plane->properties = props;
|
||||
|
||||
if (desc->type == ATMEL_HLCDC_BASE_LAYER)
|
||||
type = DRM_PLANE_TYPE_PRIMARY;
|
||||
@ -1081,7 +1041,7 @@ static int atmel_hlcdc_plane_create(struct drm_device *dev,
|
||||
&atmel_hlcdc_layer_plane_helper_funcs);
|
||||
|
||||
/* Set default property values*/
|
||||
ret = atmel_hlcdc_plane_init_properties(plane, props);
|
||||
ret = atmel_hlcdc_plane_init_properties(plane);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1090,34 +1050,13 @@ static int atmel_hlcdc_plane_create(struct drm_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct atmel_hlcdc_plane_properties *
|
||||
atmel_hlcdc_plane_create_properties(struct drm_device *dev)
|
||||
{
|
||||
struct atmel_hlcdc_plane_properties *props;
|
||||
|
||||
props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
|
||||
if (!props)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
|
||||
if (!props->alpha)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
int atmel_hlcdc_create_planes(struct drm_device *dev)
|
||||
{
|
||||
struct atmel_hlcdc_dc *dc = dev->dev_private;
|
||||
struct atmel_hlcdc_plane_properties *props;
|
||||
const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
|
||||
int nlayers = dc->desc->nlayers;
|
||||
int i, ret;
|
||||
|
||||
props = atmel_hlcdc_plane_create_properties(dev);
|
||||
if (IS_ERR(props))
|
||||
return PTR_ERR(props);
|
||||
|
||||
dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
|
||||
sizeof(struct atmel_hlcdc_dma_channel_dscr),
|
||||
sizeof(u64), 0);
|
||||
@ -1130,7 +1069,7 @@ int atmel_hlcdc_create_planes(struct drm_device *dev)
|
||||
descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
|
||||
continue;
|
||||
|
||||
ret = atmel_hlcdc_plane_create(dev, &descs[i], props);
|
||||
ret = atmel_hlcdc_plane_create(dev, &descs[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ static int bochs_connector_get_modes(struct drm_connector *connector)
|
||||
return count;
|
||||
}
|
||||
|
||||
static int bochs_connector_mode_valid(struct drm_connector *connector,
|
||||
static enum drm_mode_status bochs_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct bochs_device *bochs =
|
||||
|
@ -25,6 +25,16 @@ config DRM_ANALOGIX_ANX78XX
|
||||
the HDMI output of an application processor to MyDP
|
||||
or DisplayPort.
|
||||
|
||||
config DRM_CDNS_DSI
|
||||
tristate "Cadence DPI/DSI bridge"
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_MIPI_DSI
|
||||
select DRM_PANEL_BRIDGE
|
||||
depends on OF
|
||||
help
|
||||
Support Cadence DPI to DSI bridge. This is an internal
|
||||
bridge and is meant to be directly embedded in a SoC.
|
||||
|
||||
config DRM_DUMB_VGA_DAC
|
||||
tristate "Dumb VGA DAC Bridge support"
|
||||
depends on OF
|
||||
@ -93,6 +103,12 @@ config DRM_SII9234
|
||||
It is an I2C driver, that detects connection of MHL bridge
|
||||
and starts encapsulation of HDMI signal.
|
||||
|
||||
config DRM_THINE_THC63LVD1024
|
||||
tristate "Thine THC63LVD1024 LVDS decoder bridge"
|
||||
depends on OF
|
||||
---help---
|
||||
Thine THC63LVD1024 LVDS/parallel converter driver.
|
||||
|
||||
config DRM_TOSHIBA_TC358767
|
||||
tristate "Toshiba TC358767 eDP bridge"
|
||||
depends on OF
|
||||
|
@ -1,5 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
|
||||
obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
|
||||
obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o
|
||||
obj-$(CONFIG_DRM_LVDS_ENCODER) += lvds-encoder.o
|
||||
obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
|
||||
@ -8,6 +9,7 @@ obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
|
||||
obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o
|
||||
obj-$(CONFIG_DRM_SII902X) += sii902x.o
|
||||
obj-$(CONFIG_DRM_SII9234) += sii9234.o
|
||||
obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o
|
||||
obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
|
||||
obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
|
||||
obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
|
||||
|
@ -93,6 +93,11 @@
|
||||
#define ADV7511_REG_CHIP_ID_HIGH 0xf5
|
||||
#define ADV7511_REG_CHIP_ID_LOW 0xf6
|
||||
|
||||
/* Hardware defined default addresses for I2C register maps */
|
||||
#define ADV7511_CEC_I2C_ADDR_DEFAULT 0x3c
|
||||
#define ADV7511_EDID_I2C_ADDR_DEFAULT 0x3f
|
||||
#define ADV7511_PACKET_I2C_ADDR_DEFAULT 0x38
|
||||
|
||||
#define ADV7511_CSC_ENABLE BIT(7)
|
||||
#define ADV7511_CSC_UPDATE_MODE BIT(5)
|
||||
|
||||
@ -321,6 +326,7 @@ enum adv7511_type {
|
||||
struct adv7511 {
|
||||
struct i2c_client *i2c_main;
|
||||
struct i2c_client *i2c_edid;
|
||||
struct i2c_client *i2c_packet;
|
||||
struct i2c_client *i2c_cec;
|
||||
|
||||
struct regmap *regmap;
|
||||
|
@ -586,7 +586,7 @@ static int adv7511_get_modes(struct adv7511 *adv7511,
|
||||
/* Reading the EDID only works if the device is powered */
|
||||
if (!adv7511->powered) {
|
||||
unsigned int edid_i2c_addr =
|
||||
(adv7511->i2c_main->addr << 1) + 4;
|
||||
(adv7511->i2c_edid->addr << 1);
|
||||
|
||||
__adv7511_power_on(adv7511);
|
||||
|
||||
@ -654,7 +654,7 @@ adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector)
|
||||
return status;
|
||||
}
|
||||
|
||||
static int adv7511_mode_valid(struct adv7511 *adv7511,
|
||||
static enum drm_mode_status adv7511_mode_valid(struct adv7511 *adv7511,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
if (mode->clock > 165000)
|
||||
@ -969,10 +969,10 @@ static int adv7511_init_cec_regmap(struct adv7511 *adv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
adv->i2c_cec = i2c_new_dummy(adv->i2c_main->adapter,
|
||||
adv->i2c_main->addr - 1);
|
||||
adv->i2c_cec = i2c_new_secondary_device(adv->i2c_main, "cec",
|
||||
ADV7511_CEC_I2C_ADDR_DEFAULT);
|
||||
if (!adv->i2c_cec)
|
||||
return -ENOMEM;
|
||||
return -EINVAL;
|
||||
i2c_set_clientdata(adv->i2c_cec, adv);
|
||||
|
||||
adv->regmap_cec = devm_regmap_init_i2c(adv->i2c_cec,
|
||||
@ -1082,8 +1082,6 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
|
||||
struct adv7511_link_config link_config;
|
||||
struct adv7511 *adv7511;
|
||||
struct device *dev = &i2c->dev;
|
||||
unsigned int main_i2c_addr = i2c->addr << 1;
|
||||
unsigned int edid_i2c_addr = main_i2c_addr + 4;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
@ -1153,23 +1151,34 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
|
||||
if (ret)
|
||||
goto uninit_regulators;
|
||||
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr);
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
|
||||
main_i2c_addr - 0xa);
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR,
|
||||
main_i2c_addr - 2);
|
||||
|
||||
adv7511_packet_disable(adv7511, 0xffff);
|
||||
|
||||
adv7511->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1);
|
||||
adv7511->i2c_edid = i2c_new_secondary_device(i2c, "edid",
|
||||
ADV7511_EDID_I2C_ADDR_DEFAULT);
|
||||
if (!adv7511->i2c_edid) {
|
||||
ret = -ENOMEM;
|
||||
ret = -EINVAL;
|
||||
goto uninit_regulators;
|
||||
}
|
||||
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
|
||||
adv7511->i2c_edid->addr << 1);
|
||||
|
||||
adv7511->i2c_packet = i2c_new_secondary_device(i2c, "packet",
|
||||
ADV7511_PACKET_I2C_ADDR_DEFAULT);
|
||||
if (!adv7511->i2c_packet) {
|
||||
ret = -EINVAL;
|
||||
goto err_i2c_unregister_edid;
|
||||
}
|
||||
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
|
||||
adv7511->i2c_packet->addr << 1);
|
||||
|
||||
ret = adv7511_init_cec_regmap(adv7511);
|
||||
if (ret)
|
||||
goto err_i2c_unregister_edid;
|
||||
goto err_i2c_unregister_packet;
|
||||
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR,
|
||||
adv7511->i2c_cec->addr << 1);
|
||||
|
||||
INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work);
|
||||
|
||||
@ -1207,6 +1216,8 @@ err_unregister_cec:
|
||||
i2c_unregister_device(adv7511->i2c_cec);
|
||||
if (adv7511->cec_clk)
|
||||
clk_disable_unprepare(adv7511->cec_clk);
|
||||
err_i2c_unregister_packet:
|
||||
i2c_unregister_device(adv7511->i2c_packet);
|
||||
err_i2c_unregister_edid:
|
||||
i2c_unregister_device(adv7511->i2c_edid);
|
||||
uninit_regulators:
|
||||
@ -1233,6 +1244,7 @@ static int adv7511_remove(struct i2c_client *i2c)
|
||||
|
||||
cec_unregister_adapter(adv7511->cec_adap);
|
||||
|
||||
i2c_unregister_device(adv7511->i2c_packet);
|
||||
i2c_unregister_device(adv7511->i2c_edid);
|
||||
|
||||
return 0;
|
||||
|
@ -43,8 +43,10 @@ struct bridge_init {
|
||||
struct device_node *node;
|
||||
};
|
||||
|
||||
static void analogix_dp_init_dp(struct analogix_dp_device *dp)
|
||||
static int analogix_dp_init_dp(struct analogix_dp_device *dp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
analogix_dp_reset(dp);
|
||||
|
||||
analogix_dp_swreset(dp);
|
||||
@ -56,10 +58,13 @@ static void analogix_dp_init_dp(struct analogix_dp_device *dp)
|
||||
analogix_dp_enable_sw_function(dp);
|
||||
|
||||
analogix_dp_config_interrupt(dp);
|
||||
analogix_dp_init_analog_func(dp);
|
||||
ret = analogix_dp_init_analog_func(dp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
analogix_dp_init_hpd(dp);
|
||||
analogix_dp_init_aux(dp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
|
||||
@ -71,7 +76,7 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
|
||||
return 0;
|
||||
|
||||
timeout_loop++;
|
||||
usleep_range(10, 11);
|
||||
usleep_range(1000, 1100);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -148,87 +153,146 @@ int analogix_dp_disable_psr(struct analogix_dp_device *dp)
|
||||
psr_vsc.DB1 = 0;
|
||||
|
||||
ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
|
||||
if (ret != 1)
|
||||
if (ret != 1) {
|
||||
dev_err(dp->dev, "Failed to set DP Power0 %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return analogix_dp_send_psr_spd(dp, &psr_vsc, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
|
||||
|
||||
static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
|
||||
static int analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
|
||||
{
|
||||
unsigned char psr_version;
|
||||
int ret;
|
||||
|
||||
ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_SUPPORT, &psr_version);
|
||||
if (ret != 1) {
|
||||
dev_err(dp->dev, "failed to get PSR version, disable it\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_dp_dpcd_readb(&dp->aux, DP_PSR_SUPPORT, &psr_version);
|
||||
dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
|
||||
|
||||
return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
|
||||
dp->psr_enable = (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
|
||||
static int analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
|
||||
{
|
||||
unsigned char psr_en;
|
||||
int ret;
|
||||
|
||||
/* Disable psr function */
|
||||
drm_dp_dpcd_readb(&dp->aux, DP_PSR_EN_CFG, &psr_en);
|
||||
ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_EN_CFG, &psr_en);
|
||||
if (ret != 1) {
|
||||
dev_err(dp->dev, "failed to get psr config\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
psr_en &= ~DP_PSR_ENABLE;
|
||||
drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
|
||||
ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
|
||||
if (ret != 1) {
|
||||
dev_err(dp->dev, "failed to disable panel psr\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Main-Link transmitter remains active during PSR active states */
|
||||
psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION;
|
||||
drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
|
||||
ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
|
||||
if (ret != 1) {
|
||||
dev_err(dp->dev, "failed to set panel psr\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Enable psr function */
|
||||
psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE |
|
||||
DP_PSR_CRC_VERIFICATION;
|
||||
drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
|
||||
ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
|
||||
if (ret != 1) {
|
||||
dev_err(dp->dev, "failed to set panel psr\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
analogix_dp_enable_psr_crc(dp);
|
||||
|
||||
return 0;
|
||||
end:
|
||||
dev_err(dp->dev, "enable psr fail, force to disable psr\n");
|
||||
dp->psr_enable = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp,
|
||||
bool enable)
|
||||
{
|
||||
u8 data;
|
||||
int ret;
|
||||
|
||||
drm_dp_dpcd_readb(&dp->aux, DP_LANE_COUNT_SET, &data);
|
||||
ret = drm_dp_dpcd_readb(&dp->aux, DP_LANE_COUNT_SET, &data);
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
||||
if (enable)
|
||||
drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
|
||||
DP_LANE_COUNT_ENHANCED_FRAME_EN |
|
||||
DPCD_LANE_COUNT_SET(data));
|
||||
ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
|
||||
DP_LANE_COUNT_ENHANCED_FRAME_EN |
|
||||
DPCD_LANE_COUNT_SET(data));
|
||||
else
|
||||
drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
|
||||
DPCD_LANE_COUNT_SET(data));
|
||||
ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET,
|
||||
DPCD_LANE_COUNT_SET(data));
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static int analogix_dp_is_enhanced_mode_available(struct analogix_dp_device *dp)
|
||||
static int analogix_dp_is_enhanced_mode_available(struct analogix_dp_device *dp,
|
||||
u8 *enhanced_mode_support)
|
||||
{
|
||||
u8 data;
|
||||
int retval;
|
||||
int ret;
|
||||
|
||||
drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data);
|
||||
retval = DPCD_ENHANCED_FRAME_CAP(data);
|
||||
ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data);
|
||||
if (ret != 1) {
|
||||
*enhanced_mode_support = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return retval;
|
||||
*enhanced_mode_support = DPCD_ENHANCED_FRAME_CAP(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void analogix_dp_set_enhanced_mode(struct analogix_dp_device *dp)
|
||||
static int analogix_dp_set_enhanced_mode(struct analogix_dp_device *dp)
|
||||
{
|
||||
u8 data;
|
||||
int ret;
|
||||
|
||||
ret = analogix_dp_is_enhanced_mode_available(dp, &data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = analogix_dp_enable_rx_to_enhanced_mode(dp, data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data = analogix_dp_is_enhanced_mode_available(dp);
|
||||
analogix_dp_enable_rx_to_enhanced_mode(dp, data);
|
||||
analogix_dp_enable_enhanced_mode(dp, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void analogix_dp_training_pattern_dis(struct analogix_dp_device *dp)
|
||||
static int analogix_dp_training_pattern_dis(struct analogix_dp_device *dp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
analogix_dp_set_training_pattern(dp, DP_NONE);
|
||||
|
||||
drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
|
||||
DP_TRAINING_PATTERN_DISABLE);
|
||||
ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
|
||||
DP_TRAINING_PATTERN_DISABLE);
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -276,6 +340,12 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp)
|
||||
retval = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, 2);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
/* set enhanced mode if available */
|
||||
retval = analogix_dp_set_enhanced_mode(dp);
|
||||
if (retval < 0) {
|
||||
dev_err(dp->dev, "failed to set enhance mode\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Set TX pre-emphasis to minimum */
|
||||
for (lane = 0; lane < lane_count; lane++)
|
||||
@ -531,7 +601,7 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
|
||||
{
|
||||
int lane, lane_count, retval;
|
||||
u32 reg;
|
||||
u8 link_align, link_status[2], adjust_request[2], spread;
|
||||
u8 link_align, link_status[2], adjust_request[2];
|
||||
|
||||
usleep_range(400, 401);
|
||||
|
||||
@ -560,10 +630,11 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
|
||||
|
||||
if (!analogix_dp_channel_eq_ok(link_status, link_align, lane_count)) {
|
||||
/* traing pattern Set to Normal */
|
||||
analogix_dp_training_pattern_dis(dp);
|
||||
retval = analogix_dp_training_pattern_dis(dp);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
dev_info(dp->dev, "Link Training success!\n");
|
||||
|
||||
analogix_dp_get_link_bandwidth(dp, ®);
|
||||
dp->link_train.link_rate = reg;
|
||||
dev_dbg(dp->dev, "final bandwidth = %.2x\n",
|
||||
@ -574,22 +645,6 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
|
||||
dev_dbg(dp->dev, "final lane count = %.2x\n",
|
||||
dp->link_train.lane_count);
|
||||
|
||||
retval = drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD,
|
||||
&spread);
|
||||
if (retval != 1) {
|
||||
dev_err(dp->dev, "failed to read downspread %d\n",
|
||||
retval);
|
||||
dp->fast_train_support = false;
|
||||
} else {
|
||||
dp->fast_train_support =
|
||||
(spread & DP_NO_AUX_HANDSHAKE_LINK_TRAINING) ?
|
||||
true : false;
|
||||
}
|
||||
dev_dbg(dp->dev, "fast link training %s\n",
|
||||
dp->fast_train_support ? "supported" : "unsupported");
|
||||
|
||||
/* set enhanced mode if available */
|
||||
analogix_dp_set_enhanced_mode(dp);
|
||||
dp->link_train.lt_state = FINISHED;
|
||||
|
||||
return 0;
|
||||
@ -793,7 +848,7 @@ static int analogix_dp_fast_link_train(struct analogix_dp_device *dp)
|
||||
|
||||
static int analogix_dp_train_link(struct analogix_dp_device *dp)
|
||||
{
|
||||
if (dp->fast_train_support)
|
||||
if (dp->fast_train_enable)
|
||||
return analogix_dp_fast_link_train(dp);
|
||||
|
||||
return analogix_dp_full_link_train(dp, dp->video_info.max_lane_count,
|
||||
@ -819,11 +874,10 @@ static int analogix_dp_config_video(struct analogix_dp_device *dp)
|
||||
if (analogix_dp_is_slave_video_stream_clock_on(dp) == 0)
|
||||
break;
|
||||
if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) {
|
||||
dev_err(dp->dev, "Timeout of video streamclk ok\n");
|
||||
dev_err(dp->dev, "Timeout of slave video streamclk ok\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
usleep_range(1, 2);
|
||||
usleep_range(1000, 1001);
|
||||
}
|
||||
|
||||
/* Set to use the register calculated M/N video */
|
||||
@ -838,6 +892,9 @@ static int analogix_dp_config_video(struct analogix_dp_device *dp)
|
||||
/* Configure video slave mode */
|
||||
analogix_dp_enable_video_master(dp, 0);
|
||||
|
||||
/* Enable video */
|
||||
analogix_dp_start_video(dp);
|
||||
|
||||
timeout_loop = 0;
|
||||
|
||||
for (;;) {
|
||||
@ -850,8 +907,9 @@ static int analogix_dp_config_video(struct analogix_dp_device *dp)
|
||||
done_count = 0;
|
||||
}
|
||||
if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) {
|
||||
dev_err(dp->dev, "Timeout of video streamclk ok\n");
|
||||
return -ETIMEDOUT;
|
||||
dev_warn(dp->dev,
|
||||
"Ignoring timeout of video streamclk ok\n");
|
||||
break;
|
||||
}
|
||||
|
||||
usleep_range(1000, 1001);
|
||||
@ -860,24 +918,32 @@ static int analogix_dp_config_video(struct analogix_dp_device *dp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void analogix_dp_enable_scramble(struct analogix_dp_device *dp,
|
||||
bool enable)
|
||||
static int analogix_dp_enable_scramble(struct analogix_dp_device *dp,
|
||||
bool enable)
|
||||
{
|
||||
u8 data;
|
||||
int ret;
|
||||
|
||||
if (enable) {
|
||||
analogix_dp_enable_scrambling(dp);
|
||||
|
||||
drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, &data);
|
||||
drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
|
||||
ret = drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET,
|
||||
&data);
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
|
||||
(u8)(data & ~DP_LINK_SCRAMBLING_DISABLE));
|
||||
} else {
|
||||
analogix_dp_disable_scrambling(dp);
|
||||
|
||||
drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, &data);
|
||||
drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
|
||||
ret = drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET,
|
||||
&data);
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
|
||||
(u8)(data | DP_LINK_SCRAMBLING_DISABLE));
|
||||
}
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static irqreturn_t analogix_dp_hardirq(int irq, void *arg)
|
||||
@ -916,7 +982,23 @@ static irqreturn_t analogix_dp_irq_thread(int irq, void *arg)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void analogix_dp_commit(struct analogix_dp_device *dp)
|
||||
static int analogix_dp_fast_link_train_detection(struct analogix_dp_device *dp)
|
||||
{
|
||||
int ret;
|
||||
u8 spread;
|
||||
|
||||
ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD, &spread);
|
||||
if (ret != 1) {
|
||||
dev_err(dp->dev, "failed to read downspread %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
dp->fast_train_enable = !!(spread & DP_NO_AUX_HANDSHAKE_LINK_TRAINING);
|
||||
dev_dbg(dp->dev, "fast link training %s\n",
|
||||
dp->fast_train_enable ? "supported" : "unsupported");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int analogix_dp_commit(struct analogix_dp_device *dp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -926,34 +1008,50 @@ static void analogix_dp_commit(struct analogix_dp_device *dp)
|
||||
DRM_ERROR("failed to disable the panel\n");
|
||||
}
|
||||
|
||||
ret = readx_poll_timeout(analogix_dp_train_link, dp, ret, !ret, 100,
|
||||
DP_TIMEOUT_TRAINING_US * 5);
|
||||
ret = analogix_dp_train_link(dp);
|
||||
if (ret) {
|
||||
dev_err(dp->dev, "unable to do link train, ret=%d\n", ret);
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
analogix_dp_enable_scramble(dp, 1);
|
||||
analogix_dp_enable_rx_to_enhanced_mode(dp, 1);
|
||||
analogix_dp_enable_enhanced_mode(dp, 1);
|
||||
ret = analogix_dp_enable_scramble(dp, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(dp->dev, "can not enable scramble\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
analogix_dp_init_video(dp);
|
||||
ret = analogix_dp_config_video(dp);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
dev_err(dp->dev, "unable to config video\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Safe to enable the panel now */
|
||||
if (dp->plat_data->panel) {
|
||||
if (drm_panel_enable(dp->plat_data->panel))
|
||||
ret = drm_panel_enable(dp->plat_data->panel);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to enable the panel\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable video */
|
||||
analogix_dp_start_video(dp);
|
||||
ret = analogix_dp_detect_sink_psr(dp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dp->psr_enable = analogix_dp_detect_sink_psr(dp);
|
||||
if (dp->psr_enable)
|
||||
analogix_dp_enable_sink_psr(dp);
|
||||
if (dp->psr_enable) {
|
||||
ret = analogix_dp_enable_sink_psr(dp);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Check whether panel supports fast training */
|
||||
ret = analogix_dp_fast_link_train_detection(dp);
|
||||
if (ret)
|
||||
dp->psr_enable = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1150,24 +1248,80 @@ static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge)
|
||||
DRM_ERROR("failed to setup the panel ret = %d\n", ret);
|
||||
}
|
||||
|
||||
static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pm_runtime_get_sync(dp->dev);
|
||||
|
||||
ret = clk_prepare_enable(dp->clock);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("Failed to prepare_enable the clock clk [%d]\n", ret);
|
||||
goto out_dp_clk_pre;
|
||||
}
|
||||
|
||||
if (dp->plat_data->power_on_start)
|
||||
dp->plat_data->power_on_start(dp->plat_data);
|
||||
|
||||
phy_power_on(dp->phy);
|
||||
|
||||
ret = analogix_dp_init_dp(dp);
|
||||
if (ret)
|
||||
goto out_dp_init;
|
||||
|
||||
/*
|
||||
* According to DP spec v1.3 chap 3.5.1.2 Link Training,
|
||||
* We should first make sure the HPD signal is asserted high by device
|
||||
* when we want to establish a link with it.
|
||||
*/
|
||||
ret = analogix_dp_detect_hpd(dp);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to get hpd single ret = %d\n", ret);
|
||||
goto out_dp_init;
|
||||
}
|
||||
|
||||
ret = analogix_dp_commit(dp);
|
||||
if (ret) {
|
||||
DRM_ERROR("dp commit error, ret = %d\n", ret);
|
||||
goto out_dp_init;
|
||||
}
|
||||
|
||||
if (dp->plat_data->power_on_end)
|
||||
dp->plat_data->power_on_end(dp->plat_data);
|
||||
|
||||
enable_irq(dp->irq);
|
||||
return 0;
|
||||
|
||||
out_dp_init:
|
||||
phy_power_off(dp->phy);
|
||||
if (dp->plat_data->power_off)
|
||||
dp->plat_data->power_off(dp->plat_data);
|
||||
clk_disable_unprepare(dp->clock);
|
||||
out_dp_clk_pre:
|
||||
pm_runtime_put_sync(dp->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void analogix_dp_bridge_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
int timeout_loop = 0;
|
||||
|
||||
if (dp->dpms_mode == DRM_MODE_DPMS_ON)
|
||||
return;
|
||||
|
||||
pm_runtime_get_sync(dp->dev);
|
||||
|
||||
if (dp->plat_data->power_on)
|
||||
dp->plat_data->power_on(dp->plat_data);
|
||||
|
||||
phy_power_on(dp->phy);
|
||||
analogix_dp_init_dp(dp);
|
||||
enable_irq(dp->irq);
|
||||
analogix_dp_commit(dp);
|
||||
|
||||
dp->dpms_mode = DRM_MODE_DPMS_ON;
|
||||
while (timeout_loop < MAX_PLL_LOCK_LOOP) {
|
||||
if (analogix_dp_set_bridge(dp) == 0) {
|
||||
dp->dpms_mode = DRM_MODE_DPMS_ON;
|
||||
return;
|
||||
}
|
||||
dev_err(dp->dev, "failed to set bridge, retry: %d\n",
|
||||
timeout_loop);
|
||||
timeout_loop++;
|
||||
usleep_range(10, 11);
|
||||
}
|
||||
dev_err(dp->dev, "too many times retry set bridge, give it up\n");
|
||||
}
|
||||
|
||||
static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
|
||||
@ -1186,11 +1340,15 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
|
||||
}
|
||||
|
||||
disable_irq(dp->irq);
|
||||
phy_power_off(dp->phy);
|
||||
|
||||
if (dp->plat_data->power_off)
|
||||
dp->plat_data->power_off(dp->plat_data);
|
||||
|
||||
analogix_dp_set_analog_power_down(dp, POWER_ALL, 1);
|
||||
phy_power_off(dp->phy);
|
||||
|
||||
clk_disable_unprepare(dp->clock);
|
||||
|
||||
pm_runtime_put_sync(dp->dev);
|
||||
|
||||
ret = analogix_dp_prepare_panel(dp, false, true);
|
||||
@ -1198,6 +1356,7 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
|
||||
DRM_ERROR("failed to setup the panel ret = %d\n", ret);
|
||||
|
||||
dp->psr_enable = false;
|
||||
dp->fast_train_enable = false;
|
||||
dp->dpms_mode = DRM_MODE_DPMS_OFF;
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#define DP_TIMEOUT_LOOP_COUNT 100
|
||||
#define MAX_CR_LOOP 5
|
||||
#define MAX_EQ_LOOP 5
|
||||
#define MAX_PLL_LOCK_LOOP 5
|
||||
|
||||
/* Training takes 22ms if AUX channel comm fails. Use this as retry interval */
|
||||
#define DP_TIMEOUT_TRAINING_US 22000
|
||||
@ -173,7 +174,7 @@ struct analogix_dp_device {
|
||||
int hpd_gpio;
|
||||
bool force_hpd;
|
||||
bool psr_enable;
|
||||
bool fast_train_support;
|
||||
bool fast_train_enable;
|
||||
|
||||
struct mutex panel_lock;
|
||||
bool panel_is_modeset;
|
||||
@ -197,7 +198,7 @@ void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable);
|
||||
void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
|
||||
enum analog_power_block block,
|
||||
bool enable);
|
||||
void analogix_dp_init_analog_func(struct analogix_dp_device *dp);
|
||||
int analogix_dp_init_analog_func(struct analogix_dp_device *dp);
|
||||
void analogix_dp_init_hpd(struct analogix_dp_device *dp);
|
||||
void analogix_dp_force_hpd(struct analogix_dp_device *dp);
|
||||
enum dp_irq_type analogix_dp_get_irq_type(struct analogix_dp_device *dp);
|
||||
|
@ -126,9 +126,14 @@ void analogix_dp_reset(struct analogix_dp_device *dp)
|
||||
analogix_dp_stop_video(dp);
|
||||
analogix_dp_enable_video_mute(dp, 0);
|
||||
|
||||
reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
|
||||
AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
|
||||
HDCP_FUNC_EN_N | SW_FUNC_EN_N;
|
||||
if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
|
||||
reg = RK_VID_CAP_FUNC_EN_N | RK_VID_FIFO_FUNC_EN_N |
|
||||
SW_FUNC_EN_N;
|
||||
else
|
||||
reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
|
||||
AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
|
||||
HDCP_FUNC_EN_N | SW_FUNC_EN_N;
|
||||
|
||||
writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1);
|
||||
|
||||
reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
|
||||
@ -230,16 +235,20 @@ enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp)
|
||||
void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable)
|
||||
{
|
||||
u32 reg;
|
||||
u32 mask = DP_PLL_PD;
|
||||
u32 pd_addr = ANALOGIX_DP_PLL_CTL;
|
||||
|
||||
if (enable) {
|
||||
reg = readl(dp->reg_base + ANALOGIX_DP_PLL_CTL);
|
||||
reg |= DP_PLL_PD;
|
||||
writel(reg, dp->reg_base + ANALOGIX_DP_PLL_CTL);
|
||||
} else {
|
||||
reg = readl(dp->reg_base + ANALOGIX_DP_PLL_CTL);
|
||||
reg &= ~DP_PLL_PD;
|
||||
writel(reg, dp->reg_base + ANALOGIX_DP_PLL_CTL);
|
||||
if (dp->plat_data && is_rockchip(dp->plat_data->dev_type)) {
|
||||
pd_addr = ANALOGIX_DP_PD;
|
||||
mask = RK_PLL_PD;
|
||||
}
|
||||
|
||||
reg = readl(dp->reg_base + pd_addr);
|
||||
if (enable)
|
||||
reg |= mask;
|
||||
else
|
||||
reg &= ~mask;
|
||||
writel(reg, dp->reg_base + pd_addr);
|
||||
}
|
||||
|
||||
void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
|
||||
@ -248,83 +257,98 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
|
||||
{
|
||||
u32 reg;
|
||||
u32 phy_pd_addr = ANALOGIX_DP_PHY_PD;
|
||||
u32 mask;
|
||||
|
||||
if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
|
||||
phy_pd_addr = ANALOGIX_DP_PD;
|
||||
|
||||
switch (block) {
|
||||
case AUX_BLOCK:
|
||||
if (enable) {
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
reg |= AUX_PD;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
} else {
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
reg &= ~AUX_PD;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
}
|
||||
if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
|
||||
mask = RK_AUX_PD;
|
||||
else
|
||||
mask = AUX_PD;
|
||||
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
if (enable)
|
||||
reg |= mask;
|
||||
else
|
||||
reg &= ~mask;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
break;
|
||||
case CH0_BLOCK:
|
||||
if (enable) {
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
reg |= CH0_PD;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
} else {
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
reg &= ~CH0_PD;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
}
|
||||
mask = CH0_PD;
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
|
||||
if (enable)
|
||||
reg |= mask;
|
||||
else
|
||||
reg &= ~mask;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
break;
|
||||
case CH1_BLOCK:
|
||||
if (enable) {
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
reg |= CH1_PD;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
} else {
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
reg &= ~CH1_PD;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
}
|
||||
mask = CH1_PD;
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
|
||||
if (enable)
|
||||
reg |= mask;
|
||||
else
|
||||
reg &= ~mask;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
break;
|
||||
case CH2_BLOCK:
|
||||
if (enable) {
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
reg |= CH2_PD;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
} else {
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
reg &= ~CH2_PD;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
}
|
||||
mask = CH2_PD;
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
|
||||
if (enable)
|
||||
reg |= mask;
|
||||
else
|
||||
reg &= ~mask;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
break;
|
||||
case CH3_BLOCK:
|
||||
if (enable) {
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
reg |= CH3_PD;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
} else {
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
reg &= ~CH3_PD;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
}
|
||||
mask = CH3_PD;
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
|
||||
if (enable)
|
||||
reg |= mask;
|
||||
else
|
||||
reg &= ~mask;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
break;
|
||||
case ANALOG_TOTAL:
|
||||
if (enable) {
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
reg |= DP_PHY_PD;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
} else {
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
reg &= ~DP_PHY_PD;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
}
|
||||
/*
|
||||
* There is no bit named DP_PHY_PD, so We used DP_INC_BG
|
||||
* to power off everything instead of DP_PHY_PD in
|
||||
* Rockchip
|
||||
*/
|
||||
if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
|
||||
mask = DP_INC_BG;
|
||||
else
|
||||
mask = DP_PHY_PD;
|
||||
|
||||
reg = readl(dp->reg_base + phy_pd_addr);
|
||||
if (enable)
|
||||
reg |= mask;
|
||||
else
|
||||
reg &= ~mask;
|
||||
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
|
||||
usleep_range(10, 15);
|
||||
break;
|
||||
case POWER_ALL:
|
||||
if (enable) {
|
||||
reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD |
|
||||
CH1_PD | CH0_PD;
|
||||
reg = DP_ALL_PD;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
} else {
|
||||
reg = DP_ALL_PD;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
usleep_range(10, 15);
|
||||
reg &= ~DP_INC_BG;
|
||||
writel(reg, dp->reg_base + phy_pd_addr);
|
||||
usleep_range(10, 15);
|
||||
|
||||
writel(0x00, dp->reg_base + phy_pd_addr);
|
||||
}
|
||||
break;
|
||||
@ -333,7 +357,7 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
|
||||
}
|
||||
}
|
||||
|
||||
void analogix_dp_init_analog_func(struct analogix_dp_device *dp)
|
||||
int analogix_dp_init_analog_func(struct analogix_dp_device *dp)
|
||||
{
|
||||
u32 reg;
|
||||
int timeout_loop = 0;
|
||||
@ -355,7 +379,7 @@ void analogix_dp_init_analog_func(struct analogix_dp_device *dp)
|
||||
timeout_loop++;
|
||||
if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
|
||||
dev_err(dp->dev, "failed to get pll lock status\n");
|
||||
return;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
usleep_range(10, 20);
|
||||
}
|
||||
@ -366,6 +390,7 @@ void analogix_dp_init_analog_func(struct analogix_dp_device *dp)
|
||||
reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N
|
||||
| AUX_FUNC_EN_N);
|
||||
writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void analogix_dp_clear_hotplug_interrupts(struct analogix_dp_device *dp)
|
||||
@ -450,17 +475,22 @@ void analogix_dp_init_aux(struct analogix_dp_device *dp)
|
||||
reg = RPLY_RECEIV | AUX_ERR;
|
||||
writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA);
|
||||
|
||||
analogix_dp_set_analog_power_down(dp, AUX_BLOCK, true);
|
||||
usleep_range(10, 11);
|
||||
analogix_dp_set_analog_power_down(dp, AUX_BLOCK, false);
|
||||
|
||||
analogix_dp_reset_aux(dp);
|
||||
|
||||
/* Disable AUX transaction H/W retry */
|
||||
/* AUX_BIT_PERIOD_EXPECTED_DELAY doesn't apply to Rockchip IP */
|
||||
if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
|
||||
reg = AUX_BIT_PERIOD_EXPECTED_DELAY(0) |
|
||||
AUX_HW_RETRY_COUNT_SEL(3) |
|
||||
AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
|
||||
reg = 0;
|
||||
else
|
||||
reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) |
|
||||
AUX_HW_RETRY_COUNT_SEL(0) |
|
||||
AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
|
||||
reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3);
|
||||
|
||||
/* Disable AUX transaction H/W retry */
|
||||
reg |= AUX_HW_RETRY_COUNT_SEL(0) |
|
||||
AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
|
||||
|
||||
writel(reg, dp->reg_base + ANALOGIX_DP_AUX_HW_RETRY_CTL);
|
||||
|
||||
/* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */
|
||||
@ -947,8 +977,12 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp)
|
||||
u32 reg;
|
||||
|
||||
reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_1);
|
||||
reg &= ~(MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N);
|
||||
reg |= MASTER_VID_FUNC_EN_N;
|
||||
if (dp->plat_data && is_rockchip(dp->plat_data->dev_type)) {
|
||||
reg &= ~(RK_VID_CAP_FUNC_EN_N | RK_VID_FIFO_FUNC_EN_N);
|
||||
} else {
|
||||
reg &= ~(MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N);
|
||||
reg |= MASTER_VID_FUNC_EN_N;
|
||||
}
|
||||
writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_1);
|
||||
|
||||
reg = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10);
|
||||
@ -1072,10 +1106,11 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
|
||||
struct drm_dp_aux_msg *msg)
|
||||
{
|
||||
u32 reg;
|
||||
u32 status_reg;
|
||||
u8 *buffer = msg->buffer;
|
||||
int timeout_loop = 0;
|
||||
unsigned int i;
|
||||
int num_transferred = 0;
|
||||
int ret;
|
||||
|
||||
/* Buffer size of AUX CH is 16 bytes */
|
||||
if (WARN_ON(msg->size > 16))
|
||||
@ -1139,17 +1174,20 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
|
||||
|
||||
writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2);
|
||||
|
||||
/* Is AUX CH command reply received? */
|
||||
ret = readx_poll_timeout(readl, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2,
|
||||
reg, !(reg & AUX_EN), 25, 500 * 1000);
|
||||
if (ret) {
|
||||
dev_err(dp->dev, "AUX CH enable timeout!\n");
|
||||
goto aux_error;
|
||||
}
|
||||
|
||||
/* TODO: Wait for an interrupt instead of looping? */
|
||||
reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
|
||||
while (!(reg & RPLY_RECEIV)) {
|
||||
timeout_loop++;
|
||||
if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) {
|
||||
dev_err(dp->dev, "AUX CH command reply failed!\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
|
||||
usleep_range(10, 11);
|
||||
/* Is AUX CH command reply received? */
|
||||
ret = readx_poll_timeout(readl, dp->reg_base + ANALOGIX_DP_INT_STA,
|
||||
reg, reg & RPLY_RECEIV, 10, 20 * 1000);
|
||||
if (ret) {
|
||||
dev_err(dp->dev, "AUX CH cmd reply timeout!\n");
|
||||
goto aux_error;
|
||||
}
|
||||
|
||||
/* Clear interrupt source for AUX CH command reply */
|
||||
@ -1157,17 +1195,13 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
|
||||
|
||||
/* Clear interrupt source for AUX CH access error */
|
||||
reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
|
||||
if (reg & AUX_ERR) {
|
||||
status_reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA);
|
||||
if ((reg & AUX_ERR) || (status_reg & AUX_STATUS_MASK)) {
|
||||
writel(AUX_ERR, dp->reg_base + ANALOGIX_DP_INT_STA);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
/* Check AUX CH error access status */
|
||||
reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA);
|
||||
if ((reg & AUX_STATUS_MASK)) {
|
||||
dev_err(dp->dev, "AUX CH error happened: %d\n\n",
|
||||
reg & AUX_STATUS_MASK);
|
||||
return -EREMOTEIO;
|
||||
dev_warn(dp->dev, "AUX CH error happened: %#x (%d)\n",
|
||||
status_reg & AUX_STATUS_MASK, !!(reg & AUX_ERR));
|
||||
goto aux_error;
|
||||
}
|
||||
|
||||
if (msg->request & DP_AUX_I2C_READ) {
|
||||
@ -1193,4 +1227,10 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
|
||||
msg->reply = DP_AUX_NATIVE_REPLY_ACK;
|
||||
|
||||
return num_transferred > 0 ? num_transferred : -EBUSY;
|
||||
|
||||
aux_error:
|
||||
/* if aux err happen, reset aux */
|
||||
analogix_dp_init_aux(dp);
|
||||
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
@ -127,7 +127,9 @@
|
||||
|
||||
/* ANALOGIX_DP_FUNC_EN_1 */
|
||||
#define MASTER_VID_FUNC_EN_N (0x1 << 7)
|
||||
#define RK_VID_CAP_FUNC_EN_N (0x1 << 6)
|
||||
#define SLAVE_VID_FUNC_EN_N (0x1 << 5)
|
||||
#define RK_VID_FIFO_FUNC_EN_N (0x1 << 5)
|
||||
#define AUD_FIFO_FUNC_EN_N (0x1 << 4)
|
||||
#define AUD_FUNC_EN_N (0x1 << 3)
|
||||
#define HDCP_FUNC_EN_N (0x1 << 2)
|
||||
@ -342,12 +344,17 @@
|
||||
#define DP_PLL_REF_BIT_1_2500V (0x7 << 0)
|
||||
|
||||
/* ANALOGIX_DP_PHY_PD */
|
||||
#define DP_INC_BG (0x1 << 7)
|
||||
#define DP_EXP_BG (0x1 << 6)
|
||||
#define DP_PHY_PD (0x1 << 5)
|
||||
#define RK_AUX_PD (0x1 << 5)
|
||||
#define AUX_PD (0x1 << 4)
|
||||
#define RK_PLL_PD (0x1 << 4)
|
||||
#define CH3_PD (0x1 << 3)
|
||||
#define CH2_PD (0x1 << 2)
|
||||
#define CH1_PD (0x1 << 1)
|
||||
#define CH0_PD (0x1 << 0)
|
||||
#define DP_ALL_PD (0xff)
|
||||
|
||||
/* ANALOGIX_DP_PHY_TEST */
|
||||
#define MACRO_RST (0x1 << 5)
|
||||
|
1623
drivers/gpu/drm/bridge/cdns-dsi.c
Normal file
1623
drivers/gpu/drm/bridge/cdns-dsi.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -152,7 +152,6 @@ static struct platform_driver snd_dw_hdmi_driver = {
|
||||
.remove = snd_dw_hdmi_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
module_platform_driver(snd_dw_hdmi_driver);
|
||||
|
@ -1,12 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
|
||||
* Copyright (C) STMicroelectronics SA 2017
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Modified by Philippe Cornu <philippe.cornu@st.com>
|
||||
* This generic Synopsys DesignWare MIPI DSI host driver is based on the
|
||||
* Rockchip version from rockchip/dw-mipi-dsi.c with phy & bridge APIs.
|
||||
@ -775,20 +771,20 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
|
||||
|
||||
clk_prepare_enable(dsi->pclk);
|
||||
|
||||
ret = phy_ops->get_lane_mbps(priv_data, mode, dsi->mode_flags,
|
||||
ret = phy_ops->get_lane_mbps(priv_data, adjusted_mode, dsi->mode_flags,
|
||||
dsi->lanes, dsi->format, &dsi->lane_mbps);
|
||||
if (ret)
|
||||
DRM_DEBUG_DRIVER("Phy get_lane_mbps() failed\n");
|
||||
|
||||
pm_runtime_get_sync(dsi->dev);
|
||||
dw_mipi_dsi_init(dsi);
|
||||
dw_mipi_dsi_dpi_config(dsi, mode);
|
||||
dw_mipi_dsi_dpi_config(dsi, adjusted_mode);
|
||||
dw_mipi_dsi_packet_handler_config(dsi);
|
||||
dw_mipi_dsi_video_mode_config(dsi);
|
||||
dw_mipi_dsi_video_packet_config(dsi, mode);
|
||||
dw_mipi_dsi_video_packet_config(dsi, adjusted_mode);
|
||||
dw_mipi_dsi_command_mode_config(dsi);
|
||||
dw_mipi_dsi_line_timer_config(dsi, mode);
|
||||
dw_mipi_dsi_vertical_timing_config(dsi, mode);
|
||||
dw_mipi_dsi_line_timer_config(dsi, adjusted_mode);
|
||||
dw_mipi_dsi_vertical_timing_config(dsi, adjusted_mode);
|
||||
|
||||
dw_mipi_dsi_dphy_init(dsi);
|
||||
dw_mipi_dsi_dphy_timing_config(dsi);
|
||||
@ -802,7 +798,7 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
|
||||
|
||||
dw_mipi_dsi_dphy_enable(dsi);
|
||||
|
||||
dw_mipi_dsi_wait_for_two_frames(mode);
|
||||
dw_mipi_dsi_wait_for_two_frames(adjusted_mode);
|
||||
|
||||
/* Switch to cmd mode for panel-bridge pre_enable & panel prepare */
|
||||
dw_mipi_dsi_set_mode(dsi, 0);
|
||||
|
@ -1102,7 +1102,7 @@ static bool tc_bridge_mode_fixup(struct drm_bridge *bridge,
|
||||
return true;
|
||||
}
|
||||
|
||||
static int tc_connector_mode_valid(struct drm_connector *connector,
|
||||
static enum drm_mode_status tc_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
/* DPI interface clock limitation: upto 154 MHz */
|
||||
|
206
drivers/gpu/drm/bridge/thc63lvd1024.c
Normal file
206
drivers/gpu/drm/bridge/thc63lvd1024.c
Normal file
@ -0,0 +1,206 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* THC63LVD1024 LVDS to parallel data DRM bridge driver.
|
||||
*
|
||||
* Copyright (C) 2018 Jacopo Mondi <jacopo+renesas@jmondi.org>
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
enum thc63_ports {
|
||||
THC63_LVDS_IN0,
|
||||
THC63_LVDS_IN1,
|
||||
THC63_RGB_OUT0,
|
||||
THC63_RGB_OUT1,
|
||||
};
|
||||
|
||||
struct thc63_dev {
|
||||
struct device *dev;
|
||||
|
||||
struct regulator *vcc;
|
||||
|
||||
struct gpio_desc *pdwn;
|
||||
struct gpio_desc *oe;
|
||||
|
||||
struct drm_bridge bridge;
|
||||
struct drm_bridge *next;
|
||||
};
|
||||
|
||||
static inline struct thc63_dev *to_thc63(struct drm_bridge *bridge)
|
||||
{
|
||||
return container_of(bridge, struct thc63_dev, bridge);
|
||||
}
|
||||
|
||||
static int thc63_attach(struct drm_bridge *bridge)
|
||||
{
|
||||
struct thc63_dev *thc63 = to_thc63(bridge);
|
||||
|
||||
return drm_bridge_attach(bridge->encoder, thc63->next, bridge);
|
||||
}
|
||||
|
||||
static void thc63_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct thc63_dev *thc63 = to_thc63(bridge);
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable(thc63->vcc);
|
||||
if (ret) {
|
||||
dev_err(thc63->dev,
|
||||
"Failed to enable regulator \"vcc\": %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
gpiod_set_value(thc63->pdwn, 0);
|
||||
gpiod_set_value(thc63->oe, 1);
|
||||
}
|
||||
|
||||
static void thc63_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct thc63_dev *thc63 = to_thc63(bridge);
|
||||
int ret;
|
||||
|
||||
gpiod_set_value(thc63->oe, 0);
|
||||
gpiod_set_value(thc63->pdwn, 1);
|
||||
|
||||
ret = regulator_disable(thc63->vcc);
|
||||
if (ret)
|
||||
dev_err(thc63->dev,
|
||||
"Failed to disable regulator \"vcc\": %d\n", ret);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs thc63_bridge_func = {
|
||||
.attach = thc63_attach,
|
||||
.enable = thc63_enable,
|
||||
.disable = thc63_disable,
|
||||
};
|
||||
|
||||
static int thc63_parse_dt(struct thc63_dev *thc63)
|
||||
{
|
||||
struct device_node *thc63_out;
|
||||
struct device_node *remote;
|
||||
|
||||
thc63_out = of_graph_get_endpoint_by_regs(thc63->dev->of_node,
|
||||
THC63_RGB_OUT0, -1);
|
||||
if (!thc63_out) {
|
||||
dev_err(thc63->dev, "Missing endpoint in port@%u\n",
|
||||
THC63_RGB_OUT0);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
remote = of_graph_get_remote_port_parent(thc63_out);
|
||||
of_node_put(thc63_out);
|
||||
if (!remote) {
|
||||
dev_err(thc63->dev, "Endpoint in port@%u unconnected\n",
|
||||
THC63_RGB_OUT0);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!of_device_is_available(remote)) {
|
||||
dev_err(thc63->dev, "port@%u remote endpoint is disabled\n",
|
||||
THC63_RGB_OUT0);
|
||||
of_node_put(remote);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
thc63->next = of_drm_find_bridge(remote);
|
||||
of_node_put(remote);
|
||||
if (!thc63->next)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int thc63_gpio_init(struct thc63_dev *thc63)
|
||||
{
|
||||
thc63->oe = devm_gpiod_get_optional(thc63->dev, "oe", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(thc63->oe)) {
|
||||
dev_err(thc63->dev, "Unable to get \"oe-gpios\": %ld\n",
|
||||
PTR_ERR(thc63->oe));
|
||||
return PTR_ERR(thc63->oe);
|
||||
}
|
||||
|
||||
thc63->pdwn = devm_gpiod_get_optional(thc63->dev, "powerdown",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(thc63->pdwn)) {
|
||||
dev_err(thc63->dev, "Unable to get \"powerdown-gpios\": %ld\n",
|
||||
PTR_ERR(thc63->pdwn));
|
||||
return PTR_ERR(thc63->pdwn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int thc63_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct thc63_dev *thc63;
|
||||
int ret;
|
||||
|
||||
thc63 = devm_kzalloc(&pdev->dev, sizeof(*thc63), GFP_KERNEL);
|
||||
if (!thc63)
|
||||
return -ENOMEM;
|
||||
|
||||
thc63->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, thc63);
|
||||
|
||||
thc63->vcc = devm_regulator_get_optional(thc63->dev, "vcc");
|
||||
if (IS_ERR(thc63->vcc)) {
|
||||
if (PTR_ERR(thc63->vcc) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dev_err(thc63->dev, "Unable to get \"vcc\" supply: %ld\n",
|
||||
PTR_ERR(thc63->vcc));
|
||||
return PTR_ERR(thc63->vcc);
|
||||
}
|
||||
|
||||
ret = thc63_gpio_init(thc63);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = thc63_parse_dt(thc63);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
thc63->bridge.driver_private = thc63;
|
||||
thc63->bridge.of_node = pdev->dev.of_node;
|
||||
thc63->bridge.funcs = &thc63_bridge_func;
|
||||
|
||||
drm_bridge_add(&thc63->bridge);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int thc63_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct thc63_dev *thc63 = platform_get_drvdata(pdev);
|
||||
|
||||
drm_bridge_remove(&thc63->bridge);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id thc63_match[] = {
|
||||
{ .compatible = "thine,thc63lvd1024", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, thc63_match);
|
||||
|
||||
static struct platform_driver thc63_driver = {
|
||||
.probe = thc63_probe,
|
||||
.remove = thc63_remove,
|
||||
.driver = {
|
||||
.name = "thc63lvd1024",
|
||||
.of_match_table = thc63_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(thc63_driver);
|
||||
|
||||
MODULE_AUTHOR("Jacopo Mondi <jacopo@jmondi.org>");
|
||||
MODULE_DESCRIPTION("Thine THC63LVD1024 LVDS decoder DRM bridge driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -783,6 +783,8 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane,
|
||||
state->src_w = val;
|
||||
} else if (property == config->prop_src_h) {
|
||||
state->src_h = val;
|
||||
} else if (property == plane->alpha_property) {
|
||||
state->alpha = val;
|
||||
} else if (property == plane->rotation_property) {
|
||||
if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK))
|
||||
return -EINVAL;
|
||||
@ -848,6 +850,8 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
|
||||
*val = state->src_w;
|
||||
} else if (property == config->prop_src_h) {
|
||||
*val = state->src_h;
|
||||
} else if (property == plane->alpha_property) {
|
||||
*val = state->alpha;
|
||||
} else if (property == plane->rotation_property) {
|
||||
*val = state->rotation;
|
||||
} else if (property == plane->zpos_property) {
|
||||
@ -1492,6 +1496,14 @@ EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
|
||||
* Otherwise, if &drm_plane_state.fence is not set this function we just set it
|
||||
* with the received implicit fence. In both cases this function consumes a
|
||||
* reference for @fence.
|
||||
*
|
||||
* This way explicit fencing can be used to overrule implicit fencing, which is
|
||||
* important to make explicit fencing use-cases work: One example is using one
|
||||
* buffer for 2 screens with different refresh rates. Implicit fencing will
|
||||
* clamp rendering to the refresh rate of the slower screen, whereas explicit
|
||||
* fence allows 2 independent render and display loops on a single buffer. If a
|
||||
* driver allows obeys both implicit and explicit fences for plane updates, then
|
||||
* it will break all the benefits of explicit fencing.
|
||||
*/
|
||||
void
|
||||
drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state,
|
||||
|
@ -875,6 +875,11 @@ EXPORT_SYMBOL(drm_atomic_helper_check_planes);
|
||||
* functions depend upon an updated adjusted_mode.clock to e.g. properly compute
|
||||
* watermarks.
|
||||
*
|
||||
* Note that zpos normalization will add all enable planes to the state which
|
||||
* might not desired for some drivers.
|
||||
* For example enable/disable of a cursor plane which have fixed zpos value
|
||||
* would trigger all other enabled planes to be forced to the state change.
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero for success or -errno
|
||||
*/
|
||||
@ -887,6 +892,12 @@ int drm_atomic_helper_check(struct drm_device *dev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (dev->mode_config.normalize_zpos) {
|
||||
ret = drm_atomic_normalize_zpos(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = drm_atomic_helper_check_planes(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -1561,6 +1572,17 @@ void drm_atomic_helper_async_commit(struct drm_device *dev,
|
||||
for_each_new_plane_in_state(state, plane, plane_state, i) {
|
||||
funcs = plane->helper_private;
|
||||
funcs->atomic_async_update(plane, plane_state);
|
||||
|
||||
/*
|
||||
* ->atomic_async_update() is supposed to update the
|
||||
* plane->state in-place, make sure at least common
|
||||
* properties have been properly updated.
|
||||
*/
|
||||
WARN_ON_ONCE(plane->state->fb != plane_state->fb);
|
||||
WARN_ON_ONCE(plane->state->crtc_x != plane_state->crtc_x);
|
||||
WARN_ON_ONCE(plane->state->crtc_y != plane_state->crtc_y);
|
||||
WARN_ON_ONCE(plane->state->src_x != plane_state->src_x);
|
||||
WARN_ON_ONCE(plane->state->src_y != plane_state->src_y);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_async_commit);
|
||||
@ -2659,7 +2681,7 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (plane_state->crtc && (plane == plane->crtc->cursor))
|
||||
if (plane_state->crtc && plane_state->crtc->cursor == plane)
|
||||
plane_state->state->legacy_cursor_update = true;
|
||||
|
||||
ret = __drm_atomic_helper_disable_plane(plane, plane_state);
|
||||
@ -2881,31 +2903,9 @@ commit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_disable_all - disable all currently active outputs
|
||||
* @dev: DRM device
|
||||
* @ctx: lock acquisition context
|
||||
*
|
||||
* Loops through all connectors, finding those that aren't turned off and then
|
||||
* turns them off by setting their DPMS mode to OFF and deactivating the CRTC
|
||||
* that they are connected to.
|
||||
*
|
||||
* This is used for example in suspend/resume to disable all currently active
|
||||
* functions when suspending. If you just want to shut down everything at e.g.
|
||||
* driver unload, look at drm_atomic_helper_shutdown().
|
||||
*
|
||||
* Note that if callers haven't already acquired all modeset locks this might
|
||||
* return -EDEADLK, which must be handled by calling drm_modeset_backoff().
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success or a negative error code on failure.
|
||||
*
|
||||
* See also:
|
||||
* drm_atomic_helper_suspend(), drm_atomic_helper_resume() and
|
||||
* drm_atomic_helper_shutdown().
|
||||
*/
|
||||
int drm_atomic_helper_disable_all(struct drm_device *dev,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
static int __drm_atomic_helper_disable_all(struct drm_device *dev,
|
||||
struct drm_modeset_acquire_ctx *ctx,
|
||||
bool clean_old_fbs)
|
||||
{
|
||||
struct drm_atomic_state *state;
|
||||
struct drm_connector_state *conn_state;
|
||||
@ -2957,8 +2957,11 @@ int drm_atomic_helper_disable_all(struct drm_device *dev,
|
||||
goto free;
|
||||
|
||||
drm_atomic_set_fb_for_plane(plane_state, NULL);
|
||||
plane_mask |= BIT(drm_plane_index(plane));
|
||||
plane->old_fb = plane->fb;
|
||||
|
||||
if (clean_old_fbs) {
|
||||
plane->old_fb = plane->fb;
|
||||
plane_mask |= BIT(drm_plane_index(plane));
|
||||
}
|
||||
}
|
||||
|
||||
ret = drm_atomic_commit(state);
|
||||
@ -2969,6 +2972,34 @@ free:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_disable_all - disable all currently active outputs
|
||||
* @dev: DRM device
|
||||
* @ctx: lock acquisition context
|
||||
*
|
||||
* Loops through all connectors, finding those that aren't turned off and then
|
||||
* turns them off by setting their DPMS mode to OFF and deactivating the CRTC
|
||||
* that they are connected to.
|
||||
*
|
||||
* This is used for example in suspend/resume to disable all currently active
|
||||
* functions when suspending. If you just want to shut down everything at e.g.
|
||||
* driver unload, look at drm_atomic_helper_shutdown().
|
||||
*
|
||||
* Note that if callers haven't already acquired all modeset locks this might
|
||||
* return -EDEADLK, which must be handled by calling drm_modeset_backoff().
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success or a negative error code on failure.
|
||||
*
|
||||
* See also:
|
||||
* drm_atomic_helper_suspend(), drm_atomic_helper_resume() and
|
||||
* drm_atomic_helper_shutdown().
|
||||
*/
|
||||
int drm_atomic_helper_disable_all(struct drm_device *dev,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
return __drm_atomic_helper_disable_all(dev, ctx, false);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_disable_all);
|
||||
|
||||
/**
|
||||
@ -2991,7 +3022,7 @@ void drm_atomic_helper_shutdown(struct drm_device *dev)
|
||||
while (1) {
|
||||
ret = drm_modeset_lock_all_ctx(dev, &ctx);
|
||||
if (!ret)
|
||||
ret = drm_atomic_helper_disable_all(dev, &ctx);
|
||||
ret = __drm_atomic_helper_disable_all(dev, &ctx, true);
|
||||
|
||||
if (ret != -EDEADLK)
|
||||
break;
|
||||
@ -3095,14 +3126,14 @@ int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state,
|
||||
struct drm_connector_state *new_conn_state;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
unsigned plane_mask = 0;
|
||||
struct drm_device *dev = state->dev;
|
||||
int ret;
|
||||
|
||||
state->acquire_ctx = ctx;
|
||||
|
||||
for_each_new_plane_in_state(state, plane, new_plane_state, i) {
|
||||
plane_mask |= BIT(drm_plane_index(plane));
|
||||
WARN_ON(plane->crtc != new_plane_state->crtc);
|
||||
WARN_ON(plane->fb != new_plane_state->fb);
|
||||
WARN_ON(plane->old_fb);
|
||||
|
||||
state->planes[i].old_state = plane->state;
|
||||
}
|
||||
|
||||
@ -3112,11 +3143,7 @@ int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state,
|
||||
for_each_new_connector_in_state(state, connector, new_conn_state, i)
|
||||
state->connectors[i].old_state = connector->state;
|
||||
|
||||
ret = drm_atomic_commit(state);
|
||||
if (plane_mask)
|
||||
drm_atomic_clean_old_fb(dev, plane_mask, ret);
|
||||
|
||||
return ret;
|
||||
return drm_atomic_commit(state);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_commit_duplicated_state);
|
||||
|
||||
@ -3484,6 +3511,10 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane)
|
||||
if (plane->state) {
|
||||
plane->state->plane = plane;
|
||||
plane->state->rotation = DRM_MODE_ROTATE_0;
|
||||
|
||||
/* Reset the alpha value to fully opaque if it matters */
|
||||
if (plane->alpha_property)
|
||||
plane->state->alpha = plane->alpha_property->values[1];
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
|
||||
|
@ -88,6 +88,13 @@
|
||||
* On top of this basic transformation additional properties can be exposed by
|
||||
* the driver:
|
||||
*
|
||||
* alpha:
|
||||
* Alpha is setup with drm_plane_create_alpha_property(). It controls the
|
||||
* plane-wide opacity, from transparent (0) to opaque (0xffff). It can be
|
||||
* combined with pixel alpha.
|
||||
* The pixel values in the framebuffers are expected to not be
|
||||
* pre-multiplied by the global alpha associated to the plane.
|
||||
*
|
||||
* rotation:
|
||||
* Rotation is set up with drm_plane_create_rotation_property(). It adds a
|
||||
* rotation and reflection step between the source and destination rectangles.
|
||||
@ -105,6 +112,38 @@
|
||||
* exposed and assumed to be black).
|
||||
*/
|
||||
|
||||
/**
|
||||
* drm_plane_create_alpha_property - create a new alpha property
|
||||
* @plane: drm plane
|
||||
*
|
||||
* This function creates a generic, mutable, alpha property and enables support
|
||||
* for it in the DRM core. It is attached to @plane.
|
||||
*
|
||||
* The alpha property will be allowed to be within the bounds of 0
|
||||
* (transparent) to 0xffff (opaque).
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success, negative error code on failure.
|
||||
*/
|
||||
int drm_plane_create_alpha_property(struct drm_plane *plane)
|
||||
{
|
||||
struct drm_property *prop;
|
||||
|
||||
prop = drm_property_create_range(plane->dev, 0, "alpha",
|
||||
0, DRM_BLEND_ALPHA_OPAQUE);
|
||||
if (!prop)
|
||||
return -ENOMEM;
|
||||
|
||||
drm_object_attach_property(&plane->base, prop, DRM_BLEND_ALPHA_OPAQUE);
|
||||
plane->alpha_property = prop;
|
||||
|
||||
if (plane->state)
|
||||
plane->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_plane_create_alpha_property);
|
||||
|
||||
/**
|
||||
* drm_plane_create_rotation_property - create a new rotation property
|
||||
* @plane: drm plane
|
||||
|
@ -402,6 +402,7 @@ int drm_mode_getcrtc(struct drm_device *dev,
|
||||
{
|
||||
struct drm_mode_crtc *crtc_resp = data;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_plane *plane;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
@ -410,34 +411,36 @@ int drm_mode_getcrtc(struct drm_device *dev,
|
||||
if (!crtc)
|
||||
return -ENOENT;
|
||||
|
||||
plane = crtc->primary;
|
||||
|
||||
crtc_resp->gamma_size = crtc->gamma_size;
|
||||
|
||||
drm_modeset_lock(&crtc->primary->mutex, NULL);
|
||||
if (crtc->primary->state && crtc->primary->state->fb)
|
||||
crtc_resp->fb_id = crtc->primary->state->fb->base.id;
|
||||
else if (!crtc->primary->state && crtc->primary->fb)
|
||||
crtc_resp->fb_id = crtc->primary->fb->base.id;
|
||||
drm_modeset_lock(&plane->mutex, NULL);
|
||||
if (plane->state && plane->state->fb)
|
||||
crtc_resp->fb_id = plane->state->fb->base.id;
|
||||
else if (!plane->state && plane->fb)
|
||||
crtc_resp->fb_id = plane->fb->base.id;
|
||||
else
|
||||
crtc_resp->fb_id = 0;
|
||||
|
||||
if (crtc->primary->state) {
|
||||
crtc_resp->x = crtc->primary->state->src_x >> 16;
|
||||
crtc_resp->y = crtc->primary->state->src_y >> 16;
|
||||
if (plane->state) {
|
||||
crtc_resp->x = plane->state->src_x >> 16;
|
||||
crtc_resp->y = plane->state->src_y >> 16;
|
||||
}
|
||||
drm_modeset_unlock(&crtc->primary->mutex);
|
||||
drm_modeset_unlock(&plane->mutex);
|
||||
|
||||
drm_modeset_lock(&crtc->mutex, NULL);
|
||||
if (crtc->state) {
|
||||
if (crtc->state->enable) {
|
||||
drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode);
|
||||
crtc_resp->mode_valid = 1;
|
||||
|
||||
} else {
|
||||
crtc_resp->mode_valid = 0;
|
||||
}
|
||||
} else {
|
||||
crtc_resp->x = crtc->x;
|
||||
crtc_resp->y = crtc->y;
|
||||
|
||||
if (crtc->enabled) {
|
||||
drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->mode);
|
||||
crtc_resp->mode_valid = 1;
|
||||
@ -471,7 +474,7 @@ static int __drm_mode_set_config_internal(struct drm_mode_set *set,
|
||||
|
||||
ret = crtc->funcs->set_config(set, ctx);
|
||||
if (ret == 0) {
|
||||
crtc->primary->crtc = crtc;
|
||||
crtc->primary->crtc = fb ? crtc : NULL;
|
||||
crtc->primary->fb = fb;
|
||||
}
|
||||
|
||||
@ -554,6 +557,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
||||
struct drm_mode_config *config = &dev->mode_config;
|
||||
struct drm_mode_crtc *crtc_req = data;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_plane *plane;
|
||||
struct drm_connector **connector_set = NULL, *connector;
|
||||
struct drm_framebuffer *fb = NULL;
|
||||
struct drm_display_mode *mode = NULL;
|
||||
@ -580,22 +584,33 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
||||
}
|
||||
DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
|
||||
|
||||
plane = crtc->primary;
|
||||
|
||||
mutex_lock(&crtc->dev->mode_config.mutex);
|
||||
drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
|
||||
retry:
|
||||
ret = drm_modeset_lock_all_ctx(crtc->dev, &ctx);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (crtc_req->mode_valid) {
|
||||
/* If we have a mode we need a framebuffer. */
|
||||
/* If we pass -1, set the mode with the currently bound fb */
|
||||
if (crtc_req->fb_id == -1) {
|
||||
if (!crtc->primary->fb) {
|
||||
struct drm_framebuffer *old_fb;
|
||||
|
||||
if (plane->state)
|
||||
old_fb = plane->state->fb;
|
||||
else
|
||||
old_fb = plane->fb;
|
||||
|
||||
if (!old_fb) {
|
||||
DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
fb = crtc->primary->fb;
|
||||
|
||||
fb = old_fb;
|
||||
/* Make refcounting symmetric with the lookup path. */
|
||||
drm_framebuffer_get(fb);
|
||||
} else {
|
||||
@ -627,8 +642,8 @@ retry:
|
||||
* match real hardware capabilities. Skip the check in that
|
||||
* case.
|
||||
*/
|
||||
if (!crtc->primary->format_default) {
|
||||
ret = drm_plane_check_pixel_format(crtc->primary,
|
||||
if (!plane->format_default) {
|
||||
ret = drm_plane_check_pixel_format(plane,
|
||||
fb->format->format,
|
||||
fb->modifier);
|
||||
if (ret) {
|
||||
|
@ -220,3 +220,5 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
||||
|
||||
/* drm_edid.c */
|
||||
void drm_mode_fixup_1366x768(struct drm_display_mode *mode);
|
||||
void drm_reset_display_info(struct drm_connector *connector);
|
||||
u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid);
|
||||
|
@ -2941,12 +2941,14 @@ static void drm_dp_mst_dump_mstb(struct seq_file *m,
|
||||
}
|
||||
}
|
||||
|
||||
#define DP_PAYLOAD_TABLE_SIZE 64
|
||||
|
||||
static bool dump_dp_payload_table(struct drm_dp_mst_topology_mgr *mgr,
|
||||
char *buf)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 64; i += 16) {
|
||||
for (i = 0; i < DP_PAYLOAD_TABLE_SIZE; i += 16) {
|
||||
if (drm_dp_dpcd_read(mgr->aux,
|
||||
DP_PAYLOAD_TABLE_UPDATE_STATUS + i,
|
||||
&buf[i], 16) != 16)
|
||||
@ -3015,7 +3017,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m,
|
||||
|
||||
mutex_lock(&mgr->lock);
|
||||
if (mgr->mst_primary) {
|
||||
u8 buf[64];
|
||||
u8 buf[DP_PAYLOAD_TABLE_SIZE];
|
||||
int ret;
|
||||
|
||||
ret = drm_dp_dpcd_read(mgr->aux, DP_DPCD_REV, buf, DP_RECEIVER_CAP_SIZE);
|
||||
@ -3033,8 +3035,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m,
|
||||
seq_printf(m, " revision: hw: %x.%x sw: %x.%x\n",
|
||||
buf[0x9] >> 4, buf[0x9] & 0xf, buf[0xa], buf[0xb]);
|
||||
if (dump_dp_payload_table(mgr, buf))
|
||||
seq_printf(m, "payload table: %*ph\n", 63, buf);
|
||||
|
||||
seq_printf(m, "payload table: %*ph\n", DP_PAYLOAD_TABLE_SIZE, buf);
|
||||
}
|
||||
|
||||
mutex_unlock(&mgr->lock);
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/srcu.h>
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drmP.h>
|
||||
@ -75,6 +76,8 @@ static bool drm_core_init_complete = false;
|
||||
|
||||
static struct dentry *drm_debugfs_root;
|
||||
|
||||
DEFINE_STATIC_SRCU(drm_unplug_srcu);
|
||||
|
||||
/*
|
||||
* DRM Minors
|
||||
* A DRM device can provide several char-dev interfaces on the DRM-Major. Each
|
||||
@ -318,18 +321,51 @@ void drm_put_dev(struct drm_device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_put_dev);
|
||||
|
||||
static void drm_device_set_unplugged(struct drm_device *dev)
|
||||
/**
|
||||
* drm_dev_enter - Enter device critical section
|
||||
* @dev: DRM device
|
||||
* @idx: Pointer to index that will be passed to the matching drm_dev_exit()
|
||||
*
|
||||
* This function marks and protects the beginning of a section that should not
|
||||
* be entered after the device has been unplugged. The section end is marked
|
||||
* with drm_dev_exit(). Calls to this function can be nested.
|
||||
*
|
||||
* Returns:
|
||||
* True if it is OK to enter the section, false otherwise.
|
||||
*/
|
||||
bool drm_dev_enter(struct drm_device *dev, int *idx)
|
||||
{
|
||||
smp_wmb();
|
||||
atomic_set(&dev->unplugged, 1);
|
||||
*idx = srcu_read_lock(&drm_unplug_srcu);
|
||||
|
||||
if (dev->unplugged) {
|
||||
srcu_read_unlock(&drm_unplug_srcu, *idx);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dev_enter);
|
||||
|
||||
/**
|
||||
* drm_dev_exit - Exit device critical section
|
||||
* @idx: index returned from drm_dev_enter()
|
||||
*
|
||||
* This function marks the end of a section that should not be entered after
|
||||
* the device has been unplugged.
|
||||
*/
|
||||
void drm_dev_exit(int idx)
|
||||
{
|
||||
srcu_read_unlock(&drm_unplug_srcu, idx);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dev_exit);
|
||||
|
||||
/**
|
||||
* drm_dev_unplug - unplug a DRM device
|
||||
* @dev: DRM device
|
||||
*
|
||||
* This unplugs a hotpluggable DRM device, which makes it inaccessible to
|
||||
* userspace operations. Entry-points can use drm_dev_is_unplugged(). This
|
||||
* userspace operations. Entry-points can use drm_dev_enter() and
|
||||
* drm_dev_exit() to protect device resources in a race free manner. This
|
||||
* essentially unregisters the device like drm_dev_unregister(), but can be
|
||||
* called while there are still open users of @dev.
|
||||
*/
|
||||
@ -338,10 +374,18 @@ void drm_dev_unplug(struct drm_device *dev)
|
||||
drm_dev_unregister(dev);
|
||||
|
||||
mutex_lock(&drm_global_mutex);
|
||||
drm_device_set_unplugged(dev);
|
||||
if (dev->open_count == 0)
|
||||
drm_dev_put(dev);
|
||||
mutex_unlock(&drm_global_mutex);
|
||||
|
||||
/*
|
||||
* After synchronizing any critical read section is guaranteed to see
|
||||
* the new value of ->unplugged, and any critical section which might
|
||||
* still have seen the old value of ->unplugged is guaranteed to have
|
||||
* finished.
|
||||
*/
|
||||
dev->unplugged = true;
|
||||
synchronize_srcu(&drm_unplug_srcu);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dev_unplug);
|
||||
|
||||
|
@ -4455,7 +4455,6 @@ drm_reset_display_info(struct drm_connector *connector)
|
||||
|
||||
info->non_desktop = 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_reset_display_info);
|
||||
|
||||
u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)
|
||||
{
|
||||
@ -4533,7 +4532,6 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi
|
||||
info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
|
||||
return quirks;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_add_display_info);
|
||||
|
||||
static int validate_displayid(u8 *displayid, int length, int idx)
|
||||
{
|
||||
|
@ -468,29 +468,31 @@ int drm_mode_getfb(struct drm_device *dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!fb->funcs->create_handle) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r->height = fb->height;
|
||||
r->width = fb->width;
|
||||
r->depth = fb->format->depth;
|
||||
r->bpp = fb->format->cpp[0] * 8;
|
||||
r->pitch = fb->pitches[0];
|
||||
if (fb->funcs->create_handle) {
|
||||
if (drm_is_current_master(file_priv) || capable(CAP_SYS_ADMIN) ||
|
||||
drm_is_control_client(file_priv)) {
|
||||
ret = fb->funcs->create_handle(fb, file_priv,
|
||||
&r->handle);
|
||||
} else {
|
||||
/* GET_FB() is an unprivileged ioctl so we must not
|
||||
* return a buffer-handle to non-master processes! For
|
||||
* backwards-compatibility reasons, we cannot make
|
||||
* GET_FB() privileged, so just return an invalid handle
|
||||
* for non-masters. */
|
||||
r->handle = 0;
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
ret = -ENODEV;
|
||||
|
||||
/* GET_FB() is an unprivileged ioctl so we must not return a
|
||||
* buffer-handle to non-master processes! For
|
||||
* backwards-compatibility reasons, we cannot make GET_FB() privileged,
|
||||
* so just return an invalid handle for non-masters.
|
||||
*/
|
||||
if (!drm_is_current_master(file_priv) && !capable(CAP_SYS_ADMIN) &&
|
||||
!drm_is_control_client(file_priv)) {
|
||||
r->handle = 0;
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = fb->funcs->create_handle(fb, file_priv, &r->handle);
|
||||
|
||||
out:
|
||||
drm_framebuffer_put(fb);
|
||||
|
||||
|
@ -436,9 +436,12 @@ err_unref:
|
||||
* @obj: object to register
|
||||
* @handlep: pionter to return the created handle to the caller
|
||||
*
|
||||
* Create a handle for this object. This adds a handle reference
|
||||
* to the object, which includes a regular reference count. Callers
|
||||
* will likely want to dereference the object afterwards.
|
||||
* Create a handle for this object. This adds a handle reference to the object,
|
||||
* which includes a regular reference count. Callers will likely want to
|
||||
* dereference the object afterwards.
|
||||
*
|
||||
* Since this publishes @obj to userspace it must be fully set up by this point,
|
||||
* drivers must call this last in their buffer object creation callbacks.
|
||||
*/
|
||||
int drm_gem_handle_create(struct drm_file *file_priv,
|
||||
struct drm_gem_object *obj,
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_modeset_helper.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
|
||||
/**
|
||||
* DOC: overview
|
||||
@ -265,6 +266,24 @@ int drm_gem_fb_prepare_fb(struct drm_plane *plane,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_gem_fb_prepare_fb);
|
||||
|
||||
/**
|
||||
* drm_gem_fb_simple_display_pipe_prepare_fb - prepare_fb helper for
|
||||
* &drm_simple_display_pipe
|
||||
* @pipe: Simple display pipe
|
||||
* @plane_state: Plane state
|
||||
*
|
||||
* This function uses drm_gem_fb_prepare_fb() to check if the plane FB has a
|
||||
* &dma_buf attached, extracts the exclusive fence and attaches it to plane
|
||||
* state for the atomic helper to wait on. Drivers can use this as their
|
||||
* &drm_simple_display_pipe_funcs.prepare_fb callback.
|
||||
*/
|
||||
int drm_gem_fb_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *plane_state)
|
||||
{
|
||||
return drm_gem_fb_prepare_fb(&pipe->plane, plane_state);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_fb_simple_display_pipe_prepare_fb);
|
||||
|
||||
/**
|
||||
* drm_gem_fbdev_fb_create - Create a GEM backed &drm_framebuffer for fbdev
|
||||
* emulation
|
||||
|
@ -340,7 +340,7 @@ static void _drm_lease_revoke(struct drm_master *top)
|
||||
break;
|
||||
|
||||
/* Over */
|
||||
master = list_entry(master->lessee_list.next, struct drm_master, lessee_list);
|
||||
master = list_next_entry(master, lessee_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ static const struct drm_dmi_panel_orientation_data itworks_tw891 = {
|
||||
.orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
|
||||
};
|
||||
|
||||
static const struct drm_dmi_panel_orientation_data vios_lth17 = {
|
||||
static const struct drm_dmi_panel_orientation_data lcd800x1280_rightside_up = {
|
||||
.width = 800,
|
||||
.height = 1280,
|
||||
.orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
|
||||
@ -102,12 +102,30 @@ static const struct dmi_system_id orientation_data[] = {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "TW891"),
|
||||
},
|
||||
.driver_data = (void *)&itworks_tw891,
|
||||
}, { /*
|
||||
* Lenovo Ideapad Miix 310 laptop, only some production batches
|
||||
* have a portrait screen, the resolution checks makes the quirk
|
||||
* apply only to those batches.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80SG"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "MIIX 310-10ICR"),
|
||||
},
|
||||
.driver_data = (void *)&lcd800x1280_rightside_up,
|
||||
}, { /* Lenovo Ideapad Miix 320 */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80XF"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"),
|
||||
},
|
||||
.driver_data = (void *)&lcd800x1280_rightside_up,
|
||||
}, { /* VIOS LTH17 */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "VIOS"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LTH17"),
|
||||
},
|
||||
.driver_data = (void *)&vios_lth17,
|
||||
.driver_data = (void *)&lcd800x1280_rightside_up,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
@ -756,6 +756,7 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_plane *plane = crtc->cursor;
|
||||
struct drm_framebuffer *fb = NULL;
|
||||
struct drm_mode_fb_cmd2 fbreq = {
|
||||
.width = req->width,
|
||||
@ -769,8 +770,8 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,
|
||||
uint32_t src_w = 0, src_h = 0;
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(!crtc->cursor);
|
||||
WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL);
|
||||
BUG_ON(!plane);
|
||||
WARN_ON(plane->crtc != crtc && plane->crtc != NULL);
|
||||
|
||||
/*
|
||||
* Obtain fb we'll be using (either new or existing) and take an extra
|
||||
@ -784,13 +785,18 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,
|
||||
DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
|
||||
return PTR_ERR(fb);
|
||||
}
|
||||
|
||||
fb->hot_x = req->hot_x;
|
||||
fb->hot_y = req->hot_y;
|
||||
} else {
|
||||
fb = NULL;
|
||||
}
|
||||
} else {
|
||||
fb = crtc->cursor->fb;
|
||||
if (plane->state)
|
||||
fb = plane->state->fb;
|
||||
else
|
||||
fb = plane->fb;
|
||||
|
||||
if (fb)
|
||||
drm_framebuffer_get(fb);
|
||||
}
|
||||
@ -810,7 +816,7 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,
|
||||
src_h = fb->height << 16;
|
||||
}
|
||||
|
||||
ret = __setplane_internal(crtc->cursor, crtc, fb,
|
||||
ret = __setplane_internal(plane, crtc, fb,
|
||||
crtc_x, crtc_y, crtc_w, crtc_h,
|
||||
0, 0, src_w, src_h, ctx);
|
||||
|
||||
@ -931,7 +937,8 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
||||
{
|
||||
struct drm_mode_crtc_page_flip_target *page_flip = data;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_framebuffer *fb = NULL;
|
||||
struct drm_plane *plane;
|
||||
struct drm_framebuffer *fb = NULL, *old_fb;
|
||||
struct drm_pending_vblank_event *e = NULL;
|
||||
u32 target_vblank = page_flip->sequence;
|
||||
struct drm_modeset_acquire_ctx ctx;
|
||||
@ -959,6 +966,8 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
||||
if (!crtc)
|
||||
return -ENOENT;
|
||||
|
||||
plane = crtc->primary;
|
||||
|
||||
if (crtc->funcs->page_flip_target) {
|
||||
u32 current_vblank;
|
||||
int r;
|
||||
@ -1003,11 +1012,16 @@ retry:
|
||||
ret = drm_modeset_lock(&crtc->mutex, &ctx);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = drm_modeset_lock(&crtc->primary->mutex, &ctx);
|
||||
ret = drm_modeset_lock(&plane->mutex, &ctx);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (crtc->primary->fb == NULL) {
|
||||
if (plane->state)
|
||||
old_fb = plane->state->fb;
|
||||
else
|
||||
old_fb = plane->fb;
|
||||
|
||||
if (old_fb == NULL) {
|
||||
/* The framebuffer is currently unbound, presumably
|
||||
* due to a hotplug event, that userspace has not
|
||||
* yet discovered.
|
||||
@ -1022,8 +1036,8 @@ retry:
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (crtc->state) {
|
||||
const struct drm_plane_state *state = crtc->primary->state;
|
||||
if (plane->state) {
|
||||
const struct drm_plane_state *state = plane->state;
|
||||
|
||||
ret = drm_framebuffer_check_src_coords(state->src_x,
|
||||
state->src_y,
|
||||
@ -1031,12 +1045,13 @@ retry:
|
||||
state->src_h,
|
||||
fb);
|
||||
} else {
|
||||
ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb);
|
||||
ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y,
|
||||
&crtc->mode, fb);
|
||||
}
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (crtc->primary->fb->format != fb->format) {
|
||||
if (old_fb->format != fb->format) {
|
||||
DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
@ -1048,10 +1063,12 @@ retry:
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
|
||||
e->event.base.length = sizeof(e->event);
|
||||
e->event.vbl.user_data = page_flip->user_data;
|
||||
e->event.vbl.crtc_id = crtc->base.id;
|
||||
|
||||
ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
|
||||
if (ret) {
|
||||
kfree(e);
|
||||
@ -1060,7 +1077,7 @@ retry:
|
||||
}
|
||||
}
|
||||
|
||||
crtc->primary->old_fb = crtc->primary->fb;
|
||||
plane->old_fb = plane->fb;
|
||||
if (crtc->funcs->page_flip_target)
|
||||
ret = crtc->funcs->page_flip_target(crtc, fb, e,
|
||||
page_flip->flags,
|
||||
@ -1073,19 +1090,18 @@ retry:
|
||||
if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)
|
||||
drm_event_cancel_free(dev, &e->base);
|
||||
/* Keep the old fb, don't unref it. */
|
||||
crtc->primary->old_fb = NULL;
|
||||
plane->old_fb = NULL;
|
||||
} else {
|
||||
crtc->primary->fb = fb;
|
||||
/* Unref only the old framebuffer. */
|
||||
fb = NULL;
|
||||
plane->fb = fb;
|
||||
drm_framebuffer_get(fb);
|
||||
}
|
||||
|
||||
out:
|
||||
if (fb)
|
||||
drm_framebuffer_put(fb);
|
||||
if (crtc->primary->old_fb)
|
||||
drm_framebuffer_put(crtc->primary->old_fb);
|
||||
crtc->primary->old_fb = NULL;
|
||||
if (plane->old_fb)
|
||||
drm_framebuffer_put(plane->old_fb);
|
||||
plane->old_fb = NULL;
|
||||
|
||||
if (ret == -EDEADLK) {
|
||||
ret = drm_modeset_backoff(&ctx);
|
||||
|
@ -331,6 +331,9 @@ EXPORT_SYMBOL(drm_gem_map_dma_buf);
|
||||
|
||||
/**
|
||||
* drm_gem_unmap_dma_buf - unmap_dma_buf implementation for GEM
|
||||
* @attach: attachment to unmap buffer from
|
||||
* @sgt: scatterlist info of the buffer to unmap
|
||||
* @dir: direction of DMA transfer
|
||||
*
|
||||
* Not implemented. The unmap is done at drm_gem_map_detach(). This can be
|
||||
* used as the &dma_buf_ops.unmap_dma_buf callback.
|
||||
@ -429,6 +432,8 @@ EXPORT_SYMBOL(drm_gem_dmabuf_vunmap);
|
||||
|
||||
/**
|
||||
* drm_gem_dmabuf_kmap_atomic - map_atomic implementation for GEM
|
||||
* @dma_buf: buffer to be mapped
|
||||
* @page_num: page number within the buffer
|
||||
*
|
||||
* Not implemented. This can be used as the &dma_buf_ops.map_atomic callback.
|
||||
*/
|
||||
@ -441,6 +446,9 @@ EXPORT_SYMBOL(drm_gem_dmabuf_kmap_atomic);
|
||||
|
||||
/**
|
||||
* drm_gem_dmabuf_kunmap_atomic - unmap_atomic implementation for GEM
|
||||
* @dma_buf: buffer to be unmapped
|
||||
* @page_num: page number within the buffer
|
||||
* @addr: virtual address of the buffer
|
||||
*
|
||||
* Not implemented. This can be used as the &dma_buf_ops.unmap_atomic callback.
|
||||
*/
|
||||
@ -453,6 +461,8 @@ EXPORT_SYMBOL(drm_gem_dmabuf_kunmap_atomic);
|
||||
|
||||
/**
|
||||
* drm_gem_dmabuf_kmap - map implementation for GEM
|
||||
* @dma_buf: buffer to be mapped
|
||||
* @page_num: page number within the buffer
|
||||
*
|
||||
* Not implemented. This can be used as the &dma_buf_ops.map callback.
|
||||
*/
|
||||
@ -464,6 +474,9 @@ EXPORT_SYMBOL(drm_gem_dmabuf_kmap);
|
||||
|
||||
/**
|
||||
* drm_gem_dmabuf_kunmap - unmap implementation for GEM
|
||||
* @dma_buf: buffer to be unmapped
|
||||
* @page_num: page number within the buffer
|
||||
* @addr: virtual address of the buffer
|
||||
*
|
||||
* Not implemented. This can be used as the &dma_buf_ops.unmap callback.
|
||||
*/
|
||||
|
@ -141,7 +141,7 @@ bool drm_scdc_get_scrambling_status(struct i2c_adapter *adapter)
|
||||
|
||||
ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS, &status);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("Failed to read scrambling status: %d\n", ret);
|
||||
DRM_DEBUG_KMS("Failed to read scrambling status: %d\n", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -168,7 +168,7 @@ bool drm_scdc_set_scrambling(struct i2c_adapter *adapter, bool enable)
|
||||
|
||||
ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("Failed to read TMDS config: %d\n", ret);
|
||||
DRM_DEBUG_KMS("Failed to read TMDS config: %d\n", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -179,7 +179,7 @@ bool drm_scdc_set_scrambling(struct i2c_adapter *adapter, bool enable)
|
||||
|
||||
ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("Failed to enable scrambling: %d\n", ret);
|
||||
DRM_DEBUG_KMS("Failed to enable scrambling: %d\n", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -223,7 +223,7 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct i2c_adapter *adapter, bool set)
|
||||
|
||||
ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("Failed to read TMDS config: %d\n", ret);
|
||||
DRM_DEBUG_KMS("Failed to read TMDS config: %d\n", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -234,7 +234,7 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct i2c_adapter *adapter, bool set)
|
||||
|
||||
ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("Failed to set TMDS clock ratio: %d\n", ret);
|
||||
DRM_DEBUG_KMS("Failed to set TMDS clock ratio: %d\n", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -64,13 +64,15 @@ static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
|
||||
static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_state)
|
||||
{
|
||||
struct drm_plane *plane;
|
||||
struct drm_simple_display_pipe *pipe;
|
||||
|
||||
pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
|
||||
if (!pipe->funcs || !pipe->funcs->enable)
|
||||
return;
|
||||
|
||||
pipe->funcs->enable(pipe, crtc->state);
|
||||
plane = &pipe->plane;
|
||||
pipe->funcs->enable(pipe, crtc->state, plane->state);
|
||||
}
|
||||
|
||||
static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
|
||||
|
@ -162,7 +162,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
|
||||
dp->drm_dev = drm_dev;
|
||||
|
||||
dp->plat_data.dev_type = EXYNOS_DP;
|
||||
dp->plat_data.power_on = exynos_dp_poweron;
|
||||
dp->plat_data.power_on_start = exynos_dp_poweron;
|
||||
dp->plat_data.power_off = exynos_dp_poweroff;
|
||||
dp->plat_data.attach = exynos_dp_bridge_attach;
|
||||
dp->plat_data.get_modes = exynos_dp_get_modes;
|
||||
|
@ -37,26 +37,6 @@
|
||||
#define DRIVER_MAJOR 1
|
||||
#define DRIVER_MINOR 0
|
||||
|
||||
int exynos_atomic_check(struct drm_device *dev,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = drm_atomic_helper_check_modeset(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_atomic_normalize_zpos(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_atomic_helper_check_planes(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
struct drm_exynos_file_private *file_priv;
|
||||
|
@ -275,7 +275,6 @@ static inline int exynos_dpi_bind(struct drm_device *dev,
|
||||
|
||||
int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
|
||||
bool nonblock);
|
||||
int exynos_atomic_check(struct drm_device *dev, struct drm_atomic_state *state);
|
||||
|
||||
|
||||
extern struct platform_driver fimd_driver;
|
||||
|
@ -161,7 +161,7 @@ static struct drm_mode_config_helper_funcs exynos_drm_mode_config_helpers = {
|
||||
static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
|
||||
.fb_create = exynos_user_fb_create,
|
||||
.output_poll_changed = drm_fb_helper_output_poll_changed,
|
||||
.atomic_check = exynos_atomic_check,
|
||||
.atomic_check = drm_atomic_helper_check,
|
||||
.atomic_commit = drm_atomic_helper_commit,
|
||||
};
|
||||
|
||||
@ -182,4 +182,6 @@ void exynos_drm_mode_config_init(struct drm_device *dev)
|
||||
dev->mode_config.helper_private = &exynos_drm_mode_config_helpers;
|
||||
|
||||
dev->mode_config.allow_fb_modifiers = true;
|
||||
|
||||
dev->mode_config.normalize_zpos = true;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode)
|
||||
REG_WRITE(reg, temp);
|
||||
}
|
||||
|
||||
static int cdv_intel_crt_mode_valid(struct drm_connector *connector,
|
||||
static enum drm_mode_status cdv_intel_crt_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
|
@ -505,7 +505,7 @@ static void cdv_intel_edp_backlight_off (struct gma_encoder *intel_encoder)
|
||||
msleep(intel_dp->backlight_off_delay);
|
||||
}
|
||||
|
||||
static int
|
||||
static enum drm_mode_status
|
||||
cdv_intel_dp_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
|
@ -223,7 +223,7 @@ static int cdv_hdmi_get_modes(struct drm_connector *connector)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cdv_hdmi_mode_valid(struct drm_connector *connector,
|
||||
static enum drm_mode_status cdv_hdmi_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
if (mode->clock > 165000)
|
||||
|
@ -244,7 +244,7 @@ static void cdv_intel_lvds_restore(struct drm_connector *connector)
|
||||
{
|
||||
}
|
||||
|
||||
static int cdv_intel_lvds_mode_valid(struct drm_connector *connector,
|
||||
static enum drm_mode_status cdv_intel_lvds_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
|
@ -346,7 +346,7 @@ static int mdfld_dsi_connector_get_modes(struct drm_connector *connector)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdfld_dsi_connector_mode_valid(struct drm_connector *connector,
|
||||
static enum drm_mode_status mdfld_dsi_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct mdfld_dsi_connector *dsi_connector =
|
||||
|
@ -509,7 +509,7 @@ static void oaktrail_hdmi_dpms(struct drm_encoder *encoder, int mode)
|
||||
HDMI_WRITE(HDMI_VIDEO_REG, temp);
|
||||
}
|
||||
|
||||
static int oaktrail_hdmi_mode_valid(struct drm_connector *connector,
|
||||
static enum drm_mode_status oaktrail_hdmi_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
if (mode->clock > 165000)
|
||||
|
@ -255,7 +255,7 @@ extern int intelfb_remove(struct drm_device *dev,
|
||||
extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern int psb_intel_lvds_mode_valid(struct drm_connector *connector,
|
||||
extern enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode);
|
||||
extern int psb_intel_lvds_set_property(struct drm_connector *connector,
|
||||
struct drm_property *property,
|
||||
|
@ -343,7 +343,7 @@ static void psb_intel_lvds_restore(struct drm_connector *connector)
|
||||
}
|
||||
}
|
||||
|
||||
int psb_intel_lvds_mode_valid(struct drm_connector *connector,
|
||||
enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = connector->dev->dev_private;
|
||||
|
@ -1157,7 +1157,7 @@ static void psb_intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
|
||||
return;
|
||||
}
|
||||
|
||||
static int psb_intel_sdvo_mode_valid(struct drm_connector *connector,
|
||||
static enum drm_mode_status psb_intel_sdvo_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector);
|
||||
|
@ -27,7 +27,7 @@ static int hibmc_connector_get_modes(struct drm_connector *connector)
|
||||
return drm_add_modes_noedid(connector, 800, 600);
|
||||
}
|
||||
|
||||
static int hibmc_connector_mode_valid(struct drm_connector *connector,
|
||||
static enum drm_mode_status hibmc_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
return MODE_OK;
|
||||
|
@ -1106,7 +1106,7 @@ static int tda998x_connector_get_modes(struct drm_connector *connector)
|
||||
return n;
|
||||
}
|
||||
|
||||
static int tda998x_connector_mode_valid(struct drm_connector *connector,
|
||||
static enum drm_mode_status tda998x_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
/* TDA19988 dotclock can go up to 165MHz */
|
||||
|
@ -748,6 +748,11 @@ intel_crt_detect(struct drm_connector *connector,
|
||||
connector->base.id, connector->name,
|
||||
force);
|
||||
|
||||
if (i915_modparams.load_detect_test) {
|
||||
intel_display_power_get(dev_priv, intel_encoder->power_domain);
|
||||
goto load_detect;
|
||||
}
|
||||
|
||||
/* Skip machines without VGA that falsely report hotplug events */
|
||||
if (dmi_check_system(intel_spurious_crt_detect))
|
||||
return connector_status_disconnected;
|
||||
@ -776,11 +781,12 @@ intel_crt_detect(struct drm_connector *connector,
|
||||
* broken monitor (without edid) to work behind a broken kvm (that fails
|
||||
* to have the right resistors for HP detection) needs to fix this up.
|
||||
* For now just bail out. */
|
||||
if (I915_HAS_HOTPLUG(dev_priv) && !i915_modparams.load_detect_test) {
|
||||
if (I915_HAS_HOTPLUG(dev_priv)) {
|
||||
status = connector_status_disconnected;
|
||||
goto out;
|
||||
}
|
||||
|
||||
load_detect:
|
||||
if (!force) {
|
||||
status = connector->status;
|
||||
goto out;
|
||||
|
@ -2824,7 +2824,7 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
|
||||
continue;
|
||||
|
||||
if (intel_plane_ggtt_offset(state) == plane_config->base) {
|
||||
fb = c->primary->fb;
|
||||
fb = state->base.fb;
|
||||
drm_framebuffer_get(fb);
|
||||
goto valid_fb;
|
||||
}
|
||||
@ -9974,6 +9974,8 @@ found:
|
||||
ret = PTR_ERR_OR_ZERO(drm_atomic_get_connector_state(restore_state, connector));
|
||||
if (!ret)
|
||||
ret = PTR_ERR_OR_ZERO(drm_atomic_get_crtc_state(restore_state, crtc));
|
||||
if (!ret)
|
||||
ret = drm_atomic_add_affected_planes(restore_state, crtc);
|
||||
if (ret) {
|
||||
DRM_DEBUG_KMS("Failed to create a copy of old state to restore: %i\n", ret);
|
||||
goto fail;
|
||||
|
@ -640,7 +640,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
|
||||
if (!crtc->state->active)
|
||||
continue;
|
||||
|
||||
WARN(!crtc->primary->fb,
|
||||
WARN(!crtc->primary->state->fb,
|
||||
"re-used BIOS config but lost an fb on crtc %d\n",
|
||||
crtc->base.id);
|
||||
}
|
||||
|
@ -1586,7 +1586,7 @@ static uint32_t mga_vga_calculate_mode_bandwidth(struct drm_display_mode *mode,
|
||||
|
||||
#define MODE_BANDWIDTH MODE_BAD
|
||||
|
||||
static int mga_vga_mode_valid(struct drm_connector *connector,
|
||||
static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
|
@ -99,7 +99,8 @@ static const struct drm_mode_config_funcs mxsfb_mode_config_funcs = {
|
||||
};
|
||||
|
||||
static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_crtc_state *crtc_state)
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_plane_state *plane_state)
|
||||
{
|
||||
struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
|
||||
|
||||
@ -125,12 +126,6 @@ static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe,
|
||||
mxsfb_plane_atomic_update(mxsfb, plane_state);
|
||||
}
|
||||
|
||||
static int mxsfb_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *plane_state)
|
||||
{
|
||||
return drm_gem_fb_prepare_fb(&pipe->plane, plane_state);
|
||||
}
|
||||
|
||||
static int mxsfb_pipe_enable_vblank(struct drm_simple_display_pipe *pipe)
|
||||
{
|
||||
struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
|
||||
@ -159,7 +154,7 @@ static struct drm_simple_display_pipe_funcs mxsfb_funcs = {
|
||||
.enable = mxsfb_pipe_enable,
|
||||
.disable = mxsfb_pipe_disable,
|
||||
.update = mxsfb_pipe_update,
|
||||
.prepare_fb = mxsfb_pipe_prepare_fb,
|
||||
.prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
|
||||
.enable_vblank = mxsfb_pipe_enable_vblank,
|
||||
.disable_vblank = mxsfb_pipe_disable_vblank,
|
||||
};
|
||||
|
@ -134,7 +134,7 @@ nvkm_cstate_find_best(struct nvkm_clk *clk, struct nvkm_pstate *pstate,
|
||||
nvkm_volt_map(volt, volt->max2_id, clk->temp));
|
||||
|
||||
for (cstate = start; &cstate->head != &pstate->list;
|
||||
cstate = list_entry(cstate->head.prev, typeof(*cstate), head)) {
|
||||
cstate = list_prev_entry(cstate, head)) {
|
||||
if (nvkm_cstate_valid(clk, cstate, max_volt, clk->temp))
|
||||
break;
|
||||
}
|
||||
|
@ -319,6 +319,9 @@ static int omap_modeset_init(struct drm_device *dev)
|
||||
dev->mode_config.max_width = 8192;
|
||||
dev->mode_config.max_height = 8192;
|
||||
|
||||
/* We want the zpos to be normalized */
|
||||
dev->mode_config.normalize_zpos = true;
|
||||
|
||||
dev->mode_config.funcs = &omap_mode_config_funcs;
|
||||
dev->mode_config.helper_private = &omap_mode_config_helper_funcs;
|
||||
|
||||
|
@ -65,7 +65,7 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
|
||||
info.rotation_type = OMAP_DSS_ROT_NONE;
|
||||
info.rotation = DRM_MODE_ROTATE_0;
|
||||
info.global_alpha = 0xff;
|
||||
info.zorder = state->zpos;
|
||||
info.zorder = state->normalized_zpos;
|
||||
|
||||
/* update scanout: */
|
||||
omap_framebuffer_update_scanout(state->fb, state, &info);
|
||||
|
@ -120,7 +120,8 @@ static int pl111_display_check(struct drm_simple_display_pipe *pipe,
|
||||
}
|
||||
|
||||
static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_crtc_state *cstate)
|
||||
struct drm_crtc_state *cstate,
|
||||
struct drm_plane_state *plane_state)
|
||||
{
|
||||
struct drm_crtc *crtc = &pipe->crtc;
|
||||
struct drm_plane *plane = &pipe->plane;
|
||||
@ -376,19 +377,13 @@ static void pl111_display_disable_vblank(struct drm_simple_display_pipe *pipe)
|
||||
writel(0, priv->regs + priv->ienb);
|
||||
}
|
||||
|
||||
static int pl111_display_prepare_fb(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *plane_state)
|
||||
{
|
||||
return drm_gem_fb_prepare_fb(&pipe->plane, plane_state);
|
||||
}
|
||||
|
||||
static struct drm_simple_display_pipe_funcs pl111_display_funcs = {
|
||||
.mode_valid = pl111_mode_valid,
|
||||
.check = pl111_display_check,
|
||||
.enable = pl111_display_enable,
|
||||
.disable = pl111_display_disable,
|
||||
.update = pl111_display_update,
|
||||
.prepare_fb = pl111_display_prepare_fb,
|
||||
.prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
|
||||
};
|
||||
|
||||
static int pl111_clk_div_choose_div(struct clk_hw *hw, unsigned long rate,
|
||||
|
@ -1037,7 +1037,7 @@ static int qxl_conn_get_modes(struct drm_connector *connector)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qxl_conn_mode_valid(struct drm_connector *connector,
|
||||
static enum drm_mode_status qxl_conn_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_device *ddev = connector->dev;
|
||||
|
@ -87,7 +87,6 @@ struct rcar_du_device {
|
||||
struct rcar_du_vsp vsps[RCAR_DU_MAX_VSPS];
|
||||
|
||||
struct {
|
||||
struct drm_property *alpha;
|
||||
struct drm_property *colorkey;
|
||||
} props;
|
||||
|
||||
|
@ -233,15 +233,7 @@ static int rcar_du_atomic_check(struct drm_device *dev,
|
||||
struct rcar_du_device *rcdu = dev->dev_private;
|
||||
int ret;
|
||||
|
||||
ret = drm_atomic_helper_check_modeset(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_atomic_normalize_zpos(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_atomic_helper_check_planes(dev, state);
|
||||
ret = drm_atomic_helper_check(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -415,11 +407,6 @@ static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
|
||||
|
||||
static int rcar_du_properties_init(struct rcar_du_device *rcdu)
|
||||
{
|
||||
rcdu->props.alpha =
|
||||
drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255);
|
||||
if (rcdu->props.alpha == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* The color key is expressed as an RGB888 triplet stored in a 32-bit
|
||||
* integer in XRGB8888 format. Bit 24 is used as a flag to disable (0)
|
||||
@ -529,6 +516,7 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
|
||||
dev->mode_config.min_height = 0;
|
||||
dev->mode_config.max_width = 4095;
|
||||
dev->mode_config.max_height = 2047;
|
||||
dev->mode_config.normalize_zpos = true;
|
||||
dev->mode_config.funcs = &rcar_du_mode_config_funcs;
|
||||
dev->mode_config.helper_private = &rcar_du_mode_config_helper;
|
||||
|
||||
|
@ -423,7 +423,7 @@ static void rcar_du_plane_setup_mode(struct rcar_du_group *rgrp,
|
||||
rcar_du_plane_write(rgrp, index, PnALPHAR, PnALPHAR_ABIT_0);
|
||||
else
|
||||
rcar_du_plane_write(rgrp, index, PnALPHAR,
|
||||
PnALPHAR_ABIT_X | state->alpha);
|
||||
PnALPHAR_ABIT_X | state->state.alpha >> 8);
|
||||
|
||||
pnmr = PnMR_BM_MD | state->format->pnmr;
|
||||
|
||||
@ -692,11 +692,11 @@ static void rcar_du_plane_reset(struct drm_plane *plane)
|
||||
|
||||
state->hwindex = -1;
|
||||
state->source = RCAR_DU_PLANE_MEMORY;
|
||||
state->alpha = 255;
|
||||
state->colorkey = RCAR_DU_COLORKEY_NONE;
|
||||
state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
|
||||
|
||||
plane->state = &state->state;
|
||||
plane->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
|
||||
plane->state->plane = plane;
|
||||
}
|
||||
|
||||
@ -708,9 +708,7 @@ static int rcar_du_plane_atomic_set_property(struct drm_plane *plane,
|
||||
struct rcar_du_plane_state *rstate = to_rcar_plane_state(state);
|
||||
struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev;
|
||||
|
||||
if (property == rcdu->props.alpha)
|
||||
rstate->alpha = val;
|
||||
else if (property == rcdu->props.colorkey)
|
||||
if (property == rcdu->props.colorkey)
|
||||
rstate->colorkey = val;
|
||||
else
|
||||
return -EINVAL;
|
||||
@ -726,9 +724,7 @@ static int rcar_du_plane_atomic_get_property(struct drm_plane *plane,
|
||||
container_of(state, const struct rcar_du_plane_state, state);
|
||||
struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev;
|
||||
|
||||
if (property == rcdu->props.alpha)
|
||||
*val = rstate->alpha;
|
||||
else if (property == rcdu->props.colorkey)
|
||||
if (property == rcdu->props.colorkey)
|
||||
*val = rstate->colorkey;
|
||||
else
|
||||
return -EINVAL;
|
||||
@ -796,11 +792,10 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp)
|
||||
if (type == DRM_PLANE_TYPE_PRIMARY)
|
||||
continue;
|
||||
|
||||
drm_object_attach_property(&plane->plane.base,
|
||||
rcdu->props.alpha, 255);
|
||||
drm_object_attach_property(&plane->plane.base,
|
||||
rcdu->props.colorkey,
|
||||
RCAR_DU_COLORKEY_NONE);
|
||||
drm_plane_create_alpha_property(&plane->plane);
|
||||
drm_plane_create_zpos_property(&plane->plane, 1, 1, 7);
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,6 @@ static inline struct rcar_du_plane *to_rcar_plane(struct drm_plane *plane)
|
||||
* @state: base DRM plane state
|
||||
* @format: information about the pixel format used by the plane
|
||||
* @hwindex: 0-based hardware plane index, -1 means unused
|
||||
* @alpha: value of the plane alpha property
|
||||
* @colorkey: value of the plane colorkey property
|
||||
*/
|
||||
struct rcar_du_plane_state {
|
||||
@ -60,7 +59,6 @@ struct rcar_du_plane_state {
|
||||
int hwindex;
|
||||
enum rcar_du_plane_source source;
|
||||
|
||||
unsigned int alpha;
|
||||
unsigned int colorkey;
|
||||
};
|
||||
|
||||
|
@ -54,6 +54,7 @@ void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
|
||||
};
|
||||
struct rcar_du_plane_state state = {
|
||||
.state = {
|
||||
.alpha = DRM_BLEND_ALPHA_OPAQUE,
|
||||
.crtc = &crtc->crtc,
|
||||
.dst.x1 = 0,
|
||||
.dst.y1 = 0,
|
||||
@ -67,7 +68,6 @@ void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
|
||||
},
|
||||
.format = rcar_du_format_info(DRM_FORMAT_ARGB8888),
|
||||
.source = RCAR_DU_PLANE_VSPD1,
|
||||
.alpha = 255,
|
||||
.colorkey = 0,
|
||||
};
|
||||
|
||||
@ -173,7 +173,7 @@ static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane)
|
||||
struct vsp1_du_atomic_config cfg = {
|
||||
.pixelformat = 0,
|
||||
.pitch = fb->pitches[0],
|
||||
.alpha = state->alpha,
|
||||
.alpha = state->state.alpha >> 8,
|
||||
.zpos = state->state.zpos,
|
||||
};
|
||||
unsigned int i;
|
||||
@ -335,44 +335,13 @@ static void rcar_du_vsp_plane_reset(struct drm_plane *plane)
|
||||
if (state == NULL)
|
||||
return;
|
||||
|
||||
state->alpha = 255;
|
||||
state->state.alpha = DRM_BLEND_ALPHA_OPAQUE;
|
||||
state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
|
||||
|
||||
plane->state = &state->state;
|
||||
plane->state->plane = plane;
|
||||
}
|
||||
|
||||
static int rcar_du_vsp_plane_atomic_set_property(struct drm_plane *plane,
|
||||
struct drm_plane_state *state, struct drm_property *property,
|
||||
uint64_t val)
|
||||
{
|
||||
struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state);
|
||||
struct rcar_du_device *rcdu = to_rcar_vsp_plane(plane)->vsp->dev;
|
||||
|
||||
if (property == rcdu->props.alpha)
|
||||
rstate->alpha = val;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_du_vsp_plane_atomic_get_property(struct drm_plane *plane,
|
||||
const struct drm_plane_state *state, struct drm_property *property,
|
||||
uint64_t *val)
|
||||
{
|
||||
const struct rcar_du_vsp_plane_state *rstate =
|
||||
container_of(state, const struct rcar_du_vsp_plane_state, state);
|
||||
struct rcar_du_device *rcdu = to_rcar_vsp_plane(plane)->vsp->dev;
|
||||
|
||||
if (property == rcdu->props.alpha)
|
||||
*val = rstate->alpha;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_plane_funcs rcar_du_vsp_plane_funcs = {
|
||||
.update_plane = drm_atomic_helper_update_plane,
|
||||
.disable_plane = drm_atomic_helper_disable_plane,
|
||||
@ -380,8 +349,6 @@ static const struct drm_plane_funcs rcar_du_vsp_plane_funcs = {
|
||||
.destroy = drm_plane_cleanup,
|
||||
.atomic_duplicate_state = rcar_du_vsp_plane_atomic_duplicate_state,
|
||||
.atomic_destroy_state = rcar_du_vsp_plane_atomic_destroy_state,
|
||||
.atomic_set_property = rcar_du_vsp_plane_atomic_set_property,
|
||||
.atomic_get_property = rcar_du_vsp_plane_atomic_get_property,
|
||||
};
|
||||
|
||||
int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
|
||||
@ -438,8 +405,7 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
|
||||
if (type == DRM_PLANE_TYPE_PRIMARY)
|
||||
continue;
|
||||
|
||||
drm_object_attach_property(&plane->plane.base,
|
||||
rcdu->props.alpha, 255);
|
||||
drm_plane_create_alpha_property(&plane->plane);
|
||||
drm_plane_create_zpos_property(&plane->plane, 1, 1,
|
||||
vsp->num_planes - 1);
|
||||
}
|
||||
|
@ -44,15 +44,12 @@ static inline struct rcar_du_vsp_plane *to_rcar_vsp_plane(struct drm_plane *p)
|
||||
* @state: base DRM plane state
|
||||
* @format: information about the pixel format used by the plane
|
||||
* @sg_tables: scatter-gather tables for the frame buffer memory
|
||||
* @alpha: value of the plane alpha property
|
||||
*/
|
||||
struct rcar_du_vsp_plane_state {
|
||||
struct drm_plane_state state;
|
||||
|
||||
const struct rcar_du_format_info *format;
|
||||
struct sg_table sg_tables[3];
|
||||
|
||||
unsigned int alpha;
|
||||
};
|
||||
|
||||
static inline struct rcar_du_vsp_plane_state *
|
||||
|
@ -77,13 +77,13 @@ struct rockchip_dp_device {
|
||||
struct analogix_dp_plat_data plat_data;
|
||||
};
|
||||
|
||||
static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
|
||||
static int analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
|
||||
{
|
||||
struct rockchip_dp_device *dp = to_dp(encoder);
|
||||
int ret;
|
||||
|
||||
if (!analogix_dp_psr_enabled(dp->adp))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
|
||||
|
||||
@ -91,13 +91,13 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
|
||||
PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dp->dev, "line flag interrupt did not arrive\n");
|
||||
return;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (enabled)
|
||||
analogix_dp_enable_psr(dp->adp);
|
||||
return analogix_dp_enable_psr(dp->adp);
|
||||
else
|
||||
analogix_dp_disable_psr(dp->adp);
|
||||
return analogix_dp_disable_psr(dp->adp);
|
||||
}
|
||||
|
||||
static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
|
||||
@ -109,7 +109,7 @@ static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data)
|
||||
static int rockchip_dp_poweron_start(struct analogix_dp_plat_data *plat_data)
|
||||
{
|
||||
struct rockchip_dp_device *dp = to_dp(plat_data);
|
||||
int ret;
|
||||
@ -127,7 +127,14 @@ static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return rockchip_drm_psr_activate(&dp->encoder);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_dp_poweron_end(struct analogix_dp_plat_data *plat_data)
|
||||
{
|
||||
struct rockchip_dp_device *dp = to_dp(plat_data);
|
||||
|
||||
return rockchip_drm_psr_inhibit_put(&dp->encoder);
|
||||
}
|
||||
|
||||
static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data)
|
||||
@ -135,7 +142,7 @@ static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data)
|
||||
struct rockchip_dp_device *dp = to_dp(plat_data);
|
||||
int ret;
|
||||
|
||||
ret = rockchip_drm_psr_deactivate(&dp->encoder);
|
||||
ret = rockchip_drm_psr_inhibit_get(&dp->encoder);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
@ -218,6 +225,7 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
|
||||
struct drm_display_info *di = &conn_state->connector->display_info;
|
||||
|
||||
/*
|
||||
* The hardware IC designed that VOP must output the RGB10 video
|
||||
@ -229,6 +237,7 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
|
||||
s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
|
||||
s->output_type = DRM_MODE_CONNECTOR_eDP;
|
||||
s->output_bpc = di->bpc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -328,7 +337,8 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
|
||||
dp->plat_data.encoder = &dp->encoder;
|
||||
|
||||
dp->plat_data.dev_type = dp->data->chip_type;
|
||||
dp->plat_data.power_on = rockchip_dp_poweron;
|
||||
dp->plat_data.power_on_start = rockchip_dp_poweron_start;
|
||||
dp->plat_data.power_on_end = rockchip_dp_poweron_end;
|
||||
dp->plat_data.power_off = rockchip_dp_powerdown;
|
||||
dp->plat_data.get_modes = rockchip_dp_get_modes;
|
||||
|
||||
@ -358,6 +368,8 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
|
||||
analogix_dp_unbind(dp->adp);
|
||||
rockchip_drm_psr_unregister(&dp->encoder);
|
||||
dp->encoder.funcs->destroy(&dp->encoder);
|
||||
|
||||
dp->adp = ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static const struct component_ops rockchip_dp_component_ops = {
|
||||
@ -381,6 +393,7 @@ static int rockchip_dp_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
dp->dev = dev;
|
||||
dp->adp = ERR_PTR(-ENODEV);
|
||||
dp->plat_data.panel = panel;
|
||||
|
||||
ret = rockchip_dp_of_probe(dp);
|
||||
@ -404,6 +417,9 @@ static int rockchip_dp_suspend(struct device *dev)
|
||||
{
|
||||
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
|
||||
|
||||
if (IS_ERR(dp->adp))
|
||||
return 0;
|
||||
|
||||
return analogix_dp_suspend(dp->adp);
|
||||
}
|
||||
|
||||
@ -411,6 +427,9 @@ static int rockchip_dp_resume(struct device *dev)
|
||||
{
|
||||
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
|
||||
|
||||
if (IS_ERR(dp->adp))
|
||||
return 0;
|
||||
|
||||
return analogix_dp_resume(dp->adp);
|
||||
}
|
||||
#endif
|
||||
|
@ -36,6 +36,7 @@ struct rockchip_crtc_state {
|
||||
struct drm_crtc_state base;
|
||||
int output_type;
|
||||
int output_mode;
|
||||
int output_bpc;
|
||||
};
|
||||
#define to_rockchip_crtc_state(s) \
|
||||
container_of(s, struct rockchip_crtc_state, base)
|
||||
|
@ -167,8 +167,67 @@ err_gem_object_unreference:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static void
|
||||
rockchip_drm_psr_inhibit_get_state(struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
struct drm_encoder *encoder;
|
||||
u32 encoder_mask = 0;
|
||||
int i;
|
||||
|
||||
for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
encoder_mask |= crtc_state->encoder_mask;
|
||||
encoder_mask |= crtc->state->encoder_mask;
|
||||
}
|
||||
|
||||
drm_for_each_encoder_mask(encoder, state->dev, encoder_mask)
|
||||
rockchip_drm_psr_inhibit_get(encoder);
|
||||
}
|
||||
|
||||
static void
|
||||
rockchip_drm_psr_inhibit_put_state(struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
struct drm_encoder *encoder;
|
||||
u32 encoder_mask = 0;
|
||||
int i;
|
||||
|
||||
for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
encoder_mask |= crtc_state->encoder_mask;
|
||||
encoder_mask |= crtc->state->encoder_mask;
|
||||
}
|
||||
|
||||
drm_for_each_encoder_mask(encoder, state->dev, encoder_mask)
|
||||
rockchip_drm_psr_inhibit_put(encoder);
|
||||
}
|
||||
|
||||
static void
|
||||
rockchip_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state)
|
||||
{
|
||||
struct drm_device *dev = old_state->dev;
|
||||
|
||||
rockchip_drm_psr_inhibit_get_state(old_state);
|
||||
|
||||
drm_atomic_helper_commit_modeset_disables(dev, old_state);
|
||||
|
||||
drm_atomic_helper_commit_modeset_enables(dev, old_state);
|
||||
|
||||
drm_atomic_helper_commit_planes(dev, old_state,
|
||||
DRM_PLANE_COMMIT_ACTIVE_ONLY);
|
||||
|
||||
rockchip_drm_psr_inhibit_put_state(old_state);
|
||||
|
||||
drm_atomic_helper_commit_hw_done(old_state);
|
||||
|
||||
drm_atomic_helper_wait_for_vblanks(dev, old_state);
|
||||
|
||||
drm_atomic_helper_cleanup_planes(dev, old_state);
|
||||
}
|
||||
|
||||
static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = {
|
||||
.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
|
||||
.atomic_commit_tail = rockchip_atomic_helper_commit_tail_rpm,
|
||||
};
|
||||
|
||||
static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
|
||||
|
@ -357,8 +357,8 @@ err_free_rk_obj:
|
||||
}
|
||||
|
||||
/*
|
||||
* rockchip_gem_free_object - (struct drm_driver)->gem_free_object callback
|
||||
* function
|
||||
* rockchip_gem_free_object - (struct drm_driver)->gem_free_object_unlocked
|
||||
* callback function
|
||||
*/
|
||||
void rockchip_gem_free_object(struct drm_gem_object *obj)
|
||||
{
|
||||
|
@ -20,42 +20,19 @@
|
||||
|
||||
#define PSR_FLUSH_TIMEOUT_MS 100
|
||||
|
||||
enum psr_state {
|
||||
PSR_FLUSH,
|
||||
PSR_ENABLE,
|
||||
PSR_DISABLE,
|
||||
};
|
||||
|
||||
struct psr_drv {
|
||||
struct list_head list;
|
||||
struct drm_encoder *encoder;
|
||||
|
||||
struct mutex lock;
|
||||
bool active;
|
||||
enum psr_state state;
|
||||
int inhibit_count;
|
||||
bool enabled;
|
||||
|
||||
struct delayed_work flush_work;
|
||||
|
||||
void (*set)(struct drm_encoder *encoder, bool enable);
|
||||
int (*set)(struct drm_encoder *encoder, bool enable);
|
||||
};
|
||||
|
||||
static struct psr_drv *find_psr_by_crtc(struct drm_crtc *crtc)
|
||||
{
|
||||
struct rockchip_drm_private *drm_drv = crtc->dev->dev_private;
|
||||
struct psr_drv *psr;
|
||||
|
||||
mutex_lock(&drm_drv->psr_list_lock);
|
||||
list_for_each_entry(psr, &drm_drv->psr_list, list) {
|
||||
if (psr->encoder->crtc == crtc)
|
||||
goto out;
|
||||
}
|
||||
psr = ERR_PTR(-ENODEV);
|
||||
|
||||
out:
|
||||
mutex_unlock(&drm_drv->psr_list_lock);
|
||||
return psr;
|
||||
}
|
||||
|
||||
static struct psr_drv *find_psr_by_encoder(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
|
||||
@ -73,46 +50,22 @@ out:
|
||||
return psr;
|
||||
}
|
||||
|
||||
static void psr_set_state_locked(struct psr_drv *psr, enum psr_state state)
|
||||
static int psr_set_state_locked(struct psr_drv *psr, bool enable)
|
||||
{
|
||||
/*
|
||||
* Allowed finite state machine:
|
||||
*
|
||||
* PSR_ENABLE < = = = = = > PSR_FLUSH
|
||||
* | ^ |
|
||||
* | | |
|
||||
* v | |
|
||||
* PSR_DISABLE < - - - - - - - - -
|
||||
*/
|
||||
if (state == psr->state || !psr->active)
|
||||
return;
|
||||
int ret;
|
||||
|
||||
/* Already disabled in flush, change the state, but not the hardware */
|
||||
if (state == PSR_DISABLE && psr->state == PSR_FLUSH) {
|
||||
psr->state = state;
|
||||
return;
|
||||
}
|
||||
if (psr->inhibit_count > 0)
|
||||
return -EINVAL;
|
||||
|
||||
psr->state = state;
|
||||
if (enable == psr->enabled)
|
||||
return 0;
|
||||
|
||||
/* Actually commit the state change to hardware */
|
||||
switch (psr->state) {
|
||||
case PSR_ENABLE:
|
||||
psr->set(psr->encoder, true);
|
||||
break;
|
||||
ret = psr->set(psr->encoder, enable);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
case PSR_DISABLE:
|
||||
case PSR_FLUSH:
|
||||
psr->set(psr->encoder, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void psr_set_state(struct psr_drv *psr, enum psr_state state)
|
||||
{
|
||||
mutex_lock(&psr->lock);
|
||||
psr_set_state_locked(psr, state);
|
||||
mutex_unlock(&psr->lock);
|
||||
psr->enabled = enable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void psr_flush_handler(struct work_struct *work)
|
||||
@ -120,21 +73,24 @@ static void psr_flush_handler(struct work_struct *work)
|
||||
struct psr_drv *psr = container_of(to_delayed_work(work),
|
||||
struct psr_drv, flush_work);
|
||||
|
||||
/* If the state has changed since we initiated the flush, do nothing */
|
||||
mutex_lock(&psr->lock);
|
||||
if (psr->state == PSR_FLUSH)
|
||||
psr_set_state_locked(psr, PSR_ENABLE);
|
||||
psr_set_state_locked(psr, true);
|
||||
mutex_unlock(&psr->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* rockchip_drm_psr_activate - activate PSR on the given pipe
|
||||
* rockchip_drm_psr_inhibit_put - release PSR inhibit on given encoder
|
||||
* @encoder: encoder to obtain the PSR encoder
|
||||
*
|
||||
* Decrements PSR inhibit count on given encoder. Should be called only
|
||||
* for a PSR inhibit count increment done before. If PSR inhibit counter
|
||||
* reaches zero, PSR flush work is scheduled to make the hardware enter
|
||||
* PSR mode in PSR_FLUSH_TIMEOUT_MS.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative errno on failure.
|
||||
*/
|
||||
int rockchip_drm_psr_activate(struct drm_encoder *encoder)
|
||||
int rockchip_drm_psr_inhibit_put(struct drm_encoder *encoder)
|
||||
{
|
||||
struct psr_drv *psr = find_psr_by_encoder(encoder);
|
||||
|
||||
@ -142,21 +98,30 @@ int rockchip_drm_psr_activate(struct drm_encoder *encoder)
|
||||
return PTR_ERR(psr);
|
||||
|
||||
mutex_lock(&psr->lock);
|
||||
psr->active = true;
|
||||
--psr->inhibit_count;
|
||||
WARN_ON(psr->inhibit_count < 0);
|
||||
if (!psr->inhibit_count)
|
||||
mod_delayed_work(system_wq, &psr->flush_work,
|
||||
PSR_FLUSH_TIMEOUT_MS);
|
||||
mutex_unlock(&psr->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_drm_psr_activate);
|
||||
EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put);
|
||||
|
||||
/**
|
||||
* rockchip_drm_psr_deactivate - deactivate PSR on the given pipe
|
||||
* rockchip_drm_psr_inhibit_get - acquire PSR inhibit on given encoder
|
||||
* @encoder: encoder to obtain the PSR encoder
|
||||
*
|
||||
* Increments PSR inhibit count on given encoder. This function guarantees
|
||||
* that after it returns PSR is turned off on given encoder and no PSR-related
|
||||
* hardware state change occurs at least until a matching call to
|
||||
* rockchip_drm_psr_inhibit_put() is done.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative errno on failure.
|
||||
*/
|
||||
int rockchip_drm_psr_deactivate(struct drm_encoder *encoder)
|
||||
int rockchip_drm_psr_inhibit_get(struct drm_encoder *encoder)
|
||||
{
|
||||
struct psr_drv *psr = find_psr_by_encoder(encoder);
|
||||
|
||||
@ -164,37 +129,25 @@ int rockchip_drm_psr_deactivate(struct drm_encoder *encoder)
|
||||
return PTR_ERR(psr);
|
||||
|
||||
mutex_lock(&psr->lock);
|
||||
psr->active = false;
|
||||
psr_set_state_locked(psr, false);
|
||||
++psr->inhibit_count;
|
||||
mutex_unlock(&psr->lock);
|
||||
cancel_delayed_work_sync(&psr->flush_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_drm_psr_deactivate);
|
||||
EXPORT_SYMBOL(rockchip_drm_psr_inhibit_get);
|
||||
|
||||
static void rockchip_drm_do_flush(struct psr_drv *psr)
|
||||
{
|
||||
psr_set_state(psr, PSR_FLUSH);
|
||||
mod_delayed_work(system_wq, &psr->flush_work, PSR_FLUSH_TIMEOUT_MS);
|
||||
}
|
||||
cancel_delayed_work_sync(&psr->flush_work);
|
||||
|
||||
/**
|
||||
* rockchip_drm_psr_flush - flush a single pipe
|
||||
* @crtc: CRTC of the pipe to flush
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success, -errno on fail
|
||||
*/
|
||||
int rockchip_drm_psr_flush(struct drm_crtc *crtc)
|
||||
{
|
||||
struct psr_drv *psr = find_psr_by_crtc(crtc);
|
||||
if (IS_ERR(psr))
|
||||
return PTR_ERR(psr);
|
||||
|
||||
rockchip_drm_do_flush(psr);
|
||||
return 0;
|
||||
mutex_lock(&psr->lock);
|
||||
if (!psr_set_state_locked(psr, false))
|
||||
mod_delayed_work(system_wq, &psr->flush_work,
|
||||
PSR_FLUSH_TIMEOUT_MS);
|
||||
mutex_unlock(&psr->lock);
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_drm_psr_flush);
|
||||
|
||||
/**
|
||||
* rockchip_drm_psr_flush_all - force to flush all registered PSR encoders
|
||||
@ -225,11 +178,16 @@ EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
|
||||
* @encoder: encoder that obtain the PSR function
|
||||
* @psr_set: call back to set PSR state
|
||||
*
|
||||
* The function returns with PSR inhibit counter initialized with one
|
||||
* and the caller (typically encoder driver) needs to call
|
||||
* rockchip_drm_psr_inhibit_put() when it becomes ready to accept PSR
|
||||
* enable request.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative errno on failure.
|
||||
*/
|
||||
int rockchip_drm_psr_register(struct drm_encoder *encoder,
|
||||
void (*psr_set)(struct drm_encoder *, bool enable))
|
||||
int (*psr_set)(struct drm_encoder *, bool enable))
|
||||
{
|
||||
struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
|
||||
struct psr_drv *psr;
|
||||
@ -244,8 +202,8 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder,
|
||||
INIT_DELAYED_WORK(&psr->flush_work, psr_flush_handler);
|
||||
mutex_init(&psr->lock);
|
||||
|
||||
psr->active = true;
|
||||
psr->state = PSR_DISABLE;
|
||||
psr->inhibit_count = 1;
|
||||
psr->enabled = false;
|
||||
psr->encoder = encoder;
|
||||
psr->set = psr_set;
|
||||
|
||||
@ -262,6 +220,11 @@ EXPORT_SYMBOL(rockchip_drm_psr_register);
|
||||
* @encoder: encoder that obtain the PSR function
|
||||
* @psr_set: call back to set PSR state
|
||||
*
|
||||
* It is expected that the PSR inhibit counter is 1 when this function is
|
||||
* called, which corresponds to a state when related encoder has been
|
||||
* disconnected from any CRTCs and its driver called
|
||||
* rockchip_drm_psr_inhibit_get() to stop the PSR logic.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative errno on failure.
|
||||
*/
|
||||
@ -273,7 +236,12 @@ void rockchip_drm_psr_unregister(struct drm_encoder *encoder)
|
||||
mutex_lock(&drm_drv->psr_list_lock);
|
||||
list_for_each_entry_safe(psr, n, &drm_drv->psr_list, list) {
|
||||
if (psr->encoder == encoder) {
|
||||
cancel_delayed_work_sync(&psr->flush_work);
|
||||
/*
|
||||
* Any other value would mean that the encoder
|
||||
* is still in use.
|
||||
*/
|
||||
WARN_ON(psr->inhibit_count != 1);
|
||||
|
||||
list_del(&psr->list);
|
||||
kfree(psr);
|
||||
}
|
||||
|
@ -16,13 +16,12 @@
|
||||
#define __ROCKCHIP_DRM_PSR___
|
||||
|
||||
void rockchip_drm_psr_flush_all(struct drm_device *dev);
|
||||
int rockchip_drm_psr_flush(struct drm_crtc *crtc);
|
||||
|
||||
int rockchip_drm_psr_activate(struct drm_encoder *encoder);
|
||||
int rockchip_drm_psr_deactivate(struct drm_encoder *encoder);
|
||||
int rockchip_drm_psr_inhibit_put(struct drm_encoder *encoder);
|
||||
int rockchip_drm_psr_inhibit_get(struct drm_encoder *encoder);
|
||||
|
||||
int rockchip_drm_psr_register(struct drm_encoder *encoder,
|
||||
void (*psr_set)(struct drm_encoder *, bool enable));
|
||||
int (*psr_set)(struct drm_encoder *, bool enable));
|
||||
void rockchip_drm_psr_unregister(struct drm_encoder *encoder);
|
||||
|
||||
#endif /* __ROCKCHIP_DRM_PSR__ */
|
||||
|
@ -925,6 +925,12 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
|
||||
!(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10))
|
||||
s->output_mode = ROCKCHIP_OUT_MODE_P888;
|
||||
|
||||
if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && s->output_bpc == 8)
|
||||
VOP_REG_SET(vop, common, pre_dither_down, 1);
|
||||
else
|
||||
VOP_REG_SET(vop, common, pre_dither_down, 0);
|
||||
|
||||
VOP_REG_SET(vop, common, out_mode, s->output_mode);
|
||||
|
||||
VOP_REG_SET(vop, modeset, htotal_pw, (htotal << 16) | hsync_len);
|
||||
@ -1017,22 +1023,15 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
|
||||
continue;
|
||||
|
||||
drm_framebuffer_get(old_plane_state->fb);
|
||||
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
|
||||
drm_flip_work_queue(&vop->fb_unref_work, old_plane_state->fb);
|
||||
set_bit(VOP_PENDING_FB_UNREF, &vop->pending);
|
||||
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void vop_crtc_atomic_begin(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_crtc_state)
|
||||
{
|
||||
rockchip_drm_psr_flush(crtc);
|
||||
}
|
||||
|
||||
static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
|
||||
.mode_fixup = vop_crtc_mode_fixup,
|
||||
.atomic_flush = vop_crtc_atomic_flush,
|
||||
.atomic_begin = vop_crtc_atomic_begin,
|
||||
.atomic_enable = vop_crtc_atomic_enable,
|
||||
.atomic_disable = vop_crtc_atomic_disable,
|
||||
};
|
||||
|
@ -67,6 +67,7 @@ struct vop_common {
|
||||
struct vop_reg cfg_done;
|
||||
struct vop_reg dsp_blank;
|
||||
struct vop_reg data_blank;
|
||||
struct vop_reg pre_dither_down;
|
||||
struct vop_reg dither_down;
|
||||
struct vop_reg dither_up;
|
||||
struct vop_reg gate_en;
|
||||
|
@ -264,6 +264,7 @@ static const struct vop_common rk3288_common = {
|
||||
.standby = VOP_REG_SYNC(RK3288_SYS_CTRL, 0x1, 22),
|
||||
.gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23),
|
||||
.mmu_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 20),
|
||||
.pre_dither_down = VOP_REG(RK3288_DSP_CTRL1, 0x1, 1),
|
||||
.dither_down = VOP_REG(RK3288_DSP_CTRL1, 0xf, 1),
|
||||
.dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6),
|
||||
.data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19),
|
||||
|
@ -1,6 +1,6 @@
|
||||
config DRM_STI
|
||||
tristate "DRM Support for STMicroelectronics SoC stiH4xx Series"
|
||||
depends on DRM && (ARCH_STI || ARCH_MULTIPLATFORM)
|
||||
depends on OF && DRM && (ARCH_STI || ARCH_MULTIPLATFORM)
|
||||
select RESET_CONTROLLER
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_GEM_CMA_HELPER
|
||||
@ -8,6 +8,5 @@ config DRM_STI
|
||||
select DRM_PANEL
|
||||
select FW_LOADER
|
||||
select SND_SOC_HDMI_CODEC if SND_SOC
|
||||
select OF
|
||||
help
|
||||
Choose this option to enable DRM on STM stiH4xx chipset
|
||||
|
@ -119,30 +119,10 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sti_atomic_check(struct drm_device *dev,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = drm_atomic_helper_check_modeset(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_atomic_normalize_zpos(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_atomic_helper_check_planes(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_mode_config_funcs sti_mode_config_funcs = {
|
||||
.fb_create = drm_gem_fb_create,
|
||||
.output_poll_changed = drm_fb_helper_output_poll_changed,
|
||||
.atomic_check = sti_atomic_check,
|
||||
.atomic_check = drm_atomic_helper_check,
|
||||
.atomic_commit = drm_atomic_helper_commit,
|
||||
};
|
||||
|
||||
@ -160,6 +140,8 @@ static void sti_mode_config_init(struct drm_device *dev)
|
||||
dev->mode_config.max_height = STI_MAX_FB_HEIGHT;
|
||||
|
||||
dev->mode_config.funcs = &sti_mode_config_funcs;
|
||||
|
||||
dev->mode_config.normalize_zpos = true;
|
||||
}
|
||||
|
||||
DEFINE_DRM_GEM_CMA_FOPS(sti_driver_fops);
|
||||
|
@ -40,6 +40,7 @@ void sti_plane_update_fps(struct sti_plane *plane,
|
||||
bool new_frame,
|
||||
bool new_field)
|
||||
{
|
||||
struct drm_plane_state *state = plane->drm_plane.state;
|
||||
ktime_t now;
|
||||
struct sti_fps_info *fps;
|
||||
int fpks, fipks, ms_since_last, num_frames, num_fields;
|
||||
@ -66,14 +67,14 @@ void sti_plane_update_fps(struct sti_plane *plane,
|
||||
fps->last_timestamp = now;
|
||||
fps->last_frame_counter = fps->curr_frame_counter;
|
||||
|
||||
if (plane->drm_plane.fb) {
|
||||
if (state->fb) {
|
||||
fpks = (num_frames * 1000000) / ms_since_last;
|
||||
snprintf(plane->fps_info.fps_str, FPS_LENGTH,
|
||||
"%-8s %4dx%-4d %.4s @ %3d.%-3.3d fps (%s)",
|
||||
plane->drm_plane.name,
|
||||
plane->drm_plane.fb->width,
|
||||
plane->drm_plane.fb->height,
|
||||
(char *)&plane->drm_plane.fb->format->format,
|
||||
state->fb->width,
|
||||
state->fb->height,
|
||||
(char *)&state->fb->format->format,
|
||||
fpks / 1000, fpks % 1000,
|
||||
sti_plane_to_str(plane));
|
||||
}
|
||||
|
@ -72,8 +72,6 @@ static struct drm_driver drv_driver = {
|
||||
.gem_prime_vmap = drm_gem_cma_prime_vmap,
|
||||
.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
|
||||
.gem_prime_mmap = drm_gem_cma_prime_mmap,
|
||||
.enable_vblank = ltdc_crtc_enable_vblank,
|
||||
.disable_vblank = ltdc_crtc_disable_vblank,
|
||||
};
|
||||
|
||||
static int drv_load(struct drm_device *ddev)
|
||||
|
@ -392,9 +392,6 @@ static void ltdc_crtc_update_clut(struct drm_crtc *crtc)
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
if (!crtc || !crtc->state)
|
||||
return;
|
||||
|
||||
if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
|
||||
return;
|
||||
|
||||
@ -569,9 +566,9 @@ static const struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = {
|
||||
.atomic_disable = ltdc_crtc_atomic_disable,
|
||||
};
|
||||
|
||||
int ltdc_crtc_enable_vblank(struct drm_device *ddev, unsigned int pipe)
|
||||
static int ltdc_crtc_enable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct ltdc_device *ldev = ddev->dev_private;
|
||||
struct ltdc_device *ldev = crtc_to_ltdc(crtc);
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
reg_set(ldev->regs, LTDC_IER, IER_LIE);
|
||||
@ -579,9 +576,9 @@ int ltdc_crtc_enable_vblank(struct drm_device *ddev, unsigned int pipe)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ltdc_crtc_disable_vblank(struct drm_device *ddev, unsigned int pipe)
|
||||
static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
struct ltdc_device *ldev = ddev->dev_private;
|
||||
struct ltdc_device *ldev = crtc_to_ltdc(crtc);
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
reg_clear(ldev->regs, LTDC_IER, IER_LIE);
|
||||
@ -594,6 +591,8 @@ static const struct drm_crtc_funcs ltdc_crtc_funcs = {
|
||||
.reset = drm_atomic_helper_crtc_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
|
||||
.enable_vblank = ltdc_crtc_enable_vblank,
|
||||
.disable_vblank = ltdc_crtc_disable_vblank,
|
||||
.gamma_set = drm_atomic_helper_legacy_gamma_set,
|
||||
};
|
||||
|
||||
@ -727,6 +726,8 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane,
|
||||
reg_update_bits(ldev->regs, LTDC_L1CR + lofs,
|
||||
LXCR_LEN | LXCR_CLUTEN, val);
|
||||
|
||||
ldev->plane_fpsi[plane->index].counter++;
|
||||
|
||||
mutex_lock(&ldev->err_lock);
|
||||
if (ldev->error_status & ISR_FUIF) {
|
||||
DRM_DEBUG_DRIVER("Fifo underrun\n");
|
||||
@ -752,6 +753,25 @@ static void ltdc_plane_atomic_disable(struct drm_plane *plane,
|
||||
oldstate->crtc->base.id, plane->base.id);
|
||||
}
|
||||
|
||||
static void ltdc_plane_atomic_print_state(struct drm_printer *p,
|
||||
const struct drm_plane_state *state)
|
||||
{
|
||||
struct drm_plane *plane = state->plane;
|
||||
struct ltdc_device *ldev = plane_to_ltdc(plane);
|
||||
struct fps_info *fpsi = &ldev->plane_fpsi[plane->index];
|
||||
int ms_since_last;
|
||||
ktime_t now;
|
||||
|
||||
now = ktime_get();
|
||||
ms_since_last = ktime_to_ms(ktime_sub(now, fpsi->last_timestamp));
|
||||
|
||||
drm_printf(p, "\tuser_updates=%dfps\n",
|
||||
DIV_ROUND_CLOSEST(fpsi->counter * 1000, ms_since_last));
|
||||
|
||||
fpsi->last_timestamp = now;
|
||||
fpsi->counter = 0;
|
||||
}
|
||||
|
||||
static const struct drm_plane_funcs ltdc_plane_funcs = {
|
||||
.update_plane = drm_atomic_helper_update_plane,
|
||||
.disable_plane = drm_atomic_helper_disable_plane,
|
||||
@ -759,6 +779,7 @@ static const struct drm_plane_funcs ltdc_plane_funcs = {
|
||||
.reset = drm_atomic_helper_plane_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
|
||||
.atomic_print_state = ltdc_plane_atomic_print_state,
|
||||
};
|
||||
|
||||
static const struct drm_plane_helper_funcs ltdc_plane_helper_funcs = {
|
||||
|
@ -20,6 +20,13 @@ struct ltdc_caps {
|
||||
bool non_alpha_only_l1; /* non-native no-alpha formats on layer 1 */
|
||||
};
|
||||
|
||||
#define LTDC_MAX_LAYER 4
|
||||
|
||||
struct fps_info {
|
||||
unsigned int counter;
|
||||
ktime_t last_timestamp;
|
||||
};
|
||||
|
||||
struct ltdc_device {
|
||||
void __iomem *regs;
|
||||
struct clk *pixel_clk; /* lcd pixel clock */
|
||||
@ -27,10 +34,9 @@ struct ltdc_device {
|
||||
struct ltdc_caps caps;
|
||||
u32 error_status;
|
||||
u32 irq_status;
|
||||
struct fps_info plane_fpsi[LTDC_MAX_LAYER];
|
||||
};
|
||||
|
||||
int ltdc_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe);
|
||||
void ltdc_crtc_disable_vblank(struct drm_device *dev, unsigned int pipe);
|
||||
int ltdc_load(struct drm_device *ddev);
|
||||
void ltdc_unload(struct drm_device *ddev);
|
||||
|
||||
|
@ -40,6 +40,16 @@ config DRM_SUN4I_BACKEND
|
||||
do some alpha blending and feed graphics to TCON. If M is
|
||||
selected the module will be called sun4i-backend.
|
||||
|
||||
config DRM_SUN6I_DSI
|
||||
tristate "Allwinner A31 MIPI-DSI Controller Support"
|
||||
default MACH_SUN8I
|
||||
select CRC_CCITT
|
||||
select DRM_MIPI_DSI
|
||||
help
|
||||
Choose this option if you want have an Allwinner SoC with
|
||||
MIPI-DSI support. If M is selected the module will be called
|
||||
sun6i-dsi
|
||||
|
||||
config DRM_SUN8I_DW_HDMI
|
||||
tristate "Support for Allwinner version of DesignWare HDMI"
|
||||
depends on DRM_SUN4I
|
||||
|
@ -24,6 +24,9 @@ sun4i-tcon-y += sun4i_lvds.o
|
||||
sun4i-tcon-y += sun4i_tcon.o
|
||||
sun4i-tcon-y += sun4i_rgb.o
|
||||
|
||||
sun6i-dsi-y += sun6i_mipi_dphy.o
|
||||
sun6i-dsi-y += sun6i_mipi_dsi.o
|
||||
|
||||
obj-$(CONFIG_DRM_SUN4I) += sun4i-drm.o
|
||||
obj-$(CONFIG_DRM_SUN4I) += sun4i-tcon.o
|
||||
obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o
|
||||
@ -31,5 +34,6 @@ obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o
|
||||
|
||||
obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o sun4i-frontend.o
|
||||
obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o
|
||||
obj-$(CONFIG_DRM_SUN6I_DSI) += sun6i-dsi.o
|
||||
obj-$(CONFIG_DRM_SUN8I_DW_HDMI) += sun8i-drm-hdmi.o
|
||||
obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o
|
||||
|
@ -295,6 +295,15 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
|
||||
DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n",
|
||||
interlaced ? "on" : "off");
|
||||
|
||||
val = SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA(state->alpha >> 8);
|
||||
if (state->alpha != DRM_BLEND_ALPHA_OPAQUE)
|
||||
val |= SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA_EN;
|
||||
regmap_update_bits(backend->engine.regs,
|
||||
SUN4I_BACKEND_ATTCTL_REG0(layer),
|
||||
SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA_MASK |
|
||||
SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA_EN,
|
||||
val);
|
||||
|
||||
if (sun4i_backend_format_is_yuv(fb->format->format))
|
||||
return sun4i_backend_update_yuv_format(backend, layer, plane);
|
||||
|
||||
@ -490,7 +499,7 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
|
||||
DRM_DEBUG_DRIVER("Plane FB format is %s\n",
|
||||
drm_get_format_name(fb->format->format,
|
||||
&format_name));
|
||||
if (fb->format->has_alpha)
|
||||
if (fb->format->has_alpha || (plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE))
|
||||
num_alpha_planes++;
|
||||
|
||||
if (sun4i_backend_format_is_yuv(fb->format->format)) {
|
||||
@ -548,7 +557,8 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
|
||||
}
|
||||
|
||||
/* We can't have an alpha plane at the lowest position */
|
||||
if (plane_states[0]->fb->format->has_alpha)
|
||||
if (plane_states[0]->fb->format->has_alpha ||
|
||||
(plane_states[0]->alpha != DRM_BLEND_ALPHA_OPAQUE))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 1; i < num_planes; i++) {
|
||||
@ -560,7 +570,7 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
|
||||
* The only alpha position is the lowest plane of the
|
||||
* second pipe.
|
||||
*/
|
||||
if (fb->format->has_alpha)
|
||||
if (fb->format->has_alpha || (p_state->alpha != DRM_BLEND_ALPHA_OPAQUE))
|
||||
current_pipe++;
|
||||
|
||||
s_state->pipe = current_pipe;
|
||||
|
@ -68,12 +68,15 @@
|
||||
#define SUN4I_BACKEND_CKMIN_REG 0x884
|
||||
#define SUN4I_BACKEND_CKCFG_REG 0x888
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0(l) (0x890 + (0x4 * (l)))
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA_MASK GENMASK(31, 24)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA(x) ((x) << 24)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK BIT(15)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x) ((x) << 15)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK GENMASK(11, 10)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x) ((x) << 10)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN BIT(2)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN BIT(1)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA_EN BIT(0)
|
||||
|
||||
#define SUN4I_BACKEND_ATTCTL_REG1(l) (0x8a0 + (0x4 * (l)))
|
||||
#define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT GENMASK(15, 14)
|
||||
|
@ -37,6 +37,7 @@ static void sun4i_backend_layer_reset(struct drm_plane *plane)
|
||||
if (state) {
|
||||
plane->state = &state->state;
|
||||
plane->state->plane = plane;
|
||||
plane->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
|
||||
plane->state->zpos = layer->id;
|
||||
}
|
||||
}
|
||||
@ -167,6 +168,7 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
|
||||
&sun4i_backend_layer_helper_funcs);
|
||||
layer->backend = backend;
|
||||
|
||||
drm_plane_create_alpha_property(&layer->plane);
|
||||
drm_plane_create_zpos_property(&layer->plane, 0, 0,
|
||||
SUN4I_BACKEND_NUM_LAYERS - 1);
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "sun4i_lvds.h"
|
||||
#include "sun4i_rgb.h"
|
||||
#include "sun4i_tcon.h"
|
||||
#include "sun6i_mipi_dsi.h"
|
||||
#include "sunxi_engine.h"
|
||||
|
||||
static struct drm_connector *sun4i_tcon_get_connector(const struct drm_encoder *encoder)
|
||||
@ -169,6 +170,7 @@ void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
|
||||
case DRM_MODE_ENCODER_LVDS:
|
||||
is_lvds = true;
|
||||
/* Fallthrough */
|
||||
case DRM_MODE_ENCODER_DSI:
|
||||
case DRM_MODE_ENCODER_NONE:
|
||||
channel = 0;
|
||||
break;
|
||||
@ -201,7 +203,8 @@ void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
|
||||
DRM_DEBUG_DRIVER("%sabling VBLANK interrupt\n", enable ? "En" : "Dis");
|
||||
|
||||
mask = SUN4I_TCON_GINT0_VBLANK_ENABLE(0) |
|
||||
SUN4I_TCON_GINT0_VBLANK_ENABLE(1);
|
||||
SUN4I_TCON_GINT0_VBLANK_ENABLE(1) |
|
||||
SUN4I_TCON_GINT0_TCON0_TRI_FINISH_ENABLE;
|
||||
|
||||
if (enable)
|
||||
val = mask;
|
||||
@ -273,6 +276,71 @@ static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
|
||||
SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
|
||||
}
|
||||
|
||||
static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon,
|
||||
struct mipi_dsi_device *device,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
u8 bpp = mipi_dsi_pixel_format_to_bpp(device->format);
|
||||
u8 lanes = device->lanes;
|
||||
u32 block_space, start_delay;
|
||||
u32 tcon_div;
|
||||
|
||||
tcon->dclk_min_div = 4;
|
||||
tcon->dclk_max_div = 127;
|
||||
|
||||
sun4i_tcon0_mode_set_common(tcon, mode);
|
||||
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
|
||||
SUN4I_TCON0_CTL_IF_MASK,
|
||||
SUN4I_TCON0_CTL_IF_8080);
|
||||
|
||||
regmap_write(tcon->regs, SUN4I_TCON_ECC_FIFO_REG,
|
||||
SUN4I_TCON_ECC_FIFO_EN);
|
||||
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_CPU_IF_REG,
|
||||
SUN4I_TCON0_CPU_IF_MODE_DSI |
|
||||
SUN4I_TCON0_CPU_IF_TRI_FIFO_FLUSH |
|
||||
SUN4I_TCON0_CPU_IF_TRI_FIFO_EN |
|
||||
SUN4I_TCON0_CPU_IF_TRI_EN);
|
||||
|
||||
/*
|
||||
* This looks suspicious, but it works...
|
||||
*
|
||||
* The datasheet says that this should be set higher than 20 *
|
||||
* pixel cycle, but it's not clear what a pixel cycle is.
|
||||
*/
|
||||
regmap_read(tcon->regs, SUN4I_TCON0_DCLK_REG, &tcon_div);
|
||||
tcon_div &= GENMASK(6, 0);
|
||||
block_space = mode->htotal * bpp / (tcon_div * lanes);
|
||||
block_space -= mode->hdisplay + 40;
|
||||
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI0_REG,
|
||||
SUN4I_TCON0_CPU_TRI0_BLOCK_SPACE(block_space) |
|
||||
SUN4I_TCON0_CPU_TRI0_BLOCK_SIZE(mode->hdisplay));
|
||||
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI1_REG,
|
||||
SUN4I_TCON0_CPU_TRI1_BLOCK_NUM(mode->vdisplay));
|
||||
|
||||
start_delay = (mode->crtc_vtotal - mode->crtc_vdisplay - 10 - 1);
|
||||
start_delay = start_delay * mode->crtc_htotal * 149;
|
||||
start_delay = start_delay / (mode->crtc_clock / 1000) / 8;
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI2_REG,
|
||||
SUN4I_TCON0_CPU_TRI2_TRANS_START_SET(10) |
|
||||
SUN4I_TCON0_CPU_TRI2_START_DELAY(start_delay));
|
||||
|
||||
/*
|
||||
* The Allwinner BSP has a comment that the period should be
|
||||
* the display clock * 15, but uses an hardcoded 3000...
|
||||
*/
|
||||
regmap_write(tcon->regs, SUN4I_TCON_SAFE_PERIOD_REG,
|
||||
SUN4I_TCON_SAFE_PERIOD_NUM(3000) |
|
||||
SUN4I_TCON_SAFE_PERIOD_MODE(3));
|
||||
|
||||
/* Enable the output on the pins */
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG,
|
||||
0xe0000000);
|
||||
}
|
||||
|
||||
static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
|
||||
const struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode)
|
||||
@ -538,7 +606,17 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,
|
||||
const struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct sun6i_dsi *dsi;
|
||||
|
||||
switch (encoder->encoder_type) {
|
||||
case DRM_MODE_ENCODER_DSI:
|
||||
/*
|
||||
* This is not really elegant, but it's the "cleaner"
|
||||
* way I could think of...
|
||||
*/
|
||||
dsi = encoder_to_sun6i_dsi(encoder);
|
||||
sun4i_tcon0_mode_set_cpu(tcon, dsi->device, mode);
|
||||
break;
|
||||
case DRM_MODE_ENCODER_LVDS:
|
||||
sun4i_tcon0_mode_set_lvds(tcon, encoder, mode);
|
||||
break;
|
||||
@ -582,7 +660,8 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
|
||||
regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
|
||||
|
||||
if (!(status & (SUN4I_TCON_GINT0_VBLANK_INT(0) |
|
||||
SUN4I_TCON_GINT0_VBLANK_INT(1))))
|
||||
SUN4I_TCON_GINT0_VBLANK_INT(1) |
|
||||
SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT)))
|
||||
return IRQ_NONE;
|
||||
|
||||
drm_crtc_handle_vblank(&scrtc->crtc);
|
||||
@ -591,7 +670,8 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
|
||||
/* Acknowledge the interrupt */
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG,
|
||||
SUN4I_TCON_GINT0_VBLANK_INT(0) |
|
||||
SUN4I_TCON_GINT0_VBLANK_INT(1),
|
||||
SUN4I_TCON_GINT0_VBLANK_INT(1) |
|
||||
SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT,
|
||||
0);
|
||||
|
||||
if (engine->ops->vblank_quirk)
|
||||
|
@ -28,13 +28,32 @@
|
||||
|
||||
#define SUN4I_TCON_GINT0_REG 0x4
|
||||
#define SUN4I_TCON_GINT0_VBLANK_ENABLE(pipe) BIT(31 - (pipe))
|
||||
#define SUN4I_TCON_GINT0_TCON0_TRI_FINISH_ENABLE BIT(27)
|
||||
#define SUN4I_TCON_GINT0_TCON0_TRI_COUNTER_ENABLE BIT(26)
|
||||
#define SUN4I_TCON_GINT0_VBLANK_INT(pipe) BIT(15 - (pipe))
|
||||
#define SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT BIT(11)
|
||||
#define SUN4I_TCON_GINT0_TCON0_TRI_COUNTER_INT BIT(10)
|
||||
|
||||
#define SUN4I_TCON_GINT1_REG 0x8
|
||||
|
||||
#define SUN4I_TCON_FRM_CTL_REG 0x10
|
||||
#define SUN4I_TCON_FRM_CTL_EN BIT(31)
|
||||
|
||||
#define SUN4I_TCON_FRM_SEED_PR_REG 0x14
|
||||
#define SUN4I_TCON_FRM_SEED_PG_REG 0x18
|
||||
#define SUN4I_TCON_FRM_SEED_PB_REG 0x1c
|
||||
#define SUN4I_TCON_FRM_SEED_LR_REG 0x20
|
||||
#define SUN4I_TCON_FRM_SEED_LG_REG 0x24
|
||||
#define SUN4I_TCON_FRM_SEED_LB_REG 0x28
|
||||
#define SUN4I_TCON_FRM_TBL0_REG 0x2c
|
||||
#define SUN4I_TCON_FRM_TBL1_REG 0x30
|
||||
#define SUN4I_TCON_FRM_TBL2_REG 0x34
|
||||
#define SUN4I_TCON_FRM_TBL3_REG 0x38
|
||||
|
||||
#define SUN4I_TCON0_CTL_REG 0x40
|
||||
#define SUN4I_TCON0_CTL_TCON_ENABLE BIT(31)
|
||||
#define SUN4I_TCON0_CTL_IF_MASK GENMASK(25, 24)
|
||||
#define SUN4I_TCON0_CTL_IF_8080 (1 << 24)
|
||||
#define SUN4I_TCON0_CTL_CLK_DELAY_MASK GENMASK(8, 4)
|
||||
#define SUN4I_TCON0_CTL_CLK_DELAY(delay) ((delay << 4) & SUN4I_TCON0_CTL_CLK_DELAY_MASK)
|
||||
#define SUN4I_TCON0_CTL_SRC_SEL_MASK GENMASK(2, 0)
|
||||
@ -61,7 +80,14 @@
|
||||
#define SUN4I_TCON0_BASIC3_V_SYNC(height) (((height) - 1) & 0x7ff)
|
||||
|
||||
#define SUN4I_TCON0_HV_IF_REG 0x58
|
||||
|
||||
#define SUN4I_TCON0_CPU_IF_REG 0x60
|
||||
#define SUN4I_TCON0_CPU_IF_MODE_MASK GENMASK(31, 28)
|
||||
#define SUN4I_TCON0_CPU_IF_MODE_DSI (1 << 28)
|
||||
#define SUN4I_TCON0_CPU_IF_TRI_FIFO_FLUSH BIT(16)
|
||||
#define SUN4I_TCON0_CPU_IF_TRI_FIFO_EN BIT(2)
|
||||
#define SUN4I_TCON0_CPU_IF_TRI_EN BIT(0)
|
||||
|
||||
#define SUN4I_TCON0_CPU_WR_REG 0x64
|
||||
#define SUN4I_TCON0_CPU_RD0_REG 0x68
|
||||
#define SUN4I_TCON0_CPU_RDA_REG 0x6c
|
||||
@ -128,6 +154,10 @@
|
||||
|
||||
#define SUN4I_TCON1_IO_POL_REG 0xf0
|
||||
#define SUN4I_TCON1_IO_TRI_REG 0xf4
|
||||
|
||||
#define SUN4I_TCON_ECC_FIFO_REG 0xf8
|
||||
#define SUN4I_TCON_ECC_FIFO_EN BIT(3)
|
||||
|
||||
#define SUN4I_TCON_CEU_CTL_REG 0x100
|
||||
#define SUN4I_TCON_CEU_MUL_RR_REG 0x110
|
||||
#define SUN4I_TCON_CEU_MUL_RG_REG 0x114
|
||||
@ -144,6 +174,22 @@
|
||||
#define SUN4I_TCON_CEU_RANGE_R_REG 0x140
|
||||
#define SUN4I_TCON_CEU_RANGE_G_REG 0x144
|
||||
#define SUN4I_TCON_CEU_RANGE_B_REG 0x148
|
||||
|
||||
#define SUN4I_TCON0_CPU_TRI0_REG 0x160
|
||||
#define SUN4I_TCON0_CPU_TRI0_BLOCK_SPACE(space) ((((space) - 1) & 0xfff) << 16)
|
||||
#define SUN4I_TCON0_CPU_TRI0_BLOCK_SIZE(size) (((size) - 1) & 0xfff)
|
||||
|
||||
#define SUN4I_TCON0_CPU_TRI1_REG 0x164
|
||||
#define SUN4I_TCON0_CPU_TRI1_BLOCK_NUM(num) (((num) - 1) & 0xffff)
|
||||
|
||||
#define SUN4I_TCON0_CPU_TRI2_REG 0x168
|
||||
#define SUN4I_TCON0_CPU_TRI2_START_DELAY(delay) (((delay) & 0xffff) << 16)
|
||||
#define SUN4I_TCON0_CPU_TRI2_TRANS_START_SET(set) ((set) & 0xfff)
|
||||
|
||||
#define SUN4I_TCON_SAFE_PERIOD_REG 0x1f0
|
||||
#define SUN4I_TCON_SAFE_PERIOD_NUM(num) (((num) & 0xfff) << 16)
|
||||
#define SUN4I_TCON_SAFE_PERIOD_MODE(mode) ((mode) & 0x3)
|
||||
|
||||
#define SUN4I_TCON_MUX_CTRL_REG 0x200
|
||||
|
||||
#define SUN4I_TCON0_LVDS_ANA0_REG 0x220
|
||||
|
292
drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c
Normal file
292
drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c
Normal file
@ -0,0 +1,292 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2016 Allwinnertech Co., Ltd.
|
||||
* Copyright (C) 2017-2018 Bootlin
|
||||
*
|
||||
* Maxime Ripard <maxime.ripard@free-electrons.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "sun6i_mipi_dsi.h"
|
||||
|
||||
#define SUN6I_DPHY_GCTL_REG 0x00
|
||||
#define SUN6I_DPHY_GCTL_LANE_NUM(n) ((((n) - 1) & 3) << 4)
|
||||
#define SUN6I_DPHY_GCTL_EN BIT(0)
|
||||
|
||||
#define SUN6I_DPHY_TX_CTL_REG 0x04
|
||||
#define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT BIT(28)
|
||||
|
||||
#define SUN6I_DPHY_TX_TIME0_REG 0x10
|
||||
#define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24)
|
||||
#define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16)
|
||||
#define SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(n) ((n) & 0xff)
|
||||
|
||||
#define SUN6I_DPHY_TX_TIME1_REG 0x14
|
||||
#define SUN6I_DPHY_TX_TIME1_CLK_POST(n) (((n) & 0xff) << 24)
|
||||
#define SUN6I_DPHY_TX_TIME1_CLK_PRE(n) (((n) & 0xff) << 16)
|
||||
#define SUN6I_DPHY_TX_TIME1_CLK_ZERO(n) (((n) & 0xff) << 8)
|
||||
#define SUN6I_DPHY_TX_TIME1_CLK_PREPARE(n) ((n) & 0xff)
|
||||
|
||||
#define SUN6I_DPHY_TX_TIME2_REG 0x18
|
||||
#define SUN6I_DPHY_TX_TIME2_CLK_TRAIL(n) ((n) & 0xff)
|
||||
|
||||
#define SUN6I_DPHY_TX_TIME3_REG 0x1c
|
||||
|
||||
#define SUN6I_DPHY_TX_TIME4_REG 0x20
|
||||
#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n) (((n) & 0xff) << 8)
|
||||
#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n) ((n) & 0xff)
|
||||
|
||||
#define SUN6I_DPHY_ANA0_REG 0x4c
|
||||
#define SUN6I_DPHY_ANA0_REG_PWS BIT(31)
|
||||
#define SUN6I_DPHY_ANA0_REG_DMPC BIT(28)
|
||||
#define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24)
|
||||
#define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12)
|
||||
#define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8)
|
||||
|
||||
#define SUN6I_DPHY_ANA1_REG 0x50
|
||||
#define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31)
|
||||
#define SUN6I_DPHY_ANA1_REG_CSMPS(n) (((n) & 3) << 28)
|
||||
#define SUN6I_DPHY_ANA1_REG_SVTT(n) (((n) & 0xf) << 24)
|
||||
|
||||
#define SUN6I_DPHY_ANA2_REG 0x54
|
||||
#define SUN6I_DPHY_ANA2_EN_P2S_CPU(n) (((n) & 0xf) << 24)
|
||||
#define SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK GENMASK(27, 24)
|
||||
#define SUN6I_DPHY_ANA2_EN_CK_CPU BIT(4)
|
||||
#define SUN6I_DPHY_ANA2_REG_ENIB BIT(1)
|
||||
|
||||
#define SUN6I_DPHY_ANA3_REG 0x58
|
||||
#define SUN6I_DPHY_ANA3_EN_VTTD(n) (((n) & 0xf) << 28)
|
||||
#define SUN6I_DPHY_ANA3_EN_VTTD_MASK GENMASK(31, 28)
|
||||
#define SUN6I_DPHY_ANA3_EN_VTTC BIT(27)
|
||||
#define SUN6I_DPHY_ANA3_EN_DIV BIT(26)
|
||||
#define SUN6I_DPHY_ANA3_EN_LDOC BIT(25)
|
||||
#define SUN6I_DPHY_ANA3_EN_LDOD BIT(24)
|
||||
#define SUN6I_DPHY_ANA3_EN_LDOR BIT(18)
|
||||
|
||||
#define SUN6I_DPHY_ANA4_REG 0x5c
|
||||
#define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24)
|
||||
#define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20)
|
||||
#define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12)
|
||||
#define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10)
|
||||
#define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8)
|
||||
#define SUN6I_DPHY_ANA4_REG_TXDNSC(n) (((n) & 3) << 6)
|
||||
#define SUN6I_DPHY_ANA4_REG_TXDNSD(n) (((n) & 3) << 4)
|
||||
#define SUN6I_DPHY_ANA4_REG_TXPUSC(n) (((n) & 3) << 2)
|
||||
#define SUN6I_DPHY_ANA4_REG_TXPUSD(n) ((n) & 3)
|
||||
|
||||
#define SUN6I_DPHY_DBG5_REG 0xf4
|
||||
|
||||
int sun6i_dphy_init(struct sun6i_dphy *dphy, unsigned int lanes)
|
||||
{
|
||||
reset_control_deassert(dphy->reset);
|
||||
clk_prepare_enable(dphy->mod_clk);
|
||||
clk_set_rate_exclusive(dphy->mod_clk, 150000000);
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG,
|
||||
SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT);
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG,
|
||||
SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) |
|
||||
SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) |
|
||||
SUN6I_DPHY_TX_TIME0_HS_TRAIL(10));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG,
|
||||
SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) |
|
||||
SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) |
|
||||
SUN6I_DPHY_TX_TIME1_CLK_PRE(3) |
|
||||
SUN6I_DPHY_TX_TIME1_CLK_POST(10));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG,
|
||||
SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0);
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG,
|
||||
SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) |
|
||||
SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG,
|
||||
SUN6I_DPHY_GCTL_LANE_NUM(lanes) |
|
||||
SUN6I_DPHY_GCTL_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sun6i_dphy_power_on(struct sun6i_dphy *dphy, unsigned int lanes)
|
||||
{
|
||||
u8 lanes_mask = GENMASK(lanes - 1, 0);
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
|
||||
SUN6I_DPHY_ANA0_REG_PWS |
|
||||
SUN6I_DPHY_ANA0_REG_DMPC |
|
||||
SUN6I_DPHY_ANA0_REG_SLV(7) |
|
||||
SUN6I_DPHY_ANA0_REG_DMPD(lanes_mask) |
|
||||
SUN6I_DPHY_ANA0_REG_DEN(lanes_mask));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG,
|
||||
SUN6I_DPHY_ANA1_REG_CSMPS(1) |
|
||||
SUN6I_DPHY_ANA1_REG_SVTT(7));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG,
|
||||
SUN6I_DPHY_ANA4_REG_CKDV(1) |
|
||||
SUN6I_DPHY_ANA4_REG_TMSC(1) |
|
||||
SUN6I_DPHY_ANA4_REG_TMSD(1) |
|
||||
SUN6I_DPHY_ANA4_REG_TXDNSC(1) |
|
||||
SUN6I_DPHY_ANA4_REG_TXDNSD(1) |
|
||||
SUN6I_DPHY_ANA4_REG_TXPUSC(1) |
|
||||
SUN6I_DPHY_ANA4_REG_TXPUSD(1) |
|
||||
SUN6I_DPHY_ANA4_REG_DMPLVC |
|
||||
SUN6I_DPHY_ANA4_REG_DMPLVD(lanes_mask));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG,
|
||||
SUN6I_DPHY_ANA2_REG_ENIB);
|
||||
udelay(5);
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG,
|
||||
SUN6I_DPHY_ANA3_EN_LDOR |
|
||||
SUN6I_DPHY_ANA3_EN_LDOC |
|
||||
SUN6I_DPHY_ANA3_EN_LDOD);
|
||||
udelay(1);
|
||||
|
||||
regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
|
||||
SUN6I_DPHY_ANA3_EN_VTTC |
|
||||
SUN6I_DPHY_ANA3_EN_VTTD_MASK,
|
||||
SUN6I_DPHY_ANA3_EN_VTTC |
|
||||
SUN6I_DPHY_ANA3_EN_VTTD(lanes_mask));
|
||||
udelay(1);
|
||||
|
||||
regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
|
||||
SUN6I_DPHY_ANA3_EN_DIV,
|
||||
SUN6I_DPHY_ANA3_EN_DIV);
|
||||
udelay(1);
|
||||
|
||||
regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
|
||||
SUN6I_DPHY_ANA2_EN_CK_CPU,
|
||||
SUN6I_DPHY_ANA2_EN_CK_CPU);
|
||||
udelay(1);
|
||||
|
||||
regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
|
||||
SUN6I_DPHY_ANA1_REG_VTTMODE,
|
||||
SUN6I_DPHY_ANA1_REG_VTTMODE);
|
||||
|
||||
regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
|
||||
SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK,
|
||||
SUN6I_DPHY_ANA2_EN_P2S_CPU(lanes_mask));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sun6i_dphy_power_off(struct sun6i_dphy *dphy)
|
||||
{
|
||||
regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
|
||||
SUN6I_DPHY_ANA1_REG_VTTMODE, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sun6i_dphy_exit(struct sun6i_dphy *dphy)
|
||||
{
|
||||
clk_rate_exclusive_put(dphy->mod_clk);
|
||||
clk_disable_unprepare(dphy->mod_clk);
|
||||
reset_control_assert(dphy->reset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct regmap_config sun6i_dphy_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = SUN6I_DPHY_DBG5_REG,
|
||||
.name = "mipi-dphy",
|
||||
};
|
||||
|
||||
static const struct of_device_id sun6i_dphy_of_table[] = {
|
||||
{ .compatible = "allwinner,sun6i-a31-mipi-dphy" },
|
||||
{ }
|
||||
};
|
||||
|
||||
int sun6i_dphy_probe(struct sun6i_dsi *dsi, struct device_node *node)
|
||||
{
|
||||
struct sun6i_dphy *dphy;
|
||||
struct resource res;
|
||||
void __iomem *regs;
|
||||
int ret;
|
||||
|
||||
if (!of_match_node(sun6i_dphy_of_table, node)) {
|
||||
dev_err(dsi->dev, "Incompatible D-PHY\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dphy = devm_kzalloc(dsi->dev, sizeof(*dphy), GFP_KERNEL);
|
||||
if (!dphy)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_address_to_resource(node, 0, &res);
|
||||
if (ret) {
|
||||
dev_err(dsi->dev, "phy: Couldn't get our resources\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
regs = devm_ioremap_resource(dsi->dev, &res);
|
||||
if (IS_ERR(regs)) {
|
||||
dev_err(dsi->dev, "Couldn't map the DPHY encoder registers\n");
|
||||
return PTR_ERR(regs);
|
||||
}
|
||||
|
||||
dphy->regs = devm_regmap_init_mmio(dsi->dev, regs,
|
||||
&sun6i_dphy_regmap_config);
|
||||
if (IS_ERR(dphy->regs)) {
|
||||
dev_err(dsi->dev, "Couldn't create the DPHY encoder regmap\n");
|
||||
return PTR_ERR(dphy->regs);
|
||||
}
|
||||
|
||||
dphy->reset = of_reset_control_get_shared(node, NULL);
|
||||
if (IS_ERR(dphy->reset)) {
|
||||
dev_err(dsi->dev, "Couldn't get our reset line\n");
|
||||
return PTR_ERR(dphy->reset);
|
||||
}
|
||||
|
||||
dphy->bus_clk = of_clk_get_by_name(node, "bus");
|
||||
if (IS_ERR(dphy->bus_clk)) {
|
||||
dev_err(dsi->dev, "Couldn't get the DPHY bus clock\n");
|
||||
ret = PTR_ERR(dphy->bus_clk);
|
||||
goto err_free_reset;
|
||||
}
|
||||
regmap_mmio_attach_clk(dphy->regs, dphy->bus_clk);
|
||||
|
||||
dphy->mod_clk = of_clk_get_by_name(node, "mod");
|
||||
if (IS_ERR(dphy->mod_clk)) {
|
||||
dev_err(dsi->dev, "Couldn't get the DPHY mod clock\n");
|
||||
ret = PTR_ERR(dphy->mod_clk);
|
||||
goto err_free_bus;
|
||||
}
|
||||
|
||||
dsi->dphy = dphy;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_bus:
|
||||
regmap_mmio_detach_clk(dphy->regs);
|
||||
clk_put(dphy->bus_clk);
|
||||
err_free_reset:
|
||||
reset_control_put(dphy->reset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sun6i_dphy_remove(struct sun6i_dsi *dsi)
|
||||
{
|
||||
struct sun6i_dphy *dphy = dsi->dphy;
|
||||
|
||||
regmap_mmio_detach_clk(dphy->regs);
|
||||
clk_put(dphy->mod_clk);
|
||||
clk_put(dphy->bus_clk);
|
||||
reset_control_put(dphy->reset);
|
||||
|
||||
return 0;
|
||||
}
|
1107
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
Normal file
1107
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user