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:
"#size-cells": true
compatible:
const: allwinner,sun6i-a31-mipi-dsi
enum:
- allwinner,sun6i-a31-mipi-dsi
- allwinner,sun50i-a64-mipi-dsi
reg:
maxItems: 1
......@@ -24,6 +26,8 @@ properties:
maxItems: 1
clocks:
minItems: 1
maxItems: 2
items:
- description: Bus Clock
- description: Module Clock
......@@ -63,13 +67,38 @@ required:
- reg
- interrupts
- clocks
- clock-names
- phys
- phy-names
- resets
- vcc-dsi-supply
- 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
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
Required properties:
- #address-cells: Should be <1>.
- #size-cells: Should be <0>.
- compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi".
"rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi".
- compatible: one of
"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.
- interrupts: Represent the controller's interrupt to the CPU(s).
- clocks, clock-names: Phandles to the controller's pll reference
clock(ref) and APB clock(pclk). For RK3399, a phy config clock
(phy_cfg) and a grf clock(grf) are required. As described in [1].
clock(ref) when using an internal dphy and APB clock(pclk).
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.
- 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.
......@@ -18,6 +21,8 @@ Required properties:
- video port 1 for either a panel or subsequent encoder
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.
- resets: list of phandle + reset specifier pairs, as described in [3].
- reset-names: string reset name, must be "apb".
......
......@@ -15,7 +15,11 @@ properties:
const: 0
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:
maxItems: 1
......
......@@ -65,6 +65,9 @@ Valid options are::
- reflect_y (boolean): Perform an axial symmetry on the Y axis
- rotate (integer): Rotate the initial framebuffer by x
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
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
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
now have DRM_DEV_* variants of the drm print macros, so we can start to convert
those drivers back to using drm-formwatted specific log messages.
now have drm_* variants of the drm print functions, so we can start to convert
those drivers back to using drm-formatted specific log messages.
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
......
......@@ -106,8 +106,8 @@ static long dma_heap_ioctl_allocate(struct file *file, void *data)
return 0;
}
unsigned int dma_heap_ioctl_cmds[] = {
DMA_HEAP_IOC_ALLOC,
static unsigned int dma_heap_ioctl_cmds[] = {
DMA_HEAP_IOCTL_ALLOC,
};
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);
switch (kcmd) {
case DMA_HEAP_IOC_ALLOC:
case DMA_HEAP_IOCTL_ALLOC:
ret = dma_heap_ioctl_allocate(file, kdata);
break;
default:
return -ENOTTY;
ret = -ENOTTY;
goto err;
}
if (copy_to_user((void __user *)arg, kdata, out_size) != 0)
......
......@@ -109,7 +109,7 @@ static int system_heap_create(void)
struct dma_heap_export_info exp_info;
int ret = 0;
exp_info.name = "system_heap";
exp_info.name = "system";
exp_info.ops = &system_heap_ops;
exp_info.priv = NULL;
......
......@@ -122,8 +122,7 @@ static int begin_cpu_udmabuf(struct dma_buf *buf,
if (IS_ERR(ubuf->sg))
return PTR_ERR(ubuf->sg);
} else {
dma_sync_sg_for_device(dev, ubuf->sg->sgl,
ubuf->sg->nents,
dma_sync_sg_for_cpu(dev, ubuf->sg->sgl, ubuf->sg->nents,
direction);
}
......@@ -139,7 +138,7 @@ static int end_cpu_udmabuf(struct dma_buf *buf,
if (!ubuf->sg)
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;
}
......
......@@ -20,8 +20,10 @@ static u64 get_lpu_event(struct d71_pipeline *d71_pipeline)
evts |= KOMEDA_EVENT_IBSY;
if (raw_status & LPU_IRQ_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;
/* Check error of LPU status */
status = malidp_read32(reg, BLK_STATUS);
......@@ -45,6 +47,15 @@ static u64 get_lpu_event(struct d71_pipeline *d71_pipeline)
restore |= LPU_STATUS_ACE3;
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)
malidp_write32_mask(reg, BLK_STATUS, restore, 0);
......
......@@ -175,6 +175,7 @@
#define TBU_DOUTSTDCAPB_MASK 0x3F
/* LPU_IRQ_BITS */
#define LPU_IRQ_OVR BIT(9)
#define LPU_IRQ_IBSY BIT(10)
#define LPU_IRQ_ERR BIT(11)
#define LPU_IRQ_EOW BIT(12)
......@@ -185,6 +186,8 @@
#define LPU_STATUS_AXIE BIT(4)
#define LPU_STATUS_AXIRP BIT(5)
#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_ACE1 BIT(17)
#define LPU_STATUS_ACE2 BIT(18)
......
......@@ -5,6 +5,7 @@
*
*/
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/spinlock.h>
#include <drm/drm_atomic.h>
......@@ -274,6 +275,7 @@ static void
komeda_crtc_atomic_enable(struct drm_crtc *crtc,
struct drm_crtc_state *old)
{
pm_runtime_get_sync(crtc->dev->dev);
komeda_crtc_prepare(to_kcrtc(crtc));
drm_crtc_vblank_on(crtc);
WARN_ON(drm_crtc_vblank_get(crtc));
......@@ -372,6 +374,7 @@ komeda_crtc_atomic_disable(struct drm_crtc *crtc,
drm_crtc_vblank_put(crtc);
drm_crtc_vblank_off(crtc);
komeda_crtc_unprepare(kcrtc);
pm_runtime_put(crtc->dev->dev);
}
static void
......
......@@ -10,6 +10,7 @@
#include <linux/of_graph.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/dma-mapping.h>
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
......@@ -27,12 +28,16 @@ static int komeda_register_show(struct seq_file *sf, void *x)
seq_puts(sf, "\n====== Komeda register dump =========\n");
pm_runtime_get_sync(mdev->dev);
if (mdev->funcs->dump_register)
mdev->funcs->dump_register(mdev, sf);
for (i = 0; i < mdev->n_pipelines; i++)
komeda_pipeline_dump_register(mdev->pipelines[i], sf);
pm_runtime_put(mdev->dev);
return 0;
}
......@@ -263,15 +268,6 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
if (!mdev->iommu)
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);
err = sysfs_create_group(&dev->kobj, &komeda_sysfs_attr_group);
......@@ -310,11 +306,6 @@ void komeda_dev_destroy(struct komeda_dev *mdev)
if (mdev->aclk)
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++) {
komeda_pipeline_destroy(mdev, mdev->pipelines[i]);
mdev->pipelines[i] = NULL;
......@@ -343,44 +334,26 @@ void komeda_dev_destroy(struct komeda_dev *mdev)
int komeda_dev_resume(struct komeda_dev *mdev)
{
int ret = 0;
clk_prepare_enable(mdev->aclk);
if (mdev->iommu && mdev->funcs->connect_iommu) {
ret = mdev->funcs->connect_iommu(mdev);
if (ret < 0) {
DRM_ERROR("connect iommu failed.\n");
goto disable_clk;
}
}
ret = mdev->funcs->enable_irq(mdev);
mdev->funcs->enable_irq(mdev);
disable_clk:
clk_disable_unprepare(mdev->aclk);
if (mdev->iommu && mdev->funcs->connect_iommu)
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 ret = 0;
clk_prepare_enable(mdev->aclk);
if (mdev->iommu && mdev->funcs->disconnect_iommu) {
ret = mdev->funcs->disconnect_iommu(mdev);
if (ret < 0) {
if (mdev->iommu && mdev->funcs->disconnect_iommu)
if (mdev->funcs->disconnect_iommu(mdev))
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);
return ret;
return 0;
}
......@@ -20,6 +20,8 @@
#define KOMEDA_EVENT_OVR BIT_ULL(4)
#define KOMEDA_EVENT_EOW BIT_ULL(5)
#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_TEMR BIT_ULL(15)
......@@ -49,7 +51,8 @@
KOMEDA_ERR_ZME | KOMEDA_ERR_MERR | KOMEDA_ERR_TCF |\
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 \
| KOMEDA_EVENT_VSYNC \
......
......@@ -33,6 +33,12 @@ static void komeda_unbind(struct device *dev)
return;
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);
dev_set_drvdata(dev, NULL);
......@@ -54,6 +60,10 @@ static int komeda_bind(struct device *dev)
goto free_mdrv;
}
pm_runtime_enable(dev);
if (!pm_runtime_enabled(dev))
komeda_dev_resume(mdrv->mdev);
mdrv->kms = komeda_kms_attach(mdrv->mdev);
if (IS_ERR(mdrv->kms)) {
err = PTR_ERR(mdrv->kms);
......@@ -65,6 +75,11 @@ static int komeda_bind(struct device *dev)
return 0;
destroy_mdev:
if (pm_runtime_enabled(dev))
pm_runtime_disable(dev);
else
komeda_dev_suspend(mdrv->mdev);
komeda_dev_destroy(mdrv->mdev);
free_mdrv:
......@@ -131,14 +146,28 @@ static const struct of_device_id 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)
{
struct komeda_drv *mdrv = dev_get_drvdata(dev);
struct drm_device *drm = &mdrv->kms->base;
int res;
res = drm_mode_config_helper_suspend(drm);
res = drm_mode_config_helper_suspend(&mdrv->kms->base);
if (!pm_runtime_status_suspended(dev))
komeda_dev_suspend(mdrv->mdev);
return res;
......@@ -147,15 +176,16 @@ static int __maybe_unused komeda_pm_suspend(struct device *dev)
static int __maybe_unused komeda_pm_resume(struct device *dev)
{
struct komeda_drv *mdrv = dev_get_drvdata(dev);
struct drm_device *drm = &mdrv->kms->base;
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 = {
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 = {
......
......@@ -78,6 +78,8 @@ static void evt_str(struct komeda_str *str, u64 events)
/* LPU errors or events */
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_ACE0, "ACE0|");
evt_sprintf(str, events & KOMEDA_ERR_ACE1, "ACE1|");
......
......@@ -308,10 +308,6 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
if (err)
goto free_component_binding;
err = mdev->funcs->enable_irq(mdev);
if (err)
goto free_component_binding;
drm->irq_enabled = true;
drm_kms_helper_poll_init(drm);
......@@ -325,7 +321,6 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
free_interrupts:
drm_kms_helper_poll_fini(drm);
drm->irq_enabled = false;
mdev->funcs->disable_irq(mdev);
free_component_binding:
component_unbind_all(mdev->dev, drm);
cleanup_mode_config:
......@@ -347,7 +342,6 @@ void komeda_kms_detach(struct komeda_kms_dev *kms)
drm_kms_helper_poll_fini(drm);
drm_atomic_helper_shutdown(drm);
drm->irq_enabled = false;
mdev->funcs->disable_irq(mdev);
component_unbind_all(mdev->dev, drm);
drm_mode_config_cleanup(drm);
komeda_kms_cleanup_private_objs(kms);
......
......@@ -512,7 +512,7 @@ static int malidp_de_plane_check(struct drm_plane *plane,
int i, ret;
unsigned int block_w, block_h;
if (!state->crtc || !state->fb)
if (!state->crtc || WARN_ON(!state->fb))
return 0;
fb = state->fb;
......
......@@ -255,7 +255,7 @@ void bochs_hw_setformat(struct bochs_device *bochs,
DRM_ERROR("%s: Huh? Got framebuffer format 0x%x",
__func__, format->format);
break;
};
}
}
void bochs_hw_setbase(struct bochs_device *bochs,
......
......@@ -35,14 +35,14 @@ config DRM_DUMB_VGA_DAC
Support for non-programmable RGB to VGA DAC bridges, such as ADI
ADV7123, TI THS8134 and THS8135 or passive resistor ladder DACs.
config DRM_LVDS_ENCODER
tristate "Transparent parallel to LVDS encoder support"
config DRM_LVDS_CODEC
tristate "Transparent LVDS encoders and decoders support"
depends on OF
select DRM_KMS_HELPER
select DRM_PANEL_BRIDGE
help
Support for transparent parallel to LVDS encoders that don't require
any configuration.
Support for transparent LVDS encoders and decoders that don't
require any configuration.
config DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW
tristate "MegaChips stdp4028-ge-b850v3-fw and stdp2690-ge-b850v3-fw"
......
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o
obj-$(CONFIG_DRM_LVDS_ENCODER) += lvds-encoder.o
obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.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_PARADE_PS8622) += parade-ps8622.o
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2019 Renesas Electronics Corporation
* Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*/
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <drm/drm_bridge.h>
#include <drm/drm_panel.h>
struct lvds_encoder {
struct lvds_codec {
struct drm_bridge bridge;
struct drm_bridge *panel_bridge;
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_encoder,
bridge);
struct lvds_codec *lvds_codec = container_of(bridge,
struct lvds_codec, bridge);
return drm_bridge_attach(bridge->encoder, lvds_encoder->panel_bridge,
return drm_bridge_attach(bridge->encoder, lvds_codec->panel_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_encoder,
bridge);
struct lvds_codec *lvds_codec = container_of(bridge,
struct lvds_codec, bridge);
if (lvds_encoder->powerdown_gpio)
gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 0);
if (lvds_codec->powerdown_gpio)
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_encoder,
bridge);
struct lvds_codec *lvds_codec = container_of(bridge,
struct lvds_codec, bridge);
if (lvds_encoder->powerdown_gpio)
gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 1);
if (lvds_codec->powerdown_gpio)
gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 1);
}
static struct drm_bridge_funcs funcs = {
.attach = lvds_encoder_attach,
.enable = lvds_encoder_enable,
.disable = lvds_encoder_disable,
.attach = lvds_codec_attach,
.enable = lvds_codec_enable,
.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_node *port;
struct device_node *endpoint;
struct device_node *panel_node;
struct drm_panel *panel;
struct lvds_encoder *lvds_encoder;
struct lvds_codec *lvds_codec;
lvds_encoder = devm_kzalloc(dev, sizeof(*lvds_encoder), GFP_KERNEL);
if (!lvds_encoder)
lvds_codec = devm_kzalloc(dev, sizeof(*lvds_codec), GFP_KERNEL);
if (!lvds_codec)
return -ENOMEM;
lvds_encoder->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
lvds_codec->connector_type = (uintptr_t)of_device_get_match_data(dev);
lvds_codec->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
GPIOD_OUT_HIGH);
if (IS_ERR(lvds_encoder->powerdown_gpio)) {
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)
dev_err(dev, "powerdown GPIO failure: %d\n", err);
......@@ -78,23 +77,9 @@ static int lvds_encoder_probe(struct platform_device *pdev)
}
/* Locate the panel DT node. */
port = of_graph_get_port_by_id(dev->of_node, 1);
if (!port) {
dev_dbg(dev, "port 1 not found\n");
return -ENXIO;
}
endpoint = of_get_child_by_name(port, "endpoint");
of_node_put(port);
if (!endpoint) {
dev_dbg(dev, "no endpoint for port 1\n");
return -ENXIO;
}
panel_node = of_graph_get_remote_port_parent(endpoint);
of_node_put(endpoint);
panel_node = of_graph_get_remote_node(dev->of_node, 1, 0);
if (!panel_node) {
dev_dbg(dev, "no remote endpoint for port 1\n");
dev_dbg(dev, "panel DT node not found\n");
return -ENXIO;
}
......@@ -105,51 +90,62 @@ static int lvds_encoder_probe(struct platform_device *pdev)
return PTR_ERR(panel);
}
lvds_encoder->panel_bridge =
lvds_codec->panel_bridge =
devm_drm_panel_bridge_add_typed(dev, panel,
DRM_MODE_CONNECTOR_LVDS);
if (IS_ERR(lvds_encoder->panel_bridge))
return PTR_ERR(lvds_encoder->panel_bridge);
lvds_codec->connector_type);
if (IS_ERR(lvds_codec->panel_bridge))
return PTR_ERR(lvds_codec->panel_bridge);
/* The panel_bridge bridge is attached to the panel's of_node,
/*
* The panel_bridge bridge is attached to the panel's of_node,
* but we need a bridge attached to our of_node for our user
* to look up.
*/
lvds_encoder->bridge.of_node = dev->of_node;
lvds_encoder->bridge.funcs = &funcs;
drm_bridge_add(&lvds_encoder->bridge);
lvds_codec->bridge.of_node = dev->of_node;
lvds_codec->bridge.funcs = &funcs;
drm_bridge_add(&lvds_codec->bridge);
platform_set_drvdata(pdev, lvds_encoder);
platform_set_drvdata(pdev, lvds_codec);
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;
}
static const struct of_device_id lvds_encoder_match[] = {
{ .compatible = "lvds-encoder" },
{ .compatible = "thine,thc63lvdm83d" },
static const struct of_device_id lvds_codec_match[] = {
{
.compatible = "lvds-decoder",
.data = (void *)DRM_MODE_CONNECTOR_DPI,
},
{
.compatible = "lvds-encoder",
.data = (void *)DRM_MODE_CONNECTOR_LVDS,
},
{
.compatible = "thine,thc63lvdm83d",
.data = (void *)DRM_MODE_CONNECTOR_LVDS,
},
{},
};
MODULE_DEVICE_TABLE(of, lvds_encoder_match);
MODULE_DEVICE_TABLE(of, lvds_codec_match);
static struct platform_driver lvds_encoder_driver = {
.probe = lvds_encoder_probe,
.remove = lvds_encoder_remove,
static struct platform_driver lvds_codec_driver = {
.probe = lvds_codec_probe,
.remove = lvds_codec_remove,
.driver = {
.name = "lvds-encoder",
.of_match_table = lvds_encoder_match,
.name = "lvds-codec",
.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_DESCRIPTION("Transparent parallel to LVDS encoder");
MODULE_DESCRIPTION("LVDS encoders and decoders");
MODULE_LICENSE("GPL");
......@@ -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)
{
const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
struct dw_mipi_dsi_dphy_timing timing;
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
......@@ -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;
if (hw_version >= HWVER_131) {
dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME_V131(0x40) |
PHY_LP2HS_TIME_V131(0x40));
dsi_write(dsi, DSI_PHY_TMR_CFG,
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));
} else {
dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40) |
PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000));
dsi_write(dsi, DSI_PHY_TMR_CFG,
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)
| PHY_CLKLP2HS_TIME(0x40));
dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG,
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)
......@@ -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);
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 &
* panel unprepare.
......@@ -817,6 +826,9 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
*/
dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge);
if (phy_ops->power_off)
phy_ops->power_off(dsi->plat_data->priv_data);
if (dsi->slave) {
dw_mipi_dsi_disable(dsi->slave);
clk_disable_unprepare(dsi->slave->pclk);
......@@ -883,6 +895,9 @@ static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi,
/* Switch to cmd mode for panel-bridge pre_enable & panel prepare */
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,
......@@ -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)
{
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 */
dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO);
if (dsi->slave)
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
......@@ -991,7 +1002,8 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
dsi->dev = dev;
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");
return ERR_PTR(-ENODEV);
}
......
......@@ -251,7 +251,7 @@ EXPORT_SYMBOL(drm_atomic_state_clear);
* @ref: This atomic state to deallocate
*
* 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)
{
......@@ -272,12 +272,12 @@ void __drm_atomic_state_free(struct kref *ref)
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
* @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
* needed. It will also grab the relevant crtc lock to make sure that the state
* 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
* is consistent.
*
* Returns:
......@@ -1018,14 +1018,14 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
}
/**
* drm_atomic_add_affected_connectors - add connectors for crtc
* drm_atomic_add_affected_connectors - add connectors for CRTC
* @state: atomic state
* @crtc: DRM crtc
* @crtc: DRM CRTC
*
* This function walks the current configuration and adds all connectors
* currently using @crtc to the atomic configuration @state. Note that this
* 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
* full modeset needs to happen due to some change).
*
......@@ -1078,9 +1078,9 @@ drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
EXPORT_SYMBOL(drm_atomic_add_affected_connectors);
/**
* drm_atomic_add_affected_planes - add planes for crtc
* drm_atomic_add_affected_planes - add planes for CRTC
* @state: atomic state
* @crtc: DRM crtc
* @crtc: DRM CRTC
*
* This function walks the current configuration and adds all planes
* currently used by @crtc to the atomic configuration @state. This is useful
......
......@@ -150,8 +150,8 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state,
* is not set, an error is returned. Userspace can provide a solution
* through the atomic ioctl.
*
* If the flag is set conflicting connectors are removed from the crtc
* and the crtc is disabled if no encoder is left. This preserves
* If the flag is set conflicting connectors are removed from the CRTC
* and the CRTC is disabled if no encoder is left. This preserves
* compatibility with the legacy set_config behavior.
*/
drm_connector_list_iter_begin(state->dev, &conn_iter);
......@@ -561,27 +561,27 @@ mode_valid(struct drm_atomic_state *state)
* @state: the driver state object
*
* Check the state object to see if the requested state is physically possible.
* This does all the crtc and connector related computations for an atomic
* This does all the CRTC and connector related computations for an atomic
* update and adds any additional connectors needed for full modesets. It calls
* the various per-object callbacks in the follow order:
*
* 1. &drm_connector_helper_funcs.atomic_best_encoder for determining the new encoder.
* 2. &drm_connector_helper_funcs.atomic_check to validate the connector state.
* 3. If it's determined a modeset is needed then all connectors on the affected crtc
* crtc are added and &drm_connector_helper_funcs.atomic_check is run on them.
* 3. If it's determined a modeset is needed then all connectors on the affected
* CRTC are added and &drm_connector_helper_funcs.atomic_check is run on them.
* 4. &drm_encoder_helper_funcs.mode_valid, &drm_bridge_funcs.mode_valid and
* &drm_crtc_helper_funcs.mode_valid are called on the affected components.
* 5. &drm_bridge_funcs.mode_fixup is called on all encoder bridges.
* 6. &drm_encoder_helper_funcs.atomic_check is called to validate any encoder state.
* This function is only called when the encoder will be part of a configured crtc,
* This function is only called when the encoder will be part of a configured CRTC,
* it must not be used for implementing connector property validation.
* If this function is NULL, &drm_atomic_encoder_helper_funcs.mode_fixup is called
* instead.
* 7. &drm_crtc_helper_funcs.mode_fixup is called last, to fix up the mode with crtc constraints.
* 7. &drm_crtc_helper_funcs.mode_fixup is called last, to fix up the mode with CRTC constraints.
*
* &drm_crtc_state.mode_changed is set when the input mode is changed.
* &drm_crtc_state.connectors_changed is set when a connector is added or
* removed from the crtc. &drm_crtc_state.active_changed is set when
* removed from the CRTC. &drm_crtc_state.active_changed is set when
* &drm_crtc_state.active changes, which is used for DPMS.
* See also: drm_atomic_crtc_needs_modeset()
*
......@@ -692,7 +692,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
/*
* After all the routing has been prepared we need to add in any
* connector which is itself unchanged, but whose crtc changes its
* connector which is itself unchanged, but whose CRTC changes its
* configuration. This must be done before calling mode_fixup in case a
* crtc only changed its mode but has the same set of connectors.
*/
......@@ -741,13 +741,13 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset);
/**
* drm_atomic_helper_check_plane_state() - Check plane state for validity
* @plane_state: plane state to check
* @crtc_state: crtc state to check
* @crtc_state: CRTC state to check
* @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
* @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
* @can_position: is it legal to position the plane such that it
* doesn't cover the entire crtc? This will generally
* doesn't cover the entire CRTC? This will generally
* only be false for primary planes.
* @can_update_disabled: can the plane be updated while the crtc
* @can_update_disabled: can the plane be updated while the CRTC
* is disabled?
*
* Checks that a desired plane update is valid, and updates various
......@@ -844,7 +844,7 @@ EXPORT_SYMBOL(drm_atomic_helper_check_plane_state);
* &drm_crtc_helper_funcs.atomic_check and &drm_plane_helper_funcs.atomic_check
* hooks provided by the driver.
*
* It also sets &drm_crtc_state.planes_changed to indicate that a crtc has
* It also sets &drm_crtc_state.planes_changed to indicate that a CRTC has
* updated planes.
*
* RETURNS:
......@@ -908,7 +908,7 @@ EXPORT_SYMBOL(drm_atomic_helper_check_planes);
* @state: the driver state object
*
* Check the state object to see if the requested state is physically possible.
* Only crtcs and planes have check callbacks, so for any additional (global)
* Only CRTCs and planes have check callbacks, so for any additional (global)
* checking that a driver needs it can simply wrap that around this function.
* Drivers without such needs can directly use this as their
* &drm_mode_config_funcs.atomic_check callback.
......@@ -961,14 +961,14 @@ crtc_needs_disable(struct drm_crtc_state *old_state,
struct drm_crtc_state *new_state)
{
/*
* No new_state means the crtc is off, so the only criteria is whether
* No new_state means the CRTC is off, so the only criteria is whether
* it's currently active or in self refresh mode.
*/
if (!new_state)
return drm_atomic_crtc_effectively_active(old_state);
/*
* We need to run through the crtc_funcs->disable() function if the crtc
* We need to run through the crtc_funcs->disable() function if the CRTC
* is currently on, if it's transitioning to self refresh mode, or if
* it's in self refresh mode and needs to be fully disabled.
*/
......@@ -1087,7 +1087,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
* @old_state: atomic state object with old state structures
*
* This function updates all the various legacy modeset state pointers in
* connectors, encoders and crtcs. It also updates the timestamping constants
* connectors, encoders and CRTCs. It also updates the timestamping constants
* used for precise vblank timestamps by calling
* drm_calc_timestamping_constants().
*
......@@ -1236,7 +1236,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
* This function shuts down all the outputs that need to be shut down and
* prepares them (if required) with the new mode.
*
* For compatibility with legacy crtc helpers this should be called before
* For compatibility with legacy CRTC helpers this should be called before
* drm_atomic_helper_commit_planes(), which is what the default commit function
* does. But drivers with different needs can group the modeset commits together
* and do the plane commits at the end. This is useful for drivers doing runtime
......@@ -1282,7 +1282,7 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev,
* This function enables all the outputs with the new configuration which had to
* be turned off for the update.
*
* For compatibility with legacy crtc helpers this should be called after
* For compatibility with legacy CRTC helpers this should be called after
* drm_atomic_helper_commit_planes(), which is what the default commit function
* does. But drivers with different needs can group the modeset commits together
* and do the plane commits at the end. This is useful for drivers doing runtime
......@@ -1414,12 +1414,12 @@ int drm_atomic_helper_wait_for_fences(struct drm_device *dev,
EXPORT_SYMBOL(drm_atomic_helper_wait_for_fences);
/**
* drm_atomic_helper_wait_for_vblanks - wait for vblank on crtcs
* drm_atomic_helper_wait_for_vblanks - wait for vblank on CRTCs
* @dev: DRM device
* @old_state: atomic state object with old state structures
*
* Helper to, after atomic commit, wait for vblanks on all effected
* crtcs (ie. before cleaning up old framebuffers using
* Helper to, after atomic commit, wait for vblanks on all affected
* CRTCs (ie. before cleaning up old framebuffers using
* drm_atomic_helper_cleanup_planes()). It will only wait on CRTCs where the
* framebuffers have actually changed to optimize for the legacy cursor and
* plane update use-case.
......@@ -1478,10 +1478,10 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);
* @dev: DRM device
* @old_state: atomic state object with old state structures
*
* Helper to, after atomic commit, wait for page flips on all effected
* Helper to, after atomic commit, wait for page flips on all affected
* crtcs (ie. before cleaning up old framebuffers using
* drm_atomic_helper_cleanup_planes()). Compared to
* drm_atomic_helper_wait_for_vblanks() this waits for the completion of on all
* drm_atomic_helper_wait_for_vblanks() this waits for the completion on all
* CRTCs, assuming that cursors-only updates are signalling their completion
* immediately (or using a different path).
*
......@@ -2208,7 +2208,7 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
* drm_atomic_helper_fake_vblank - fake VBLANK events if needed
* @old_state: atomic state object with old state structures
*
* This function walks all CRTCs and fake VBLANK events on those with
* This function walks all CRTCs and fakes VBLANK events on those with
* &drm_crtc_state.no_vblank set to true and &drm_crtc_state.event != NULL.
* The primary use of this function is writeback connectors working in oneshot
* mode and faking VBLANK events. In this case they only fake the VBLANK event
......@@ -2404,7 +2404,7 @@ static bool plane_crtc_active(const struct drm_plane_state *state)
* @flags: flags for committing plane state
*
* This function commits the new plane state using the plane and atomic helper
* functions for planes and crtcs. It assumes that the atomic state has already
* functions for planes and CRTCs. It assumes that the atomic state has already
* been pushed into the relevant object state pointers, since this step can no
* longer fail.
*
......@@ -2525,15 +2525,15 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
EXPORT_SYMBOL(drm_atomic_helper_commit_planes);
/**
* drm_atomic_helper_commit_planes_on_crtc - commit plane state for a crtc
* @old_crtc_state: atomic state object with the old crtc state
* drm_atomic_helper_commit_planes_on_crtc - commit plane state for a CRTC
* @old_crtc_state: atomic state object with the old CRTC state
*
* This function commits the new plane state using the plane and atomic helper
* functions for planes on the specific crtc. It assumes that the atomic state
* functions for planes on the specific CRTC. It assumes that the atomic state
* has already been pushed into the relevant object state pointers, since this
* step can no longer fail.
*
* This function is useful when plane updates should be done crtc-by-crtc
* This function is useful when plane updates should be done CRTC-by-CRTC
* instead of one global step like drm_atomic_helper_commit_planes() does.
*
* This function can only be savely used when planes are not allowed to move
......@@ -2823,10 +2823,10 @@ EXPORT_SYMBOL(drm_atomic_helper_swap_state);
* @plane: plane object to update
* @crtc: owning CRTC of owning plane
* @fb: framebuffer to flip onto plane
* @crtc_x: x offset of primary plane on crtc
* @crtc_y: y offset of primary plane on crtc
* @crtc_w: width of primary plane rectangle on crtc
* @crtc_h: height of primary plane rectangle on crtc
* @crtc_x: x offset of primary plane on @crtc
* @crtc_y: y offset of primary plane on @crtc
* @crtc_w: width of primary plane rectangle on @crtc
* @crtc_h: height of primary plane rectangle on @crtc
* @src_x: x offset of @fb for panning
* @src_y: y offset of @fb for panning
* @src_w: width of source rectangle in @fb
......@@ -2932,7 +2932,7 @@ EXPORT_SYMBOL(drm_atomic_helper_disable_plane);
* @set: mode set configuration
* @ctx: lock acquisition context
*
* Provides a default crtc set_config handler using the atomic driver interface.
* Provides a default CRTC set_config handler using the atomic driver interface.
*
* NOTE: For backwards compatibility with old userspace this automatically
* resets the "link-status" property to GOOD, to force any link
......@@ -3345,7 +3345,7 @@ static int page_flip_common(struct drm_atomic_state *state,
/**
* drm_atomic_helper_page_flip - execute a legacy page flip
* @crtc: DRM crtc
* @crtc: DRM CRTC
* @fb: DRM framebuffer
* @event: optional DRM event to signal upon completion
* @flags: flip flags for non-vblank sync'ed updates
......@@ -3389,7 +3389,7 @@ EXPORT_SYMBOL(drm_atomic_helper_page_flip);
/**
* drm_atomic_helper_page_flip_target - do page flip on target vblank period.
* @crtc: DRM crtc
* @crtc: DRM CRTC
* @fb: DRM framebuffer
* @event: optional DRM event to signal upon completion
* @flags: flip flags for non-vblank sync'ed updates
......
......@@ -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);
/**
* 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
* @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
* for the new crtc, as needed. This function takes care of all these details
* 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
* besides updating the pointer in the state object itself.
*
* Returns:
......@@ -279,12 +279,12 @@ drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state,
EXPORT_SYMBOL(drm_atomic_set_fence_for_plane);
/**
* 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
* @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
* state for the new crtc, as needed. This function takes care of all these
* 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
* details besides updating the pointer in the state object itself.
*
* Returns:
......
......@@ -150,7 +150,7 @@ void drm_client_release(struct drm_client_dev *client)
{
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_close(client);
......@@ -203,7 +203,7 @@ void drm_client_dev_hotplug(struct drm_device *dev)
continue;
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);
}
......@@ -223,7 +223,7 @@ void drm_client_dev_restore(struct drm_device *dev)
continue;
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 */
break;
}
......@@ -351,7 +351,7 @@ 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);
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);
buffer->fb = NULL;
......
......@@ -622,7 +622,8 @@ int drm_dev_init(struct drm_device *dev,
return -ENODEV;
}
BUG_ON(!parent);
if (WARN_ON(!parent))
return -EINVAL;
kref_init(&dev->ref);
dev->dev = get_device(parent);
......@@ -725,7 +726,7 @@ int devm_drm_dev_init(struct device *parent,
{
int ret;
if (WARN_ON(!parent || !driver->release))
if (WARN_ON(!driver->release))
return -EINVAL;
ret = drm_dev_init(dev, driver, parent);
......
......@@ -710,14 +710,11 @@ static const struct minimode extra_modes[] = {
};
/*
* Probably taken from CEA-861 spec.
* This table is converted from xorg's hw/xfree86/modes/xf86EdidModes.c.
* From CEA/CTA-861 spec.
*
* Index using the VIC.
* Do not access directly, instead always use cea_mode_for_vic().
*/
static const struct drm_display_mode edid_cea_modes[] = {
/* 0 - dummy, VICs start at 1 */
{ },
static const struct drm_display_mode edid_cea_modes_1[] = {
/* 1 - 640x480@60Hz 4:3 */
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
752, 800, 0, 480, 490, 492, 525, 0,
......@@ -1380,6 +1377,149 @@ static const struct drm_display_mode edid_cea_modes[] = {
.vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
};
/*
* From CEA/CTA-861 spec.
*
* Do not access directly, instead always use cea_mode_for_vic().
*/
static const struct drm_display_mode edid_cea_modes_193[] = {
/* 193 - 5120x2160@120Hz 64:27 */
{ DRM_MODE("5120x2160", DRM_MODE_TYPE_DRIVER, 1485000, 5120, 5284,
5372, 5500, 0, 2160, 2168, 2178, 2250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 194 - 7680x4320@24Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10232,
10408, 11000, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 195 - 7680x4320@25Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10032,
10208, 10800, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 196 - 7680x4320@30Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 8232,
8408, 9000, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 197 - 7680x4320@48Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10232,
10408, 11000, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 48, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 198 - 7680x4320@50Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10032,
10208, 10800, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 199 - 7680x4320@60Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 8232,
8408, 9000, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 200 - 7680x4320@100Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 9792,
9968, 10560, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 201 - 7680x4320@120Hz 16:9 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 8032,
8208, 8800, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 202 - 7680x4320@24Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10232,
10408, 11000, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 203 - 7680x4320@25Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 10032,
10208, 10800, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 204 - 7680x4320@30Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 1188000, 7680, 8232,
8408, 9000, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 205 - 7680x4320@48Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10232,
10408, 11000, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 48, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 206 - 7680x4320@50Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 10032,
10208, 10800, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 207 - 7680x4320@60Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 2376000, 7680, 8232,
8408, 9000, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 208 - 7680x4320@100Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 9792,
9968, 10560, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 209 - 7680x4320@120Hz 64:27 */
{ DRM_MODE("7680x4320", DRM_MODE_TYPE_DRIVER, 4752000, 7680, 8032,
8208, 8800, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 210 - 10240x4320@24Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 1485000, 10240, 11732,
11908, 12500, 0, 4320, 4336, 4356, 4950, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 211 - 10240x4320@25Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 1485000, 10240, 12732,
12908, 13500, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 212 - 10240x4320@30Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 1485000, 10240, 10528,
10704, 11000, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 213 - 10240x4320@48Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 2970000, 10240, 11732,
11908, 12500, 0, 4320, 4336, 4356, 4950, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 48, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 214 - 10240x4320@50Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 2970000, 10240, 12732,
12908, 13500, 0, 4320, 4336, 4356, 4400, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 215 - 10240x4320@60Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 2970000, 10240, 10528,
10704, 11000, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 216 - 10240x4320@100Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 5940000, 10240, 12432,
12608, 13200, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 217 - 10240x4320@120Hz 64:27 */
{ DRM_MODE("10240x4320", DRM_MODE_TYPE_DRIVER, 5940000, 10240, 10528,
10704, 11000, 0, 4320, 4336, 4356, 4500, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
/* 218 - 4096x2160@100Hz 256:135 */
{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 1188000, 4096, 4896,
4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
/* 219 - 4096x2160@120Hz 256:135 */
{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 1188000, 4096, 4184,
4272, 4400, 0, 2160, 2168, 2178, 2250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
};
/*
* HDMI 1.4 4k modes. Index using the VIC.
*/
......@@ -3071,6 +3211,30 @@ static u8 *drm_find_cea_extension(const struct edid *edid)
return cea;
}
static const struct drm_display_mode *cea_mode_for_vic(u8 vic)
{
BUILD_BUG_ON(1 + ARRAY_SIZE(edid_cea_modes_1) - 1 != 127);
BUILD_BUG_ON(193 + ARRAY_SIZE(edid_cea_modes_193) - 1 != 219);
if (vic >= 1 && vic < 1 + ARRAY_SIZE(edid_cea_modes_1))
return &edid_cea_modes_1[vic - 1];
if (vic >= 193 && vic < 193 + ARRAY_SIZE(edid_cea_modes_193))
return &edid_cea_modes_193[vic - 193];
return NULL;
}
static u8 cea_num_vics(void)
{
return 193 + ARRAY_SIZE(edid_cea_modes_193);
}
static u8 cea_next_vic(u8 vic)
{
if (++vic == 1 + ARRAY_SIZE(edid_cea_modes_1))
vic = 193;
return vic;
}
/*
* Calculate the alternate clock for the CEA mode
* (60Hz vs. 59.94Hz etc.)
......@@ -3108,14 +3272,14 @@ cea_mode_alternate_timings(u8 vic, struct drm_display_mode *mode)
* get the other variants by simply increasing the
* vertical front porch length.
*/
BUILD_BUG_ON(edid_cea_modes[8].vtotal != 262 ||
edid_cea_modes[9].vtotal != 262 ||
edid_cea_modes[12].vtotal != 262 ||
edid_cea_modes[13].vtotal != 262 ||
edid_cea_modes[23].vtotal != 312 ||
edid_cea_modes[24].vtotal != 312 ||
edid_cea_modes[27].vtotal != 312 ||
edid_cea_modes[28].vtotal != 312);
BUILD_BUG_ON(cea_mode_for_vic(8)->vtotal != 262 ||
cea_mode_for_vic(9)->vtotal != 262 ||
cea_mode_for_vic(12)->vtotal != 262 ||
cea_mode_for_vic(13)->vtotal != 262 ||
cea_mode_for_vic(23)->vtotal != 312 ||
cea_mode_for_vic(24)->vtotal != 312 ||
cea_mode_for_vic(27)->vtotal != 312 ||
cea_mode_for_vic(28)->vtotal != 312);
if (((vic == 8 || vic == 9 ||
vic == 12 || vic == 13) && mode->vtotal < 263) ||
......@@ -3143,8 +3307,8 @@ static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_m
if (to_match->picture_aspect_ratio)
match_flags |= DRM_MODE_MATCH_ASPECT_RATIO;
for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) {
struct drm_display_mode cea_mode = edid_cea_modes[vic];
for (vic = 1; vic < cea_num_vics(); vic = cea_next_vic(vic)) {
struct drm_display_mode cea_mode = *cea_mode_for_vic(vic);
unsigned int clock1, clock2;
/* Check both 60Hz and 59.94Hz */
......@@ -3182,8 +3346,8 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
if (to_match->picture_aspect_ratio)
match_flags |= DRM_MODE_MATCH_ASPECT_RATIO;
for (vic = 1; vic < ARRAY_SIZE(edid_cea_modes); vic++) {
struct drm_display_mode cea_mode = edid_cea_modes[vic];
for (vic = 1; vic < cea_num_vics(); vic = cea_next_vic(vic)) {
struct drm_display_mode cea_mode = *cea_mode_for_vic(vic);
unsigned int clock1, clock2;
/* Check both 60Hz and 59.94Hz */
......@@ -3206,12 +3370,17 @@ EXPORT_SYMBOL(drm_match_cea_mode);
static bool drm_valid_cea_vic(u8 vic)
{
return vic > 0 && vic < ARRAY_SIZE(edid_cea_modes);
return cea_mode_for_vic(vic) != NULL;
}
static enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code)
{
return edid_cea_modes[video_code].picture_aspect_ratio;
const struct drm_display_mode *mode = cea_mode_for_vic(video_code);
if (mode)
return mode->picture_aspect_ratio;
return HDMI_PICTURE_ASPECT_NONE;
}
static enum hdmi_picture_aspect drm_get_hdmi_aspect_ratio(const u8 video_code)
......@@ -3323,7 +3492,7 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid)
unsigned int clock1, clock2;
if (drm_valid_cea_vic(vic)) {
cea_mode = &edid_cea_modes[vic];
cea_mode = cea_mode_for_vic(vic);
clock2 = cea_mode_alternate_clock(cea_mode);
} else {
vic = drm_match_hdmi_mode(mode);
......@@ -3398,7 +3567,7 @@ drm_display_mode_from_vic_index(struct drm_connector *connector,
if (!drm_valid_cea_vic(vic))
return NULL;
newmode = drm_mode_duplicate(dev, &edid_cea_modes[vic]);
newmode = drm_mode_duplicate(dev, cea_mode_for_vic(vic));
if (!newmode)
return NULL;
......@@ -3432,7 +3601,7 @@ static int do_y420vdb_modes(struct drm_connector *connector,
if (!drm_valid_cea_vic(vic))
continue;
newmode = drm_mode_duplicate(dev, &edid_cea_modes[vic]);
newmode = drm_mode_duplicate(dev, cea_mode_for_vic(vic));
if (!newmode)
break;
bitmap_set(hdmi->y420_vdb_modes, vic, 1);
......@@ -4001,7 +4170,7 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
vic = drm_match_cea_mode_clock_tolerance(mode, 5);
if (drm_valid_cea_vic(vic)) {
type = "CEA";
cea_mode = &edid_cea_modes[vic];
cea_mode = cea_mode_for_vic(vic);
clock1 = cea_mode->clock;
clock2 = cea_mode_alternate_clock(cea_mode);
} else {
......@@ -4577,7 +4746,7 @@ static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector,
if (scdc->supported) {
scdc->scrambling.supported = true;
/* Few sinks support scrambling for cloks < 340M */
/* Few sinks support scrambling for clocks < 340M */
if ((hf_vsdb[6] & 0x8))
scdc->scrambling.low_rates = true;
}
......
......@@ -191,6 +191,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
{
struct drm_fb_helper *helper = info->par;
struct drm_client_dev *client = &helper->client;
struct drm_device *dev = helper->dev;
struct drm_crtc *crtc;
const struct drm_crtc_helper_funcs *funcs;
struct drm_mode_set *mode_set;
......@@ -209,7 +210,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
continue;
if (!fb) {
DRM_ERROR("no fb to restore??\n");
drm_err(dev, "no fb to restore?\n");
continue;
}
......@@ -1248,12 +1249,13 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
{
struct drm_fb_helper *fb_helper = info->par;
struct drm_framebuffer *fb = fb_helper->fb;
struct drm_device *dev = fb_helper->dev;
if (in_dbg_master())
return -EINVAL;
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;
}
......@@ -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 ||
var->xres > fb->width || var->yres > 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",
var->xres, var->yres, var->bits_per_pixel,
var->xres_virtual, var->yres_virtual,
......@@ -1295,7 +1297,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
* so reject all pixel format changing requests.
*/
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;
}
......@@ -1320,7 +1322,7 @@ int drm_fb_helper_set_par(struct fb_info *info)
return -EBUSY;
if (var->pixclock != 0) {
DRM_ERROR("PIXEL CLOCK SET\n");
drm_err(fb_helper->dev, "PIXEL CLOCK SET\n");
return -EINVAL;
}
......@@ -1430,6 +1432,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
int preferred_bpp)
{
struct drm_client_dev *client = &fb_helper->client;
struct drm_device *dev = fb_helper->dev;
int ret = 0;
int crtc_count = 0;
struct drm_connector_list_iter conn_iter;
......@@ -1493,7 +1496,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
struct drm_plane *plane = crtc->primary;
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++) {
const struct drm_format_info *fmt;
......@@ -1526,7 +1529,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
}
}
if (sizes.surface_depth != best_depth && best_depth) {
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_depth = best_depth;
}
......@@ -1574,7 +1577,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
mutex_unlock(&client->modeset_mutex);
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.. */
if (!fb_helper->deferred_setup)
......@@ -1889,7 +1892,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
drm_master_internal_release(fb_helper->dev);
DRM_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_setup_crtcs_fb(fb_helper);
......@@ -2026,13 +2029,14 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
struct drm_fb_helper_surface_size *sizes)
{
struct drm_client_dev *client = &fb_helper->client;
struct drm_device *dev = fb_helper->dev;
struct drm_client_buffer *buffer;
struct drm_framebuffer *fb;
struct fb_info *fbi;
u32 format;
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_bpp);
......@@ -2118,7 +2122,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
return drm_fb_helper_hotplug_event(dev->fb_helper);
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;
}
......@@ -2143,7 +2147,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
fb_helper->dev = 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;
}
......@@ -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);
if (ret) {
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;
}
......@@ -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);
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);
......
......@@ -74,8 +74,7 @@ drm_gem_fb_alloc(struct drm_device *dev,
ret = drm_framebuffer_init(dev, fb, funcs);
if (ret) {
DRM_DEV_ERROR(dev->dev, "Failed to init framebuffer: %d\n",
ret);
drm_err(dev, "Failed to init framebuffer: %d\n", ret);
kfree(fb);
return ERR_PTR(ret);
}
......@@ -160,7 +159,7 @@ drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file,
objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
if (!objs[i]) {
DRM_DEBUG_KMS("Failed to lookup GEM object\n");
drm_dbg_kms(dev, "Failed to lookup GEM object\n");
ret = -ENOENT;
goto err_gem_object_put;
}
......
......@@ -1568,33 +1568,76 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
return 0;
}
static int drm_mode_parse_cmdline_options(char *str, size_t len,
const struct drm_connector *connector,
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)
{
unsigned int rotation = 0;
char *sep = str;
const char *value;
while ((sep = strchr(sep, ','))) {
char *delim, *option;
if (*delim != '=')
return -EINVAL;
option = sep + 1;
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,
struct drm_cmdline_mode *mode)
{
unsigned int deg, margin, rotation = 0;
const char *delim, *option, *sep;
option = str;
do {
delim = strchr(option, '=');
if (!delim) {
delim = strchr(option, ',');
if (!delim)
delim = str + len;
delim = option + strlen(option);
}
if (!strncmp(option, "rotate", delim - option)) {
const char *value = delim + 1;
unsigned int deg;
deg = simple_strtol(value, &sep, 10);
/* Make sure we have parsed something */
if (sep == value)
if (drm_mode_parse_cmdline_int(delim, &deg))
return -EINVAL;
switch (deg) {
......@@ -1619,58 +1662,40 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
}
} else if (!strncmp(option, "reflect_x", delim - option)) {
rotation |= DRM_MODE_REFLECT_X;
sep = delim;
} else if (!strncmp(option, "reflect_y", delim - option)) {
rotation |= DRM_MODE_REFLECT_Y;
sep = delim;
} else if (!strncmp(option, "margin_right", delim - option)) {
const char *value = delim + 1;
unsigned int margin;
margin = simple_strtol(value, &sep, 10);
/* Make sure we have parsed something */
if (sep == value)
if (drm_mode_parse_cmdline_int(delim, &margin))
return -EINVAL;
mode->tv_margins.right = margin;
} else if (!strncmp(option, "margin_left", delim - option)) {
const char *value = delim + 1;
unsigned int margin;
margin = simple_strtol(value, &sep, 10);
/* Make sure we have parsed something */
if (sep == value)
if (drm_mode_parse_cmdline_int(delim, &margin))
return -EINVAL;
mode->tv_margins.left = margin;
} else if (!strncmp(option, "margin_top", delim - option)) {
const char *value = delim + 1;
unsigned int margin;
margin = simple_strtol(value, &sep, 10);
/* Make sure we have parsed something */
if (sep == value)
if (drm_mode_parse_cmdline_int(delim, &margin))
return -EINVAL;
mode->tv_margins.top = margin;
} else if (!strncmp(option, "margin_bottom", delim - option)) {
const char *value = delim + 1;
unsigned int margin;
margin = simple_strtol(value, &sep, 10);
/* Make sure we have parsed something */
if (sep == value)
if (drm_mode_parse_cmdline_int(delim, &margin))
return -EINVAL;
mode->tv_margins.bottom = margin;
} else if (!strncmp(option, "panel_orientation", delim - option)) {
if (drm_mode_parse_panel_orientation(delim, mode))
return -EINVAL;
} else {
return -EINVAL;
}
}
sep = strchr(delim, ',');
option = sep + 1;
} while (sep);
if (rotation && freestanding)
return -EINVAL;
mode->rotation_reflection = rotation;
......@@ -1682,17 +1707,6 @@ static const char * const drm_named_modes_whitelist[] = {
"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
* @mode_option: optional per connector mode option
......@@ -1723,72 +1737,30 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
struct drm_cmdline_mode *mode)
{
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 mode_end = 0;
char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
char *options_ptr = NULL;
const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
const char *options_ptr = NULL;
char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
int ret;
int i, len, ret;
#ifdef CONFIG_FB
if (!mode_option)
mode_option = fb_mode_option;
#endif
memset(mode, 0, sizeof(*mode));
mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
if (!mode_option) {
mode->specified = false;
if (!mode_option)
return false;
}
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 */
bpp_ptr = strchr(name, '-');
if (bpp_ptr) {
if (bpp_ptr)
bpp_off = bpp_ptr - name;
mode->bpp_specified = true;
}
refresh_ptr = strchr(name, '@');
if (refresh_ptr) {
if (named_mode)
return false;
if (refresh_ptr)
refresh_off = refresh_ptr - name;
mode->refresh_specified = true;
}
/* Locate the start of named options */
options_ptr = strchr(name, ',');
......@@ -1802,33 +1774,58 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
mode_end = refresh_off;
} else if (options_ptr) {
mode_end = options_off;
parse_extras = true;
} else {
mode_end = strlen(name);
parse_extras = true;
}
if (named_mode) {
if (mode_end + 1 > DRM_DISPLAY_MODE_LEN)
return false;
/* First check for a named mode */
for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
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))
return false;
strcpy(mode->name, drm_named_modes_whitelist[i]);
mode->specified = true;
break;
}
}
strscpy(mode->name, name, mode_end + 1);
} else {
/* No named mode? Check for a normal mode argument, e.g. 1024x768 */
if (!mode->specified && isdigit(name[0])) {
ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
parse_extras,
connector,
mode);
if (ret)
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;
}
if (bpp_ptr) {
ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
if (ret)
return false;
mode->bpp_specified = true;
}
if (refresh_ptr) {
......@@ -1836,6 +1833,8 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
&refresh_end_ptr, mode);
if (ret)
return false;
mode->refresh_specified = true;
}
/*
......@@ -1849,20 +1848,21 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
else if (refresh_ptr)
extra_ptr = refresh_end_ptr;
if (extra_ptr &&
extra_ptr != options_ptr) {
int len = strlen(name) - (extra_ptr - name);
if (extra_ptr) {
if (options_ptr)
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);
if (ret)
return false;
}
if (options_ptr) {
int len = strlen(name) - (options_ptr - name);
ret = drm_mode_parse_cmdline_options(options_ptr, len,
ret = drm_mode_parse_cmdline_options(options_ptr + 1,
freestanding,
connector, mode);
if (ret)
return false;
......
......@@ -302,7 +302,7 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np)
EXPORT_SYMBOL(of_drm_find_panel);
#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
* @panel: DRM panel
......
......@@ -113,7 +113,7 @@ static void submit_unlock_object(struct etnaviv_gem_submit *submit, int i)
if (submit->bos[i].flags & BO_LOCKED) {
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;
}
}
......@@ -133,8 +133,7 @@ static int submit_lock_objects(struct etnaviv_gem_submit *submit,
contended = i;
if (!(submit->bos[i].flags & BO_LOCKED)) {
ret = ww_mutex_lock_interruptible(&obj->resv->lock,
ticket);
ret = dma_resv_lock_interruptible(obj->resv, ticket);
if (ret == -EALREADY)
DRM_ERROR("BO at index %u already on submit list\n",
i);
......@@ -161,8 +160,7 @@ static int submit_lock_objects(struct etnaviv_gem_submit *submit,
obj = &submit->bos[contended].obj->base;
/* we lost out in a seqno race, lock and retry.. */
ret = ww_mutex_lock_slow_interruptible(&obj->resv->lock,
ticket);
ret = dma_resv_lock_slow_interruptible(obj->resv, ticket);
if (!ret) {
submit->bos[contended].flags |= BO_LOCKED;
slow_locked = contended;
......
......@@ -228,8 +228,8 @@ static void psbfb_copyarea_accel(struct fb_info *info,
{
struct drm_fb_helper *fb_helper = info->par;
struct drm_framebuffer *fb = fb_helper->fb;
struct drm_device *dev = fb->dev;
struct drm_psb_private *dev_priv = dev->dev_private;
struct drm_device *dev;
struct drm_psb_private *dev_priv;
uint32_t offset;
uint32_t stride;
uint32_t src_format;
......@@ -238,6 +238,8 @@ static void psbfb_copyarea_accel(struct fb_info *info,
if (!fb)
return;
dev = fb->dev;
dev_priv = dev->dev_private;
offset = to_gtt_range(fb->obj[0])->offset;
stride = fb->pitches[0];
......
......@@ -388,13 +388,14 @@ void mcde_dsi_te_request(struct mipi_dsi_device *mdsi)
static void mcde_dsi_setup_video_mode(struct mcde_dsi *d,
const struct drm_display_mode *mode)
{
u8 bpp = mipi_dsi_pixel_format_to_bpp(d->mdsi->format);
/* cpp, characters per pixel, number of bytes per pixel */
u8 cpp = mipi_dsi_pixel_format_to_bpp(d->mdsi->format) / 8;
u64 pclk;
u64 bpl;
u32 hfp;
u32 hbp;
u32 hsa;
int hfp;
int hbp;
int hsa;
u32 blkline_pck, line_duration;
u32 blkeol_pck, blkeol_duration;
u32 val;
val = 0;
......@@ -431,11 +432,21 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d,
return;
}
/* TODO: TVG could be enabled here */
/* TODO: TVG (test video generator) could be enabled here */
/* Send blanking packet */
/*
* During vertical blanking: go to LP mode
* Like with the EOL setting, if this is not set, the EOL area will be
* filled with NULL or blanking packets in the vblank area.
* FIXME: some Samsung phones and display panels such as s6e63m0 use
* DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_BLANKING here instead,
* figure out how to properly configure that from the panel.
*/
val |= DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_LP_0;
/* Send EOL packet */
/*
* During EOL: go to LP mode. If this is not set, the EOL area will be
* filled with NULL or blanking packets.
*/
val |= DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0;
/* Recovery mode 1 */
val |= 1 << DSI_VID_MAIN_CTL_RECOVERY_MODE_SHIFT;
......@@ -443,13 +454,13 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d,
writel(val, d->regs + DSI_VID_MAIN_CTL);
/* Vertical frame parameters are pretty straight-forward */
val = mode->vdisplay << DSI_VID_VSIZE_VSA_LENGTH_SHIFT;
val = mode->vdisplay << DSI_VID_VSIZE_VACT_LENGTH_SHIFT;
/* vertical front porch */
val |= (mode->vsync_start - mode->vdisplay)
<< DSI_VID_VSIZE_VFP_LENGTH_SHIFT;
/* vertical sync active */
val |= (mode->vsync_end - mode->vsync_start)
<< DSI_VID_VSIZE_VACT_LENGTH_SHIFT;
<< DSI_VID_VSIZE_VSA_LENGTH_SHIFT;
/* vertical back porch */
val |= (mode->vtotal - mode->vsync_end)
<< DSI_VID_VSIZE_VBP_LENGTH_SHIFT;
......@@ -457,36 +468,54 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d,
/*
* Horizontal frame parameters:
* horizontal resolution is given in pixels and must be re-calculated
* into bytes since this is what the hardware expects.
* horizontal resolution is given in pixels but must be re-calculated
* into bytes since this is what the hardware expects, these registers
* define the payload size of the packet.
*
* hfp = horizontal front porch in bytes
* hbp = horizontal back porch in bytes
* hsa = horizontal sync active in bytes
*
* 6 + 2 is HFP header + checksum
*/
hfp = (mode->hsync_start - mode->hdisplay) * bpp - 6 - 2;
hfp = (mode->hsync_start - mode->hdisplay) * cpp - 6 - 2;
if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
/*
* Use sync pulse for sync: explicit HSA time
* 6 is HBP header + checksum
* 4 is RGB header + checksum
*/
hbp = (mode->htotal - mode->hsync_end) * bpp - 4 - 6;
hbp = (mode->htotal - mode->hsync_end) * cpp - 4 - 6;
/*
* 6 is HBP header + checksum
* 4 is HSW packet bytes
* 4 is RGB header + checksum
*/
hsa = (mode->hsync_end - mode->hsync_start) * bpp - 4 - 4 - 6;
hsa = (mode->hsync_end - mode->hsync_start) * cpp - 4 - 4 - 6;
} else {
/*
* HBP includes both back porch and sync
* Use event for sync: HBP includes both back porch and sync
* 6 is HBP header + checksum
* 4 is HSW packet bytes
* 4 is RGB header + checksum
*/
hbp = (mode->htotal - mode->hsync_start) * bpp - 4 - 4 - 6;
/* HSA is not considered in this mode and set to 0 */
hbp = (mode->htotal - mode->hsync_start) * cpp - 4 - 4 - 6;
/* HSA is not present in this mode and set to 0 */
hsa = 0;
}
dev_dbg(d->dev, "hfp: %u, hbp: %u, hsa: %u\n",
if (hfp < 0) {
dev_info(d->dev, "hfp negative, set to 0\n");
hfp = 0;
}
if (hbp < 0) {
dev_info(d->dev, "hbp negative, set to 0\n");
hbp = 0;
}
if (hsa < 0) {
dev_info(d->dev, "hsa negative, set to 0\n");
hsa = 0;
}
dev_dbg(d->dev, "hfp: %u, hbp: %u, hsa: %u bytes\n",
hfp, hbp, hsa);
/* Frame parameters: horizontal sync active */
......@@ -497,71 +526,185 @@ static void mcde_dsi_setup_video_mode(struct mcde_dsi *d,
val |= hfp << DSI_VID_HSIZE1_HFP_LENGTH_SHIFT;
writel(val, d->regs + DSI_VID_HSIZE1);
/* RGB data length (bytes on one scanline) */
val = mode->hdisplay * (bpp / 8);
/* RGB data length (visible bytes on one scanline) */
val = mode->hdisplay * cpp;
writel(val, d->regs + DSI_VID_HSIZE2);
dev_dbg(d->dev, "RGB length, visible area on a line: %u bytes\n", val);
/* TODO: further adjustments for TVG mode here */
/*
* Calculate the time between two pixels in picoseconds using
* the supplied refresh rate and total resolution including
* porches and sync.
*/
/* (ps/s) / (pixels/s) = ps/pixels */
pclk = DIV_ROUND_UP_ULL(1000000000000,
(mode->vrefresh * mode->htotal * mode->vtotal));
dev_dbg(d->dev, "picoseconds between two pixels: %llu\n",
pclk);
/*
* EOL packet length from bits per line calculations: pixel clock
* is given in kHz, calculate the time between two pixels in
* picoseconds.
* How many bytes per line will this update frequency yield?
*
* Calculate the number of picoseconds for one scanline (1), then
* divide by 1000000000000 (2) to get in pixels per second we
* want to output.
*
* Multiply with number of bytes per second at this video display
* frequency (3) to get number of bytes transferred during this
* time. Notice that we use the frequency the display wants,
* not what we actually get from the DSI PLL, which is hs_freq.
*
* These arithmetics are done in a different order to avoid
* overflow.
*/
bpl = mode->clock * mode->htotal;
bpl *= (d->hs_freq / 8);
do_div(bpl, 1000000); /* microseconds */
do_div(bpl, 1000000); /* seconds */
bpl = pclk * mode->htotal; /* (1) picoseconds per line */
dev_dbg(d->dev, "picoseconds per line: %llu\n", bpl);
/* Multiply with bytes per second (3) */
bpl *= (d->mdsi->hs_rate / 8);
/* Pixels per second (2) */
bpl = DIV_ROUND_DOWN_ULL(bpl, 1000000); /* microseconds */
bpl = DIV_ROUND_DOWN_ULL(bpl, 1000000); /* seconds */
/* parallel transactions in all lanes */
bpl *= d->mdsi->lanes;
dev_dbg(d->dev, "calculated bytes per line: %llu\n", bpl);
dev_dbg(d->dev,
"calculated bytes per line: %llu @ %d Hz with HS %lu Hz\n",
bpl, mode->vrefresh, d->mdsi->hs_rate);
/*
* 6 is header + checksum, header = 4 bytes, checksum = 2 bytes
* 4 is short packet for vsync/hsync
*/
if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
/* Fixme: isn't the hsync width in pixels? */
/* Set the event packet size to 0 (not used) */
writel(0, d->regs + DSI_VID_BLKSIZE1);
/*
* FIXME: isn't the hsync width in pixels? The porch and
* sync area size is in pixels here, but this -6
* seems to be for bytes. It looks like this in the vendor
* code though. Is it completely untested?
*/
blkline_pck = bpl - (mode->hsync_end - mode->hsync_start) - 6;
val = blkline_pck << DSI_VID_BLKSIZE2_BLKLINE_PULSE_PCK_SHIFT;
writel(val, d->regs + DSI_VID_BLKSIZE2);
} else {
/* Set the sync pulse packet size to 0 (not used) */
writel(0, d->regs + DSI_VID_BLKSIZE2);
/* Specifying payload size in bytes (-4-6 from manual) */
blkline_pck = bpl - 4 - 6;
if (blkline_pck > 0x1FFF)
dev_err(d->dev, "blkline_pck too big %d bytes\n",
blkline_pck);
val = blkline_pck << DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_SHIFT;
val &= DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_MASK;
writel(val, d->regs + DSI_VID_BLKSIZE1);
}
line_duration = (blkline_pck + 6) / d->mdsi->lanes;
dev_dbg(d->dev, "line duration %u\n", line_duration);
/*
* The line duration is used to scale back the frequency from
* the max frequency supported by the HS clock to the desired
* update frequency in vrefresh.
*/
line_duration = blkline_pck + 6;
/*
* The datasheet contains this complex condition to decreasing
* the line duration by 1 under very specific circumstances.
* Here we also imply that LP is used during burst EOL.
*/
if (d->mdsi->lanes == 2 && (hsa & 0x01) && (hfp & 0x01)
&& (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST))
line_duration--;
line_duration = DIV_ROUND_CLOSEST(line_duration, d->mdsi->lanes);
dev_dbg(d->dev, "line duration %u bytes\n", line_duration);
val = line_duration << DSI_VID_DPHY_TIME_REG_LINE_DURATION_SHIFT;
/*
* This is the time to perform LP->HS on D-PHY
* FIXME: nowhere to get this from: DT property on the DSI?
* The manual says this is "system dependent".
* values like 48 and 72 seen in the vendor code.
*/
val |= 0 << DSI_VID_DPHY_TIME_REG_WAKEUP_TIME_SHIFT;
val |= 48 << DSI_VID_DPHY_TIME_REG_WAKEUP_TIME_SHIFT;
writel(val, d->regs + DSI_VID_DPHY_TIME);
/* Calculate block end of line */
blkeol_pck = bpl - mode->hdisplay * bpp - 6;
blkeol_duration = (blkeol_pck + 6) / d->mdsi->lanes;
dev_dbg(d->dev, "blkeol pck: %u, duration: %u\n",
blkeol_pck, blkeol_duration);
/*
* See the manual figure 657 page 2203 for understanding the impact
* of the different burst mode settings.
*/
if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) {
/* Set up EOL clock for burst mode */
int blkeol_pck, blkeol_duration;
/*
* Packet size at EOL for burst mode, this is only used
* if DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0 is NOT set,
* but we instead send NULL or blanking packets at EOL.
* This is given in number of bytes.
*
* See the manual page 2198 for the 13 reg_blkeol_pck bits.
*/
blkeol_pck = bpl - (mode->htotal * cpp) - 6;
if (blkeol_pck < 0) {
dev_err(d->dev, "video block does not fit on line!\n");
dev_err(d->dev,
"calculated bytes per line: %llu @ %d Hz\n",
bpl, mode->vrefresh);
dev_err(d->dev,
"bytes per line (blkline_pck) %u bytes\n",
blkline_pck);
dev_err(d->dev,
"blkeol_pck becomes %d bytes\n", blkeol_pck);
return;
}
dev_dbg(d->dev, "BLKEOL packet: %d bytes\n", blkeol_pck);
val = readl(d->regs + DSI_VID_BLKSIZE1);
val &= ~DSI_VID_BLKSIZE1_BLKEOL_PCK_MASK;
val |= blkeol_pck << DSI_VID_BLKSIZE1_BLKEOL_PCK_SHIFT;
writel(val, d->regs + DSI_VID_BLKSIZE1);
writel(blkeol_pck, d->regs + DSI_VID_VCA_SETTING2);
writel(blkeol_duration, d->regs + DSI_VID_PCK_TIME);
writel(blkeol_duration - 6, d->regs + DSI_VID_VCA_SETTING1);
/* Use the same value for exact burst limit */
val = blkeol_pck <<
DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_SHIFT;
val &= DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_MASK;
writel(val, d->regs + DSI_VID_VCA_SETTING2);
/*
* This BLKEOL duration is claimed to be the duration in clock
* cycles of the BLLP end-of-line (EOL) period for each line if
* DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0 is set.
*
* It is hard to trust the manuals' claim that this is in clock
* cycles as we mimic the behaviour of the vendor code, which
* appears to write a number of bytes that would have been
* transferred on a single lane.
*
* See the manual figure 657 page 2203 and page 2198 for the 13
* reg_blkeol_duration bits.
*
* FIXME: should this also be set up also for non-burst mode
* according to figure 565 page 2202?
*/
blkeol_duration = DIV_ROUND_CLOSEST(blkeol_pck + 6,
d->mdsi->lanes);
dev_dbg(d->dev, "BLKEOL duration: %d clock cycles\n",
blkeol_duration);
val = readl(d->regs + DSI_VID_PCK_TIME);
val &= ~DSI_VID_PCK_TIME_BLKEOL_DURATION_MASK;
val |= blkeol_duration <<
DSI_VID_PCK_TIME_BLKEOL_DURATION_SHIFT;
writel(val, d->regs + DSI_VID_PCK_TIME);
/* Max burst limit, this is given in bytes */
val = readl(d->regs + DSI_VID_VCA_SETTING1);
val &= ~DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT_MASK;
val |= (blkeol_pck - 6) <<
DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT_SHIFT;
writel(val, d->regs + DSI_VID_VCA_SETTING1);
}
/* Maximum line limit */
val = readl(d->regs + DSI_VID_VCA_SETTING2);
val |= blkline_pck <<
DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_SHIFT;
val &= ~DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT_MASK;
val |= (blkline_pck - 6) <<
DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT_SHIFT;
writel(val, d->regs + DSI_VID_VCA_SETTING2);
dev_dbg(d->dev, "blkline pck: %d bytes\n", blkline_pck - 6);
}
static void mcde_dsi_start(struct mcde_dsi *d)
......
......@@ -228,6 +228,7 @@
#define DSI_VID_PCK_TIME 0x000000A8
#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_REG_LINE_DURATION_SHIFT 0
......
......@@ -94,7 +94,7 @@ static int mtk_plane_atomic_check(struct drm_plane *plane,
if (!fb)
return 0;
if (!state->crtc)
if (WARN_ON(!state->crtc))
return 0;
ret = mtk_drm_crtc_plane_check(state->crtc, plane,
......
......@@ -157,7 +157,7 @@ static void submit_unlock_unpin_bo(struct msm_gem_submit *submit,
msm_gem_unpin_iova(&msm_obj->base, submit->aspace);
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))
submit->bos[i].iova = 0;
......@@ -180,7 +180,7 @@ static int submit_lock_objects(struct msm_gem_submit *submit)
contended = i;
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);
if (ret)
goto fail;
......@@ -202,7 +202,7 @@ static int submit_lock_objects(struct msm_gem_submit *submit)
if (ret == -EDEADLK) {
struct msm_gem_object *msm_obj = submit->bos[contended].obj;
/* 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);
if (!ret) {
submit->bos[contended].flags |= BO_LOCKED;
......
......@@ -42,7 +42,7 @@ static int lg4573_spi_write_u16(struct lg4573 *ctx, u16 data)
struct spi_transfer xfer = {
.len = 2,
};
u16 temp = cpu_to_be16(data);
__be16 temp = cpu_to_be16(data);
struct spi_message msg;
dev_dbg(ctx->panel.dev, "writing data: %x\n", data);
......
......@@ -46,6 +46,7 @@ config ROCKCHIP_DW_HDMI
config ROCKCHIP_DW_MIPI_DSI
bool "Rockchip specific extensions for Synopsys DW MIPI DSI"
select GENERIC_PHY_MIPI_DPHY
help
This selects support for Rockchip SoC specific extensions
for the Synopsys DesignWare HDMI driver. If you want to
......
......@@ -12,6 +12,7 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
......@@ -139,6 +140,12 @@
#define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0)
#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_DSI0_LCDC_SEL BIT(6)
#define RK3288_DSI1_LCDC_SEL BIT(9)
......@@ -223,6 +230,10 @@ struct dw_mipi_dsi_rockchip {
bool is_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 */
u16 input_div;
u16 feedback_div;
......@@ -359,6 +370,9 @@ static int dw_mipi_dsi_phy_init(void *priv_data)
struct dw_mipi_dsi_rockchip *dsi = priv_data;
int ret, i, vco;
if (dsi->phy)
return 0;
/*
* Get vco from frequency(lane_mbps)
* vco frequency table
......@@ -467,6 +481,28 @@ static int dw_mipi_dsi_phy_init(void *priv_data)
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
dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
unsigned long mode_flags, u32 lanes, u32 format,
......@@ -504,6 +540,17 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
"DPHY clock frequency is out of range\n");
}
/* 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);
fout = target_mbps * USEC_PER_SEC;
......@@ -559,9 +606,89 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
return 0;
}
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 = {
.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_timing = dw_mipi_dsi_phy_get_timing,
};
static void dw_mipi_dsi_rockchip_config(struct dw_mipi_dsi_rockchip *dsi,
......@@ -920,13 +1047,30 @@ static int dw_mipi_dsi_rockchip_probe(struct platform_device *pdev)
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");
if (IS_ERR(dsi->pllref_clk)) {
if (dsi->phy) {
/*
* if external phy is present, pll will be
* 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);
"Unable to get pll reference clock: %d\n",
ret);
return ret;
}
}
if (dsi->cdata->flags & DW_MIPI_NEEDS_PHY_CFG_CLK) {
dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg");
......@@ -989,6 +1133,24 @@ static int dw_mipi_dsi_rockchip_remove(struct platform_device *pdev)
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[] = {
{
.reg = 0xff960000,
......@@ -1057,6 +1219,9 @@ static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = {
static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = {
{
.compatible = "rockchip,px30-mipi-dsi",
.data = &px30_chip_data,
}, {
.compatible = "rockchip,rk3288-mipi-dsi",
.data = &rk3288_chip_data,
}, {
......
......@@ -60,3 +60,8 @@ cmdline_test(drm_cmdline_test_vmirror)
cmdline_test(drm_cmdline_test_margin_options)
cmdline_test(drm_cmdline_test_multiple_options)
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)
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"
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,
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 = {
.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_timing = dw_mipi_dsi_phy_get_timing,
};
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,
/* Commit shadow registers = update planes at next vblank */
reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR);
/* Enable LTDC */
reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN);
drm_crtc_vblank_on(crtc);
}
......@@ -453,9 +450,6 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc,
drm_crtc_vblank_off(crtc);
/* disable LTDC */
reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN);
/* disable IRQ */
reg_clear(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE);
......@@ -1044,14 +1038,31 @@ static const struct drm_encoder_funcs ltdc_encoder_funcs = {
static void ltdc_encoder_disable(struct drm_encoder *encoder)
{
struct drm_device *ddev = encoder->dev;
struct ltdc_device *ldev = ddev->dev_private;
DRM_DEBUG_DRIVER("\n");
/* Disable LTDC */
reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN);
/* Set to sleep state the pinctrl whatever type of encoder */
pinctrl_pm_select_sleep_state(ddev->dev);
}
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;
......@@ -1069,6 +1080,7 @@ static void ltdc_encoder_enable(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs ltdc_encoder_helper_funcs = {
.disable = ltdc_encoder_disable,
.enable = ltdc_encoder_enable,
.mode_set = ltdc_encoder_mode_set,
};
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,
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)
{
struct component_match *match = NULL;
......@@ -418,6 +439,7 @@ static struct platform_driver sun4i_drv_platform_driver = {
.driver = {
.name = "sun4i-drm",
.of_match_table = sun4i_drv_of_table,
.pm = &sun4i_drv_drm_pm_ops,
},
};
module_platform_driver(sun4i_drv_platform_driver);
......
......@@ -1081,6 +1081,7 @@ static const struct component_ops sun6i_dsi_ops = {
static int sun6i_dsi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const char *bus_clk_name = NULL;
struct sun6i_dsi *dsi;
struct resource *res;
void __iomem *base;
......@@ -1094,6 +1095,10 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
dsi->host.ops = &sun6i_dsi_host_ops;
dsi->host.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);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base)) {
......@@ -1107,23 +1112,36 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
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);
if (IS_ERR(dsi->reset)) {
dev_err(dev, "Couldn't get our reset line\n");
return PTR_ERR(dsi->reset);
}
dsi->regs = devm_regmap_init_mmio(dev, base, &sun6i_dsi_regmap_config);
if (IS_ERR(dsi->regs)) {
dev_err(dev, "Couldn't init regmap\n");
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");
return PTR_ERR(dsi->mod_clk);
ret = PTR_ERR(dsi->mod_clk);
goto err_attach_clk;
}
}
/*
......@@ -1161,6 +1179,9 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
pm_runtime_disable(dev);
err_unprotect_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;
}
......@@ -1174,6 +1195,9 @@ static int sun6i_dsi_remove(struct platform_device *pdev)
pm_runtime_disable(dev);
clk_rate_exclusive_put(dsi->mod_clk);
if (!IS_ERR(dsi->bus_clk))
regmap_mmio_detach_clk(dsi->regs);
return 0;
}
......@@ -1232,6 +1256,7 @@ static const struct dev_pm_ops sun6i_dsi_pm_ops = {
static const struct of_device_id sun6i_dsi_of_table[] = {
{ .compatible = "allwinner,sun6i-a31-mipi-dsi" },
{ .compatible = "allwinner,sun50i-a64-mipi-dsi" },
{ }
};
MODULE_DEVICE_TABLE(of, sun6i_dsi_of_table);
......
......@@ -568,7 +568,7 @@ vc4_unlock_bo_reservations(struct drm_device *dev,
for (i = 0; i < exec->bo_count; i++) {
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);
......@@ -595,8 +595,7 @@ vc4_lock_bo_reservations(struct drm_device *dev,
retry:
if (contended_lock != -1) {
bo = &exec->bo[contended_lock]->base;
ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock,
acquire_ctx);
ret = dma_resv_lock_slow_interruptible(bo->resv, acquire_ctx);
if (ret) {
ww_acquire_done(acquire_ctx);
return ret;
......@@ -609,19 +608,19 @@ vc4_lock_bo_reservations(struct drm_device *dev,
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) {
int j;
for (j = 0; j < i; j++) {
bo = &exec->bo[j]->base;
ww_mutex_unlock(&bo->resv->lock);
dma_resv_unlock(bo->resv);
}
if (contended_lock != -1 && contended_lock >= i) {
bo = &exec->bo[contended_lock]->base;
ww_mutex_unlock(&bo->resv->lock);
dma_resv_unlock(bo->resv);
}
if (ret == -EDEADLK) {
......
......@@ -43,6 +43,9 @@
#define XRES_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 = {
.set_config = drm_atomic_helper_set_config,
.destroy = drm_crtc_cleanup,
......@@ -59,7 +62,7 @@ static const struct drm_framebuffer_funcs virtio_gpu_fb_funcs = {
.dirty = drm_atomic_helper_dirtyfb,
};
int
static int
virtio_gpu_framebuffer_init(struct drm_device *dev,
struct virtio_gpu_framebuffer *vgfb,
const struct drm_mode_fb_cmd2 *mode_cmd,
......
......@@ -103,8 +103,6 @@ struct virtio_gpu_fence {
struct virtio_gpu_fence_driver *drv;
struct list_head node;
};
#define to_virtio_fence(x) \
container_of(x, struct virtio_gpu_fence, f)
struct virtio_gpu_vbuffer {
char *buf;
......@@ -135,10 +133,6 @@ struct virtio_gpu_output {
};
#define drm_crtc_to_virtio_gpu_output(x) \
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 drm_framebuffer base;
......@@ -183,6 +177,9 @@ struct virtio_gpu_device {
struct kmem_cache *vbufs;
bool vqs_ready;
bool disable_notify;
bool pending_notify;
struct ida resource_ida;
wait_queue_head_t resp_wq;
......@@ -335,11 +332,10 @@ void virtio_gpu_dequeue_ctrl_func(struct work_struct *work);
void virtio_gpu_dequeue_cursor_func(struct work_struct *work);
void virtio_gpu_dequeue_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 */
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_fini(struct virtio_gpu_device *vgdev);
......@@ -350,7 +346,6 @@ struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev,
int index);
/* virtio_gpu_fence.c */
bool virtio_fence_signaled(struct dma_fence *f);
struct virtio_gpu_fence *virtio_gpu_fence_alloc(
struct virtio_gpu_device *vgdev);
void virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev,
......@@ -366,18 +361,12 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
struct virtio_gpu_object_params *params,
struct virtio_gpu_object **bo_ptr,
struct virtio_gpu_fence *fence);
/* virtgpu_prime.c */
struct drm_gem_object *virtgpu_gem_prime_import_sg_table(
struct drm_device *dev, struct dma_buf_attachment *attach,
struct sg_table *sgt);
static inline u64 virtio_gpu_object_mmap_offset(struct virtio_gpu_object *bo)
{
return drm_vma_node_offset_addr(&bo->base.base.vma_node);
}
/* virgl debufs */
/* virgl debugfs */
int virtio_gpu_debugfs_init(struct drm_minor *minor);
#endif
......@@ -27,6 +27,9 @@
#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)
{
return "virtio_gpu";
......@@ -37,7 +40,7 @@ static const char *virtio_get_timeline_name(struct dma_fence *f)
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);
......
......@@ -96,14 +96,12 @@ int virtio_gpu_mode_dumb_mmap(struct drm_file *file_priv,
uint32_t handle, uint64_t *offset_p)
{
struct drm_gem_object *gobj;
struct virtio_gpu_object *obj;
BUG_ON(!offset_p);
gobj = drm_gem_object_lookup(file_priv, handle);
if (gobj == NULL)
return -ENOENT;
obj = gem_to_virtio_gpu_obj(gobj);
*offset_p = virtio_gpu_object_mmap_offset(obj);
*offset_p = drm_vma_node_offset_addr(&gobj->vma_node);
drm_gem_object_put_unlocked(gobj);
return 0;
}
......
......@@ -24,6 +24,7 @@
*/
#include <drm/drm_atomic_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
......@@ -88,7 +89,7 @@ static int virtio_gpu_plane_atomic_check(struct drm_plane *plane,
struct drm_crtc_state *crtc_state;
int ret;
if (!state->fb || !state->crtc)
if (!state->fb || WARN_ON(!state->crtc))
return 0;
crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
......@@ -103,21 +104,25 @@ static int virtio_gpu_plane_atomic_check(struct drm_plane *plane,
}
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;
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);
if (!objs)
return;
virtio_gpu_array_add_obj(objs, &bo->base.base);
virtio_gpu_cmd_transfer_to_host_2d
(vgdev, 0,
state->src_w >> 16,
state->src_h >> 16,
state->src_x >> 16,
state->src_y >> 16,
virtio_gpu_cmd_transfer_to_host_2d(vgdev, off, w, h, x, y,
objs, NULL);
}
......@@ -127,8 +132,8 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
struct drm_device *dev = plane->dev;
struct virtio_gpu_device *vgdev = dev->dev_private;
struct virtio_gpu_output *output = NULL;
struct virtio_gpu_framebuffer *vgfb;
struct virtio_gpu_object *bo;
struct drm_rect rect;
if (plane->state->crtc)
output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
......@@ -146,11 +151,20 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
return;
}
vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
if (!drm_atomic_helper_damage_merged(old_state, plane->state, &rect))
return;
virtio_gpu_disable_notify(vgdev);
bo = gem_to_virtio_gpu_obj(plane->state->fb->obj[0]);
if (bo->dumb)
virtio_gpu_update_dumb_bo(vgdev, bo, plane->state);
virtio_gpu_update_dumb_bo(vgdev, plane->state, &rect);
if (plane->state->fb != old_state->fb ||
plane->state->src_w != old_state->src_w ||
plane->state->src_h != old_state->src_h ||
plane->state->src_x != old_state->src_x ||
plane->state->src_y != old_state->src_y) {
DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n",
bo->hw_res_handle,
plane->state->crtc_w, plane->state->crtc_h,
......@@ -165,11 +179,15 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
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,
plane->state->src_x >> 16,
plane->state->src_y >> 16,
plane->state->src_w >> 16,
plane->state->src_h >> 16);
rect.x1,
rect.y1,
rect.x2 - rect.x1,
rect.y2 - rect.y1);
virtio_gpu_enable_notify(vgdev);
}
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,
}
notify = virtio_gpu_queue_ctrl_buffer_locked(vgdev, vbuf, vout);
spin_unlock(&vgdev->ctrlq.qlock);
if (notify)
if (notify) {
if (vgdev->disable_notify)
vgdev->pending_notify = true;
else
virtqueue_notify(vgdev->ctrlq.vq);
}
if (sgt) {
sg_free_table(sgt);
......@@ -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,
struct virtio_gpu_vbuffer *vbuf)
{
......
......@@ -19,6 +19,13 @@ struct dw_mipi_dsi;
struct mipi_dsi_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 {
int (*init)(void *priv_data);
void (*power_on)(void *priv_data);
......@@ -27,6 +34,8 @@ struct dw_mipi_dsi_phy_ops {
const struct drm_display_mode *mode,
unsigned long mode_flags, u32 lanes, u32 format,
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 {
......
......@@ -35,7 +35,7 @@
* struct drm_crtc_commit - track modeset commits on a CRTC
*
* 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,
* without holding any locks.
*
......@@ -363,7 +363,7 @@ struct drm_atomic_state {
* When a connector or plane is not bound to any CRTC, it's still important
* 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.
*/
struct drm_crtc_commit *fake_commit;
......@@ -476,12 +476,12 @@ drm_atomic_get_new_connector_for_encoder(struct drm_atomic_state *state,
struct drm_encoder *encoder);
/**
* 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
* @crtc: crtc to grab
* @crtc: CRTC to grab
*
* This function returns the crtc state for the given crtc, or NULL
* if the crtc is not part of the global atomic state.
* This function returns the CRTC state for the given CRTC, or NULL
* if the CRTC is not part of the global atomic state.
*
* This function is deprecated, @drm_atomic_get_old_crtc_state or
* @drm_atomic_get_new_crtc_state should be used instead.
......@@ -494,12 +494,12 @@ drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state,
}
/**
* drm_atomic_get_old_crtc_state - get old crtc state, if it exists
* drm_atomic_get_old_crtc_state - get old CRTC state, if it exists
* @state: global atomic state object
* @crtc: crtc to grab
* @crtc: CRTC to grab
*
* This function returns the old crtc state for the given crtc, or
* NULL if the crtc is not part of the global atomic state.
* This function returns the old CRTC state for the given CRTC, or
* NULL if the CRTC is not part of the global atomic state.
*/
static inline struct drm_crtc_state *
drm_atomic_get_old_crtc_state(struct drm_atomic_state *state,
......@@ -508,12 +508,12 @@ drm_atomic_get_old_crtc_state(struct drm_atomic_state *state,
return state->crtcs[drm_crtc_index(crtc)].old_state;
}
/**
* 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
* @crtc: crtc to grab
* @crtc: CRTC to grab
*
* This function returns the new crtc state for the given crtc, or
* NULL if the crtc is not part of the global atomic state.
* This function returns the new CRTC state for the given CRTC, or
* NULL if the CRTC is not part of the global atomic state.
*/
static inline struct drm_crtc_state *
drm_atomic_get_new_crtc_state(struct drm_atomic_state *state,
......@@ -978,11 +978,11 @@ drm_atomic_crtc_needs_modeset(const struct drm_crtc_state *state)
}
/**
* drm_atomic_crtc_effectively_active - compute whether crtc is actually active
* drm_atomic_crtc_effectively_active - compute whether CRTC is actually active
* @state: &drm_crtc_state for the CRTC
*
* 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).
* 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,
/**
* drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
* @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
* atomic state after it has been checked and swapped. To iterate over the
......@@ -166,7 +166,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
/**
* drm_crtc_atomic_state_for_each_plane - iterate over attached planes in new state
* @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
* attached if the specified state is applied. Useful during for example
......@@ -180,7 +180,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
* drm_crtc_atomic_state_for_each_plane_state - iterate over attached planes in new state
* @plane: the loop cursor
* @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
* attached if the specified state is applied. Useful during for example
......@@ -189,7 +189,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
*
* Compared to just drm_atomic_crtc_state_for_each_plane() this also fills in a
* 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) \
drm_for_each_plane_mask(plane, (crtc_state)->state->dev, (crtc_state)->plane_mask) \
......
......@@ -1069,6 +1069,14 @@ struct drm_cmdline_mode {
*/
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.
*/
......
......@@ -198,7 +198,7 @@ static inline struct drm_panel *of_drm_find_panel(const struct device_node *np)
}
#endif
#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
#if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE)
int drm_panel_of_backlight(struct drm_panel *panel);
#else
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)
/*
* struct device based logging
*
* Prefer drm_device based logging over device or prink based logging.
*/
__printf(3, 4)
......@@ -417,8 +419,71 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category,
_DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_PRIME, \
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
*
* Prefer drm_device based logging over device or prink based logging.
*/
__printf(2, 3)
......
......@@ -42,12 +42,12 @@ struct dma_heap_allocation_data {
#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
* 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)
#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,
if (!dmabuf_fd)
return -EINVAL;
ret = ioctl(fd, DMA_HEAP_IOC_ALLOC, &data);
ret = ioctl(fd, DMA_HEAP_IOCTL_ALLOC, &data);
if (ret < 0)
return ret;
*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