drm-misc-next for v5.6:

UAPI Changes:
 - Commandline parser: Add support for panel orientation, and per-mode options.
 - Fix IOCTL naming for dma-buf heaps.
 
 Cross-subsystem Changes:
 - Rename DMA_HEAP_IOC_ALLOC to DMA_HEAP_IOCTL_ALLOC before it becomes abi.
 - Change DMA-BUF system-heap's name to system.
 - Fix leak in error handling in dma_heap_ioctl(), and make a symbol static.
 - Fix udma-buf cpu access.
 - Fix ti devicetree bindings.
 
 Core Changes:
 - Add CTA-861-G modes with VIC >= 193.
 - Change error handling and remove bug_on in *drm_dev_init.
 - Export drm_panel_of_backlight() correctly once more.
 - Add support for lvds decoders.
 - Convert drm/client and drm/(gem-,)fb-helper to drm-device based logging and update logging todo.
 
 Driver Changes:
 - Add support for dsi/px30 to rockchip.
 - Add fb damage support to virtio.
 - Use dma_resv locking wrappers in vc4, msm, etnaviv.
 - Make functions in virtio static, and perform some simplifications.
 - Add suspend support to sun4i.
 - Add A64 mipi dsi support to sun4i.
 - Add runtime pm suspend to komeda.
 - Associated driver fixes.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAl4N6t8ACgkQ/lWMcqZw
 E8P0ww/9EEa1W1nkaYmxfWCtmBV3D6QS4490jj62RMBXETezZmLPV11xpFqTPzcw
 9vRwD7PwP+rIDPTnEcg8vIMnhDgZuUMGv93PZrFZMHxe4MHeykQ6BOj4pWEnrkr4
 CQxC0exyIG8sQkH5+OngXkPnANPpzsegAAQ2rGbUf0HxxdZ1WeV3aqlQFo2YDpd9
 c8ouYhgnIP4NfLPYnVN3NQs/hQIVJRJ9vOHr+o8k7Fn9YoFak7ry6UFsSAan4j7I
 ZQDQzPnT5CQBBSRTh9vQinOexj5bkW3AFyNFA7mknv05LHYb1kMPIIqnY01pbi2w
 SyWc5oqJwwdCFPCLZIUHZMOBKYqGKWP0KTjy7+QKx2ty+Sjgf3hTZwnVdtNVLFJe
 7WsXP6Dg+PoSsSEGZuwGOzbr7GCJitSXhUs5GGiMbdbTPzr3rJsDLuyf9/Q1ObUC
 F+yIKkcwYZogeXRShFFQ3wjAxEQ83yyuTchyagvqSoqFsT5ccUjuUqInGAbYifPS
 QfhI1U9hQGmINqXPSkQYHXxMKg+Vl2KWvFknhmLIc0Cf3fRsu+wf3NAokrHsraxd
 RINvo2U5XDhPctRYXaPjPiYtPlnikR69mhyGcd7VG81F72ECzZr/2q1NmsEMmUac
 VqowhgoG8Tm4LcZHloMw4UlCtjV2esvztc2T6b95Mg6j1r4aav0=
 =ye8f
 -----END PGP SIGNATURE-----

Merge tag 'drm-misc-next-2020-01-02' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for v5.6:

UAPI Changes:
- Commandline parser: Add support for panel orientation, and per-mode options.
- Fix IOCTL naming for dma-buf heaps.

Cross-subsystem Changes:
- Rename DMA_HEAP_IOC_ALLOC to DMA_HEAP_IOCTL_ALLOC before it becomes abi.
- Change DMA-BUF system-heap's name to system.
- Fix leak in error handling in dma_heap_ioctl(), and make a symbol static.
- Fix udma-buf cpu access.
- Fix ti devicetree bindings.

Core Changes:
- Add CTA-861-G modes with VIC >= 193.
- Change error handling and remove bug_on in *drm_dev_init.
- Export drm_panel_of_backlight() correctly once more.
- Add support for lvds decoders.
- Convert drm/client and drm/(gem-,)fb-helper to drm-device based logging and update logging todo.

Driver Changes:
- Add support for dsi/px30 to rockchip.
- Add fb damage support to virtio.
- Use dma_resv locking wrappers in vc4, msm, etnaviv.
- Make functions in virtio static, and perform some simplifications.
- Add suspend support to sun4i.
- Add A64 mipi dsi support to sun4i.
- Add runtime pm suspend to komeda.
- Associated driver fixes.

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/efc11139-1653-86bc-1b0f-0aefde219850@linux.intel.com
This commit is contained in:
Dave Airlie 2020-01-03 11:43:31 +10:00
commit f5c547efa1
67 changed files with 1645 additions and 824 deletions

View File

@ -15,7 +15,9 @@ properties:
"#size-cells": true "#size-cells": true
compatible: compatible:
const: allwinner,sun6i-a31-mipi-dsi enum:
- allwinner,sun6i-a31-mipi-dsi
- allwinner,sun50i-a64-mipi-dsi
reg: reg:
maxItems: 1 maxItems: 1
@ -24,6 +26,8 @@ properties:
maxItems: 1 maxItems: 1
clocks: clocks:
minItems: 1
maxItems: 2
items: items:
- description: Bus Clock - description: Bus Clock
- description: Module Clock - description: Module Clock
@ -63,13 +67,38 @@ required:
- reg - reg
- interrupts - interrupts
- clocks - clocks
- clock-names
- phys - phys
- phy-names - phy-names
- resets - resets
- vcc-dsi-supply - vcc-dsi-supply
- port - port
allOf:
- if:
properties:
compatible:
contains:
const: allwinner,sun6i-a31-mipi-dsi
then:
properties:
clocks:
minItems: 2
required:
- clock-names
- if:
properties:
compatible:
contains:
const: allwinner,sun50i-a64-mipi-dsi
then:
properties:
clocks:
minItems: 1
additionalProperties: false additionalProperties: false
examples: examples:

View File

@ -0,0 +1,131 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/bridge/lvds-codec.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Transparent LVDS encoders and decoders
maintainers:
- Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
description: |
This binding supports transparent LVDS encoders and decoders that don't
require any configuration.
LVDS is a physical layer specification defined in ANSI/TIA/EIA-644-A. Multiple
incompatible data link layers have been used over time to transmit image data
to LVDS panels. This binding targets devices compatible with the following
specifications only.
[JEIDA] "Digital Interface Standards for Monitor", JEIDA-59-1999, February
1999 (Version 1.0), Japan Electronic Industry Development Association (JEIDA)
[LDI] "Open LVDS Display Interface", May 1999 (Version 0.95), National
Semiconductor
[VESA] "VESA Notebook Panel Standard", October 2007 (Version 1.0), Video
Electronics Standards Association (VESA)
Those devices have been marketed under the FPD-Link and FlatLink brand names
among others.
properties:
compatible:
oneOf:
- items:
- enum:
- ti,ds90c185 # For the TI DS90C185 FPD-Link Serializer
- ti,ds90c187 # For the TI DS90C187 FPD-Link Serializer
- ti,sn75lvds83 # For the TI SN75LVDS83 FlatLink transmitter
- const: lvds-encoder # Generic LVDS encoder compatible fallback
- items:
- enum:
- ti,ds90cf384a # For the DS90CF384A FPD-Link LVDS Receiver
- const: lvds-decoder # Generic LVDS decoders compatible fallback
- enum:
- thine,thc63lvdm83d # For the THC63LVDM83D LVDS serializer
ports:
type: object
description: |
This device has two video ports. Their connections are modeled using the
OF graph bindings specified in Documentation/devicetree/bindings/graph.txt
properties:
port@0:
type: object
description: |
For LVDS encoders, port 0 is the parallel input
For LVDS decoders, port 0 is the LVDS input
port@1:
type: object
description: |
For LVDS encoders, port 1 is the LVDS output
For LVDS decoders, port 1 is the parallel output
required:
- port@0
- port@1
powerdown-gpios:
description:
The GPIO used to control the power down line of this device.
maxItems: 1
required:
- compatible
- ports
examples:
- |
lvds-encoder {
compatible = "ti,ds90c185", "lvds-encoder";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
lvds_enc_in: endpoint {
remote-endpoint = <&display_out_rgb>;
};
};
port@1 {
reg = <1>;
lvds_enc_out: endpoint {
remote-endpoint = <&lvds_panel_in>;
};
};
};
};
- |
lvds-decoder {
compatible = "ti,ds90cf384a", "lvds-decoder";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
lvds_dec_in: endpoint {
remote-endpoint = <&display_out_lvds>;
};
};
port@1 {
reg = <1>;
lvds_dec_out: endpoint {
remote-endpoint = <&rgb_panel_in>;
};
};
};
};
...

View File

@ -1,66 +0,0 @@
Parallel to LVDS Encoder
------------------------
This binding supports the parallel to LVDS encoders that don't require any
configuration.
LVDS is a physical layer specification defined in ANSI/TIA/EIA-644-A. Multiple
incompatible data link layers have been used over time to transmit image data
to LVDS panels. This binding targets devices compatible with the following
specifications only.
[JEIDA] "Digital Interface Standards for Monitor", JEIDA-59-1999, February
1999 (Version 1.0), Japan Electronic Industry Development Association (JEIDA)
[LDI] "Open LVDS Display Interface", May 1999 (Version 0.95), National
Semiconductor
[VESA] "VESA Notebook Panel Standard", October 2007 (Version 1.0), Video
Electronics Standards Association (VESA)
Those devices have been marketed under the FPD-Link and FlatLink brand names
among others.
Required properties:
- compatible: Must be "lvds-encoder"
Any encoder compatible with this generic binding, but with additional
properties not listed here, must list a device specific compatible first
followed by this generic compatible.
Required nodes:
This device has two video ports. Their connections are modeled using the OF
graph bindings specified in Documentation/devicetree/bindings/graph.txt.
- Video port 0 for parallel input
- Video port 1 for LVDS output
Example
-------
lvds-encoder {
compatible = "lvds-encoder";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
lvds_enc_in: endpoint {
remote-endpoint = <&display_out_rgb>;
};
};
port@1 {
reg = <1>;
lvds_enc_out: endpoint {
remote-endpoint = <&lvds_panel_in>;
};
};
};
};

View File

@ -1,50 +0,0 @@
THine Electronics THC63LVDM83D LVDS serializer
----------------------------------------------
The THC63LVDM83D is an LVDS serializer designed to support pixel data
transmission between a host and a flat panel.
Required properties:
- compatible: Should be "thine,thc63lvdm83d"
Optional properties:
- powerdown-gpios: Power down control GPIO (the /PWDN pin, active low).
Required nodes:
The THC63LVDM83D has two video ports. Their connections are modeled using the
OFgraph bindings specified in Documentation/devicetree/bindings/graph.txt.
- Video port 0 for CMOS/TTL input
- Video port 1 for LVDS output
Example
-------
lvds_enc: encoder@0 {
compatible = "thine,thc63lvdm83d";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
lvds_enc_in: endpoint@0 {
remote-endpoint = <&rgb_out>;
};
};
port@1 {
reg = <1>;
lvds_enc_out: endpoint@0 {
remote-endpoint = <&panel_in>;
};
};
};
};

View File

@ -1,55 +0,0 @@
Texas Instruments FPD-Link (LVDS) Serializer
--------------------------------------------
The DS90C185 and DS90C187 are low-power serializers for portable
battery-powered applications that reduces the size of the RGB
interface between the host GPU and the display.
Required properties:
- compatible: Should be
"ti,ds90c185", "lvds-encoder" for the TI DS90C185 FPD-Link Serializer
"ti,ds90c187", "lvds-encoder" for the TI DS90C187 FPD-Link Serializer
Optional properties:
- powerdown-gpios: Power down control GPIO (the PDB pin, active-low)
Required nodes:
The devices have two video ports. Their connections are modeled using the OF
graph bindings specified in Documentation/devicetree/bindings/graph.txt.
- Video port 0 for parallel input
- Video port 1 for LVDS output
Example
-------
lvds-encoder {
compatible = "ti,ds90c185", "lvds-encoder";
powerdown-gpios = <&gpio 17 GPIO_ACTIVE_LOW>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
lvds_enc_in: endpoint {
remote-endpoint = <&lcdc_out_rgb>;
};
};
port@1 {
reg = <1>;
lvds_enc_out: endpoint {
remote-endpoint = <&lvds_panel_in>;
};
};
};
};

View File

@ -4,13 +4,16 @@ Rockchip specific extensions to the Synopsys Designware MIPI DSI
Required properties: Required properties:
- #address-cells: Should be <1>. - #address-cells: Should be <1>.
- #size-cells: Should be <0>. - #size-cells: Should be <0>.
- compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi". - compatible: one of
"rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi". "rockchip,px30-mipi-dsi", "snps,dw-mipi-dsi"
"rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi"
"rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi"
- reg: Represent the physical address range of the controller. - reg: Represent the physical address range of the controller.
- interrupts: Represent the controller's interrupt to the CPU(s). - interrupts: Represent the controller's interrupt to the CPU(s).
- clocks, clock-names: Phandles to the controller's pll reference - clocks, clock-names: Phandles to the controller's pll reference
clock(ref) and APB clock(pclk). For RK3399, a phy config clock clock(ref) when using an internal dphy and APB clock(pclk).
(phy_cfg) and a grf clock(grf) are required. As described in [1]. For RK3399, a phy config clock (phy_cfg) and a grf clock(grf)
are required. As described in [1].
- rockchip,grf: this soc should set GRF regs to mux vopl/vopb. - rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
- ports: contain a port node with endpoint definitions as defined in [2]. - ports: contain a port node with endpoint definitions as defined in [2].
For vopb,set the reg = <0> and set the reg = <1> for vopl. For vopb,set the reg = <0> and set the reg = <1> for vopl.
@ -18,6 +21,8 @@ Required properties:
- video port 1 for either a panel or subsequent encoder - video port 1 for either a panel or subsequent encoder
Optional properties: Optional properties:
- phys: from general PHY binding: the phandle for the PHY device.
- phy-names: Should be "dphy" if phys references an external phy.
- power-domains: a phandle to mipi dsi power domain node. - power-domains: a phandle to mipi dsi power domain node.
- resets: list of phandle + reset specifier pairs, as described in [3]. - resets: list of phandle + reset specifier pairs, as described in [3].
- reset-names: string reset name, must be "apb". - reset-names: string reset name, must be "apb".

View File

@ -15,7 +15,11 @@ properties:
const: 0 const: 0
compatible: compatible:
const: allwinner,sun6i-a31-mipi-dphy oneOf:
- const: allwinner,sun6i-a31-mipi-dphy
- items:
- const: allwinner,sun50i-a64-mipi-dphy
- const: allwinner,sun6i-a31-mipi-dphy
reg: reg:
maxItems: 1 maxItems: 1

View File

@ -65,6 +65,9 @@ Valid options are::
- reflect_y (boolean): Perform an axial symmetry on the Y axis - reflect_y (boolean): Perform an axial symmetry on the Y axis
- rotate (integer): Rotate the initial framebuffer by x - rotate (integer): Rotate the initial framebuffer by x
degrees. Valid values are 0, 90, 180 and 270. degrees. Valid values are 0, 90, 180 and 270.
- panel_orientation, one of "normal", "upside_down", "left_side_up", or
"right_side_up". For KMS drivers only, this sets the "panel orientation"
property on the kms connector as hint for kms users.
----------------------------------------------------------------------------- -----------------------------------------------------------------------------

View File

@ -142,14 +142,14 @@ Contact: Daniel Vetter, respective driver maintainers
Level: Advanced Level: Advanced
Convert instances of dev_info/dev_err/dev_warn to their DRM_DEV_* equivalent Convert logging to drm_* functions with drm_device paramater
---------------------------------------------------------------------------- ------------------------------------------------------------
For drivers which could have multiple instances, it is necessary to For drivers which could have multiple instances, it is necessary to
differentiate between which is which in the logs. Since DRM_INFO/WARN/ERROR differentiate between which is which in the logs. Since DRM_INFO/WARN/ERROR
don't do this, drivers used dev_info/warn/err to make this differentiation. We don't do this, drivers used dev_info/warn/err to make this differentiation. We
now have DRM_DEV_* variants of the drm print macros, so we can start to convert now have drm_* variants of the drm print functions, so we can start to convert
those drivers back to using drm-formwatted specific log messages. those drivers back to using drm-formatted specific log messages.
Before you start this conversion please contact the relevant maintainers to make Before you start this conversion please contact the relevant maintainers to make
sure your work will be merged - not everyone agrees that the DRM dmesg macros sure your work will be merged - not everyone agrees that the DRM dmesg macros

View File

@ -106,8 +106,8 @@ static long dma_heap_ioctl_allocate(struct file *file, void *data)
return 0; return 0;
} }
unsigned int dma_heap_ioctl_cmds[] = { static unsigned int dma_heap_ioctl_cmds[] = {
DMA_HEAP_IOC_ALLOC, DMA_HEAP_IOCTL_ALLOC,
}; };
static long dma_heap_ioctl(struct file *file, unsigned int ucmd, static long dma_heap_ioctl(struct file *file, unsigned int ucmd,
@ -153,11 +153,12 @@ static long dma_heap_ioctl(struct file *file, unsigned int ucmd,
memset(kdata + in_size, 0, ksize - in_size); memset(kdata + in_size, 0, ksize - in_size);
switch (kcmd) { switch (kcmd) {
case DMA_HEAP_IOC_ALLOC: case DMA_HEAP_IOCTL_ALLOC:
ret = dma_heap_ioctl_allocate(file, kdata); ret = dma_heap_ioctl_allocate(file, kdata);
break; break;
default: default:
return -ENOTTY; ret = -ENOTTY;
goto err;
} }
if (copy_to_user((void __user *)arg, kdata, out_size) != 0) if (copy_to_user((void __user *)arg, kdata, out_size) != 0)

View File

@ -109,7 +109,7 @@ static int system_heap_create(void)
struct dma_heap_export_info exp_info; struct dma_heap_export_info exp_info;
int ret = 0; int ret = 0;
exp_info.name = "system_heap"; exp_info.name = "system";
exp_info.ops = &system_heap_ops; exp_info.ops = &system_heap_ops;
exp_info.priv = NULL; exp_info.priv = NULL;

View File

@ -122,9 +122,8 @@ static int begin_cpu_udmabuf(struct dma_buf *buf,
if (IS_ERR(ubuf->sg)) if (IS_ERR(ubuf->sg))
return PTR_ERR(ubuf->sg); return PTR_ERR(ubuf->sg);
} else { } else {
dma_sync_sg_for_device(dev, ubuf->sg->sgl, dma_sync_sg_for_cpu(dev, ubuf->sg->sgl, ubuf->sg->nents,
ubuf->sg->nents, direction);
direction);
} }
return 0; return 0;
@ -139,7 +138,7 @@ static int end_cpu_udmabuf(struct dma_buf *buf,
if (!ubuf->sg) if (!ubuf->sg)
return -EINVAL; return -EINVAL;
dma_sync_sg_for_cpu(dev, ubuf->sg->sgl, ubuf->sg->nents, direction); dma_sync_sg_for_device(dev, ubuf->sg->sgl, ubuf->sg->nents, direction);
return 0; return 0;
} }

View File

@ -20,8 +20,10 @@ static u64 get_lpu_event(struct d71_pipeline *d71_pipeline)
evts |= KOMEDA_EVENT_IBSY; evts |= KOMEDA_EVENT_IBSY;
if (raw_status & LPU_IRQ_EOW) if (raw_status & LPU_IRQ_EOW)
evts |= KOMEDA_EVENT_EOW; evts |= KOMEDA_EVENT_EOW;
if (raw_status & LPU_IRQ_OVR)
evts |= KOMEDA_EVENT_OVR;
if (raw_status & (LPU_IRQ_ERR | LPU_IRQ_IBSY)) { if (raw_status & (LPU_IRQ_ERR | LPU_IRQ_IBSY | LPU_IRQ_OVR)) {
u32 restore = 0, tbu_status; u32 restore = 0, tbu_status;
/* Check error of LPU status */ /* Check error of LPU status */
status = malidp_read32(reg, BLK_STATUS); status = malidp_read32(reg, BLK_STATUS);
@ -45,6 +47,15 @@ static u64 get_lpu_event(struct d71_pipeline *d71_pipeline)
restore |= LPU_STATUS_ACE3; restore |= LPU_STATUS_ACE3;
evts |= KOMEDA_ERR_ACE3; evts |= KOMEDA_ERR_ACE3;
} }
if (status & LPU_STATUS_FEMPTY) {
restore |= LPU_STATUS_FEMPTY;
evts |= KOMEDA_EVENT_EMPTY;
}
if (status & LPU_STATUS_FFULL) {
restore |= LPU_STATUS_FFULL;
evts |= KOMEDA_EVENT_FULL;
}
if (restore != 0) if (restore != 0)
malidp_write32_mask(reg, BLK_STATUS, restore, 0); malidp_write32_mask(reg, BLK_STATUS, restore, 0);

View File

@ -175,6 +175,7 @@
#define TBU_DOUTSTDCAPB_MASK 0x3F #define TBU_DOUTSTDCAPB_MASK 0x3F
/* LPU_IRQ_BITS */ /* LPU_IRQ_BITS */
#define LPU_IRQ_OVR BIT(9)
#define LPU_IRQ_IBSY BIT(10) #define LPU_IRQ_IBSY BIT(10)
#define LPU_IRQ_ERR BIT(11) #define LPU_IRQ_ERR BIT(11)
#define LPU_IRQ_EOW BIT(12) #define LPU_IRQ_EOW BIT(12)
@ -185,6 +186,8 @@
#define LPU_STATUS_AXIE BIT(4) #define LPU_STATUS_AXIE BIT(4)
#define LPU_STATUS_AXIRP BIT(5) #define LPU_STATUS_AXIRP BIT(5)
#define LPU_STATUS_AXIWP BIT(6) #define LPU_STATUS_AXIWP BIT(6)
#define LPU_STATUS_FEMPTY BIT(11)
#define LPU_STATUS_FFULL BIT(14)
#define LPU_STATUS_ACE0 BIT(16) #define LPU_STATUS_ACE0 BIT(16)
#define LPU_STATUS_ACE1 BIT(17) #define LPU_STATUS_ACE1 BIT(17)
#define LPU_STATUS_ACE2 BIT(18) #define LPU_STATUS_ACE2 BIT(18)

View File

@ -5,6 +5,7 @@
* *
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
@ -274,6 +275,7 @@ static void
komeda_crtc_atomic_enable(struct drm_crtc *crtc, komeda_crtc_atomic_enable(struct drm_crtc *crtc,
struct drm_crtc_state *old) struct drm_crtc_state *old)
{ {
pm_runtime_get_sync(crtc->dev->dev);
komeda_crtc_prepare(to_kcrtc(crtc)); komeda_crtc_prepare(to_kcrtc(crtc));
drm_crtc_vblank_on(crtc); drm_crtc_vblank_on(crtc);
WARN_ON(drm_crtc_vblank_get(crtc)); WARN_ON(drm_crtc_vblank_get(crtc));
@ -372,6 +374,7 @@ komeda_crtc_atomic_disable(struct drm_crtc *crtc,
drm_crtc_vblank_put(crtc); drm_crtc_vblank_put(crtc);
drm_crtc_vblank_off(crtc); drm_crtc_vblank_off(crtc);
komeda_crtc_unprepare(kcrtc); komeda_crtc_unprepare(kcrtc);
pm_runtime_put(crtc->dev->dev);
} }
static void static void

View File

@ -10,6 +10,7 @@
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/of_reserved_mem.h> #include <linux/of_reserved_mem.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h> #include <linux/debugfs.h>
@ -27,12 +28,16 @@ static int komeda_register_show(struct seq_file *sf, void *x)
seq_puts(sf, "\n====== Komeda register dump =========\n"); seq_puts(sf, "\n====== Komeda register dump =========\n");
pm_runtime_get_sync(mdev->dev);
if (mdev->funcs->dump_register) if (mdev->funcs->dump_register)
mdev->funcs->dump_register(mdev, sf); mdev->funcs->dump_register(mdev, sf);
for (i = 0; i < mdev->n_pipelines; i++) for (i = 0; i < mdev->n_pipelines; i++)
komeda_pipeline_dump_register(mdev->pipelines[i], sf); komeda_pipeline_dump_register(mdev->pipelines[i], sf);
pm_runtime_put(mdev->dev);
return 0; return 0;
} }
@ -263,15 +268,6 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
if (!mdev->iommu) if (!mdev->iommu)
DRM_INFO("continue without IOMMU support!\n"); DRM_INFO("continue without IOMMU support!\n");
if (mdev->iommu && mdev->funcs->connect_iommu) {
err = mdev->funcs->connect_iommu(mdev);
if (err) {
DRM_ERROR("connect iommu failed.\n");
mdev->iommu = NULL;
goto disable_clk;
}
}
clk_disable_unprepare(mdev->aclk); clk_disable_unprepare(mdev->aclk);
err = sysfs_create_group(&dev->kobj, &komeda_sysfs_attr_group); err = sysfs_create_group(&dev->kobj, &komeda_sysfs_attr_group);
@ -310,11 +306,6 @@ void komeda_dev_destroy(struct komeda_dev *mdev)
if (mdev->aclk) if (mdev->aclk)
clk_prepare_enable(mdev->aclk); clk_prepare_enable(mdev->aclk);
if (mdev->iommu && mdev->funcs->disconnect_iommu)
if (mdev->funcs->disconnect_iommu(mdev))
DRM_ERROR("disconnect iommu failed.\n");
mdev->iommu = NULL;
for (i = 0; i < mdev->n_pipelines; i++) { for (i = 0; i < mdev->n_pipelines; i++) {
komeda_pipeline_destroy(mdev, mdev->pipelines[i]); komeda_pipeline_destroy(mdev, mdev->pipelines[i]);
mdev->pipelines[i] = NULL; mdev->pipelines[i] = NULL;
@ -343,44 +334,26 @@ void komeda_dev_destroy(struct komeda_dev *mdev)
int komeda_dev_resume(struct komeda_dev *mdev) int komeda_dev_resume(struct komeda_dev *mdev)
{ {
int ret = 0;
clk_prepare_enable(mdev->aclk); clk_prepare_enable(mdev->aclk);
if (mdev->iommu && mdev->funcs->connect_iommu) { mdev->funcs->enable_irq(mdev);
ret = mdev->funcs->connect_iommu(mdev);
if (ret < 0) { if (mdev->iommu && mdev->funcs->connect_iommu)
if (mdev->funcs->connect_iommu(mdev))
DRM_ERROR("connect iommu failed.\n"); DRM_ERROR("connect iommu failed.\n");
goto disable_clk;
}
}
ret = mdev->funcs->enable_irq(mdev); return 0;
disable_clk:
clk_disable_unprepare(mdev->aclk);
return ret;
} }
int komeda_dev_suspend(struct komeda_dev *mdev) int komeda_dev_suspend(struct komeda_dev *mdev)
{ {
int ret = 0; if (mdev->iommu && mdev->funcs->disconnect_iommu)
if (mdev->funcs->disconnect_iommu(mdev))
clk_prepare_enable(mdev->aclk);
if (mdev->iommu && mdev->funcs->disconnect_iommu) {
ret = mdev->funcs->disconnect_iommu(mdev);
if (ret < 0) {
DRM_ERROR("disconnect iommu failed.\n"); DRM_ERROR("disconnect iommu failed.\n");
goto disable_clk;
}
}
ret = mdev->funcs->disable_irq(mdev); mdev->funcs->disable_irq(mdev);
disable_clk:
clk_disable_unprepare(mdev->aclk); clk_disable_unprepare(mdev->aclk);
return ret; return 0;
} }

View File

@ -20,6 +20,8 @@
#define KOMEDA_EVENT_OVR BIT_ULL(4) #define KOMEDA_EVENT_OVR BIT_ULL(4)
#define KOMEDA_EVENT_EOW BIT_ULL(5) #define KOMEDA_EVENT_EOW BIT_ULL(5)
#define KOMEDA_EVENT_MODE BIT_ULL(6) #define KOMEDA_EVENT_MODE BIT_ULL(6)
#define KOMEDA_EVENT_FULL BIT_ULL(7)
#define KOMEDA_EVENT_EMPTY BIT_ULL(8)
#define KOMEDA_ERR_TETO BIT_ULL(14) #define KOMEDA_ERR_TETO BIT_ULL(14)
#define KOMEDA_ERR_TEMR BIT_ULL(15) #define KOMEDA_ERR_TEMR BIT_ULL(15)
@ -49,7 +51,8 @@
KOMEDA_ERR_ZME | KOMEDA_ERR_MERR | KOMEDA_ERR_TCF |\ KOMEDA_ERR_ZME | KOMEDA_ERR_MERR | KOMEDA_ERR_TCF |\
KOMEDA_ERR_TTNG | KOMEDA_ERR_TTF) KOMEDA_ERR_TTNG | KOMEDA_ERR_TTF)
#define KOMEDA_WARN_EVENTS KOMEDA_ERR_CSCE #define KOMEDA_WARN_EVENTS \
(KOMEDA_ERR_CSCE | KOMEDA_EVENT_FULL | KOMEDA_EVENT_EMPTY)
#define KOMEDA_INFO_EVENTS (0 \ #define KOMEDA_INFO_EVENTS (0 \
| KOMEDA_EVENT_VSYNC \ | KOMEDA_EVENT_VSYNC \

View File

@ -33,6 +33,12 @@ static void komeda_unbind(struct device *dev)
return; return;
komeda_kms_detach(mdrv->kms); komeda_kms_detach(mdrv->kms);
if (pm_runtime_enabled(dev))
pm_runtime_disable(dev);
else
komeda_dev_suspend(mdrv->mdev);
komeda_dev_destroy(mdrv->mdev); komeda_dev_destroy(mdrv->mdev);
dev_set_drvdata(dev, NULL); dev_set_drvdata(dev, NULL);
@ -54,6 +60,10 @@ static int komeda_bind(struct device *dev)
goto free_mdrv; goto free_mdrv;
} }
pm_runtime_enable(dev);
if (!pm_runtime_enabled(dev))
komeda_dev_resume(mdrv->mdev);
mdrv->kms = komeda_kms_attach(mdrv->mdev); mdrv->kms = komeda_kms_attach(mdrv->mdev);
if (IS_ERR(mdrv->kms)) { if (IS_ERR(mdrv->kms)) {
err = PTR_ERR(mdrv->kms); err = PTR_ERR(mdrv->kms);
@ -65,6 +75,11 @@ static int komeda_bind(struct device *dev)
return 0; return 0;
destroy_mdev: destroy_mdev:
if (pm_runtime_enabled(dev))
pm_runtime_disable(dev);
else
komeda_dev_suspend(mdrv->mdev);
komeda_dev_destroy(mdrv->mdev); komeda_dev_destroy(mdrv->mdev);
free_mdrv: free_mdrv:
@ -131,15 +146,29 @@ static const struct of_device_id komeda_of_match[] = {
MODULE_DEVICE_TABLE(of, komeda_of_match); MODULE_DEVICE_TABLE(of, komeda_of_match);
static int komeda_rt_pm_suspend(struct device *dev)
{
struct komeda_drv *mdrv = dev_get_drvdata(dev);
return komeda_dev_suspend(mdrv->mdev);
}
static int komeda_rt_pm_resume(struct device *dev)
{
struct komeda_drv *mdrv = dev_get_drvdata(dev);
return komeda_dev_resume(mdrv->mdev);
}
static int __maybe_unused komeda_pm_suspend(struct device *dev) static int __maybe_unused komeda_pm_suspend(struct device *dev)
{ {
struct komeda_drv *mdrv = dev_get_drvdata(dev); struct komeda_drv *mdrv = dev_get_drvdata(dev);
struct drm_device *drm = &mdrv->kms->base;
int res; int res;
res = drm_mode_config_helper_suspend(drm); res = drm_mode_config_helper_suspend(&mdrv->kms->base);
komeda_dev_suspend(mdrv->mdev); if (!pm_runtime_status_suspended(dev))
komeda_dev_suspend(mdrv->mdev);
return res; return res;
} }
@ -147,15 +176,16 @@ static int __maybe_unused komeda_pm_suspend(struct device *dev)
static int __maybe_unused komeda_pm_resume(struct device *dev) static int __maybe_unused komeda_pm_resume(struct device *dev)
{ {
struct komeda_drv *mdrv = dev_get_drvdata(dev); struct komeda_drv *mdrv = dev_get_drvdata(dev);
struct drm_device *drm = &mdrv->kms->base;
komeda_dev_resume(mdrv->mdev); if (!pm_runtime_status_suspended(dev))
komeda_dev_resume(mdrv->mdev);
return drm_mode_config_helper_resume(drm); return drm_mode_config_helper_resume(&mdrv->kms->base);
} }
static const struct dev_pm_ops komeda_pm_ops = { static const struct dev_pm_ops komeda_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(komeda_pm_suspend, komeda_pm_resume) SET_SYSTEM_SLEEP_PM_OPS(komeda_pm_suspend, komeda_pm_resume)
SET_RUNTIME_PM_OPS(komeda_rt_pm_suspend, komeda_rt_pm_resume, NULL)
}; };
static struct platform_driver komeda_platform_driver = { static struct platform_driver komeda_platform_driver = {

View File

@ -78,6 +78,8 @@ static void evt_str(struct komeda_str *str, u64 events)
/* LPU errors or events */ /* LPU errors or events */
evt_sprintf(str, events & KOMEDA_EVENT_IBSY, "IBSY|"); evt_sprintf(str, events & KOMEDA_EVENT_IBSY, "IBSY|");
evt_sprintf(str, events & KOMEDA_EVENT_EMPTY, "EMPTY|");
evt_sprintf(str, events & KOMEDA_EVENT_FULL, "FULL|");
evt_sprintf(str, events & KOMEDA_ERR_AXIE, "AXIE|"); evt_sprintf(str, events & KOMEDA_ERR_AXIE, "AXIE|");
evt_sprintf(str, events & KOMEDA_ERR_ACE0, "ACE0|"); evt_sprintf(str, events & KOMEDA_ERR_ACE0, "ACE0|");
evt_sprintf(str, events & KOMEDA_ERR_ACE1, "ACE1|"); evt_sprintf(str, events & KOMEDA_ERR_ACE1, "ACE1|");

View File

@ -308,10 +308,6 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
if (err) if (err)
goto free_component_binding; goto free_component_binding;
err = mdev->funcs->enable_irq(mdev);
if (err)
goto free_component_binding;
drm->irq_enabled = true; drm->irq_enabled = true;
drm_kms_helper_poll_init(drm); drm_kms_helper_poll_init(drm);
@ -325,7 +321,6 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
free_interrupts: free_interrupts:
drm_kms_helper_poll_fini(drm); drm_kms_helper_poll_fini(drm);
drm->irq_enabled = false; drm->irq_enabled = false;
mdev->funcs->disable_irq(mdev);
free_component_binding: free_component_binding:
component_unbind_all(mdev->dev, drm); component_unbind_all(mdev->dev, drm);
cleanup_mode_config: cleanup_mode_config:
@ -347,7 +342,6 @@ void komeda_kms_detach(struct komeda_kms_dev *kms)
drm_kms_helper_poll_fini(drm); drm_kms_helper_poll_fini(drm);
drm_atomic_helper_shutdown(drm); drm_atomic_helper_shutdown(drm);
drm->irq_enabled = false; drm->irq_enabled = false;
mdev->funcs->disable_irq(mdev);
component_unbind_all(mdev->dev, drm); component_unbind_all(mdev->dev, drm);
drm_mode_config_cleanup(drm); drm_mode_config_cleanup(drm);
komeda_kms_cleanup_private_objs(kms); komeda_kms_cleanup_private_objs(kms);

View File

@ -512,7 +512,7 @@ static int malidp_de_plane_check(struct drm_plane *plane,
int i, ret; int i, ret;
unsigned int block_w, block_h; unsigned int block_w, block_h;
if (!state->crtc || !state->fb) if (!state->crtc || WARN_ON(!state->fb))
return 0; return 0;
fb = state->fb; fb = state->fb;

View File

@ -255,7 +255,7 @@ void bochs_hw_setformat(struct bochs_device *bochs,
DRM_ERROR("%s: Huh? Got framebuffer format 0x%x", DRM_ERROR("%s: Huh? Got framebuffer format 0x%x",
__func__, format->format); __func__, format->format);
break; break;
}; }
} }
void bochs_hw_setbase(struct bochs_device *bochs, void bochs_hw_setbase(struct bochs_device *bochs,

View File

@ -35,14 +35,14 @@ config DRM_DUMB_VGA_DAC
Support for non-programmable RGB to VGA DAC bridges, such as ADI Support for non-programmable RGB to VGA DAC bridges, such as ADI
ADV7123, TI THS8134 and THS8135 or passive resistor ladder DACs. ADV7123, TI THS8134 and THS8135 or passive resistor ladder DACs.
config DRM_LVDS_ENCODER config DRM_LVDS_CODEC
tristate "Transparent parallel to LVDS encoder support" tristate "Transparent LVDS encoders and decoders support"
depends on OF depends on OF
select DRM_KMS_HELPER select DRM_KMS_HELPER
select DRM_PANEL_BRIDGE select DRM_PANEL_BRIDGE
help help
Support for transparent parallel to LVDS encoders that don't require Support for transparent LVDS encoders and decoders that don't
any configuration. require any configuration.
config DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW config DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW
tristate "MegaChips stdp4028-ge-b850v3-fw and stdp2690-ge-b850v3-fw" tristate "MegaChips stdp4028-ge-b850v3-fw and stdp2690-ge-b850v3-fw"

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o
obj-$(CONFIG_DRM_LVDS_ENCODER) += lvds-encoder.o obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o
obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o

View File

@ -0,0 +1,151 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2019 Renesas Electronics Corporation
* Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*/
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <drm/drm_bridge.h>
#include <drm/drm_panel.h>
struct lvds_codec {
struct drm_bridge bridge;
struct drm_bridge *panel_bridge;
struct gpio_desc *powerdown_gpio;
u32 connector_type;
};
static int lvds_codec_attach(struct drm_bridge *bridge)
{
struct lvds_codec *lvds_codec = container_of(bridge,
struct lvds_codec, bridge);
return drm_bridge_attach(bridge->encoder, lvds_codec->panel_bridge,
bridge);
}
static void lvds_codec_enable(struct drm_bridge *bridge)
{
struct lvds_codec *lvds_codec = container_of(bridge,
struct lvds_codec, bridge);
if (lvds_codec->powerdown_gpio)
gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 0);
}
static void lvds_codec_disable(struct drm_bridge *bridge)
{
struct lvds_codec *lvds_codec = container_of(bridge,
struct lvds_codec, bridge);
if (lvds_codec->powerdown_gpio)
gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 1);
}
static struct drm_bridge_funcs funcs = {
.attach = lvds_codec_attach,
.enable = lvds_codec_enable,
.disable = lvds_codec_disable,
};
static int lvds_codec_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *panel_node;
struct drm_panel *panel;
struct lvds_codec *lvds_codec;
lvds_codec = devm_kzalloc(dev, sizeof(*lvds_codec), GFP_KERNEL);
if (!lvds_codec)
return -ENOMEM;
lvds_codec->connector_type = (uintptr_t)of_device_get_match_data(dev);
lvds_codec->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
GPIOD_OUT_HIGH);
if (IS_ERR(lvds_codec->powerdown_gpio)) {
int err = PTR_ERR(lvds_codec->powerdown_gpio);
if (err != -EPROBE_DEFER)
dev_err(dev, "powerdown GPIO failure: %d\n", err);
return err;
}
/* Locate the panel DT node. */
panel_node = of_graph_get_remote_node(dev->of_node, 1, 0);
if (!panel_node) {
dev_dbg(dev, "panel DT node not found\n");
return -ENXIO;
}
panel = of_drm_find_panel(panel_node);
of_node_put(panel_node);
if (IS_ERR(panel)) {
dev_dbg(dev, "panel not found, deferring probe\n");
return PTR_ERR(panel);
}
lvds_codec->panel_bridge =
devm_drm_panel_bridge_add_typed(dev, panel,
lvds_codec->connector_type);
if (IS_ERR(lvds_codec->panel_bridge))
return PTR_ERR(lvds_codec->panel_bridge);
/*
* The panel_bridge bridge is attached to the panel's of_node,
* but we need a bridge attached to our of_node for our user
* to look up.
*/
lvds_codec->bridge.of_node = dev->of_node;
lvds_codec->bridge.funcs = &funcs;
drm_bridge_add(&lvds_codec->bridge);
platform_set_drvdata(pdev, lvds_codec);
return 0;
}
static int lvds_codec_remove(struct platform_device *pdev)
{
struct lvds_codec *lvds_codec = platform_get_drvdata(pdev);
drm_bridge_remove(&lvds_codec->bridge);
return 0;
}
static const struct of_device_id lvds_codec_match[] = {
{
.compatible = "lvds-decoder",
.data = (void *)DRM_MODE_CONNECTOR_DPI,
},
{
.compatible = "lvds-encoder",
.data = (void *)DRM_MODE_CONNECTOR_LVDS,
},
{
.compatible = "thine,thc63lvdm83d",
.data = (void *)DRM_MODE_CONNECTOR_LVDS,
},
{},
};
MODULE_DEVICE_TABLE(of, lvds_codec_match);
static struct platform_driver lvds_codec_driver = {
.probe = lvds_codec_probe,
.remove = lvds_codec_remove,
.driver = {
.name = "lvds-codec",
.of_match_table = lvds_codec_match,
},
};
module_platform_driver(lvds_codec_driver);
MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
MODULE_DESCRIPTION("LVDS encoders and decoders");
MODULE_LICENSE("GPL");

View File

@ -1,155 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*/
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <drm/drm_bridge.h>
#include <drm/drm_panel.h>
struct lvds_encoder {
struct drm_bridge bridge;
struct drm_bridge *panel_bridge;
struct gpio_desc *powerdown_gpio;
};
static int lvds_encoder_attach(struct drm_bridge *bridge)
{
struct lvds_encoder *lvds_encoder = container_of(bridge,
struct lvds_encoder,
bridge);
return drm_bridge_attach(bridge->encoder, lvds_encoder->panel_bridge,
bridge);
}
static void lvds_encoder_enable(struct drm_bridge *bridge)
{
struct lvds_encoder *lvds_encoder = container_of(bridge,
struct lvds_encoder,
bridge);
if (lvds_encoder->powerdown_gpio)
gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 0);
}
static void lvds_encoder_disable(struct drm_bridge *bridge)
{
struct lvds_encoder *lvds_encoder = container_of(bridge,
struct lvds_encoder,
bridge);
if (lvds_encoder->powerdown_gpio)
gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 1);
}
static struct drm_bridge_funcs funcs = {
.attach = lvds_encoder_attach,
.enable = lvds_encoder_enable,
.disable = lvds_encoder_disable,
};
static int lvds_encoder_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *port;
struct device_node *endpoint;
struct device_node *panel_node;
struct drm_panel *panel;
struct lvds_encoder *lvds_encoder;
lvds_encoder = devm_kzalloc(dev, sizeof(*lvds_encoder), GFP_KERNEL);
if (!lvds_encoder)
return -ENOMEM;
lvds_encoder->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
GPIOD_OUT_HIGH);
if (IS_ERR(lvds_encoder->powerdown_gpio)) {
int err = PTR_ERR(lvds_encoder->powerdown_gpio);
if (err != -EPROBE_DEFER)
dev_err(dev, "powerdown GPIO failure: %d\n", err);
return err;
}
/* Locate the panel DT node. */
port = of_graph_get_port_by_id(dev->of_node, 1);
if (!port) {
dev_dbg(dev, "port 1 not found\n");
return -ENXIO;
}
endpoint = of_get_child_by_name(port, "endpoint");
of_node_put(port);
if (!endpoint) {
dev_dbg(dev, "no endpoint for port 1\n");
return -ENXIO;
}
panel_node = of_graph_get_remote_port_parent(endpoint);
of_node_put(endpoint);
if (!panel_node) {
dev_dbg(dev, "no remote endpoint for port 1\n");
return -ENXIO;
}
panel = of_drm_find_panel(panel_node);
of_node_put(panel_node);
if (IS_ERR(panel)) {
dev_dbg(dev, "panel not found, deferring probe\n");
return PTR_ERR(panel);
}
lvds_encoder->panel_bridge =
devm_drm_panel_bridge_add_typed(dev, panel,
DRM_MODE_CONNECTOR_LVDS);
if (IS_ERR(lvds_encoder->panel_bridge))
return PTR_ERR(lvds_encoder->panel_bridge);
/* The panel_bridge bridge is attached to the panel's of_node,
* but we need a bridge attached to our of_node for our user
* to look up.
*/
lvds_encoder->bridge.of_node = dev->of_node;
lvds_encoder->bridge.funcs = &funcs;
drm_bridge_add(&lvds_encoder->bridge);
platform_set_drvdata(pdev, lvds_encoder);
return 0;
}
static int lvds_encoder_remove(struct platform_device *pdev)
{
struct lvds_encoder *lvds_encoder = platform_get_drvdata(pdev);
drm_bridge_remove(&lvds_encoder->bridge);
return 0;
}
static const struct of_device_id lvds_encoder_match[] = {
{ .compatible = "lvds-encoder" },
{ .compatible = "thine,thc63lvdm83d" },
{},
};
MODULE_DEVICE_TABLE(of, lvds_encoder_match);
static struct platform_driver lvds_encoder_driver = {
.probe = lvds_encoder_probe,
.remove = lvds_encoder_remove,
.driver = {
.name = "lvds-encoder",
.of_match_table = lvds_encoder_match,
},
};
module_platform_driver(lvds_encoder_driver);
MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
MODULE_DESCRIPTION("Transparent parallel to LVDS encoder");
MODULE_LICENSE("GPL");

View File

@ -719,7 +719,15 @@ static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi,
static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi)
{ {
const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
struct dw_mipi_dsi_dphy_timing timing;
u32 hw_version; u32 hw_version;
int ret;
ret = phy_ops->get_timing(dsi->plat_data->priv_data,
dsi->lane_mbps, &timing);
if (ret)
DRM_DEV_ERROR(dsi->dev, "Retrieving phy timings failed\n");
/* /*
* TODO dw drv improvements * TODO dw drv improvements
@ -732,16 +740,20 @@ static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi)
hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; hw_version = dsi_read(dsi, DSI_VERSION) & VERSION;
if (hw_version >= HWVER_131) { if (hw_version >= HWVER_131) {
dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME_V131(0x40) | dsi_write(dsi, DSI_PHY_TMR_CFG,
PHY_LP2HS_TIME_V131(0x40)); PHY_HS2LP_TIME_V131(timing.data_hs2lp) |
PHY_LP2HS_TIME_V131(timing.data_lp2hs));
dsi_write(dsi, DSI_PHY_TMR_RD_CFG, MAX_RD_TIME_V131(10000)); dsi_write(dsi, DSI_PHY_TMR_RD_CFG, MAX_RD_TIME_V131(10000));
} else { } else {
dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40) | dsi_write(dsi, DSI_PHY_TMR_CFG,
PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000)); PHY_HS2LP_TIME(timing.data_hs2lp) |
PHY_LP2HS_TIME(timing.data_lp2hs) |
MAX_RD_TIME(10000));
} }
dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40) dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG,
| PHY_CLKLP2HS_TIME(0x40)); PHY_CLKHS2LP_TIME(timing.clk_hs2lp) |
PHY_CLKLP2HS_TIME(timing.clk_lp2hs));
} }
static void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi) static void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi)
@ -798,9 +810,6 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
if (phy_ops->power_off)
phy_ops->power_off(dsi->plat_data->priv_data);
/* /*
* Switch to command mode before panel-bridge post_disable & * Switch to command mode before panel-bridge post_disable &
* panel unprepare. * panel unprepare.
@ -817,6 +826,9 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
*/ */
dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge); dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge);
if (phy_ops->power_off)
phy_ops->power_off(dsi->plat_data->priv_data);
if (dsi->slave) { if (dsi->slave) {
dw_mipi_dsi_disable(dsi->slave); dw_mipi_dsi_disable(dsi->slave);
clk_disable_unprepare(dsi->slave->pclk); clk_disable_unprepare(dsi->slave->pclk);
@ -883,6 +895,9 @@ static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi,
/* Switch to cmd mode for panel-bridge pre_enable & panel prepare */ /* Switch to cmd mode for panel-bridge pre_enable & panel prepare */
dw_mipi_dsi_set_mode(dsi, 0); dw_mipi_dsi_set_mode(dsi, 0);
if (phy_ops->power_on)
phy_ops->power_on(dsi->plat_data->priv_data);
} }
static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
@ -899,15 +914,11 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge) static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge)
{ {
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
/* Switch to video mode for panel-bridge enable & panel enable */ /* Switch to video mode for panel-bridge enable & panel enable */
dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO); dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO);
if (dsi->slave) if (dsi->slave)
dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO); dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO);
if (phy_ops->power_on)
phy_ops->power_on(dsi->plat_data->priv_data);
} }
static enum drm_mode_status static enum drm_mode_status
@ -991,7 +1002,8 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
dsi->dev = dev; dsi->dev = dev;
dsi->plat_data = plat_data; dsi->plat_data = plat_data;
if (!plat_data->phy_ops->init || !plat_data->phy_ops->get_lane_mbps) { if (!plat_data->phy_ops->init || !plat_data->phy_ops->get_lane_mbps ||
!plat_data->phy_ops->get_timing) {
DRM_ERROR("Phy not properly configured\n"); DRM_ERROR("Phy not properly configured\n");
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }

View File

@ -251,7 +251,7 @@ EXPORT_SYMBOL(drm_atomic_state_clear);
* @ref: This atomic state to deallocate * @ref: This atomic state to deallocate
* *
* This frees all memory associated with an atomic state, including all the * This frees all memory associated with an atomic state, including all the
* per-object state for planes, crtcs and connectors. * per-object state for planes, CRTCs and connectors.
*/ */
void __drm_atomic_state_free(struct kref *ref) void __drm_atomic_state_free(struct kref *ref)
{ {
@ -272,12 +272,12 @@ void __drm_atomic_state_free(struct kref *ref)
EXPORT_SYMBOL(__drm_atomic_state_free); EXPORT_SYMBOL(__drm_atomic_state_free);
/** /**
* drm_atomic_get_crtc_state - get crtc state * drm_atomic_get_crtc_state - get CRTC state
* @state: global atomic state object * @state: global atomic state object
* @crtc: crtc to get state object for * @crtc: CRTC to get state object for
* *
* This function returns the crtc state for the given crtc, allocating it if * This function returns the CRTC state for the given CRTC, allocating it if
* needed. It will also grab the relevant crtc lock to make sure that the state * needed. It will also grab the relevant CRTC lock to make sure that the state
* is consistent. * is consistent.
* *
* Returns: * Returns:
@ -1018,14 +1018,14 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
} }
/** /**
* drm_atomic_add_affected_connectors - add connectors for crtc * drm_atomic_add_affected_connectors - add connectors for CRTC
* @state: atomic state * @state: atomic state
* @crtc: DRM crtc * @crtc: DRM CRTC
* *
* This function walks the current configuration and adds all connectors * This function walks the current configuration and adds all connectors
* currently using @crtc to the atomic configuration @state. Note that this * currently using @crtc to the atomic configuration @state. Note that this
* function must acquire the connection mutex. This can potentially cause * function must acquire the connection mutex. This can potentially cause
* unneeded seralization if the update is just for the planes on one crtc. Hence * unneeded seralization if the update is just for the planes on one CRTC. Hence
* drivers and helpers should only call this when really needed (e.g. when a * drivers and helpers should only call this when really needed (e.g. when a
* full modeset needs to happen due to some change). * full modeset needs to happen due to some change).
* *
@ -1078,9 +1078,9 @@ drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
EXPORT_SYMBOL(drm_atomic_add_affected_connectors); EXPORT_SYMBOL(drm_atomic_add_affected_connectors);
/** /**
* drm_atomic_add_affected_planes - add planes for crtc * drm_atomic_add_affected_planes - add planes for CRTC
* @state: atomic state * @state: atomic state
* @crtc: DRM crtc * @crtc: DRM CRTC
* *
* This function walks the current configuration and adds all planes * This function walks the current configuration and adds all planes
* currently used by @crtc to the atomic configuration @state. This is useful * currently used by @crtc to the atomic configuration @state. This is useful

View File

@ -150,8 +150,8 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state,
* is not set, an error is returned. Userspace can provide a solution * is not set, an error is returned. Userspace can provide a solution
* through the atomic ioctl. * through the atomic ioctl.
* *
* If the flag is set conflicting connectors are removed from the crtc * If the flag is set conflicting connectors are removed from the CRTC
* and the crtc is disabled if no encoder is left. This preserves * and the CRTC is disabled if no encoder is left. This preserves
* compatibility with the legacy set_config behavior. * compatibility with the legacy set_config behavior.
*/ */
drm_connector_list_iter_begin(state->dev, &conn_iter); drm_connector_list_iter_begin(state->dev, &conn_iter);
@ -220,7 +220,7 @@ set_best_encoder(struct drm_atomic_state *state,
crtc = conn_state->connector->state->crtc; crtc = conn_state->connector->state->crtc;
/* A NULL crtc is an error here because we should have /* A NULL crtc is an error here because we should have
* duplicated a NULL best_encoder when crtc was NULL. * duplicated a NULL best_encoder when crtc was NULL.
* As an exception restoring duplicated atomic state * As an exception restoring duplicated atomic state
* during resume is allowed, so don't warn when * during resume is allowed, so don't warn when
* best_encoder is equal to encoder we intend to set. * best_encoder is equal to encoder we intend to set.
@ -561,27 +561,27 @@ mode_valid(struct drm_atomic_state *state)
* @state: the driver state object * @state: the driver state object
* *
* Check the state object to see if the requested state is physically possible. * Check the state object to see if the requested state is physically possible.
* This does all the crtc and connector related computations for an atomic * This does all the CRTC and connector related computations for an atomic
* update and adds any additional connectors needed for full modesets. It calls * update and adds any additional connectors needed for full modesets. It calls
* the various per-object callbacks in the follow order: * the various per-object callbacks in the follow order:
* *
* 1. &drm_connector_helper_funcs.atomic_best_encoder for determining the new encoder. * 1. &drm_connector_helper_funcs.atomic_best_encoder for determining the new encoder.
* 2. &drm_connector_helper_funcs.atomic_check to validate the connector state. * 2. &drm_connector_helper_funcs.atomic_check to validate the connector state.
* 3. If it's determined a modeset is needed then all connectors on the affected crtc * 3. If it's determined a modeset is needed then all connectors on the affected
* crtc are added and &drm_connector_helper_funcs.atomic_check is run on them. * CRTC are added and &drm_connector_helper_funcs.atomic_check is run on them.
* 4. &drm_encoder_helper_funcs.mode_valid, &drm_bridge_funcs.mode_valid and * 4. &drm_encoder_helper_funcs.mode_valid, &drm_bridge_funcs.mode_valid and
* &drm_crtc_helper_funcs.mode_valid are called on the affected components. * &drm_crtc_helper_funcs.mode_valid are called on the affected components.
* 5. &drm_bridge_funcs.mode_fixup is called on all encoder bridges. * 5. &drm_bridge_funcs.mode_fixup is called on all encoder bridges.
* 6. &drm_encoder_helper_funcs.atomic_check is called to validate any encoder state. * 6. &drm_encoder_helper_funcs.atomic_check is called to validate any encoder state.
* This function is only called when the encoder will be part of a configured crtc, * This function is only called when the encoder will be part of a configured CRTC,
* it must not be used for implementing connector property validation. * it must not be used for implementing connector property validation.
* If this function is NULL, &drm_atomic_encoder_helper_funcs.mode_fixup is called * If this function is NULL, &drm_atomic_encoder_helper_funcs.mode_fixup is called
* instead. * instead.
* 7. &drm_crtc_helper_funcs.mode_fixup is called last, to fix up the mode with crtc constraints. * 7. &drm_crtc_helper_funcs.mode_fixup is called last, to fix up the mode with CRTC constraints.
* *
* &drm_crtc_state.mode_changed is set when the input mode is changed. * &drm_crtc_state.mode_changed is set when the input mode is changed.
* &drm_crtc_state.connectors_changed is set when a connector is added or * &drm_crtc_state.connectors_changed is set when a connector is added or
* removed from the crtc. &drm_crtc_state.active_changed is set when * removed from the CRTC. &drm_crtc_state.active_changed is set when
* &drm_crtc_state.active changes, which is used for DPMS. * &drm_crtc_state.active changes, which is used for DPMS.
* See also: drm_atomic_crtc_needs_modeset() * See also: drm_atomic_crtc_needs_modeset()
* *
@ -692,7 +692,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
/* /*
* After all the routing has been prepared we need to add in any * After all the routing has been prepared we need to add in any
* connector which is itself unchanged, but whose crtc changes its * connector which is itself unchanged, but whose CRTC changes its
* configuration. This must be done before calling mode_fixup in case a * configuration. This must be done before calling mode_fixup in case a
* crtc only changed its mode but has the same set of connectors. * crtc only changed its mode but has the same set of connectors.
*/ */
@ -741,13 +741,13 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset);
/** /**
* drm_atomic_helper_check_plane_state() - Check plane state for validity * drm_atomic_helper_check_plane_state() - Check plane state for validity
* @plane_state: plane state to check * @plane_state: plane state to check
* @crtc_state: crtc state to check * @crtc_state: CRTC state to check
* @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
* @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
* @can_position: is it legal to position the plane such that it * @can_position: is it legal to position the plane such that it
* doesn't cover the entire crtc? This will generally * doesn't cover the entire CRTC? This will generally
* only be false for primary planes. * only be false for primary planes.
* @can_update_disabled: can the plane be updated while the crtc * @can_update_disabled: can the plane be updated while the CRTC
* is disabled? * is disabled?
* *
* Checks that a desired plane update is valid, and updates various * Checks that a desired plane update is valid, and updates various
@ -844,7 +844,7 @@ EXPORT_SYMBOL(drm_atomic_helper_check_plane_state);
* &drm_crtc_helper_funcs.atomic_check and &drm_plane_helper_funcs.atomic_check * &drm_crtc_helper_funcs.atomic_check and &drm_plane_helper_funcs.atomic_check
* hooks provided by the driver. * hooks provided by the driver.
* *
* It also sets &drm_crtc_state.planes_changed to indicate that a crtc has * It also sets &drm_crtc_state.planes_changed to indicate that a CRTC has
* updated planes. * updated planes.
* *
* RETURNS: * RETURNS:
@ -908,7 +908,7 @@ EXPORT_SYMBOL(drm_atomic_helper_check_planes);
* @state: the driver state object * @state: the driver state object
* *
* Check the state object to see if the requested state is physically possible. * Check the state object to see if the requested state is physically possible.
* Only crtcs and planes have check callbacks, so for any additional (global) * Only CRTCs and planes have check callbacks, so for any additional (global)
* checking that a driver needs it can simply wrap that around this function. * checking that a driver needs it can simply wrap that around this function.
* Drivers without such needs can directly use this as their * Drivers without such needs can directly use this as their
* &drm_mode_config_funcs.atomic_check callback. * &drm_mode_config_funcs.atomic_check callback.
@ -961,14 +961,14 @@ crtc_needs_disable(struct drm_crtc_state *old_state,
struct drm_crtc_state *new_state) struct drm_crtc_state *new_state)
{ {
/* /*
* No new_state means the crtc is off, so the only criteria is whether * No new_state means the CRTC is off, so the only criteria is whether
* it's currently active or in self refresh mode. * it's currently active or in self refresh mode.
*/ */
if (!new_state) if (!new_state)
return drm_atomic_crtc_effectively_active(old_state); return drm_atomic_crtc_effectively_active(old_state);
/* /*
* We need to run through the crtc_funcs->disable() function if the crtc * We need to run through the crtc_funcs->disable() function if the CRTC
* is currently on, if it's transitioning to self refresh mode, or if * is currently on, if it's transitioning to self refresh mode, or if
* it's in self refresh mode and needs to be fully disabled. * it's in self refresh mode and needs to be fully disabled.
*/ */
@ -1087,7 +1087,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
* @old_state: atomic state object with old state structures * @old_state: atomic state object with old state structures
* *
* This function updates all the various legacy modeset state pointers in * This function updates all the various legacy modeset state pointers in
* connectors, encoders and crtcs. It also updates the timestamping constants * connectors, encoders and CRTCs. It also updates the timestamping constants
* used for precise vblank timestamps by calling * used for precise vblank timestamps by calling
* drm_calc_timestamping_constants(). * drm_calc_timestamping_constants().
* *
@ -1236,7 +1236,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
* This function shuts down all the outputs that need to be shut down and * This function shuts down all the outputs that need to be shut down and
* prepares them (if required) with the new mode. * prepares them (if required) with the new mode.
* *
* For compatibility with legacy crtc helpers this should be called before * For compatibility with legacy CRTC helpers this should be called before
* drm_atomic_helper_commit_planes(), which is what the default commit function * drm_atomic_helper_commit_planes(), which is what the default commit function
* does. But drivers with different needs can group the modeset commits together * does. But drivers with different needs can group the modeset commits together
* and do the plane commits at the end. This is useful for drivers doing runtime * and do the plane commits at the end. This is useful for drivers doing runtime
@ -1282,7 +1282,7 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev,
* This function enables all the outputs with the new configuration which had to * This function enables all the outputs with the new configuration which had to
* be turned off for the update. * be turned off for the update.
* *
* For compatibility with legacy crtc helpers this should be called after * For compatibility with legacy CRTC helpers this should be called after
* drm_atomic_helper_commit_planes(), which is what the default commit function * drm_atomic_helper_commit_planes(), which is what the default commit function
* does. But drivers with different needs can group the modeset commits together * does. But drivers with different needs can group the modeset commits together
* and do the plane commits at the end. This is useful for drivers doing runtime * and do the plane commits at the end. This is useful for drivers doing runtime
@ -1414,12 +1414,12 @@ int drm_atomic_helper_wait_for_fences(struct drm_device *dev,
EXPORT_SYMBOL(drm_atomic_helper_wait_for_fences); EXPORT_SYMBOL(drm_atomic_helper_wait_for_fences);
/** /**
* drm_atomic_helper_wait_for_vblanks - wait for vblank on crtcs * drm_atomic_helper_wait_for_vblanks - wait for vblank on CRTCs
* @dev: DRM device * @dev: DRM device
* @old_state: atomic state object with old state structures * @old_state: atomic state object with old state structures
* *
* Helper to, after atomic commit, wait for vblanks on all effected * Helper to, after atomic commit, wait for vblanks on all affected
* crtcs (ie. before cleaning up old framebuffers using * CRTCs (ie. before cleaning up old framebuffers using
* drm_atomic_helper_cleanup_planes()). It will only wait on CRTCs where the * drm_atomic_helper_cleanup_planes()). It will only wait on CRTCs where the
* framebuffers have actually changed to optimize for the legacy cursor and * framebuffers have actually changed to optimize for the legacy cursor and
* plane update use-case. * plane update use-case.
@ -1478,10 +1478,10 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);
* @dev: DRM device * @dev: DRM device
* @old_state: atomic state object with old state structures * @old_state: atomic state object with old state structures
* *
* Helper to, after atomic commit, wait for page flips on all effected * Helper to, after atomic commit, wait for page flips on all affected
* crtcs (ie. before cleaning up old framebuffers using * crtcs (ie. before cleaning up old framebuffers using
* drm_atomic_helper_cleanup_planes()). Compared to * drm_atomic_helper_cleanup_planes()). Compared to
* drm_atomic_helper_wait_for_vblanks() this waits for the completion of on all * drm_atomic_helper_wait_for_vblanks() this waits for the completion on all
* CRTCs, assuming that cursors-only updates are signalling their completion * CRTCs, assuming that cursors-only updates are signalling their completion
* immediately (or using a different path). * immediately (or using a different path).
* *
@ -2208,7 +2208,7 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
* drm_atomic_helper_fake_vblank - fake VBLANK events if needed * drm_atomic_helper_fake_vblank - fake VBLANK events if needed
* @old_state: atomic state object with old state structures * @old_state: atomic state object with old state structures
* *
* This function walks all CRTCs and fake VBLANK events on those with * This function walks all CRTCs and fakes VBLANK events on those with
* &drm_crtc_state.no_vblank set to true and &drm_crtc_state.event != NULL. * &drm_crtc_state.no_vblank set to true and &drm_crtc_state.event != NULL.
* The primary use of this function is writeback connectors working in oneshot * The primary use of this function is writeback connectors working in oneshot
* mode and faking VBLANK events. In this case they only fake the VBLANK event * mode and faking VBLANK events. In this case they only fake the VBLANK event
@ -2404,7 +2404,7 @@ static bool plane_crtc_active(const struct drm_plane_state *state)
* @flags: flags for committing plane state * @flags: flags for committing plane state
* *
* This function commits the new plane state using the plane and atomic helper * This function commits the new plane state using the plane and atomic helper
* functions for planes and crtcs. It assumes that the atomic state has already * functions for planes and CRTCs. It assumes that the atomic state has already
* been pushed into the relevant object state pointers, since this step can no * been pushed into the relevant object state pointers, since this step can no
* longer fail. * longer fail.
* *
@ -2525,15 +2525,15 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
EXPORT_SYMBOL(drm_atomic_helper_commit_planes); EXPORT_SYMBOL(drm_atomic_helper_commit_planes);
/** /**
* drm_atomic_helper_commit_planes_on_crtc - commit plane state for a crtc * drm_atomic_helper_commit_planes_on_crtc - commit plane state for a CRTC
* @old_crtc_state: atomic state object with the old crtc state * @old_crtc_state: atomic state object with the old CRTC state
* *
* This function commits the new plane state using the plane and atomic helper * This function commits the new plane state using the plane and atomic helper
* functions for planes on the specific crtc. It assumes that the atomic state * functions for planes on the specific CRTC. It assumes that the atomic state
* has already been pushed into the relevant object state pointers, since this * has already been pushed into the relevant object state pointers, since this
* step can no longer fail. * step can no longer fail.
* *
* This function is useful when plane updates should be done crtc-by-crtc * This function is useful when plane updates should be done CRTC-by-CRTC
* instead of one global step like drm_atomic_helper_commit_planes() does. * instead of one global step like drm_atomic_helper_commit_planes() does.
* *
* This function can only be savely used when planes are not allowed to move * This function can only be savely used when planes are not allowed to move
@ -2823,10 +2823,10 @@ EXPORT_SYMBOL(drm_atomic_helper_swap_state);
* @plane: plane object to update * @plane: plane object to update
* @crtc: owning CRTC of owning plane * @crtc: owning CRTC of owning plane
* @fb: framebuffer to flip onto plane * @fb: framebuffer to flip onto plane
* @crtc_x: x offset of primary plane on crtc * @crtc_x: x offset of primary plane on @crtc
* @crtc_y: y offset of primary plane on crtc * @crtc_y: y offset of primary plane on @crtc
* @crtc_w: width of primary plane rectangle on crtc * @crtc_w: width of primary plane rectangle on @crtc
* @crtc_h: height of primary plane rectangle on crtc * @crtc_h: height of primary plane rectangle on @crtc
* @src_x: x offset of @fb for panning * @src_x: x offset of @fb for panning
* @src_y: y offset of @fb for panning * @src_y: y offset of @fb for panning
* @src_w: width of source rectangle in @fb * @src_w: width of source rectangle in @fb
@ -2932,7 +2932,7 @@ EXPORT_SYMBOL(drm_atomic_helper_disable_plane);
* @set: mode set configuration * @set: mode set configuration
* @ctx: lock acquisition context * @ctx: lock acquisition context
* *
* Provides a default crtc set_config handler using the atomic driver interface. * Provides a default CRTC set_config handler using the atomic driver interface.
* *
* NOTE: For backwards compatibility with old userspace this automatically * NOTE: For backwards compatibility with old userspace this automatically
* resets the "link-status" property to GOOD, to force any link * resets the "link-status" property to GOOD, to force any link
@ -3345,7 +3345,7 @@ static int page_flip_common(struct drm_atomic_state *state,
/** /**
* drm_atomic_helper_page_flip - execute a legacy page flip * drm_atomic_helper_page_flip - execute a legacy page flip
* @crtc: DRM crtc * @crtc: DRM CRTC
* @fb: DRM framebuffer * @fb: DRM framebuffer
* @event: optional DRM event to signal upon completion * @event: optional DRM event to signal upon completion
* @flags: flip flags for non-vblank sync'ed updates * @flags: flip flags for non-vblank sync'ed updates
@ -3389,7 +3389,7 @@ EXPORT_SYMBOL(drm_atomic_helper_page_flip);
/** /**
* drm_atomic_helper_page_flip_target - do page flip on target vblank period. * drm_atomic_helper_page_flip_target - do page flip on target vblank period.
* @crtc: DRM crtc * @crtc: DRM CRTC
* @fb: DRM framebuffer * @fb: DRM framebuffer
* @event: optional DRM event to signal upon completion * @event: optional DRM event to signal upon completion
* @flags: flip flags for non-vblank sync'ed updates * @flags: flip flags for non-vblank sync'ed updates

View File

@ -160,12 +160,12 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc); EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
/** /**
* drm_atomic_set_crtc_for_plane - set crtc for plane * drm_atomic_set_crtc_for_plane - set CRTC for plane
* @plane_state: the plane whose incoming state to update * @plane_state: the plane whose incoming state to update
* @crtc: crtc to use for the plane * @crtc: CRTC to use for the plane
* *
* Changing the assigned crtc for a plane requires us to grab the lock and state * Changing the assigned CRTC for a plane requires us to grab the lock and state
* for the new crtc, as needed. This function takes care of all these details * for the new CRTC, as needed. This function takes care of all these details
* besides updating the pointer in the state object itself. * besides updating the pointer in the state object itself.
* *
* Returns: * Returns:
@ -279,12 +279,12 @@ drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state,
EXPORT_SYMBOL(drm_atomic_set_fence_for_plane); EXPORT_SYMBOL(drm_atomic_set_fence_for_plane);
/** /**
* drm_atomic_set_crtc_for_connector - set crtc for connector * drm_atomic_set_crtc_for_connector - set CRTC for connector
* @conn_state: atomic state object for the connector * @conn_state: atomic state object for the connector
* @crtc: crtc to use for the connector * @crtc: CRTC to use for the connector
* *
* Changing the assigned crtc for a connector requires us to grab the lock and * Changing the assigned CRTC for a connector requires us to grab the lock and
* state for the new crtc, as needed. This function takes care of all these * state for the new CRTC, as needed. This function takes care of all these
* details besides updating the pointer in the state object itself. * details besides updating the pointer in the state object itself.
* *
* Returns: * Returns:

View File

@ -150,7 +150,7 @@ void drm_client_release(struct drm_client_dev *client)
{ {
struct drm_device *dev = client->dev; struct drm_device *dev = client->dev;
DRM_DEV_DEBUG_KMS(dev->dev, "%s\n", client->name); drm_dbg_kms(dev, "%s\n", client->name);
drm_client_modeset_free(client); drm_client_modeset_free(client);
drm_client_close(client); drm_client_close(client);
@ -203,7 +203,7 @@ void drm_client_dev_hotplug(struct drm_device *dev)
continue; continue;
ret = client->funcs->hotplug(client); ret = client->funcs->hotplug(client);
DRM_DEV_DEBUG_KMS(dev->dev, "%s: ret=%d\n", client->name, ret); drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
} }
mutex_unlock(&dev->clientlist_mutex); mutex_unlock(&dev->clientlist_mutex);
} }
@ -223,7 +223,7 @@ void drm_client_dev_restore(struct drm_device *dev)
continue; continue;
ret = client->funcs->restore(client); ret = client->funcs->restore(client);
DRM_DEV_DEBUG_KMS(dev->dev, "%s: ret=%d\n", client->name, ret); drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
if (!ret) /* The first one to return zero gets the privilege to restore */ if (!ret) /* The first one to return zero gets the privilege to restore */
break; break;
} }
@ -351,8 +351,8 @@ static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer)
ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file); ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file);
if (ret) if (ret)
DRM_DEV_ERROR(buffer->client->dev->dev, drm_err(buffer->client->dev,
"Error removing FB:%u (%d)\n", buffer->fb->base.id, ret); "Error removing FB:%u (%d)\n", buffer->fb->base.id, ret);
buffer->fb = NULL; buffer->fb = NULL;
} }

View File

@ -622,7 +622,8 @@ int drm_dev_init(struct drm_device *dev,
return -ENODEV; return -ENODEV;
} }
BUG_ON(!parent); if (WARN_ON(!parent))
return -EINVAL;
kref_init(&dev->ref); kref_init(&dev->ref);
dev->dev = get_device(parent); dev->dev = get_device(parent);
@ -725,7 +726,7 @@ int devm_drm_dev_init(struct device *parent,
{ {
int ret; int ret;
if (WARN_ON(!parent || !driver->release)) if (WARN_ON(!driver->release))
return -EINVAL; return -EINVAL;
ret = drm_dev_init(dev, driver, parent); ret = drm_dev_init(dev, driver, parent);

View File

@ -710,14 +710,11 @@ static const struct minimode extra_modes[] = {
}; };
/* /*
* Probably taken from CEA-861 spec. * From CEA/CTA-861 spec.
* This table is converted from xorg's hw/xfree86/modes/xf86EdidModes.c.
* *
* Index using the VIC. * Do not access directly, instead always use cea_mode_for_vic().
*/ */
static const struct drm_display_mode edid_cea_modes[] = { static const struct drm_display_mode edid_cea_modes_1[] = {
/* 0 - dummy, VICs start at 1 */
{ },
/* 1 - 640x480@60Hz 4:3 */ /* 1 - 640x480@60Hz 4:3 */
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
752, 800, 0, 480, 490, 492, 525, 0, 752, 800, 0, 480, 490, 492, 525, 0,
@ -1380,6 +1377,149 @@ static const struct drm_display_mode edid_cea_modes[] = {
.vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
}; };
/*
* From CEA/CTA-861 spec.
*
* Do not access directly, instead always use cea_mode_for_vic().
*/
static const struct drm_display_mode edid_cea_modes_193[] = {
/* 193 - 5120x2160@120Hz 64:27 */
{ DRM_MODE("5120x2160", DRM_MODE_TYPE_DRIVER, 1485000, 5120, 5284,
5372, 5500, 0, 2160, 2168, 2178, 2250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 194 - 7680x4320@24Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10232,
10408, 11000, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 195 - 7680x4320@25Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10032,
10208, 10800, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 196 - 7680x4320@30Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 8232,
8408, 9000, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 197 - 7680x4320@48Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10232,
10408, 11000, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 48, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 198 - 7680x4320@50Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10032,
10208, 10800, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 199 - 7680x4320@60Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 8232,
8408, 9000, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 200 - 7680x4320@100Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 9792,
9968, 10560, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 201 - 7680x4320@120Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 8032,
8208, 8800, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 202 - 7680x4320@24Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10232,
10408, 11000, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 203 - 7680x4320@25Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10032,
10208, 10800, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 204 - 7680x4320@30Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 8232,
8408, 9000, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 205 - 7680x4320@48Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10232,
10408, 11000, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 48, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 206 - 7680x4320@50Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10032,
10208, 10800, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 207 - 7680x4320@60Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 8232,
8408, 9000, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 208 - 7680x4320@100Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 9792,
9968, 10560, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 209 - 7680x4320@120Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 8032,
8208, 8800, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 210 - 10240x4320@24Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 1485000, 10240, 11732,
11908, 12500, 0, 4320, 4336, 4356, 4950, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 211 - 10240x4320@25Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 1485000, 10240, 12732,
12908, 13500, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 212 - 10240x4320@30Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 1485000, 10240, 10528,
10704, 11000, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 213 - 10240x4320@48Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 2970000, 10240, 11732,
11908, 12500, 0, 4320, 4336, 4356, 4950, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 48, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 214 - 10240x4320@50Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 2970000, 10240, 12732,
12908, 13500, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 215 - 10240x4320@60Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 2970000, 10240, 10528,
10704, 11000, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 216 - 10240x4320@100Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 5940000, 10240, 12432,
12608, 13200, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 217 - 10240x4320@120Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 5940000, 10240, 10528,
10704, 11000, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 218 - 4096x2160@100Hz 256:135 */
{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 1188000, 4096, 4896,
4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
/* 219 - 4096x2160@120Hz 256:135 */
{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 1188000, 4096, 4184,
4272, 4400, 0, 2160, 2168, 2178, 2250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
};
/* /*
* HDMI 1.4 4k modes. Index using the VIC. * HDMI 1.4 4k modes. Index using the VIC.
*/ */
@ -3071,6 +3211,30 @@ static u8 *drm_find_cea_extension(const struct edid *edid)
return cea; return cea;
} }
static const struct drm_display_mode *cea_mode_for_vic(u8 vic)
{
BUILD_BUG_ON(1 + ARRAY_SIZE(edid_cea_modes_1) - 1 != 127);
BUILD_BUG_ON(193 + ARRAY_SIZE(edid_cea_modes_193) - 1 != 219);
if (vic >= 1 && vic < 1 + ARRAY_SIZE(edid_cea_modes_1))
return &edid_cea_modes_1[vic - 1];
if (vic >= 193 && vic < 193 + ARRAY_SIZE(edid_cea_modes_193))
return &edid_cea_modes_193[vic - 193];
return NULL;
}
static u8 cea_num_vics(void)
{
return 193 + ARRAY_SIZE(edid_cea_modes_193);
}
static u8 cea_next_vic(u8 vic)
{
if (++vic == 1 + ARRAY_SIZE(edid_cea_modes_1))
vic = 193;
return vic;
}
/* /*
* Calculate the alternate clock for the CEA mode * Calculate the alternate clock for the CEA mode
* (60Hz vs. 59.94Hz etc.) * (60Hz vs. 59.94Hz etc.)
@ -3108,14 +3272,14 @@ cea_mode_alternate_timings(u8 vic, struct drm_display_mode *mode)
* get the other variants by simply increasing the * get the other variants by simply increasing the
* vertical front porch length. * vertical front porch length.
*/ */
BUILD_BUG_ON(edid_cea_modes[8].vtotal != 262 || BUILD_BUG_ON(cea_mode_for_vic(8)->vtotal != 262 ||
edid_cea_modes[9].vtotal != 262 || cea_mode_for_vic(9)->vtotal != 262 ||
edid_cea_modes[12].vtotal != 262 || cea_mode_for_vic(12)->vtotal != 262 ||
edid_cea_modes[13].vtotal != 262 || cea_mode_for_vic(13)->vtotal != 262 ||
edid_cea_modes[23].vtotal != 312 || cea_mode_for_vic(23)->vtotal != 312 ||
edid_cea_modes[24].vtotal != 312 || cea_mode_for_vic(24)->vtotal != 312 ||
edid_cea_modes[27].vtotal != 312 || cea_mode_for_vic(27)->vtotal != 312 ||
edid_cea_modes[28].vtotal != 312); cea_mode_for_vic(28)->vtotal != 312);
if (((vic == 8 || vic == 9 || if (((vic == 8 || vic == 9 ||
vic == 12 || vic == 13) && mode->vtotal < 263) || vic == 12 || vic == 13) && mode->vtotal < 263) ||
@ -3143,8 +3307,8 @@ static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_m
if (to_match->picture_aspect_ratio) if (to_match->picture_aspect_ratio)
match_flags |= DRM_MODE_MATCH_ASPECT_RATIO; match_flags |= DRM_MODE_MATCH_ASPECT_RATIO;
for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) { for (vic = 1; vic < cea_num_vics(); vic = cea_next_vic(vic)) {
struct drm_display_mode cea_mode = edid_cea_modes[vic]; struct drm_display_mode cea_mode = *cea_mode_for_vic(vic);
unsigned int clock1, clock2; unsigned int clock1, clock2;
/* Check both 60Hz and 59.94Hz */ /* Check both 60Hz and 59.94Hz */
@ -3182,8 +3346,8 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
if (to_match->picture_aspect_ratio) if (to_match->picture_aspect_ratio)
match_flags |= DRM_MODE_MATCH_ASPECT_RATIO; match_flags |= DRM_MODE_MATCH_ASPECT_RATIO;
for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) { for (vic = 1; vic < cea_num_vics(); vic = cea_next_vic(vic)) {
struct drm_display_mode cea_mode = edid_cea_modes[vic]; struct drm_display_mode cea_mode = *cea_mode_for_vic(vic);
unsigned int clock1, clock2; unsigned int clock1, clock2;
/* Check both 60Hz and 59.94Hz */ /* Check both 60Hz and 59.94Hz */
@ -3206,12 +3370,17 @@ EXPORT_SYMBOL(drm_match_cea_mode);
static bool drm_valid_cea_vic(u8 vic) static bool drm_valid_cea_vic(u8 vic)
{ {
return vic > 0 && vic < ARRAY_SIZE(edid_cea_modes); return cea_mode_for_vic(vic) != NULL;
} }
static enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code) static enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code)
{ {
return edid_cea_modes[video_code].picture_aspect_ratio; const struct drm_display_mode *mode = cea_mode_for_vic(video_code);
if (mode)
return mode->picture_aspect_ratio;
return HDMI_PICTURE_ASPECT_NONE;
} }
static enum hdmi_picture_aspect drm_get_hdmi_aspect_ratio(const u8 video_code) static enum hdmi_picture_aspect drm_get_hdmi_aspect_ratio(const u8 video_code)
@ -3323,7 +3492,7 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid)
unsigned int clock1, clock2; unsigned int clock1, clock2;
if (drm_valid_cea_vic(vic)) { if (drm_valid_cea_vic(vic)) {
cea_mode = &edid_cea_modes[vic]; cea_mode = cea_mode_for_vic(vic);
clock2 = cea_mode_alternate_clock(cea_mode); clock2 = cea_mode_alternate_clock(cea_mode);
} else { } else {
vic = drm_match_hdmi_mode(mode); vic = drm_match_hdmi_mode(mode);
@ -3398,7 +3567,7 @@ drm_display_mode_from_vic_index(struct drm_connector *connector,
if (!drm_valid_cea_vic(vic)) if (!drm_valid_cea_vic(vic))
return NULL; return NULL;
newmode = drm_mode_duplicate(dev, &edid_cea_modes[vic]); newmode = drm_mode_duplicate(dev, cea_mode_for_vic(vic));
if (!newmode) if (!newmode)
return NULL; return NULL;
@ -3432,7 +3601,7 @@ static int do_y420vdb_modes(struct drm_connector *connector,
if (!drm_valid_cea_vic(vic)) if (!drm_valid_cea_vic(vic))
continue; continue;
newmode = drm_mode_duplicate(dev, &edid_cea_modes[vic]); newmode = drm_mode_duplicate(dev, cea_mode_for_vic(vic));
if (!newmode) if (!newmode)
break; break;
bitmap_set(hdmi->y420_vdb_modes, vic, 1); bitmap_set(hdmi->y420_vdb_modes, vic, 1);
@ -4001,7 +4170,7 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
vic = drm_match_cea_mode_clock_tolerance(mode, 5); vic = drm_match_cea_mode_clock_tolerance(mode, 5);
if (drm_valid_cea_vic(vic)) { if (drm_valid_cea_vic(vic)) {
type = "CEA"; type = "CEA";
cea_mode = &edid_cea_modes[vic]; cea_mode = cea_mode_for_vic(vic);
clock1 = cea_mode->clock; clock1 = cea_mode->clock;
clock2 = cea_mode_alternate_clock(cea_mode); clock2 = cea_mode_alternate_clock(cea_mode);
} else { } else {
@ -4577,7 +4746,7 @@ static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector,
if (scdc->supported) { if (scdc->supported) {
scdc->scrambling.supported = true; scdc->scrambling.supported = true;
/* Few sinks support scrambling for cloks < 340M */ /* Few sinks support scrambling for clocks < 340M */
if ((hf_vsdb[6] & 0x8)) if ((hf_vsdb[6] & 0x8))
scdc->scrambling.low_rates = true; scdc->scrambling.low_rates = true;
} }

View File

@ -191,6 +191,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
{ {
struct drm_fb_helper *helper = info->par; struct drm_fb_helper *helper = info->par;
struct drm_client_dev *client = &helper->client; struct drm_client_dev *client = &helper->client;
struct drm_device *dev = helper->dev;
struct drm_crtc *crtc; struct drm_crtc *crtc;
const struct drm_crtc_helper_funcs *funcs; const struct drm_crtc_helper_funcs *funcs;
struct drm_mode_set *mode_set; struct drm_mode_set *mode_set;
@ -209,7 +210,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
continue; continue;
if (!fb) { if (!fb) {
DRM_ERROR("no fb to restore??\n"); drm_err(dev, "no fb to restore?\n");
continue; continue;
} }
@ -1248,12 +1249,13 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
{ {
struct drm_fb_helper *fb_helper = info->par; struct drm_fb_helper *fb_helper = info->par;
struct drm_framebuffer *fb = fb_helper->fb; struct drm_framebuffer *fb = fb_helper->fb;
struct drm_device *dev = fb_helper->dev;
if (in_dbg_master()) if (in_dbg_master())
return -EINVAL; return -EINVAL;
if (var->pixclock != 0) { if (var->pixclock != 0) {
DRM_DEBUG("fbdev emulation doesn't support changing the pixel clock, value of pixclock is ignored\n"); drm_dbg_kms(dev, "fbdev emulation doesn't support changing the pixel clock, value of pixclock is ignored\n");
var->pixclock = 0; var->pixclock = 0;
} }
@ -1268,7 +1270,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
if (var->bits_per_pixel != fb->format->cpp[0] * 8 || if (var->bits_per_pixel != fb->format->cpp[0] * 8 ||
var->xres > fb->width || var->yres > fb->height || var->xres > fb->width || var->yres > fb->height ||
var->xres_virtual > fb->width || var->yres_virtual > fb->height) { var->xres_virtual > fb->width || var->yres_virtual > fb->height) {
DRM_DEBUG("fb requested width/height/bpp can't fit in current fb " drm_dbg_kms(dev, "fb requested width/height/bpp can't fit in current fb "
"request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n", "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n",
var->xres, var->yres, var->bits_per_pixel, var->xres, var->yres, var->bits_per_pixel,
var->xres_virtual, var->yres_virtual, var->xres_virtual, var->yres_virtual,
@ -1295,7 +1297,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
* so reject all pixel format changing requests. * so reject all pixel format changing requests.
*/ */
if (!drm_fb_pixel_format_equal(var, &info->var)) { if (!drm_fb_pixel_format_equal(var, &info->var)) {
DRM_DEBUG("fbdev emulation doesn't support changing the pixel format\n"); drm_dbg_kms(dev, "fbdev emulation doesn't support changing the pixel format\n");
return -EINVAL; return -EINVAL;
} }
@ -1320,7 +1322,7 @@ int drm_fb_helper_set_par(struct fb_info *info)
return -EBUSY; return -EBUSY;
if (var->pixclock != 0) { if (var->pixclock != 0) {
DRM_ERROR("PIXEL CLOCK SET\n"); drm_err(fb_helper->dev, "PIXEL CLOCK SET\n");
return -EINVAL; return -EINVAL;
} }
@ -1430,6 +1432,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
int preferred_bpp) int preferred_bpp)
{ {
struct drm_client_dev *client = &fb_helper->client; struct drm_client_dev *client = &fb_helper->client;
struct drm_device *dev = fb_helper->dev;
int ret = 0; int ret = 0;
int crtc_count = 0; int crtc_count = 0;
struct drm_connector_list_iter conn_iter; struct drm_connector_list_iter conn_iter;
@ -1493,7 +1496,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
struct drm_plane *plane = crtc->primary; struct drm_plane *plane = crtc->primary;
int j; int j;
DRM_DEBUG("test CRTC %u primary plane\n", drm_crtc_index(crtc)); drm_dbg_kms(dev, "test CRTC %u primary plane\n", drm_crtc_index(crtc));
for (j = 0; j < plane->format_count; j++) { for (j = 0; j < plane->format_count; j++) {
const struct drm_format_info *fmt; const struct drm_format_info *fmt;
@ -1526,7 +1529,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
} }
} }
if (sizes.surface_depth != best_depth && best_depth) { if (sizes.surface_depth != best_depth && best_depth) {
DRM_INFO("requested bpp %d, scaled depth down to %d", drm_info(dev, "requested bpp %d, scaled depth down to %d",
sizes.surface_bpp, best_depth); sizes.surface_bpp, best_depth);
sizes.surface_depth = best_depth; sizes.surface_depth = best_depth;
} }
@ -1574,7 +1577,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
mutex_unlock(&client->modeset_mutex); mutex_unlock(&client->modeset_mutex);
if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
DRM_INFO("Cannot find any crtc or sizes\n"); drm_info(dev, "Cannot find any crtc or sizes\n");
/* First time: disable all crtc's.. */ /* First time: disable all crtc's.. */
if (!fb_helper->deferred_setup) if (!fb_helper->deferred_setup)
@ -1889,7 +1892,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
drm_master_internal_release(fb_helper->dev); drm_master_internal_release(fb_helper->dev);
DRM_DEBUG_KMS("\n"); drm_dbg_kms(fb_helper->dev, "\n");
drm_client_modeset_probe(&fb_helper->client, fb_helper->fb->width, fb_helper->fb->height); drm_client_modeset_probe(&fb_helper->client, fb_helper->fb->width, fb_helper->fb->height);
drm_setup_crtcs_fb(fb_helper); drm_setup_crtcs_fb(fb_helper);
@ -2026,15 +2029,16 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
struct drm_fb_helper_surface_size *sizes) struct drm_fb_helper_surface_size *sizes)
{ {
struct drm_client_dev *client = &fb_helper->client; struct drm_client_dev *client = &fb_helper->client;
struct drm_device *dev = fb_helper->dev;
struct drm_client_buffer *buffer; struct drm_client_buffer *buffer;
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
struct fb_info *fbi; struct fb_info *fbi;
u32 format; u32 format;
void *vaddr; void *vaddr;
DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n", drm_dbg_kms(dev, "surface width(%d), height(%d) and bpp(%d)\n",
sizes->surface_width, sizes->surface_height, sizes->surface_width, sizes->surface_height,
sizes->surface_bpp); sizes->surface_bpp);
format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
buffer = drm_client_framebuffer_create(client, sizes->surface_width, buffer = drm_client_framebuffer_create(client, sizes->surface_width,
@ -2118,7 +2122,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
return drm_fb_helper_hotplug_event(dev->fb_helper); return drm_fb_helper_hotplug_event(dev->fb_helper);
if (!dev->mode_config.num_connector) { if (!dev->mode_config.num_connector) {
DRM_DEV_DEBUG(dev->dev, "No connectors found, will not create framebuffer!\n"); drm_dbg_kms(dev, "No connectors found, will not create framebuffer!\n");
return 0; return 0;
} }
@ -2143,7 +2147,7 @@ err:
fb_helper->dev = NULL; fb_helper->dev = NULL;
fb_helper->fbdev = NULL; fb_helper->fbdev = NULL;
DRM_DEV_ERROR(dev->dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret); drm_err(dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret);
return ret; return ret;
} }
@ -2200,7 +2204,7 @@ int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs); ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs);
if (ret) { if (ret) {
kfree(fb_helper); kfree(fb_helper);
DRM_DEV_ERROR(dev->dev, "Failed to register client: %d\n", ret); drm_err(dev, "Failed to register client: %d\n", ret);
return ret; return ret;
} }
@ -2212,7 +2216,7 @@ int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
ret = drm_fbdev_client_hotplug(&fb_helper->client); ret = drm_fbdev_client_hotplug(&fb_helper->client);
if (ret) if (ret)
DRM_DEV_DEBUG(dev->dev, "client hotplug ret=%d\n", ret); drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
drm_client_register(&fb_helper->client); drm_client_register(&fb_helper->client);

View File

@ -74,8 +74,7 @@ drm_gem_fb_alloc(struct drm_device *dev,
ret = drm_framebuffer_init(dev, fb, funcs); ret = drm_framebuffer_init(dev, fb, funcs);
if (ret) { if (ret) {
DRM_DEV_ERROR(dev->dev, "Failed to init framebuffer: %d\n", drm_err(dev, "Failed to init framebuffer: %d\n", ret);
ret);
kfree(fb); kfree(fb);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
@ -160,7 +159,7 @@ drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file,
objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]); objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
if (!objs[i]) { if (!objs[i]) {
DRM_DEBUG_KMS("Failed to lookup GEM object\n"); drm_dbg_kms(dev, "Failed to lookup GEM object\n");
ret = -ENOENT; ret = -ENOENT;
goto err_gem_object_put; goto err_gem_object_put;
} }

View File

@ -1568,33 +1568,76 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
return 0; return 0;
} }
static int drm_mode_parse_cmdline_options(char *str, size_t len, static int drm_mode_parse_cmdline_int(const char *delim, unsigned int *int_ret)
{
const char *value;
char *endp;
/*
* delim must point to the '=', otherwise it is a syntax error and
* if delim points to the terminating zero, then delim + 1 wil point
* past the end of the string.
*/
if (*delim != '=')
return -EINVAL;
value = delim + 1;
*int_ret = simple_strtol(value, &endp, 10);
/* Make sure we have parsed something */
if (endp == value)
return -EINVAL;
return 0;
}
static int drm_mode_parse_panel_orientation(const char *delim,
struct drm_cmdline_mode *mode)
{
const char *value;
if (*delim != '=')
return -EINVAL;
value = delim + 1;
delim = strchr(value, ',');
if (!delim)
delim = value + strlen(value);
if (!strncmp(value, "normal", delim - value))
mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
else if (!strncmp(value, "upside_down", delim - value))
mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
else if (!strncmp(value, "left_side_up", delim - value))
mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
else if (!strncmp(value, "right_side_up", delim - value))
mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
else
return -EINVAL;
return 0;
}
static int drm_mode_parse_cmdline_options(const char *str,
bool freestanding,
const struct drm_connector *connector, const struct drm_connector *connector,
struct drm_cmdline_mode *mode) struct drm_cmdline_mode *mode)
{ {
unsigned int rotation = 0; unsigned int deg, margin, rotation = 0;
char *sep = str; const char *delim, *option, *sep;
while ((sep = strchr(sep, ','))) { option = str;
char *delim, *option; do {
option = sep + 1;
delim = strchr(option, '='); delim = strchr(option, '=');
if (!delim) { if (!delim) {
delim = strchr(option, ','); delim = strchr(option, ',');
if (!delim) if (!delim)
delim = str + len; delim = option + strlen(option);
} }
if (!strncmp(option, "rotate", delim - option)) { if (!strncmp(option, "rotate", delim - option)) {
const char *value = delim + 1; if (drm_mode_parse_cmdline_int(delim, &deg))
unsigned int deg;
deg = simple_strtol(value, &sep, 10);
/* Make sure we have parsed something */
if (sep == value)
return -EINVAL; return -EINVAL;
switch (deg) { switch (deg) {
@ -1619,58 +1662,40 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
} }
} else if (!strncmp(option, "reflect_x", delim - option)) { } else if (!strncmp(option, "reflect_x", delim - option)) {
rotation |= DRM_MODE_REFLECT_X; rotation |= DRM_MODE_REFLECT_X;
sep = delim;
} else if (!strncmp(option, "reflect_y", delim - option)) { } else if (!strncmp(option, "reflect_y", delim - option)) {
rotation |= DRM_MODE_REFLECT_Y; rotation |= DRM_MODE_REFLECT_Y;
sep = delim;
} else if (!strncmp(option, "margin_right", delim - option)) { } else if (!strncmp(option, "margin_right", delim - option)) {
const char *value = delim + 1; if (drm_mode_parse_cmdline_int(delim, &margin))
unsigned int margin;
margin = simple_strtol(value, &sep, 10);
/* Make sure we have parsed something */
if (sep == value)
return -EINVAL; return -EINVAL;
mode->tv_margins.right = margin; mode->tv_margins.right = margin;
} else if (!strncmp(option, "margin_left", delim - option)) { } else if (!strncmp(option, "margin_left", delim - option)) {
const char *value = delim + 1; if (drm_mode_parse_cmdline_int(delim, &margin))
unsigned int margin;
margin = simple_strtol(value, &sep, 10);
/* Make sure we have parsed something */
if (sep == value)
return -EINVAL; return -EINVAL;
mode->tv_margins.left = margin; mode->tv_margins.left = margin;
} else if (!strncmp(option, "margin_top", delim - option)) { } else if (!strncmp(option, "margin_top", delim - option)) {
const char *value = delim + 1; if (drm_mode_parse_cmdline_int(delim, &margin))
unsigned int margin;
margin = simple_strtol(value, &sep, 10);
/* Make sure we have parsed something */
if (sep == value)
return -EINVAL; return -EINVAL;
mode->tv_margins.top = margin; mode->tv_margins.top = margin;
} else if (!strncmp(option, "margin_bottom", delim - option)) { } else if (!strncmp(option, "margin_bottom", delim - option)) {
const char *value = delim + 1; if (drm_mode_parse_cmdline_int(delim, &margin))
unsigned int margin;
margin = simple_strtol(value, &sep, 10);
/* Make sure we have parsed something */
if (sep == value)
return -EINVAL; return -EINVAL;
mode->tv_margins.bottom = margin; mode->tv_margins.bottom = margin;
} else if (!strncmp(option, "panel_orientation", delim - option)) {
if (drm_mode_parse_panel_orientation(delim, mode))
return -EINVAL;
} else { } else {
return -EINVAL; return -EINVAL;
} }
} sep = strchr(delim, ',');
option = sep + 1;
} while (sep);
if (rotation && freestanding)
return -EINVAL;
mode->rotation_reflection = rotation; mode->rotation_reflection = rotation;
@ -1682,17 +1707,6 @@ static const char * const drm_named_modes_whitelist[] = {
"PAL", "PAL",
}; };
static bool drm_named_mode_is_in_whitelist(const char *mode, unsigned int size)
{
int i;
for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++)
if (!strncmp(mode, drm_named_modes_whitelist[i], size))
return true;
return false;
}
/** /**
* drm_mode_parse_command_line_for_connector - parse command line modeline for connector * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
* @mode_option: optional per connector mode option * @mode_option: optional per connector mode option
@ -1723,72 +1737,30 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
struct drm_cmdline_mode *mode) struct drm_cmdline_mode *mode)
{ {
const char *name; const char *name;
bool named_mode = false, parse_extras = false; bool freestanding = false, parse_extras = false;
unsigned int bpp_off = 0, refresh_off = 0, options_off = 0; unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
unsigned int mode_end = 0; unsigned int mode_end = 0;
char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL; const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
char *options_ptr = NULL; const char *options_ptr = NULL;
char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL; char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
int ret; int i, len, ret;
memset(mode, 0, sizeof(*mode));
mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
#ifdef CONFIG_FB
if (!mode_option) if (!mode_option)
mode_option = fb_mode_option;
#endif
if (!mode_option) {
mode->specified = false;
return false; return false;
}
name = mode_option; name = mode_option;
/*
* This is a bit convoluted. To differentiate between the
* named modes and poorly formatted resolutions, we need a
* bunch of things:
* - We need to make sure that the first character (which
* would be our resolution in X) is a digit.
* - If not, then it's either a named mode or a force on/off.
* To distinguish between the two, we need to run the
* extra parsing function, and if not, then we consider it
* a named mode.
*
* If this isn't enough, we should add more heuristics here,
* and matching unit-tests.
*/
if (!isdigit(name[0]) && name[0] != 'x') {
unsigned int namelen = strlen(name);
/*
* Only the force on/off options can be in that case,
* and they all take a single character.
*/
if (namelen == 1) {
ret = drm_mode_parse_cmdline_extra(name, namelen, true,
connector, mode);
if (!ret)
return true;
}
named_mode = true;
}
/* Try to locate the bpp and refresh specifiers, if any */ /* Try to locate the bpp and refresh specifiers, if any */
bpp_ptr = strchr(name, '-'); bpp_ptr = strchr(name, '-');
if (bpp_ptr) { if (bpp_ptr)
bpp_off = bpp_ptr - name; bpp_off = bpp_ptr - name;
mode->bpp_specified = true;
}
refresh_ptr = strchr(name, '@'); refresh_ptr = strchr(name, '@');
if (refresh_ptr) { if (refresh_ptr)
if (named_mode)
return false;
refresh_off = refresh_ptr - name; refresh_off = refresh_ptr - name;
mode->refresh_specified = true;
}
/* Locate the start of named options */ /* Locate the start of named options */
options_ptr = strchr(name, ','); options_ptr = strchr(name, ',');
@ -1802,33 +1774,58 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
mode_end = refresh_off; mode_end = refresh_off;
} else if (options_ptr) { } else if (options_ptr) {
mode_end = options_off; mode_end = options_off;
parse_extras = true;
} else { } else {
mode_end = strlen(name); mode_end = strlen(name);
parse_extras = true; parse_extras = true;
} }
if (named_mode) { /* First check for a named mode */
if (mode_end + 1 > DRM_DISPLAY_MODE_LEN) for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
return false; ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
if (ret == mode_end) {
if (refresh_ptr)
return false; /* named + refresh is invalid */
if (!drm_named_mode_is_in_whitelist(name, mode_end)) strcpy(mode->name, drm_named_modes_whitelist[i]);
return false; mode->specified = true;
break;
}
}
strscpy(mode->name, name, mode_end + 1); /* No named mode? Check for a normal mode argument, e.g. 1024x768 */
} else { if (!mode->specified && isdigit(name[0])) {
ret = drm_mode_parse_cmdline_res_mode(name, mode_end, ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
parse_extras, parse_extras,
connector, connector,
mode); mode);
if (ret) if (ret)
return false; return false;
mode->specified = true;
}
/* No mode? Check for freestanding extras and/or options */
if (!mode->specified) {
unsigned int len = strlen(mode_option);
if (bpp_ptr || refresh_ptr)
return false; /* syntax error */
if (len == 1 || (len >= 2 && mode_option[1] == ','))
extra_ptr = mode_option;
else
options_ptr = mode_option - 1;
freestanding = true;
} }
mode->specified = true;
if (bpp_ptr) { if (bpp_ptr) {
ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode); ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
if (ret) if (ret)
return false; return false;
mode->bpp_specified = true;
} }
if (refresh_ptr) { if (refresh_ptr) {
@ -1836,6 +1833,8 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
&refresh_end_ptr, mode); &refresh_end_ptr, mode);
if (ret) if (ret)
return false; return false;
mode->refresh_specified = true;
} }
/* /*
@ -1849,20 +1848,21 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
else if (refresh_ptr) else if (refresh_ptr)
extra_ptr = refresh_end_ptr; extra_ptr = refresh_end_ptr;
if (extra_ptr && if (extra_ptr) {
extra_ptr != options_ptr) { if (options_ptr)
int len = strlen(name) - (extra_ptr - name); len = options_ptr - extra_ptr;
else
len = strlen(extra_ptr);
ret = drm_mode_parse_cmdline_extra(extra_ptr, len, false, ret = drm_mode_parse_cmdline_extra(extra_ptr, len, freestanding,
connector, mode); connector, mode);
if (ret) if (ret)
return false; return false;
} }
if (options_ptr) { if (options_ptr) {
int len = strlen(name) - (options_ptr - name); ret = drm_mode_parse_cmdline_options(options_ptr + 1,
freestanding,
ret = drm_mode_parse_cmdline_options(options_ptr, len,
connector, mode); connector, mode);
if (ret) if (ret)
return false; return false;

View File

@ -302,7 +302,7 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np)
EXPORT_SYMBOL(of_drm_find_panel); EXPORT_SYMBOL(of_drm_find_panel);
#endif #endif
#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) #if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE)
/** /**
* drm_panel_of_backlight - use backlight device node for backlight * drm_panel_of_backlight - use backlight device node for backlight
* @panel: DRM panel * @panel: DRM panel

View File

@ -113,7 +113,7 @@ static void submit_unlock_object(struct etnaviv_gem_submit *submit, int i)
if (submit->bos[i].flags & BO_LOCKED) { if (submit->bos[i].flags & BO_LOCKED) {
struct drm_gem_object *obj = &submit->bos[i].obj->base; struct drm_gem_object *obj = &submit->bos[i].obj->base;
ww_mutex_unlock(&obj->resv->lock); dma_resv_unlock(obj->resv);
submit->bos[i].flags &= ~BO_LOCKED; submit->bos[i].flags &= ~BO_LOCKED;
} }
} }
@ -133,8 +133,7 @@ retry:
contended = i; contended = i;
if (!(submit->bos[i].flags & BO_LOCKED)) { if (!(submit->bos[i].flags & BO_LOCKED)) {
ret = ww_mutex_lock_interruptible(&obj->resv->lock, ret = dma_resv_lock_interruptible(obj->resv, ticket);
ticket);
if (ret == -EALREADY) if (ret == -EALREADY)
DRM_ERROR("BO at index %u already on submit list\n", DRM_ERROR("BO at index %u already on submit list\n",
i); i);
@ -161,8 +160,7 @@ fail:
obj = &submit->bos[contended].obj->base; obj = &submit->bos[contended].obj->base;
/* we lost out in a seqno race, lock and retry.. */ /* we lost out in a seqno race, lock and retry.. */
ret = ww_mutex_lock_slow_interruptible(&obj->resv->lock, ret = dma_resv_lock_slow_interruptible(obj->resv, ticket);
ticket);
if (!ret) { if (!ret) {
submit->bos[contended].flags |= BO_LOCKED; submit->bos[contended].flags |= BO_LOCKED;
slow_locked = contended; slow_locked = contended;

View File

@ -228,8 +228,8 @@ static void psbfb_copyarea_accel(struct fb_info *info,
{ {
struct drm_fb_helper *fb_helper = info->par; struct drm_fb_helper *fb_helper = info->par;
struct drm_framebuffer *fb = fb_helper->fb; struct drm_framebuffer *fb = fb_helper->fb;
struct drm_device *dev = fb->dev; struct drm_device *dev;
struct drm_psb_private *dev_priv = dev->dev_private; struct drm_psb_private *dev_priv;
uint32_t offset; uint32_t offset;
uint32_t stride; uint32_t stride;
uint32_t src_format; uint32_t src_format;
@ -238,6 +238,8 @@ static void psbfb_copyarea_accel(struct fb_info *info,
if (!fb) if (!fb)
return; return;
dev = fb->dev;
dev_priv = dev->dev_private;
offset = to_gtt_range(fb->obj[0])->offset; offset = to_gtt_range(fb->obj[0])->offset;
stride = fb->pitches[0]; stride = fb->pitches[0];

View File

@ -388,13 +388,14 @@ void mcde_dsi_te_request(struct mipi_dsi_device *mdsi)
static void mcde_dsi_setup_video_mode(struct mcde_dsi *d, static void mcde_dsi_setup_video_mode(struct mcde_dsi *d,
const struct drm_display_mode *mode) const struct drm_display_mode *mode)
{ {
u8 bpp = mipi_dsi_pixel_format_to_bpp(d->mdsi->format); /* cpp, characters per pixel, number of bytes per pixel */
u8 cpp = mipi_dsi_pixel_format_to_bpp(d->mdsi->format) / 8;
u64 pclk;
u64 bpl; u64 bpl;
u32 hfp; int hfp;
u32 hbp; int hbp;
u32 hsa; int hsa;
u32 blkline_pck, line_duration; u32 blkline_pck, line_duration;
u32 blkeol_pck, blkeol_duration;
u32 val; u32 val;
val = 0; val = 0;
@ -431,11 +432,21 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d,
return; return;
} }
/* TODO: TVG could be enabled here */ /* TODO: TVG (test video generator) could be enabled here */
/* Send blanking packet */ /*
* During vertical blanking: go to LP mode
* Like with the EOL setting, if this is not set, the EOL area will be
* filled with NULL or blanking packets in the vblank area.
* FIXME: some Samsung phones and display panels such as s6e63m0 use
* DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_BLANKING here instead,
* figure out how to properly configure that from the panel.
*/
val |= DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_LP_0; val |= DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_LP_0;
/* Send EOL packet */ /*
* During EOL: go to LP mode. If this is not set, the EOL area will be
* filled with NULL or blanking packets.
*/
val |= DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0; val |= DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0;
/* Recovery mode 1 */ /* Recovery mode 1 */
val |= 1 << DSI_VID_MAIN_CTL_RECOVERY_MODE_SHIFT; val |= 1 << DSI_VID_MAIN_CTL_RECOVERY_MODE_SHIFT;
@ -443,13 +454,13 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d,
writel(val, d->regs + DSI_VID_MAIN_CTL); writel(val, d->regs + DSI_VID_MAIN_CTL);
/* Vertical frame parameters are pretty straight-forward */ /* Vertical frame parameters are pretty straight-forward */
val = mode->vdisplay << DSI_VID_VSIZE_VSA_LENGTH_SHIFT; val = mode->vdisplay << DSI_VID_VSIZE_VACT_LENGTH_SHIFT;
/* vertical front porch */ /* vertical front porch */
val |= (mode->vsync_start - mode->vdisplay) val |= (mode->vsync_start - mode->vdisplay)
<< DSI_VID_VSIZE_VFP_LENGTH_SHIFT; << DSI_VID_VSIZE_VFP_LENGTH_SHIFT;
/* vertical sync active */ /* vertical sync active */
val |= (mode->vsync_end - mode->vsync_start) val |= (mode->vsync_end - mode->vsync_start)
<< DSI_VID_VSIZE_VACT_LENGTH_SHIFT; << DSI_VID_VSIZE_VSA_LENGTH_SHIFT;
/* vertical back porch */ /* vertical back porch */
val |= (mode->vtotal - mode->vsync_end) val |= (mode->vtotal - mode->vsync_end)
<< DSI_VID_VSIZE_VBP_LENGTH_SHIFT; << DSI_VID_VSIZE_VBP_LENGTH_SHIFT;
@ -457,36 +468,54 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d,
/* /*
* Horizontal frame parameters: * Horizontal frame parameters:
* horizontal resolution is given in pixels and must be re-calculated * horizontal resolution is given in pixels but must be re-calculated
* into bytes since this is what the hardware expects. * into bytes since this is what the hardware expects, these registers
* define the payload size of the packet.
*
* hfp = horizontal front porch in bytes
* hbp = horizontal back porch in bytes
* hsa = horizontal sync active in bytes
* *
* 6 + 2 is HFP header + checksum * 6 + 2 is HFP header + checksum
*/ */
hfp = (mode->hsync_start - mode->hdisplay) * bpp - 6 - 2; hfp = (mode->hsync_start - mode->hdisplay) * cpp - 6 - 2;
if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
/* /*
* Use sync pulse for sync: explicit HSA time
* 6 is HBP header + checksum * 6 is HBP header + checksum
* 4 is RGB header + checksum * 4 is RGB header + checksum
*/ */
hbp = (mode->htotal - mode->hsync_end) * bpp - 4 - 6; hbp = (mode->htotal - mode->hsync_end) * cpp - 4 - 6;
/* /*
* 6 is HBP header + checksum * 6 is HBP header + checksum
* 4 is HSW packet bytes * 4 is HSW packet bytes
* 4 is RGB header + checksum * 4 is RGB header + checksum
*/ */
hsa = (mode->hsync_end - mode->hsync_start) * bpp - 4 - 4 - 6; hsa = (mode->hsync_end - mode->hsync_start) * cpp - 4 - 4 - 6;
} else { } else {
/* /*
* HBP includes both back porch and sync * Use event for sync: HBP includes both back porch and sync
* 6 is HBP header + checksum * 6 is HBP header + checksum
* 4 is HSW packet bytes * 4 is HSW packet bytes
* 4 is RGB header + checksum * 4 is RGB header + checksum
*/ */
hbp = (mode->htotal - mode->hsync_start) * bpp - 4 - 4 - 6; hbp = (mode->htotal - mode->hsync_start) * cpp - 4 - 4 - 6;
/* HSA is not considered in this mode and set to 0 */ /* HSA is not present in this mode and set to 0 */
hsa = 0; hsa = 0;
} }
dev_dbg(d->dev, "hfp: %u, hbp: %u, hsa: %u\n", if (hfp < 0) {
dev_info(d->dev, "hfp negative, set to 0\n");
hfp = 0;
}
if (hbp < 0) {
dev_info(d->dev, "hbp negative, set to 0\n");
hbp = 0;
}
if (hsa < 0) {
dev_info(d->dev, "hsa negative, set to 0\n");
hsa = 0;
}
dev_dbg(d->dev, "hfp: %u, hbp: %u, hsa: %u bytes\n",
hfp, hbp, hsa); hfp, hbp, hsa);
/* Frame parameters: horizontal sync active */ /* Frame parameters: horizontal sync active */
@ -497,71 +526,185 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d,
val |= hfp << DSI_VID_HSIZE1_HFP_LENGTH_SHIFT; val |= hfp << DSI_VID_HSIZE1_HFP_LENGTH_SHIFT;
writel(val, d->regs + DSI_VID_HSIZE1); writel(val, d->regs + DSI_VID_HSIZE1);
/* RGB data length (bytes on one scanline) */ /* RGB data length (visible bytes on one scanline) */
val = mode->hdisplay * (bpp / 8); val = mode->hdisplay * cpp;
writel(val, d->regs + DSI_VID_HSIZE2); writel(val, d->regs + DSI_VID_HSIZE2);
dev_dbg(d->dev, "RGB length, visible area on a line: %u bytes\n", val);
/* TODO: further adjustments for TVG mode here */
/* /*
* EOL packet length from bits per line calculations: pixel clock * Calculate the time between two pixels in picoseconds using
* is given in kHz, calculate the time between two pixels in * the supplied refresh rate and total resolution including
* picoseconds. * porches and sync.
*/ */
bpl = mode->clock * mode->htotal; /* (ps/s) / (pixels/s) = ps/pixels */
bpl *= (d->hs_freq / 8); pclk = DIV_ROUND_UP_ULL(1000000000000,
do_div(bpl, 1000000); /* microseconds */ (mode->vrefresh * mode->htotal * mode->vtotal));
do_div(bpl, 1000000); /* seconds */ dev_dbg(d->dev, "picoseconds between two pixels: %llu\n",
pclk);
/*
* How many bytes per line will this update frequency yield?
*
* Calculate the number of picoseconds for one scanline (1), then
* divide by 1000000000000 (2) to get in pixels per second we
* want to output.
*
* Multiply with number of bytes per second at this video display
* frequency (3) to get number of bytes transferred during this
* time. Notice that we use the frequency the display wants,
* not what we actually get from the DSI PLL, which is hs_freq.
*
* These arithmetics are done in a different order to avoid
* overflow.
*/
bpl = pclk * mode->htotal; /* (1) picoseconds per line */
dev_dbg(d->dev, "picoseconds per line: %llu\n", bpl);
/* Multiply with bytes per second (3) */
bpl *= (d->mdsi->hs_rate / 8);
/* Pixels per second (2) */
bpl = DIV_ROUND_DOWN_ULL(bpl, 1000000); /* microseconds */
bpl = DIV_ROUND_DOWN_ULL(bpl, 1000000); /* seconds */
/* parallel transactions in all lanes */
bpl *= d->mdsi->lanes; bpl *= d->mdsi->lanes;
dev_dbg(d->dev, "calculated bytes per line: %llu\n", bpl); dev_dbg(d->dev,
"calculated bytes per line: %llu @ %d Hz with HS %lu Hz\n",
bpl, mode->vrefresh, d->mdsi->hs_rate);
/* /*
* 6 is header + checksum, header = 4 bytes, checksum = 2 bytes * 6 is header + checksum, header = 4 bytes, checksum = 2 bytes
* 4 is short packet for vsync/hsync * 4 is short packet for vsync/hsync
*/ */
if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
/* Fixme: isn't the hsync width in pixels? */ /* Set the event packet size to 0 (not used) */
writel(0, d->regs + DSI_VID_BLKSIZE1);
/*
* FIXME: isn't the hsync width in pixels? The porch and
* sync area size is in pixels here, but this -6
* seems to be for bytes. It looks like this in the vendor
* code though. Is it completely untested?
*/
blkline_pck = bpl - (mode->hsync_end - mode->hsync_start) - 6; blkline_pck = bpl - (mode->hsync_end - mode->hsync_start) - 6;
val = blkline_pck << DSI_VID_BLKSIZE2_BLKLINE_PULSE_PCK_SHIFT; val = blkline_pck << DSI_VID_BLKSIZE2_BLKLINE_PULSE_PCK_SHIFT;
writel(val, d->regs + DSI_VID_BLKSIZE2); writel(val, d->regs + DSI_VID_BLKSIZE2);
} else { } else {
/* Set the sync pulse packet size to 0 (not used) */
writel(0, d->regs + DSI_VID_BLKSIZE2);
/* Specifying payload size in bytes (-4-6 from manual) */
blkline_pck = bpl - 4 - 6; blkline_pck = bpl - 4 - 6;
if (blkline_pck > 0x1FFF)
dev_err(d->dev, "blkline_pck too big %d bytes\n",
blkline_pck);
val = blkline_pck << DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_SHIFT; val = blkline_pck << DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_SHIFT;
val &= DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_MASK;
writel(val, d->regs + DSI_VID_BLKSIZE1); writel(val, d->regs + DSI_VID_BLKSIZE1);
} }
line_duration = (blkline_pck + 6) / d->mdsi->lanes; /*
dev_dbg(d->dev, "line duration %u\n", line_duration); * The line duration is used to scale back the frequency from
* the max frequency supported by the HS clock to the desired
* update frequency in vrefresh.
*/
line_duration = blkline_pck + 6;
/*
* The datasheet contains this complex condition to decreasing
* the line duration by 1 under very specific circumstances.
* Here we also imply that LP is used during burst EOL.
*/
if (d->mdsi->lanes == 2 && (hsa & 0x01) && (hfp & 0x01)
&& (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST))
line_duration--;
line_duration = DIV_ROUND_CLOSEST(line_duration, d->mdsi->lanes);
dev_dbg(d->dev, "line duration %u bytes\n", line_duration);
val = line_duration << DSI_VID_DPHY_TIME_REG_LINE_DURATION_SHIFT; val = line_duration << DSI_VID_DPHY_TIME_REG_LINE_DURATION_SHIFT;
/* /*
* This is the time to perform LP->HS on D-PHY * This is the time to perform LP->HS on D-PHY
* FIXME: nowhere to get this from: DT property on the DSI? * FIXME: nowhere to get this from: DT property on the DSI?
* The manual says this is "system dependent".
* values like 48 and 72 seen in the vendor code.
*/ */
val |= 0 << DSI_VID_DPHY_TIME_REG_WAKEUP_TIME_SHIFT; val |= 48 << DSI_VID_DPHY_TIME_REG_WAKEUP_TIME_SHIFT;
writel(val, d->regs + DSI_VID_DPHY_TIME); writel(val, d->regs + DSI_VID_DPHY_TIME);
/* Calculate block end of line */ /*
blkeol_pck = bpl - mode->hdisplay * bpp - 6; * See the manual figure 657 page 2203 for understanding the impact
blkeol_duration = (blkeol_pck + 6) / d->mdsi->lanes; * of the different burst mode settings.
dev_dbg(d->dev, "blkeol pck: %u, duration: %u\n", */
blkeol_pck, blkeol_duration);
if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) { if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) {
/* Set up EOL clock for burst mode */ int blkeol_pck, blkeol_duration;
/*
* Packet size at EOL for burst mode, this is only used
* if DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0 is NOT set,
* but we instead send NULL or blanking packets at EOL.
* This is given in number of bytes.
*
* See the manual page 2198 for the 13 reg_blkeol_pck bits.
*/
blkeol_pck = bpl - (mode->htotal * cpp) - 6;
if (blkeol_pck < 0) {
dev_err(d->dev, "video block does not fit on line!\n");
dev_err(d->dev,
"calculated bytes per line: %llu @ %d Hz\n",
bpl, mode->vrefresh);
dev_err(d->dev,
"bytes per line (blkline_pck) %u bytes\n",
blkline_pck);
dev_err(d->dev,
"blkeol_pck becomes %d bytes\n", blkeol_pck);
return;
}
dev_dbg(d->dev, "BLKEOL packet: %d bytes\n", blkeol_pck);
val = readl(d->regs + DSI_VID_BLKSIZE1); val = readl(d->regs + DSI_VID_BLKSIZE1);
val &= ~DSI_VID_BLKSIZE1_BLKEOL_PCK_MASK;
val |= blkeol_pck << DSI_VID_BLKSIZE1_BLKEOL_PCK_SHIFT; val |= blkeol_pck << DSI_VID_BLKSIZE1_BLKEOL_PCK_SHIFT;
writel(val, d->regs + DSI_VID_BLKSIZE1); writel(val, d->regs + DSI_VID_BLKSIZE1);
writel(blkeol_pck, d->regs + DSI_VID_VCA_SETTING2); /* Use the same value for exact burst limit */
val = blkeol_pck <<
DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_SHIFT;
val &= DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_MASK;
writel(val, d->regs + DSI_VID_VCA_SETTING2);
/*
* This BLKEOL duration is claimed to be the duration in clock
* cycles of the BLLP end-of-line (EOL) period for each line if
* DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0 is set.
*
* It is hard to trust the manuals' claim that this is in clock
* cycles as we mimic the behaviour of the vendor code, which
* appears to write a number of bytes that would have been
* transferred on a single lane.
*
* See the manual figure 657 page 2203 and page 2198 for the 13
* reg_blkeol_duration bits.
*
* FIXME: should this also be set up also for non-burst mode
* according to figure 565 page 2202?
*/
blkeol_duration = DIV_ROUND_CLOSEST(blkeol_pck + 6,
d->mdsi->lanes);
dev_dbg(d->dev, "BLKEOL duration: %d clock cycles\n",
blkeol_duration);
writel(blkeol_duration, d->regs + DSI_VID_PCK_TIME); val = readl(d->regs + DSI_VID_PCK_TIME);
writel(blkeol_duration - 6, d->regs + DSI_VID_VCA_SETTING1); val &= ~DSI_VID_PCK_TIME_BLKEOL_DURATION_MASK;
val |= blkeol_duration <<
DSI_VID_PCK_TIME_BLKEOL_DURATION_SHIFT;
writel(val, d->regs + DSI_VID_PCK_TIME);
/* Max burst limit, this is given in bytes */
val = readl(d->regs + DSI_VID_VCA_SETTING1);
val &= ~DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT_MASK;
val |= (blkeol_pck - 6) <<
DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT_SHIFT;
writel(val, d->regs + DSI_VID_VCA_SETTING1);
} }
/* Maximum line limit */ /* Maximum line limit */
val = readl(d->regs + DSI_VID_VCA_SETTING2); val = readl(d->regs + DSI_VID_VCA_SETTING2);
val |= blkline_pck << val &= ~DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT_MASK;
DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_SHIFT; val |= (blkline_pck - 6) <<
DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT_SHIFT;
writel(val, d->regs + DSI_VID_VCA_SETTING2); writel(val, d->regs + DSI_VID_VCA_SETTING2);
dev_dbg(d->dev, "blkline pck: %d bytes\n", blkline_pck - 6);
} }
static void mcde_dsi_start(struct mcde_dsi *d) static void mcde_dsi_start(struct mcde_dsi *d)

View File

@ -228,6 +228,7 @@
#define DSI_VID_PCK_TIME 0x000000A8 #define DSI_VID_PCK_TIME 0x000000A8
#define DSI_VID_PCK_TIME_BLKEOL_DURATION_SHIFT 0 #define DSI_VID_PCK_TIME_BLKEOL_DURATION_SHIFT 0
#define DSI_VID_PCK_TIME_BLKEOL_DURATION_MASK 0x00000FFF
#define DSI_VID_DPHY_TIME 0x000000AC #define DSI_VID_DPHY_TIME 0x000000AC
#define DSI_VID_DPHY_TIME_REG_LINE_DURATION_SHIFT 0 #define DSI_VID_DPHY_TIME_REG_LINE_DURATION_SHIFT 0

View File

@ -94,7 +94,7 @@ static int mtk_plane_atomic_check(struct drm_plane *plane,
if (!fb) if (!fb)
return 0; return 0;
if (!state->crtc) if (WARN_ON(!state->crtc))
return 0; return 0;
ret = mtk_drm_crtc_plane_check(state->crtc, plane, ret = mtk_drm_crtc_plane_check(state->crtc, plane,

View File

@ -157,7 +157,7 @@ static void submit_unlock_unpin_bo(struct msm_gem_submit *submit,
msm_gem_unpin_iova(&msm_obj->base, submit->aspace); msm_gem_unpin_iova(&msm_obj->base, submit->aspace);
if (submit->bos[i].flags & BO_LOCKED) if (submit->bos[i].flags & BO_LOCKED)
ww_mutex_unlock(&msm_obj->base.resv->lock); dma_resv_unlock(msm_obj->base.resv);
if (backoff && !(submit->bos[i].flags & BO_VALID)) if (backoff && !(submit->bos[i].flags & BO_VALID))
submit->bos[i].iova = 0; submit->bos[i].iova = 0;
@ -180,8 +180,8 @@ retry:
contended = i; contended = i;
if (!(submit->bos[i].flags & BO_LOCKED)) { if (!(submit->bos[i].flags & BO_LOCKED)) {
ret = ww_mutex_lock_interruptible(&msm_obj->base.resv->lock, ret = dma_resv_lock_interruptible(msm_obj->base.resv,
&submit->ticket); &submit->ticket);
if (ret) if (ret)
goto fail; goto fail;
submit->bos[i].flags |= BO_LOCKED; submit->bos[i].flags |= BO_LOCKED;
@ -202,8 +202,8 @@ fail:
if (ret == -EDEADLK) { if (ret == -EDEADLK) {
struct msm_gem_object *msm_obj = submit->bos[contended].obj; struct msm_gem_object *msm_obj = submit->bos[contended].obj;
/* we lost out in a seqno race, lock and retry.. */ /* we lost out in a seqno race, lock and retry.. */
ret = ww_mutex_lock_slow_interruptible(&msm_obj->base.resv->lock, ret = dma_resv_lock_slow_interruptible(msm_obj->base.resv,
&submit->ticket); &submit->ticket);
if (!ret) { if (!ret) {
submit->bos[contended].flags |= BO_LOCKED; submit->bos[contended].flags |= BO_LOCKED;
slow_locked = contended; slow_locked = contended;

View File

@ -42,7 +42,7 @@ static int lg4573_spi_write_u16(struct lg4573 *ctx, u16 data)
struct spi_transfer xfer = { struct spi_transfer xfer = {
.len = 2, .len = 2,
}; };
u16 temp = cpu_to_be16(data); __be16 temp = cpu_to_be16(data);
struct spi_message msg; struct spi_message msg;
dev_dbg(ctx->panel.dev, "writing data: %x\n", data); dev_dbg(ctx->panel.dev, "writing data: %x\n", data);

View File

@ -46,6 +46,7 @@ config ROCKCHIP_DW_HDMI
config ROCKCHIP_DW_MIPI_DSI config ROCKCHIP_DW_MIPI_DSI
bool "Rockchip specific extensions for Synopsys DW MIPI DSI" bool "Rockchip specific extensions for Synopsys DW MIPI DSI"
select GENERIC_PHY_MIPI_DPHY
help help
This selects support for Rockchip SoC specific extensions This selects support for Rockchip SoC specific extensions
for the Synopsys DesignWare HDMI driver. If you want to for the Synopsys DesignWare HDMI driver. If you want to

View File

@ -12,6 +12,7 @@
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/regmap.h> #include <linux/regmap.h>
@ -139,6 +140,12 @@
#define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0) #define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0)
#define DW_MIPI_NEEDS_GRF_CLK BIT(1) #define DW_MIPI_NEEDS_GRF_CLK BIT(1)
#define PX30_GRF_PD_VO_CON1 0x0438
#define PX30_DSI_FORCETXSTOPMODE (0xf << 7)
#define PX30_DSI_FORCERXMODE BIT(6)
#define PX30_DSI_TURNDISABLE BIT(5)
#define PX30_DSI_LCDC_SEL BIT(0)
#define RK3288_GRF_SOC_CON6 0x025c #define RK3288_GRF_SOC_CON6 0x025c
#define RK3288_DSI0_LCDC_SEL BIT(6) #define RK3288_DSI0_LCDC_SEL BIT(6)
#define RK3288_DSI1_LCDC_SEL BIT(9) #define RK3288_DSI1_LCDC_SEL BIT(9)
@ -223,6 +230,10 @@ struct dw_mipi_dsi_rockchip {
bool is_slave; bool is_slave;
struct dw_mipi_dsi_rockchip *slave; struct dw_mipi_dsi_rockchip *slave;
/* optional external dphy */
struct phy *phy;
union phy_configure_opts phy_opts;
unsigned int lane_mbps; /* per lane */ unsigned int lane_mbps; /* per lane */
u16 input_div; u16 input_div;
u16 feedback_div; u16 feedback_div;
@ -359,6 +370,9 @@ static int dw_mipi_dsi_phy_init(void *priv_data)
struct dw_mipi_dsi_rockchip *dsi = priv_data; struct dw_mipi_dsi_rockchip *dsi = priv_data;
int ret, i, vco; int ret, i, vco;
if (dsi->phy)
return 0;
/* /*
* Get vco from frequency(lane_mbps) * Get vco from frequency(lane_mbps)
* vco frequency table * vco frequency table
@ -467,6 +481,28 @@ static int dw_mipi_dsi_phy_init(void *priv_data)
return ret; return ret;
} }
static void dw_mipi_dsi_phy_power_on(void *priv_data)
{
struct dw_mipi_dsi_rockchip *dsi = priv_data;
int ret;
ret = phy_set_mode(dsi->phy, PHY_MODE_MIPI_DPHY);
if (ret) {
DRM_DEV_ERROR(dsi->dev, "failed to set phy mode: %d\n", ret);
return;
}
phy_configure(dsi->phy, &dsi->phy_opts);
phy_power_on(dsi->phy);
}
static void dw_mipi_dsi_phy_power_off(void *priv_data)
{
struct dw_mipi_dsi_rockchip *dsi = priv_data;
phy_power_off(dsi->phy);
}
static int static int
dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
unsigned long mode_flags, u32 lanes, u32 format, unsigned long mode_flags, u32 lanes, u32 format,
@ -504,6 +540,17 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
"DPHY clock frequency is out of range\n"); "DPHY clock frequency is out of range\n");
} }
/* for external phy only a the mipi_dphy_config is necessary */
if (dsi->phy) {
phy_mipi_dphy_get_default_config(mode->clock * 1000 * 10 / 8,
bpp, lanes,
&dsi->phy_opts.mipi_dphy);
dsi->lane_mbps = target_mbps;
*lane_mbps = dsi->lane_mbps;
return 0;
}
fin = clk_get_rate(dsi->pllref_clk); fin = clk_get_rate(dsi->pllref_clk);
fout = target_mbps * USEC_PER_SEC; fout = target_mbps * USEC_PER_SEC;
@ -559,9 +606,89 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
return 0; return 0;
} }
struct hstt {
unsigned int maxfreq;
struct dw_mipi_dsi_dphy_timing timing;
};
#define HSTT(_maxfreq, _c_lp2hs, _c_hs2lp, _d_lp2hs, _d_hs2lp) \
{ \
.maxfreq = _maxfreq, \
.timing = { \
.clk_lp2hs = _c_lp2hs, \
.clk_hs2lp = _c_hs2lp, \
.data_lp2hs = _d_lp2hs, \
.data_hs2lp = _d_hs2lp, \
} \
}
/* Table A-3 High-Speed Transition Times */
struct hstt hstt_table[] = {
HSTT( 90, 32, 20, 26, 13),
HSTT( 100, 35, 23, 28, 14),
HSTT( 110, 32, 22, 26, 13),
HSTT( 130, 31, 20, 27, 13),
HSTT( 140, 33, 22, 26, 14),
HSTT( 150, 33, 21, 26, 14),
HSTT( 170, 32, 20, 27, 13),
HSTT( 180, 36, 23, 30, 15),
HSTT( 200, 40, 22, 33, 15),
HSTT( 220, 40, 22, 33, 15),
HSTT( 240, 44, 24, 36, 16),
HSTT( 250, 48, 24, 38, 17),
HSTT( 270, 48, 24, 38, 17),
HSTT( 300, 50, 27, 41, 18),
HSTT( 330, 56, 28, 45, 18),
HSTT( 360, 59, 28, 48, 19),
HSTT( 400, 61, 30, 50, 20),
HSTT( 450, 67, 31, 55, 21),
HSTT( 500, 73, 31, 59, 22),
HSTT( 550, 79, 36, 63, 24),
HSTT( 600, 83, 37, 68, 25),
HSTT( 650, 90, 38, 73, 27),
HSTT( 700, 95, 40, 77, 28),
HSTT( 750, 102, 40, 84, 28),
HSTT( 800, 106, 42, 87, 30),
HSTT( 850, 113, 44, 93, 31),
HSTT( 900, 118, 47, 98, 32),
HSTT( 950, 124, 47, 102, 34),
HSTT(1000, 130, 49, 107, 35),
HSTT(1050, 135, 51, 111, 37),
HSTT(1100, 139, 51, 114, 38),
HSTT(1150, 146, 54, 120, 40),
HSTT(1200, 153, 57, 125, 41),
HSTT(1250, 158, 58, 130, 42),
HSTT(1300, 163, 58, 135, 44),
HSTT(1350, 168, 60, 140, 45),
HSTT(1400, 172, 64, 144, 47),
HSTT(1450, 176, 65, 148, 48),
HSTT(1500, 181, 66, 153, 50)
};
static int
dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps,
struct dw_mipi_dsi_dphy_timing *timing)
{
int i;
for (i = 0; i < ARRAY_SIZE(hstt_table); i++)
if (lane_mbps < hstt_table[i].maxfreq)
break;
if (i == ARRAY_SIZE(hstt_table))
i--;
*timing = hstt_table[i].timing;
return 0;
}
static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_rockchip_phy_ops = { static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_rockchip_phy_ops = {
.init = dw_mipi_dsi_phy_init, .init = dw_mipi_dsi_phy_init,
.power_on = dw_mipi_dsi_phy_power_on,
.power_off = dw_mipi_dsi_phy_power_off,
.get_lane_mbps = dw_mipi_dsi_get_lane_mbps, .get_lane_mbps = dw_mipi_dsi_get_lane_mbps,
.get_timing = dw_mipi_dsi_phy_get_timing,
}; };
static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi, static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi,
@ -920,12 +1047,29 @@ static int dw_mipi_dsi_rockchip_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
/* try to get a possible external dphy */
dsi->phy = devm_phy_optional_get(dev, "dphy");
if (IS_ERR(dsi->phy)) {
ret = PTR_ERR(dsi->phy);
DRM_DEV_ERROR(dev, "failed to get mipi dphy: %d\n", ret);
return ret;
}
dsi->pllref_clk = devm_clk_get(dev, "ref"); dsi->pllref_clk = devm_clk_get(dev, "ref");
if (IS_ERR(dsi->pllref_clk)) { if (IS_ERR(dsi->pllref_clk)) {
ret = PTR_ERR(dsi->pllref_clk); if (dsi->phy) {
DRM_DEV_ERROR(dev, /*
"Unable to get pll reference clock: %d\n", ret); * if external phy is present, pll will be
return ret; * generated there.
*/
dsi->pllref_clk = NULL;
} else {
ret = PTR_ERR(dsi->pllref_clk);
DRM_DEV_ERROR(dev,
"Unable to get pll reference clock: %d\n",
ret);
return ret;
}
} }
if (dsi->cdata->flags & DW_MIPI_NEEDS_PHY_CFG_CLK) { if (dsi->cdata->flags & DW_MIPI_NEEDS_PHY_CFG_CLK) {
@ -989,6 +1133,24 @@ static int dw_mipi_dsi_rockchip_remove(struct platform_device *pdev)
return 0; return 0;
} }
static const struct rockchip_dw_dsi_chip_data px30_chip_data[] = {
{
.reg = 0xff450000,
.lcdsel_grf_reg = PX30_GRF_PD_VO_CON1,
.lcdsel_big = HIWORD_UPDATE(0, PX30_DSI_LCDC_SEL),
.lcdsel_lit = HIWORD_UPDATE(PX30_DSI_LCDC_SEL,
PX30_DSI_LCDC_SEL),
.lanecfg1_grf_reg = PX30_GRF_PD_VO_CON1,
.lanecfg1 = HIWORD_UPDATE(0, PX30_DSI_TURNDISABLE |
PX30_DSI_FORCERXMODE |
PX30_DSI_FORCETXSTOPMODE),
.max_data_lanes = 4,
},
{ /* sentinel */ }
};
static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = { static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = {
{ {
.reg = 0xff960000, .reg = 0xff960000,
@ -1057,6 +1219,9 @@ static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = {
static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = { static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = {
{ {
.compatible = "rockchip,px30-mipi-dsi",
.data = &px30_chip_data,
}, {
.compatible = "rockchip,rk3288-mipi-dsi", .compatible = "rockchip,rk3288-mipi-dsi",
.data = &rk3288_chip_data, .data = &rk3288_chip_data,
}, { }, {

View File

@ -60,3 +60,8 @@ cmdline_test(drm_cmdline_test_vmirror)
cmdline_test(drm_cmdline_test_margin_options) cmdline_test(drm_cmdline_test_margin_options)
cmdline_test(drm_cmdline_test_multiple_options) cmdline_test(drm_cmdline_test_multiple_options)
cmdline_test(drm_cmdline_test_invalid_option) cmdline_test(drm_cmdline_test_invalid_option)
cmdline_test(drm_cmdline_test_bpp_extra_and_option)
cmdline_test(drm_cmdline_test_extra_and_option)
cmdline_test(drm_cmdline_test_freestanding_options)
cmdline_test(drm_cmdline_test_freestanding_force_e_and_options)
cmdline_test(drm_cmdline_test_panel_orientation)

View File

@ -992,6 +992,128 @@ static int drm_cmdline_test_invalid_option(void *ignored)
return 0; return 0;
} }
static int drm_cmdline_test_bpp_extra_and_option(void *ignored)
{
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24e,rotate=180",
&no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
FAIL_ON(mode.yres != 480);
FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
FAIL_ON(mode.refresh_specified);
FAIL_ON(!mode.bpp_specified);
FAIL_ON(mode.bpp != 24);
FAIL_ON(mode.rb);
FAIL_ON(mode.cvt);
FAIL_ON(mode.interlace);
FAIL_ON(mode.margins);
FAIL_ON(mode.force != DRM_FORCE_ON);
return 0;
}
static int drm_cmdline_test_extra_and_option(void *ignored)
{
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480e,rotate=180",
&no_connector,
&mode));
FAIL_ON(!mode.specified);
FAIL_ON(mode.xres != 720);
FAIL_ON(mode.yres != 480);
FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
FAIL_ON(mode.refresh_specified);
FAIL_ON(mode.bpp_specified);
FAIL_ON(mode.rb);
FAIL_ON(mode.cvt);
FAIL_ON(mode.interlace);
FAIL_ON(mode.margins);
FAIL_ON(mode.force != DRM_FORCE_ON);
return 0;
}
static int drm_cmdline_test_freestanding_options(void *ignored)
{
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
&no_connector,
&mode));
FAIL_ON(mode.specified);
FAIL_ON(mode.refresh_specified);
FAIL_ON(mode.bpp_specified);
FAIL_ON(mode.tv_margins.right != 14);
FAIL_ON(mode.tv_margins.left != 24);
FAIL_ON(mode.tv_margins.bottom != 36);
FAIL_ON(mode.tv_margins.top != 42);
FAIL_ON(mode.rb);
FAIL_ON(mode.cvt);
FAIL_ON(mode.interlace);
FAIL_ON(mode.margins);
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
return 0;
}
static int drm_cmdline_test_freestanding_force_e_and_options(void *ignored)
{
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("e,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
&no_connector,
&mode));
FAIL_ON(mode.specified);
FAIL_ON(mode.refresh_specified);
FAIL_ON(mode.bpp_specified);
FAIL_ON(mode.tv_margins.right != 14);
FAIL_ON(mode.tv_margins.left != 24);
FAIL_ON(mode.tv_margins.bottom != 36);
FAIL_ON(mode.tv_margins.top != 42);
FAIL_ON(mode.rb);
FAIL_ON(mode.cvt);
FAIL_ON(mode.interlace);
FAIL_ON(mode.margins);
FAIL_ON(mode.force != DRM_FORCE_ON);
return 0;
}
static int drm_cmdline_test_panel_orientation(void *ignored)
{
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("panel_orientation=upside_down",
&no_connector,
&mode));
FAIL_ON(mode.specified);
FAIL_ON(mode.refresh_specified);
FAIL_ON(mode.bpp_specified);
FAIL_ON(mode.panel_orientation != DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP);
FAIL_ON(mode.rb);
FAIL_ON(mode.cvt);
FAIL_ON(mode.interlace);
FAIL_ON(mode.margins);
FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
return 0;
}
#include "drm_selftest.c" #include "drm_selftest.c"
static int __init test_drm_cmdline_init(void) static int __init test_drm_cmdline_init(void)

View File

@ -309,11 +309,24 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
return 0; return 0;
} }
static int
dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps,
struct dw_mipi_dsi_dphy_timing *timing)
{
timing->clk_hs2lp = 0x40;
timing->clk_lp2hs = 0x40;
timing->data_hs2lp = 0x40;
timing->data_lp2hs = 0x40;
return 0;
}
static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = { static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = {
.init = dw_mipi_dsi_phy_init, .init = dw_mipi_dsi_phy_init,
.power_on = dw_mipi_dsi_phy_power_on, .power_on = dw_mipi_dsi_phy_power_on,
.power_off = dw_mipi_dsi_phy_power_off, .power_off = dw_mipi_dsi_phy_power_off,
.get_lane_mbps = dw_mipi_dsi_get_lane_mbps, .get_lane_mbps = dw_mipi_dsi_get_lane_mbps,
.get_timing = dw_mipi_dsi_phy_get_timing,
}; };
static struct dw_mipi_dsi_plat_data dw_mipi_dsi_stm_plat_data = { static struct dw_mipi_dsi_plat_data dw_mipi_dsi_stm_plat_data = {

View File

@ -437,9 +437,6 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc,
/* Commit shadow registers = update planes at next vblank */ /* Commit shadow registers = update planes at next vblank */
reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR); reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR);
/* Enable LTDC */
reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN);
drm_crtc_vblank_on(crtc); drm_crtc_vblank_on(crtc);
} }
@ -453,9 +450,6 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc,
drm_crtc_vblank_off(crtc); drm_crtc_vblank_off(crtc);
/* disable LTDC */
reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN);
/* disable IRQ */ /* disable IRQ */
reg_clear(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); reg_clear(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE);
@ -1044,14 +1038,31 @@ static const struct drm_encoder_funcs ltdc_encoder_funcs = {
static void ltdc_encoder_disable(struct drm_encoder *encoder) static void ltdc_encoder_disable(struct drm_encoder *encoder)
{ {
struct drm_device *ddev = encoder->dev; struct drm_device *ddev = encoder->dev;
struct ltdc_device *ldev = ddev->dev_private;
DRM_DEBUG_DRIVER("\n"); DRM_DEBUG_DRIVER("\n");
/* Disable LTDC */
reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN);
/* Set to sleep state the pinctrl whatever type of encoder */ /* Set to sleep state the pinctrl whatever type of encoder */
pinctrl_pm_select_sleep_state(ddev->dev); pinctrl_pm_select_sleep_state(ddev->dev);
} }
static void ltdc_encoder_enable(struct drm_encoder *encoder) static void ltdc_encoder_enable(struct drm_encoder *encoder)
{
struct drm_device *ddev = encoder->dev;
struct ltdc_device *ldev = ddev->dev_private;
DRM_DEBUG_DRIVER("\n");
/* Enable LTDC */
reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN);
}
static void ltdc_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{ {
struct drm_device *ddev = encoder->dev; struct drm_device *ddev = encoder->dev;
@ -1069,6 +1080,7 @@ static void ltdc_encoder_enable(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs ltdc_encoder_helper_funcs = { static const struct drm_encoder_helper_funcs ltdc_encoder_helper_funcs = {
.disable = ltdc_encoder_disable, .disable = ltdc_encoder_disable,
.enable = ltdc_encoder_enable, .enable = ltdc_encoder_enable,
.mode_set = ltdc_encoder_mode_set,
}; };
static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge) static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge)

View File

@ -346,6 +346,27 @@ static int sun4i_drv_add_endpoints(struct device *dev,
return count; return count;
} }
#ifdef CONFIG_PM_SLEEP
static int sun4i_drv_drm_sys_suspend(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
return drm_mode_config_helper_suspend(drm);
}
static int sun4i_drv_drm_sys_resume(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
return drm_mode_config_helper_resume(drm);
}
#endif
static const struct dev_pm_ops sun4i_drv_drm_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(sun4i_drv_drm_sys_suspend,
sun4i_drv_drm_sys_resume)
};
static int sun4i_drv_probe(struct platform_device *pdev) static int sun4i_drv_probe(struct platform_device *pdev)
{ {
struct component_match *match = NULL; struct component_match *match = NULL;
@ -418,6 +439,7 @@ static struct platform_driver sun4i_drv_platform_driver = {
.driver = { .driver = {
.name = "sun4i-drm", .name = "sun4i-drm",
.of_match_table = sun4i_drv_of_table, .of_match_table = sun4i_drv_of_table,
.pm = &sun4i_drv_drm_pm_ops,
}, },
}; };
module_platform_driver(sun4i_drv_platform_driver); module_platform_driver(sun4i_drv_platform_driver);

View File

@ -1081,6 +1081,7 @@ static const struct component_ops sun6i_dsi_ops = {
static int sun6i_dsi_probe(struct platform_device *pdev) static int sun6i_dsi_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
const char *bus_clk_name = NULL;
struct sun6i_dsi *dsi; struct sun6i_dsi *dsi;
struct resource *res; struct resource *res;
void __iomem *base; void __iomem *base;
@ -1094,6 +1095,10 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
dsi->host.ops = &sun6i_dsi_host_ops; dsi->host.ops = &sun6i_dsi_host_ops;
dsi->host.dev = dev; dsi->host.dev = dev;
if (of_device_is_compatible(dev->of_node,
"allwinner,sun6i-a31-mipi-dsi"))
bus_clk_name = "bus";
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res); base = devm_ioremap_resource(dev, res);
if (IS_ERR(base)) { if (IS_ERR(base)) {
@ -1107,23 +1112,36 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
return PTR_ERR(dsi->regulator); return PTR_ERR(dsi->regulator);
} }
dsi->regs = devm_regmap_init_mmio_clk(dev, "bus", base,
&sun6i_dsi_regmap_config);
if (IS_ERR(dsi->regs)) {
dev_err(dev, "Couldn't create the DSI encoder regmap\n");
return PTR_ERR(dsi->regs);
}
dsi->reset = devm_reset_control_get_shared(dev, NULL); dsi->reset = devm_reset_control_get_shared(dev, NULL);
if (IS_ERR(dsi->reset)) { if (IS_ERR(dsi->reset)) {
dev_err(dev, "Couldn't get our reset line\n"); dev_err(dev, "Couldn't get our reset line\n");
return PTR_ERR(dsi->reset); return PTR_ERR(dsi->reset);
} }
dsi->mod_clk = devm_clk_get(dev, "mod"); dsi->regs = devm_regmap_init_mmio(dev, base, &sun6i_dsi_regmap_config);
if (IS_ERR(dsi->mod_clk)) { if (IS_ERR(dsi->regs)) {
dev_err(dev, "Couldn't get the DSI mod clock\n"); dev_err(dev, "Couldn't init regmap\n");
return PTR_ERR(dsi->mod_clk); return PTR_ERR(dsi->regs);
}
dsi->bus_clk = devm_clk_get(dev, bus_clk_name);
if (IS_ERR(dsi->bus_clk)) {
dev_err(dev, "Couldn't get the DSI bus clock\n");
return PTR_ERR(dsi->bus_clk);
}
ret = regmap_mmio_attach_clk(dsi->regs, dsi->bus_clk);
if (ret)
return ret;
if (of_device_is_compatible(dev->of_node,
"allwinner,sun6i-a31-mipi-dsi")) {
dsi->mod_clk = devm_clk_get(dev, "mod");
if (IS_ERR(dsi->mod_clk)) {
dev_err(dev, "Couldn't get the DSI mod clock\n");
ret = PTR_ERR(dsi->mod_clk);
goto err_attach_clk;
}
} }
/* /*
@ -1161,6 +1179,9 @@ err_pm_disable:
pm_runtime_disable(dev); pm_runtime_disable(dev);
err_unprotect_clk: err_unprotect_clk:
clk_rate_exclusive_put(dsi->mod_clk); clk_rate_exclusive_put(dsi->mod_clk);
err_attach_clk:
if (!IS_ERR(dsi->bus_clk))
regmap_mmio_detach_clk(dsi->regs);
return ret; return ret;
} }
@ -1174,6 +1195,9 @@ static int sun6i_dsi_remove(struct platform_device *pdev)
pm_runtime_disable(dev); pm_runtime_disable(dev);
clk_rate_exclusive_put(dsi->mod_clk); clk_rate_exclusive_put(dsi->mod_clk);
if (!IS_ERR(dsi->bus_clk))
regmap_mmio_detach_clk(dsi->regs);
return 0; return 0;
} }
@ -1232,6 +1256,7 @@ static const struct dev_pm_ops sun6i_dsi_pm_ops = {
static const struct of_device_id sun6i_dsi_of_table[] = { static const struct of_device_id sun6i_dsi_of_table[] = {
{ .compatible = "allwinner,sun6i-a31-mipi-dsi" }, { .compatible = "allwinner,sun6i-a31-mipi-dsi" },
{ .compatible = "allwinner,sun50i-a64-mipi-dsi" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, sun6i_dsi_of_table); MODULE_DEVICE_TABLE(of, sun6i_dsi_of_table);

View File

@ -568,7 +568,7 @@ vc4_unlock_bo_reservations(struct drm_device *dev,
for (i = 0; i < exec->bo_count; i++) { for (i = 0; i < exec->bo_count; i++) {
struct drm_gem_object *bo = &exec->bo[i]->base; struct drm_gem_object *bo = &exec->bo[i]->base;
ww_mutex_unlock(&bo->resv->lock); dma_resv_unlock(bo->resv);
} }
ww_acquire_fini(acquire_ctx); ww_acquire_fini(acquire_ctx);
@ -595,8 +595,7 @@ vc4_lock_bo_reservations(struct drm_device *dev,
retry: retry:
if (contended_lock != -1) { if (contended_lock != -1) {
bo = &exec->bo[contended_lock]->base; bo = &exec->bo[contended_lock]->base;
ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, ret = dma_resv_lock_slow_interruptible(bo->resv, acquire_ctx);
acquire_ctx);
if (ret) { if (ret) {
ww_acquire_done(acquire_ctx); ww_acquire_done(acquire_ctx);
return ret; return ret;
@ -609,19 +608,19 @@ retry:
bo = &exec->bo[i]->base; bo = &exec->bo[i]->base;
ret = ww_mutex_lock_interruptible(&bo->resv->lock, acquire_ctx); ret = dma_resv_lock_interruptible(bo->resv, acquire_ctx);
if (ret) { if (ret) {
int j; int j;
for (j = 0; j < i; j++) { for (j = 0; j < i; j++) {
bo = &exec->bo[j]->base; bo = &exec->bo[j]->base;
ww_mutex_unlock(&bo->resv->lock); dma_resv_unlock(bo->resv);
} }
if (contended_lock != -1 && contended_lock >= i) { if (contended_lock != -1 && contended_lock >= i) {
bo = &exec->bo[contended_lock]->base; bo = &exec->bo[contended_lock]->base;
ww_mutex_unlock(&bo->resv->lock); dma_resv_unlock(bo->resv);
} }
if (ret == -EDEADLK) { if (ret == -EDEADLK) {

View File

@ -43,6 +43,9 @@
#define XRES_MAX 8192 #define XRES_MAX 8192
#define YRES_MAX 8192 #define YRES_MAX 8192
#define drm_connector_to_virtio_gpu_output(x) \
container_of(x, struct virtio_gpu_output, conn)
static const struct drm_crtc_funcs virtio_gpu_crtc_funcs = { static const struct drm_crtc_funcs virtio_gpu_crtc_funcs = {
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.destroy = drm_crtc_cleanup, .destroy = drm_crtc_cleanup,
@ -59,7 +62,7 @@ static const struct drm_framebuffer_funcs virtio_gpu_fb_funcs = {
.dirty = drm_atomic_helper_dirtyfb, .dirty = drm_atomic_helper_dirtyfb,
}; };
int static int
virtio_gpu_framebuffer_init(struct drm_device *dev, virtio_gpu_framebuffer_init(struct drm_device *dev,
struct virtio_gpu_framebuffer *vgfb, struct virtio_gpu_framebuffer *vgfb,
const struct drm_mode_fb_cmd2 *mode_cmd, const struct drm_mode_fb_cmd2 *mode_cmd,

View File

@ -103,8 +103,6 @@ struct virtio_gpu_fence {
struct virtio_gpu_fence_driver *drv; struct virtio_gpu_fence_driver *drv;
struct list_head node; struct list_head node;
}; };
#define to_virtio_fence(x) \
container_of(x, struct virtio_gpu_fence, f)
struct virtio_gpu_vbuffer { struct virtio_gpu_vbuffer {
char *buf; char *buf;
@ -135,10 +133,6 @@ struct virtio_gpu_output {
}; };
#define drm_crtc_to_virtio_gpu_output(x) \ #define drm_crtc_to_virtio_gpu_output(x) \
container_of(x, struct virtio_gpu_output, crtc) container_of(x, struct virtio_gpu_output, crtc)
#define drm_connector_to_virtio_gpu_output(x) \
container_of(x, struct virtio_gpu_output, conn)
#define drm_encoder_to_virtio_gpu_output(x) \
container_of(x, struct virtio_gpu_output, enc)
struct virtio_gpu_framebuffer { struct virtio_gpu_framebuffer {
struct drm_framebuffer base; struct drm_framebuffer base;
@ -183,6 +177,9 @@ struct virtio_gpu_device {
struct kmem_cache *vbufs; struct kmem_cache *vbufs;
bool vqs_ready; bool vqs_ready;
bool disable_notify;
bool pending_notify;
struct ida resource_ida; struct ida resource_ida;
wait_queue_head_t resp_wq; wait_queue_head_t resp_wq;
@ -335,11 +332,10 @@ void virtio_gpu_dequeue_ctrl_func(struct work_struct *work);
void virtio_gpu_dequeue_cursor_func(struct work_struct *work); void virtio_gpu_dequeue_cursor_func(struct work_struct *work);
void virtio_gpu_dequeue_fence_func(struct work_struct *work); void virtio_gpu_dequeue_fence_func(struct work_struct *work);
void virtio_gpu_disable_notify(struct virtio_gpu_device *vgdev);
void virtio_gpu_enable_notify(struct virtio_gpu_device *vgdev);
/* virtio_gpu_display.c */ /* virtio_gpu_display.c */
int virtio_gpu_framebuffer_init(struct drm_device *dev,
struct virtio_gpu_framebuffer *vgfb,
const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev); void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev);
void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev); void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev);
@ -350,7 +346,6 @@ struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev,
int index); int index);
/* virtio_gpu_fence.c */ /* virtio_gpu_fence.c */
bool virtio_fence_signaled(struct dma_fence *f);
struct virtio_gpu_fence *virtio_gpu_fence_alloc( struct virtio_gpu_fence *virtio_gpu_fence_alloc(
struct virtio_gpu_device *vgdev); struct virtio_gpu_device *vgdev);
void virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, void virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev,
@ -366,18 +361,12 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
struct virtio_gpu_object_params *params, struct virtio_gpu_object_params *params,
struct virtio_gpu_object **bo_ptr, struct virtio_gpu_object **bo_ptr,
struct virtio_gpu_fence *fence); struct virtio_gpu_fence *fence);
/* virtgpu_prime.c */ /* virtgpu_prime.c */
struct drm_gem_object *virtgpu_gem_prime_import_sg_table( struct drm_gem_object *virtgpu_gem_prime_import_sg_table(
struct drm_device *dev, struct dma_buf_attachment *attach, struct drm_device *dev, struct dma_buf_attachment *attach,
struct sg_table *sgt); struct sg_table *sgt);
static inline u64 virtio_gpu_object_mmap_offset(struct virtio_gpu_object *bo) /* virgl debugfs */
{
return drm_vma_node_offset_addr(&bo->base.base.vma_node);
}
/* virgl debufs */
int virtio_gpu_debugfs_init(struct drm_minor *minor); int virtio_gpu_debugfs_init(struct drm_minor *minor);
#endif #endif

View File

@ -27,6 +27,9 @@
#include "virtgpu_drv.h" #include "virtgpu_drv.h"
#define to_virtio_fence(x) \
container_of(x, struct virtio_gpu_fence, f)
static const char *virtio_get_driver_name(struct dma_fence *f) static const char *virtio_get_driver_name(struct dma_fence *f)
{ {
return "virtio_gpu"; return "virtio_gpu";
@ -37,7 +40,7 @@ static const char *virtio_get_timeline_name(struct dma_fence *f)
return "controlq"; return "controlq";
} }
bool virtio_fence_signaled(struct dma_fence *f) static bool virtio_fence_signaled(struct dma_fence *f)
{ {
struct virtio_gpu_fence *fence = to_virtio_fence(f); struct virtio_gpu_fence *fence = to_virtio_fence(f);

View File

@ -96,14 +96,12 @@ int virtio_gpu_mode_dumb_mmap(struct drm_file *file_priv,
uint32_t handle, uint64_t *offset_p) uint32_t handle, uint64_t *offset_p)
{ {
struct drm_gem_object *gobj; struct drm_gem_object *gobj;
struct virtio_gpu_object *obj;
BUG_ON(!offset_p); BUG_ON(!offset_p);
gobj = drm_gem_object_lookup(file_priv, handle); gobj = drm_gem_object_lookup(file_priv, handle);
if (gobj == NULL) if (gobj == NULL)
return -ENOENT; return -ENOENT;
obj = gem_to_virtio_gpu_obj(gobj); *offset_p = drm_vma_node_offset_addr(&gobj->vma_node);
*offset_p = virtio_gpu_object_mmap_offset(obj);
drm_gem_object_put_unlocked(gobj); drm_gem_object_put_unlocked(gobj);
return 0; return 0;
} }

View File

@ -24,6 +24,7 @@
*/ */
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
@ -88,7 +89,7 @@ static int virtio_gpu_plane_atomic_check(struct drm_plane *plane,
struct drm_crtc_state *crtc_state; struct drm_crtc_state *crtc_state;
int ret; int ret;
if (!state->fb || !state->crtc) if (!state->fb || WARN_ON(!state->crtc))
return 0; return 0;
crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
@ -103,22 +104,26 @@ static int virtio_gpu_plane_atomic_check(struct drm_plane *plane,
} }
static void virtio_gpu_update_dumb_bo(struct virtio_gpu_device *vgdev, static void virtio_gpu_update_dumb_bo(struct virtio_gpu_device *vgdev,
struct virtio_gpu_object *bo, struct drm_plane_state *state,
struct drm_plane_state *state) struct drm_rect *rect)
{ {
struct virtio_gpu_object *bo =
gem_to_virtio_gpu_obj(state->fb->obj[0]);
struct virtio_gpu_object_array *objs; struct virtio_gpu_object_array *objs;
uint32_t w = rect->x2 - rect->x1;
uint32_t h = rect->y2 - rect->y1;
uint32_t x = rect->x1;
uint32_t y = rect->y1;
uint32_t off = x * state->fb->format->cpp[0] +
y * state->fb->pitches[0];
objs = virtio_gpu_array_alloc(1); objs = virtio_gpu_array_alloc(1);
if (!objs) if (!objs)
return; return;
virtio_gpu_array_add_obj(objs, &bo->base.base); virtio_gpu_array_add_obj(objs, &bo->base.base);
virtio_gpu_cmd_transfer_to_host_2d
(vgdev, 0, virtio_gpu_cmd_transfer_to_host_2d(vgdev, off, w, h, x, y,
state->src_w >> 16, objs, NULL);
state->src_h >> 16,
state->src_x >> 16,
state->src_y >> 16,
objs, NULL);
} }
static void virtio_gpu_primary_plane_update(struct drm_plane *plane, static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
@ -127,8 +132,8 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
struct drm_device *dev = plane->dev; struct drm_device *dev = plane->dev;
struct virtio_gpu_device *vgdev = dev->dev_private; struct virtio_gpu_device *vgdev = dev->dev_private;
struct virtio_gpu_output *output = NULL; struct virtio_gpu_output *output = NULL;
struct virtio_gpu_framebuffer *vgfb;
struct virtio_gpu_object *bo; struct virtio_gpu_object *bo;
struct drm_rect rect;
if (plane->state->crtc) if (plane->state->crtc)
output = drm_crtc_to_virtio_gpu_output(plane->state->crtc); output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
@ -146,30 +151,43 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
return; return;
} }
vgfb = to_virtio_gpu_framebuffer(plane->state->fb); if (!drm_atomic_helper_damage_merged(old_state, plane->state, &rect))
bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]); return;
if (bo->dumb)
virtio_gpu_update_dumb_bo(vgdev, bo, plane->state); virtio_gpu_disable_notify(vgdev);
bo = gem_to_virtio_gpu_obj(plane->state->fb->obj[0]);
if (bo->dumb)
virtio_gpu_update_dumb_bo(vgdev, plane->state, &rect);
if (plane->state->fb != old_state->fb ||
plane->state->src_w != old_state->src_w ||
plane->state->src_h != old_state->src_h ||
plane->state->src_x != old_state->src_x ||
plane->state->src_y != old_state->src_y) {
DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n",
bo->hw_res_handle,
plane->state->crtc_w, plane->state->crtc_h,
plane->state->crtc_x, plane->state->crtc_y,
plane->state->src_w >> 16,
plane->state->src_h >> 16,
plane->state->src_x >> 16,
plane->state->src_y >> 16);
virtio_gpu_cmd_set_scanout(vgdev, output->index,
bo->hw_res_handle,
plane->state->src_w >> 16,
plane->state->src_h >> 16,
plane->state->src_x >> 16,
plane->state->src_y >> 16);
}
DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n",
bo->hw_res_handle,
plane->state->crtc_w, plane->state->crtc_h,
plane->state->crtc_x, plane->state->crtc_y,
plane->state->src_w >> 16,
plane->state->src_h >> 16,
plane->state->src_x >> 16,
plane->state->src_y >> 16);
virtio_gpu_cmd_set_scanout(vgdev, output->index,
bo->hw_res_handle,
plane->state->src_w >> 16,
plane->state->src_h >> 16,
plane->state->src_x >> 16,
plane->state->src_y >> 16);
virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle, virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle,
plane->state->src_x >> 16, rect.x1,
plane->state->src_y >> 16, rect.y1,
plane->state->src_w >> 16, rect.x2 - rect.x1,
plane->state->src_h >> 16); rect.y2 - rect.y1);
virtio_gpu_enable_notify(vgdev);
} }
static int virtio_gpu_cursor_prepare_fb(struct drm_plane *plane, static int virtio_gpu_cursor_prepare_fb(struct drm_plane *plane,

View File

@ -404,8 +404,12 @@ again:
} }
notify = virtio_gpu_queue_ctrl_buffer_locked(vgdev, vbuf, vout); notify = virtio_gpu_queue_ctrl_buffer_locked(vgdev, vbuf, vout);
spin_unlock(&vgdev->ctrlq.qlock); spin_unlock(&vgdev->ctrlq.qlock);
if (notify) if (notify) {
virtqueue_notify(vgdev->ctrlq.vq); if (vgdev->disable_notify)
vgdev->pending_notify = true;
else
virtqueue_notify(vgdev->ctrlq.vq);
}
if (sgt) { if (sgt) {
sg_free_table(sgt); sg_free_table(sgt);
@ -413,6 +417,21 @@ again:
} }
} }
void virtio_gpu_disable_notify(struct virtio_gpu_device *vgdev)
{
vgdev->disable_notify = true;
}
void virtio_gpu_enable_notify(struct virtio_gpu_device *vgdev)
{
vgdev->disable_notify = false;
if (!vgdev->pending_notify)
return;
vgdev->pending_notify = false;
virtqueue_notify(vgdev->ctrlq.vq);
}
static void virtio_gpu_queue_ctrl_buffer(struct virtio_gpu_device *vgdev, static void virtio_gpu_queue_ctrl_buffer(struct virtio_gpu_device *vgdev,
struct virtio_gpu_vbuffer *vbuf) struct virtio_gpu_vbuffer *vbuf)
{ {

View File

@ -19,6 +19,13 @@ struct dw_mipi_dsi;
struct mipi_dsi_device; struct mipi_dsi_device;
struct platform_device; struct platform_device;
struct dw_mipi_dsi_dphy_timing {
u16 data_hs2lp;
u16 data_lp2hs;
u16 clk_hs2lp;
u16 clk_lp2hs;
};
struct dw_mipi_dsi_phy_ops { struct dw_mipi_dsi_phy_ops {
int (*init)(void *priv_data); int (*init)(void *priv_data);
void (*power_on)(void *priv_data); void (*power_on)(void *priv_data);
@ -27,6 +34,8 @@ struct dw_mipi_dsi_phy_ops {
const struct drm_display_mode *mode, const struct drm_display_mode *mode,
unsigned long mode_flags, u32 lanes, u32 format, unsigned long mode_flags, u32 lanes, u32 format,
unsigned int *lane_mbps); unsigned int *lane_mbps);
int (*get_timing)(void *priv_data, unsigned int lane_mbps,
struct dw_mipi_dsi_dphy_timing *timing);
}; };
struct dw_mipi_dsi_host_ops { struct dw_mipi_dsi_host_ops {

View File

@ -35,7 +35,7 @@
* struct drm_crtc_commit - track modeset commits on a CRTC * struct drm_crtc_commit - track modeset commits on a CRTC
* *
* This structure is used to track pending modeset changes and atomic commit on * This structure is used to track pending modeset changes and atomic commit on
* a per-CRTC basis. Since updating the list should never block this structure * a per-CRTC basis. Since updating the list should never block, this structure
* is reference counted to allow waiters to safely wait on an event to complete, * is reference counted to allow waiters to safely wait on an event to complete,
* without holding any locks. * without holding any locks.
* *
@ -363,7 +363,7 @@ struct drm_atomic_state {
* When a connector or plane is not bound to any CRTC, it's still important * When a connector or plane is not bound to any CRTC, it's still important
* to preserve linearity to prevent the atomic states from being freed to early. * to preserve linearity to prevent the atomic states from being freed to early.
* *
* This commit (if set) is not bound to any crtc, but will be completed when * This commit (if set) is not bound to any CRTC, but will be completed when
* drm_atomic_helper_commit_hw_done() is called. * drm_atomic_helper_commit_hw_done() is called.
*/ */
struct drm_crtc_commit *fake_commit; struct drm_crtc_commit *fake_commit;
@ -476,12 +476,12 @@ drm_atomic_get_new_connector_for_encoder(struct drm_atomic_state *state,
struct drm_encoder *encoder); struct drm_encoder *encoder);
/** /**
* drm_atomic_get_existing_crtc_state - get crtc state, if it exists * drm_atomic_get_existing_crtc_state - get CRTC state, if it exists
* @state: global atomic state object * @state: global atomic state object
* @crtc: crtc to grab * @crtc: CRTC to grab
* *
* This function returns the crtc state for the given crtc, or NULL * This function returns the CRTC state for the given CRTC, or NULL
* if the crtc is not part of the global atomic state. * if the CRTC is not part of the global atomic state.
* *
* This function is deprecated, @drm_atomic_get_old_crtc_state or * This function is deprecated, @drm_atomic_get_old_crtc_state or
* @drm_atomic_get_new_crtc_state should be used instead. * @drm_atomic_get_new_crtc_state should be used instead.
@ -494,12 +494,12 @@ drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state,
} }
/** /**
* drm_atomic_get_old_crtc_state - get old crtc state, if it exists * drm_atomic_get_old_crtc_state - get old CRTC state, if it exists
* @state: global atomic state object * @state: global atomic state object
* @crtc: crtc to grab * @crtc: CRTC to grab
* *
* This function returns the old crtc state for the given crtc, or * This function returns the old CRTC state for the given CRTC, or
* NULL if the crtc is not part of the global atomic state. * NULL if the CRTC is not part of the global atomic state.
*/ */
static inline struct drm_crtc_state * static inline struct drm_crtc_state *
drm_atomic_get_old_crtc_state(struct drm_atomic_state *state, drm_atomic_get_old_crtc_state(struct drm_atomic_state *state,
@ -508,12 +508,12 @@ drm_atomic_get_old_crtc_state(struct drm_atomic_state *state,
return state->crtcs[drm_crtc_index(crtc)].old_state; return state->crtcs[drm_crtc_index(crtc)].old_state;
} }
/** /**
* drm_atomic_get_new_crtc_state - get new crtc state, if it exists * drm_atomic_get_new_crtc_state - get new CRTC state, if it exists
* @state: global atomic state object * @state: global atomic state object
* @crtc: crtc to grab * @crtc: CRTC to grab
* *
* This function returns the new crtc state for the given crtc, or * This function returns the new CRTC state for the given CRTC, or
* NULL if the crtc is not part of the global atomic state. * NULL if the CRTC is not part of the global atomic state.
*/ */
static inline struct drm_crtc_state * static inline struct drm_crtc_state *
drm_atomic_get_new_crtc_state(struct drm_atomic_state *state, drm_atomic_get_new_crtc_state(struct drm_atomic_state *state,
@ -978,11 +978,11 @@ drm_atomic_crtc_needs_modeset(const struct drm_crtc_state *state)
} }
/** /**
* drm_atomic_crtc_effectively_active - compute whether crtc is actually active * drm_atomic_crtc_effectively_active - compute whether CRTC is actually active
* @state: &drm_crtc_state for the CRTC * @state: &drm_crtc_state for the CRTC
* *
* When in self refresh mode, the crtc_state->active value will be false, since * When in self refresh mode, the crtc_state->active value will be false, since
* the crtc is off. However in some cases we're interested in whether the crtc * the CRTC is off. However in some cases we're interested in whether the CRTC
* is active, or effectively active (ie: it's connected to an active display). * is active, or effectively active (ie: it's connected to an active display).
* In these cases, use this function instead of just checking active. * In these cases, use this function instead of just checking active.
*/ */

View File

@ -152,7 +152,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
/** /**
* drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
* @plane: the loop cursor * @plane: the loop cursor
* @crtc: the crtc whose planes are iterated * @crtc: the CRTC whose planes are iterated
* *
* This iterates over the current state, useful (for example) when applying * This iterates over the current state, useful (for example) when applying
* atomic state after it has been checked and swapped. To iterate over the * atomic state after it has been checked and swapped. To iterate over the
@ -166,7 +166,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
/** /**
* drm_crtc_atomic_state_for_each_plane - iterate over attached planes in new state * drm_crtc_atomic_state_for_each_plane - iterate over attached planes in new state
* @plane: the loop cursor * @plane: the loop cursor
* @crtc_state: the incoming crtc-state * @crtc_state: the incoming CRTC state
* *
* Similar to drm_crtc_for_each_plane(), but iterates the planes that will be * Similar to drm_crtc_for_each_plane(), but iterates the planes that will be
* attached if the specified state is applied. Useful during for example * attached if the specified state is applied. Useful during for example
@ -180,7 +180,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
* drm_crtc_atomic_state_for_each_plane_state - iterate over attached planes in new state * drm_crtc_atomic_state_for_each_plane_state - iterate over attached planes in new state
* @plane: the loop cursor * @plane: the loop cursor
* @plane_state: loop cursor for the plane's state, must be const * @plane_state: loop cursor for the plane's state, must be const
* @crtc_state: the incoming crtc-state * @crtc_state: the incoming CRTC state
* *
* Similar to drm_crtc_for_each_plane(), but iterates the planes that will be * Similar to drm_crtc_for_each_plane(), but iterates the planes that will be
* attached if the specified state is applied. Useful during for example * attached if the specified state is applied. Useful during for example
@ -189,7 +189,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
* *
* Compared to just drm_atomic_crtc_state_for_each_plane() this also fills in a * Compared to just drm_atomic_crtc_state_for_each_plane() this also fills in a
* const plane_state. This is useful when a driver just wants to peek at other * const plane_state. This is useful when a driver just wants to peek at other
* active planes on this crtc, but does not need to change it. * active planes on this CRTC, but does not need to change it.
*/ */
#define drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) \ #define drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) \
drm_for_each_plane_mask(plane, (crtc_state)->state->dev, (crtc_state)->plane_mask) \ drm_for_each_plane_mask(plane, (crtc_state)->state->dev, (crtc_state)->plane_mask) \

View File

@ -1069,6 +1069,14 @@ struct drm_cmdline_mode {
*/ */
unsigned int rotation_reflection; unsigned int rotation_reflection;
/**
* @panel_orientation:
*
* drm-connector "panel orientation" property override value,
* DRM_MODE_PANEL_ORIENTATION_UNKNOWN if not set.
*/
enum drm_panel_orientation panel_orientation;
/** /**
* @tv_margins: TV margins to apply to the mode. * @tv_margins: TV margins to apply to the mode.
*/ */

View File

@ -198,7 +198,7 @@ static inline struct drm_panel *of_drm_find_panel(const struct device_node *np)
} }
#endif #endif
#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) #if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE)
int drm_panel_of_backlight(struct drm_panel *panel); int drm_panel_of_backlight(struct drm_panel *panel);
#else #else
static inline int drm_panel_of_backlight(struct drm_panel *panel) static inline int drm_panel_of_backlight(struct drm_panel *panel)

View File

@ -322,6 +322,8 @@ static inline bool drm_debug_enabled(enum drm_debug_category category)
/* /*
* struct device based logging * struct device based logging
*
* Prefer drm_device based logging over device or prink based logging.
*/ */
__printf(3, 4) __printf(3, 4)
@ -417,8 +419,71 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category,
_DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_PRIME, \ _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_PRIME, \
fmt, ##__VA_ARGS__) fmt, ##__VA_ARGS__)
/*
* struct drm_device based logging
*
* Prefer drm_device based logging over device or prink based logging.
*/
/* Helper for struct drm_device based logging. */
#define __drm_printk(drm, level, type, fmt, ...) \
dev_##level##type((drm)->dev, "[drm] " fmt, ##__VA_ARGS__)
#define drm_info(drm, fmt, ...) \
__drm_printk((drm), info,, fmt, ##__VA_ARGS__)
#define drm_notice(drm, fmt, ...) \
__drm_printk((drm), notice,, fmt, ##__VA_ARGS__)
#define drm_warn(drm, fmt, ...) \
__drm_printk((drm), warn,, fmt, ##__VA_ARGS__)
#define drm_err(drm, fmt, ...) \
__drm_printk((drm), err,, "*ERROR* " fmt, ##__VA_ARGS__)
#define drm_info_once(drm, fmt, ...) \
__drm_printk((drm), info, _once, fmt, ##__VA_ARGS__)
#define drm_notice_once(drm, fmt, ...) \
__drm_printk((drm), notice, _once, fmt, ##__VA_ARGS__)
#define drm_warn_once(drm, fmt, ...) \
__drm_printk((drm), warn, _once, fmt, ##__VA_ARGS__)
#define drm_err_once(drm, fmt, ...) \
__drm_printk((drm), err, _once, "*ERROR* " fmt, ##__VA_ARGS__)
#define drm_err_ratelimited(drm, fmt, ...) \
__drm_printk((drm), err, _ratelimited, "*ERROR* " fmt, ##__VA_ARGS__)
#define drm_dbg_core(drm, fmt, ...) \
drm_dev_dbg((drm)->dev, DRM_UT_CORE, fmt, ##__VA_ARGS__)
#define drm_dbg(drm, fmt, ...) \
drm_dev_dbg((drm)->dev, DRM_UT_DRIVER, fmt, ##__VA_ARGS__)
#define drm_dbg_kms(drm, fmt, ...) \
drm_dev_dbg((drm)->dev, DRM_UT_KMS, fmt, ##__VA_ARGS__)
#define drm_dbg_prime(drm, fmt, ...) \
drm_dev_dbg((drm)->dev, DRM_UT_PRIME, fmt, ##__VA_ARGS__)
#define drm_dbg_atomic(drm, fmt, ...) \
drm_dev_dbg((drm)->dev, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__)
#define drm_dbg_vbl(drm, fmt, ...) \
drm_dev_dbg((drm)->dev, DRM_UT_VBL, fmt, ##__VA_ARGS__)
#define drm_dbg_state(drm, fmt, ...) \
drm_dev_dbg((drm)->dev, DRM_UT_STATE, fmt, ##__VA_ARGS__)
#define drm_dbg_lease(drm, fmt, ...) \
drm_dev_dbg((drm)->dev, DRM_UT_LEASE, fmt, ##__VA_ARGS__)
#define drm_dbg_dp(drm, fmt, ...) \
drm_dev_dbg((drm)->dev, DRM_UT_DP, fmt, ##__VA_ARGS__)
/* /*
* printk based logging * printk based logging
*
* Prefer drm_device based logging over device or prink based logging.
*/ */
__printf(2, 3) __printf(2, 3)

View File

@ -42,12 +42,12 @@ struct dma_heap_allocation_data {
#define DMA_HEAP_IOC_MAGIC 'H' #define DMA_HEAP_IOC_MAGIC 'H'
/** /**
* DOC: DMA_HEAP_IOC_ALLOC - allocate memory from pool * DOC: DMA_HEAP_IOCTL_ALLOC - allocate memory from pool
* *
* Takes a dma_heap_allocation_data struct and returns it with the fd field * Takes a dma_heap_allocation_data struct and returns it with the fd field
* populated with the dmabuf handle of the allocation. * populated with the dmabuf handle of the allocation.
*/ */
#define DMA_HEAP_IOC_ALLOC _IOWR(DMA_HEAP_IOC_MAGIC, 0x0,\ #define DMA_HEAP_IOCTL_ALLOC _IOWR(DMA_HEAP_IOC_MAGIC, 0x0,\
struct dma_heap_allocation_data) struct dma_heap_allocation_data)
#endif /* _UAPI_LINUX_DMABUF_POOL_H */ #endif /* _UAPI_LINUX_DMABUF_POOL_H */

View File

@ -116,7 +116,7 @@ static int dmabuf_heap_alloc_fdflags(int fd, size_t len, unsigned int fd_flags,
if (!dmabuf_fd) if (!dmabuf_fd)
return -EINVAL; return -EINVAL;
ret = ioctl(fd, DMA_HEAP_IOC_ALLOC, &data); ret = ioctl(fd, DMA_HEAP_IOCTL_ALLOC, &data);
if (ret < 0) if (ret < 0)
return ret; return ret;
*dmabuf_fd = (int)data.fd; *dmabuf_fd = (int)data.fd;