Commit f5c547ef authored by Dave Airlie's avatar Dave Airlie

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: default avatarDave 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
parents 3ae32714 1ce0d516
...@@ -15,7 +15,9 @@ properties: ...@@ -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: ...@@ -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: ...@@ -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:
......
# 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>;
};
};
};
};
...
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>;
};
};
};
};
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>;
};
};
};
};
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>;
};
};
};
};
...@@ -4,13 +4,16 @@ Rockchip specific extensions to the Synopsys Designware MIPI DSI ...@@ -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: ...@@ -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".
......
...@@ -15,7 +15,11 @@ properties: ...@@ -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
......
...@@ -65,6 +65,9 @@ Valid options are:: ...@@ -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.
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
......
...@@ -142,14 +142,14 @@ Contact: Daniel Vetter, respective driver maintainers ...@@ -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
......
...@@ -106,8 +106,8 @@ static long dma_heap_ioctl_allocate(struct file *file, void *data) ...@@ -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, ...@@ -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)
......
...@@ -109,7 +109,7 @@ static int system_heap_create(void) ...@@ -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;
......
...@@ -122,9 +122,8 @@ static int begin_cpu_udmabuf(struct dma_buf *buf, ...@@ -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, ...@@ -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;
} }
......
...@@ -20,8 +20,10 @@ static u64 get_lpu_event(struct d71_pipeline *d71_pipeline) ...@@ -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) ...@@ -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);
......
...@@ -175,6 +175,7 @@ ...@@ -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 @@ ...@@ -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)
......
...@@ -5,6 +5,7 @@ ...@@ -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 ...@@ -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, ...@@ -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
......
...@@ -10,6 +10,7 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) {
DRM_ERROR("connect iommu failed.\n");
goto disable_clk;
}
}
ret = mdev->funcs->enable_irq(mdev);
disable_clk: if (mdev->iommu && mdev->funcs->connect_iommu)
clk_disable_unprepare(mdev->aclk); if (mdev->funcs->connect_iommu(mdev))
DRM_ERROR("connect iommu failed.\n");
return ret; return 0;
} }
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;
} }
...@@ -20,6 +20,8 @@ ...@@ -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 @@ ...@@ -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 \
......
...@@ -33,6 +33,12 @@ static void komeda_unbind(struct device *dev) ...@@ -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) ...@@ -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) ...@@ -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[] = { ...@@ -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) ...@@ -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 = {
......
...@@ -78,6 +78,8 @@ static void evt_str(struct komeda_str *str, u64 events) ...@@ -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|");
......
...@@ -308,10 +308,6 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev) ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -512,7 +512,7 @@ static int malidp_de_plane_check(struct drm_plane *plane, ...@@ -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;
......
...@@ -255,7 +255,7 @@ void bochs_hw_setformat(struct bochs_device *bochs, ...@@ -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,
......
...@@ -35,14 +35,14 @@ config DRM_DUMB_VGA_DAC ...@@ -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"
......
# 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
......
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2019 Renesas Electronics Corporation
* Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com> * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*/ */
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <drm/drm_bridge.h> #include <drm/drm_bridge.h>
#include <drm/drm_panel.h> #include <drm/drm_panel.h>
struct lvds_encoder { struct lvds_codec {
struct drm_bridge bridge; struct drm_bridge bridge;
struct drm_bridge *panel_bridge; struct drm_bridge *panel_bridge;
struct gpio_desc *powerdown_gpio; struct gpio_desc *powerdown_gpio;
u32 connector_type;
}; };
static int lvds_encoder_attach(struct drm_bridge *bridge) static int lvds_codec_attach(struct drm_bridge *bridge)
{ {
struct lvds_encoder *lvds_encoder = container_of(bridge, struct lvds_codec *lvds_codec = container_of(bridge,
struct lvds_encoder, struct lvds_codec, bridge);
bridge);
return drm_bridge_attach(bridge->encoder, lvds_encoder->panel_bridge, return drm_bridge_attach(bridge->encoder, lvds_codec->panel_bridge,
bridge); bridge);
} }
static void lvds_encoder_enable(struct drm_bridge *bridge) static void lvds_codec_enable(struct drm_bridge *bridge)
{ {
struct lvds_encoder *lvds_encoder = container_of(bridge, struct lvds_codec *lvds_codec = container_of(bridge,
struct lvds_encoder, struct lvds_codec, bridge);
bridge);
if (lvds_encoder->powerdown_gpio) if (lvds_codec->powerdown_gpio)
gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 0); gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 0);
} }
static void lvds_encoder_disable(struct drm_bridge *bridge) static void lvds_codec_disable(struct drm_bridge *bridge)
{ {
struct lvds_encoder *lvds_encoder = container_of(bridge, struct lvds_codec *lvds_codec = container_of(bridge,
struct lvds_encoder, struct lvds_codec, bridge);
bridge);
if (lvds_encoder->powerdown_gpio) if (lvds_codec->powerdown_gpio)
gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 1); gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 1);
} }
static struct drm_bridge_funcs funcs = { static struct drm_bridge_funcs funcs = {
.attach = lvds_encoder_attach, .attach = lvds_codec_attach,
.enable = lvds_encoder_enable, .enable = lvds_codec_enable,
.disable = lvds_encoder_disable, .disable = lvds_codec_disable,
}; };
static int lvds_encoder_probe(struct platform_device *pdev) static int lvds_codec_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *port;
struct device_node *endpoint;
struct device_node *panel_node; struct device_node *panel_node;
struct drm_panel *panel; struct drm_panel *panel;
struct lvds_encoder *lvds_encoder; struct lvds_codec *lvds_codec;
lvds_encoder = devm_kzalloc(dev, sizeof(*lvds_encoder), GFP_KERNEL); lvds_codec = devm_kzalloc(dev, sizeof(*lvds_codec), GFP_KERNEL);
if (!lvds_encoder) if (!lvds_codec)
return -ENOMEM; return -ENOMEM;
lvds_encoder->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown", lvds_codec->connector_type = (uintptr_t)of_device_get_match_data(dev);
GPIOD_OUT_HIGH); lvds_codec->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
if (IS_ERR(lvds_encoder->powerdown_gpio)) { GPIOD_OUT_HIGH);
int err = PTR_ERR(lvds_encoder->powerdown_gpio); if (IS_ERR(lvds_codec->powerdown_gpio)) {
int err = PTR_ERR(lvds_codec->powerdown_gpio);
if (err != -EPROBE_DEFER) if (err != -EPROBE_DEFER)
dev_err(dev, "powerdown GPIO failure: %d\n", err); dev_err(dev, "powerdown GPIO failure: %d\n", err);
...@@ -78,23 +77,9 @@ static int lvds_encoder_probe(struct platform_device *pdev) ...@@ -78,23 +77,9 @@ static int lvds_encoder_probe(struct platform_device *pdev)
} }
/* Locate the panel DT node. */ /* Locate the panel DT node. */
port = of_graph_get_port_by_id(dev->of_node, 1); panel_node = of_graph_get_remote_node(dev->of_node, 1, 0);
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) { if (!panel_node) {
dev_dbg(dev, "no remote endpoint for port 1\n"); dev_dbg(dev, "panel DT node not found\n");
return -ENXIO; return -ENXIO;
} }
...@@ -105,51 +90,62 @@ static int lvds_encoder_probe(struct platform_device *pdev) ...@@ -105,51 +90,62 @@ static int lvds_encoder_probe(struct platform_device *pdev)
return PTR_ERR(panel); return PTR_ERR(panel);
} }
lvds_encoder->panel_bridge = lvds_codec->panel_bridge =
devm_drm_panel_bridge_add_typed(dev, panel, devm_drm_panel_bridge_add_typed(dev, panel,
DRM_MODE_CONNECTOR_LVDS); lvds_codec->connector_type);
if (IS_ERR(lvds_encoder->panel_bridge)) if (IS_ERR(lvds_codec->panel_bridge))
return PTR_ERR(lvds_encoder->panel_bridge); return PTR_ERR(lvds_codec->panel_bridge);
/* The panel_bridge bridge is attached to the panel's of_node, /*
* 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 * but we need a bridge attached to our of_node for our user
* to look up. * to look up.
*/ */
lvds_encoder->bridge.of_node = dev->of_node; lvds_codec->bridge.of_node = dev->of_node;
lvds_encoder->bridge.funcs = &funcs; lvds_codec->bridge.funcs = &funcs;
drm_bridge_add(&lvds_encoder->bridge); drm_bridge_add(&lvds_codec->bridge);
platform_set_drvdata(pdev, lvds_encoder); platform_set_drvdata(pdev, lvds_codec);
return 0; return 0;
} }
static int lvds_encoder_remove(struct platform_device *pdev) static int lvds_codec_remove(struct platform_device *pdev)
{ {
struct lvds_encoder *lvds_encoder = platform_get_drvdata(pdev); struct lvds_codec *lvds_codec = platform_get_drvdata(pdev);
drm_bridge_remove(&lvds_encoder->bridge); drm_bridge_remove(&lvds_codec->bridge);
return 0; return 0;
} }
static const struct of_device_id lvds_encoder_match[] = { static const struct of_device_id lvds_codec_match[] = {
{ .compatible = "lvds-encoder" }, {
{ .compatible = "thine,thc63lvdm83d" }, .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_encoder_match); MODULE_DEVICE_TABLE(of, lvds_codec_match);
static struct platform_driver lvds_encoder_driver = { static struct platform_driver lvds_codec_driver = {
.probe = lvds_encoder_probe, .probe = lvds_codec_probe,
.remove = lvds_encoder_remove, .remove = lvds_codec_remove,
.driver = { .driver = {
.name = "lvds-encoder", .name = "lvds-codec",
.of_match_table = lvds_encoder_match, .of_match_table = lvds_codec_match,
}, },
}; };
module_platform_driver(lvds_encoder_driver); module_platform_driver(lvds_codec_driver);
MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
MODULE_DESCRIPTION("Transparent parallel to LVDS encoder"); MODULE_DESCRIPTION("LVDS encoders and decoders");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -719,7 +719,15 @@ static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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);
} }
......
...@@ -251,7 +251,7 @@ EXPORT_SYMBOL(drm_atomic_state_clear); ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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
......
This diff is collapsed.
...@@ -160,12 +160,12 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, ...@@ -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, ...@@ -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:
......
...@@ -150,7 +150,7 @@ void drm_client_release(struct drm_client_dev *client) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
} }
......
...@@ -622,7 +622,8 @@ int drm_dev_init(struct drm_device *dev, ...@@ -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, ...@@ -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);
......
This diff is collapsed.
...@@ -191,6 +191,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client) ...@@ -2143,7 +2147,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
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) ...@@ -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) ...@@ -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);
......
...@@ -74,8 +74,7 @@ drm_gem_fb_alloc(struct drm_device *dev, ...@@ -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, ...@@ -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;
} }
......
...@@ -1568,33 +1568,76 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length, ...@@ -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, ...@@ -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[] = { ...@@ -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, ...@@ -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;
#ifdef CONFIG_FB memset(mode, 0, sizeof(*mode));
if (!mode_option) mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
mode_option = fb_mode_option;
#endif
if (!mode_option) { 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, ...@@ -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, ...@@ -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, ...@@ -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;
......
...@@ -302,7 +302,7 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np) ...@@ -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
......
...@@ -113,7 +113,7 @@ static void submit_unlock_object(struct etnaviv_gem_submit *submit, int i) ...@@ -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 @@ static int submit_lock_objects(struct etnaviv_gem_submit *submit, ...@@ -133,8 +133,7 @@ static int submit_lock_objects(struct etnaviv_gem_submit *submit,
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 @@ static int submit_lock_objects(struct etnaviv_gem_submit *submit, ...@@ -161,8 +160,7 @@ static int submit_lock_objects(struct etnaviv_gem_submit *submit,
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;
......
...@@ -228,8 +228,8 @@ static void psbfb_copyarea_accel(struct fb_info *info, ...@@ -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, ...@@ -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];
......
This diff is collapsed.
...@@ -228,6 +228,7 @@ ...@@ -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
......
...@@ -94,7 +94,7 @@ static int mtk_plane_atomic_check(struct drm_plane *plane, ...@@ -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,
......
...@@ -157,7 +157,7 @@ static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, ...@@ -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 @@ static int submit_lock_objects(struct msm_gem_submit *submit) ...@@ -180,8 +180,8 @@ static int submit_lock_objects(struct msm_gem_submit *submit)
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 @@ static int submit_lock_objects(struct msm_gem_submit *submit) ...@@ -202,8 +202,8 @@ static int submit_lock_objects(struct msm_gem_submit *submit)
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;
......
...@@ -42,7 +42,7 @@ static int lg4573_spi_write_u16(struct lg4573 *ctx, u16 data) ...@@ -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);
......
...@@ -46,6 +46,7 @@ config ROCKCHIP_DW_HDMI ...@@ -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
......
...@@ -12,6 +12,7 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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[] = { ...@@ -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,
}, { }, {
......
...@@ -60,3 +60,8 @@ cmdline_test(drm_cmdline_test_vmirror) ...@@ -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)
...@@ -992,6 +992,128 @@ static int drm_cmdline_test_invalid_option(void *ignored) ...@@ -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)
......
...@@ -309,11 +309,24 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, ...@@ -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 = {
......
...@@ -437,9 +437,6 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, ...@@ -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, ...@@ -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 = { ...@@ -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) ...@@ -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)
......
...@@ -346,6 +346,27 @@ static int sun4i_drv_add_endpoints(struct device *dev, ...@@ -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 = { ...@@ -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);
......
...@@ -1081,6 +1081,7 @@ static const struct component_ops sun6i_dsi_ops = { ...@@ -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) ...@@ -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) ...@@ -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 @@ static int sun6i_dsi_probe(struct platform_device *pdev) ...@@ -1161,6 +1179,9 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
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) ...@@ -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 = { ...@@ -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);
......
...@@ -568,7 +568,7 @@ vc4_unlock_bo_reservations(struct drm_device *dev, ...@@ -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, ...@@ -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 @@ vc4_lock_bo_reservations(struct drm_device *dev, ...@@ -609,19 +608,19 @@ vc4_lock_bo_reservations(struct drm_device *dev,
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) {
......
...@@ -43,6 +43,9 @@ ...@@ -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 = { ...@@ -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,
......
...@@ -103,8 +103,6 @@ struct virtio_gpu_fence { ...@@ -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 { ...@@ -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 { ...@@ -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); ...@@ -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, ...@@ -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, ...@@ -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
...@@ -27,6 +27,9 @@ ...@@ -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) ...@@ -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);
......
...@@ -96,14 +96,12 @@ int virtio_gpu_mode_dumb_mmap(struct drm_file *file_priv, ...@@ -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;
} }
......
...@@ -24,6 +24,7 @@ ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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;
virtio_gpu_disable_notify(vgdev);
bo = gem_to_virtio_gpu_obj(plane->state->fb->obj[0]);
if (bo->dumb) if (bo->dumb)
virtio_gpu_update_dumb_bo(vgdev, bo, plane->state); virtio_gpu_update_dumb_bo(vgdev, plane->state, &rect);
DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n", if (plane->state->fb != old_state->fb ||
bo->hw_res_handle, plane->state->src_w != old_state->src_w ||
plane->state->crtc_w, plane->state->crtc_h, plane->state->src_h != old_state->src_h ||
plane->state->crtc_x, plane->state->crtc_y, plane->state->src_x != old_state->src_x ||
plane->state->src_w >> 16, plane->state->src_y != old_state->src_y) {
plane->state->src_h >> 16, DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n",
plane->state->src_x >> 16, bo->hw_res_handle,
plane->state->src_y >> 16); plane->state->crtc_w, plane->state->crtc_h,
virtio_gpu_cmd_set_scanout(vgdev, output->index, plane->state->crtc_x, plane->state->crtc_y,
bo->hw_res_handle, plane->state->src_w >> 16,
plane->state->src_w >> 16, plane->state->src_h >> 16,
plane->state->src_h >> 16, plane->state->src_x >> 16,
plane->state->src_x >> 16, plane->state->src_y >> 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,
......
...@@ -404,8 +404,12 @@ static void virtio_gpu_queue_fenced_ctrl_buffer(struct virtio_gpu_device *vgdev, ...@@ -404,8 +404,12 @@ static void virtio_gpu_queue_fenced_ctrl_buffer(struct virtio_gpu_device *vgdev,
} }
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 @@ static void virtio_gpu_queue_fenced_ctrl_buffer(struct virtio_gpu_device *vgdev, ...@@ -413,6 +417,21 @@ static void virtio_gpu_queue_fenced_ctrl_buffer(struct virtio_gpu_device *vgdev,
} }
} }
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)
{ {
......
...@@ -19,6 +19,13 @@ struct dw_mipi_dsi; ...@@ -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 { ...@@ -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 {
......
...@@ -35,7 +35,7 @@ ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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.
*/ */
......
...@@ -152,7 +152,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) \
......
...@@ -1069,6 +1069,14 @@ struct drm_cmdline_mode { ...@@ -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.
*/ */
......
...@@ -198,7 +198,7 @@ static inline struct drm_panel *of_drm_find_panel(const struct device_node *np) ...@@ -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)
......
...@@ -322,6 +322,8 @@ static inline bool drm_debug_enabled(enum drm_debug_category category) ...@@ -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, ...@@ -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)
......
...@@ -42,12 +42,12 @@ struct dma_heap_allocation_data { ...@@ -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 */
...@@ -116,7 +116,7 @@ static int dmabuf_heap_alloc_fdflags(int fd, size_t len, unsigned int fd_flags, ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment