drm-misc-next for 5.8:

UAPI Changes:
 
 Cross-subsystem Changes:
 
  * MAINTAINERS: restore alphabetical order; update cirrus driver
  * Dcomuentation: document visionix, chronteli, ite vendor prefices; update
                   documentation for Chrontel CH7033, IT6505, IVO, BOE,
 		  Panasonic, Chunghwa, AUO bindings; convert dw_mipi_dsi.txt
 		  to YAML; remove todo item for drm_display_mode.hsync removal;
 
 Core Changes:
 
  * drm: add devm_drm_dev_alloc() for managed allocations of drm_device;
         use DRM_MODESET_LOCK_ALL_*() in mode-object code; remove
         drm_display_mode.hsync; small cleanups of unused variables,
 	compiler warnings and static functions
  * drm/client: dual-lincensing: GPL-2.0 or MIT
  * drm/mm: optimize tree searches in rb_hole_addr()
 
 Driver Changes:
 
  * drm/{many}: use devm_drm_dev_alloc(); don't use drm_device.dev_private
  * drm/ast: don't double-assign to drm_crtc_funcs.set_config; drop
             drm_connector_register()
  * drm/bochs: drop drm_connector_register()
  * drm/bridge: add support for Chrontel ch7033; fix stack usage with
                old gccs; return error pointer in drm_panel_bridge_add()
  * drm/cirrus: Move to tiny
  * drm/dp_mst: don't use 2nd sideband tx slot; revert "Remove single tx
                msg restriction"
  * drm/lima: support runtime PM;
  * drm/meson: limit modes wrt chipset
  * drm/panel: add support for Visionox rm69299; fix clock on
               boe-tv101wum-n16; fix panel type for AUO G101EVN10;
 	      add support for Ivo M133NFW4 R0; add support for BOE
 	      NV133FHM-N61; add support for AUO G121EAN01.4, G156XTN01.0,
 	      G190EAN01
  * drm/pl111: improve vexpress init; fix module auto-loading
  * drm/stm: read number of endpoints from device tree
  * drm/vboxvideo: use managed PCI functions; drop DRM_MTRR_WC
  * drm/vkms: fix use-after-free in vkms_gem_create(); enable cursor
              support by default
  * fbdev: use boolean values in several drivers
  * fbdev/controlfb: fix COMPILE_TEST
  * fbdev/w100fb: fix double-free bug
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEEchf7rIzpz2NEoWjlaA3BHVMLeiMFAl6ztuYACgkQaA3BHVML
 eiMWaAgAvYpXvBqBfE/5jOTa1zWQUX9VMbmMDUqSAgec5r/HVHjmlbsDWkLff2XG
 rH7T2shMNJwluoCleHfRFYUfyUWMmXoMgri1elnf4EgddmekLZ6vNQjtAYMRFUfL
 7VegcFw5D5Z28uxK5YGnaaSQob34LvD8UTgvnCVfDQzCjcEzGYi1d9XELm7kTHje
 dF2FOWPeF8FTqP0XHM8RrHNXW/pUPy9qErpmb2bWYBQp7ebkI2Q4p6IZIpRQm757
 bnKPIdMEcy4BWMk1xtzjEYEb4bGSZhozJUWKFwpm/AHNvTrQCt9hn0GSVrXiqBcR
 UKb42BRxEVR29C/4n10pUcnnQmmi+Q==
 =yzZ9
 -----END PGP SIGNATURE-----

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

drm-misc-next for 5.8:

UAPI Changes:

Cross-subsystem Changes:

 * MAINTAINERS: restore alphabetical order; update cirrus driver
 * Dcomuentation: document visionix, chronteli, ite vendor prefices; update
                  documentation for Chrontel CH7033, IT6505, IVO, BOE,
		  Panasonic, Chunghwa, AUO bindings; convert dw_mipi_dsi.txt
		  to YAML; remove todo item for drm_display_mode.hsync removal;

Core Changes:

 * drm: add devm_drm_dev_alloc() for managed allocations of drm_device;
        use DRM_MODESET_LOCK_ALL_*() in mode-object code; remove
        drm_display_mode.hsync; small cleanups of unused variables,
	compiler warnings and static functions
 * drm/client: dual-lincensing: GPL-2.0 or MIT
 * drm/mm: optimize tree searches in rb_hole_addr()

Driver Changes:

 * drm/{many}: use devm_drm_dev_alloc(); don't use drm_device.dev_private
 * drm/ast: don't double-assign to drm_crtc_funcs.set_config; drop
            drm_connector_register()
 * drm/bochs: drop drm_connector_register()
 * drm/bridge: add support for Chrontel ch7033; fix stack usage with
               old gccs; return error pointer in drm_panel_bridge_add()
 * drm/cirrus: Move to tiny
 * drm/dp_mst: don't use 2nd sideband tx slot; revert "Remove single tx
               msg restriction"
 * drm/lima: support runtime PM;
 * drm/meson: limit modes wrt chipset
 * drm/panel: add support for Visionox rm69299; fix clock on
              boe-tv101wum-n16; fix panel type for AUO G101EVN10;
	      add support for Ivo M133NFW4 R0; add support for BOE
	      NV133FHM-N61; add support for AUO G121EAN01.4, G156XTN01.0,
	      G190EAN01
 * drm/pl111: improve vexpress init; fix module auto-loading
 * drm/stm: read number of endpoints from device tree
 * drm/vboxvideo: use managed PCI functions; drop DRM_MTRR_WC
 * drm/vkms: fix use-after-free in vkms_gem_create(); enable cursor
             support by default
 * fbdev: use boolean values in several drivers
 * fbdev/controlfb: fix COMPILE_TEST
 * fbdev/w100fb: fix double-free bug

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

From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20200507072503.GA10979@linux-uq9g
This commit is contained in:
Dave Airlie 2020-05-08 15:16:36 +10:00
commit 3fd911b69b
152 changed files with 2653 additions and 1217 deletions

View File

@ -0,0 +1,77 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2019,2020 Lubomir Rintel <lkundrak@v3.sk>
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/bridge/chrontel,ch7033.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Chrontel CH7033 Video Encoder Device Tree Bindings
maintainers:
- Lubomir Rintel <lkundrak@v3.sk>
properties:
compatible:
const: chrontel,ch7033
reg:
maxItems: 1
description: I2C address of the device
ports:
type: object
properties:
port@0:
type: object
description: |
Video port for RGB input.
port@1:
type: object
description: |
DVI port, should be connected to a node compatible with the
dvi-connector binding.
required:
- port@0
- port@1
required:
- compatible
- reg
- ports
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
vga-dvi-encoder@76 {
compatible = "chrontel,ch7033";
reg = <0x76>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
endpoint {
remote-endpoint = <&lcd0_rgb_out>;
};
};
port@1 {
reg = <1>;
endpoint {
remote-endpoint = <&dvi_in>;
};
};
};
};
};

View File

@ -1,32 +0,0 @@
Synopsys DesignWare MIPI DSI host controller
============================================
This document defines device tree properties for the Synopsys DesignWare MIPI
DSI host controller. It doesn't constitue a device tree binding specification
by itself but is meant to be referenced by platform-specific device tree
bindings.
When referenced from platform device tree bindings the properties defined in
this document are defined as follows. The platform device tree bindings are
responsible for defining whether each optional property is used or not.
- reg: Memory mapped base address and length of the DesignWare MIPI DSI
host controller registers. (mandatory)
- clocks: References to all the clocks specified in the clock-names property
as specified in [1]. (mandatory)
- clock-names:
- "pclk" is the peripheral clock for either AHB and APB. (mandatory)
- "px_clk" is the pixel clock for the DPI/RGB input. (optional)
- resets: References to all the resets specified in the reset-names property
as specified in [2]. (optional)
- reset-names: string reset name, must be "apb" if used. (optional)
- panel or bridge node: see [3]. (mandatory)
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/reset/reset.txt
[3] Documentation/devicetree/bindings/display/mipi-dsi-bus.txt

View File

@ -0,0 +1,91 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/bridge/ite,it6505.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ITE it6505 Device Tree Bindings
maintainers:
- Allen Chen <allen.chen@ite.com.tw>
description: |
The IT6505 is a high-performance DisplayPort 1.1a transmitter,
fully compliant with DisplayPort 1.1a, HDCP 1.3 specifications.
The IT6505 supports color depth of up to 36 bits (12 bits/color)
and ensures robust transmission of high-quality uncompressed video
content, along with uncompressed and compressed digital audio content.
Aside from the various video output formats supported, the IT6505
also encodes and transmits up to 8 channels of I2S digital audio,
with sampling rate up to 192kHz and sample size up to 24 bits.
In addition, an S/PDIF input port takes in compressed audio of up to
192kHz frame rate.
Each IT6505 chip comes preprogrammed with an unique HDCP key,
in compliance with the HDCP 1.3 standard so as to provide secure
transmission of high-definition content. Users of the IT6505 need not
purchase any HDCP keys or ROMs.
properties:
compatible:
const: ite,it6505
ovdd-supply:
maxItems: 1
description: I/O voltage
pwr18-supply:
maxItems: 1
description: core voltage
interrupts:
maxItems: 1
description: interrupt specifier of INT pin
reset-gpios:
maxItems: 1
description: gpio specifier of RESET pin
extcon:
maxItems: 1
description: extcon specifier for the Power Delivery
port:
type: object
description: A port node pointing to DPI host port node
required:
- compatible
- ovdd-supply
- pwr18-supply
- interrupts
- reset-gpios
- extcon
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
dp-bridge@5c {
compatible = "ite,it6505";
interrupts = <152 IRQ_TYPE_EDGE_FALLING 152 0>;
reg = <0x5c>;
pinctrl-names = "default";
pinctrl-0 = <&it6505_pins>;
ovdd-supply = <&mt6358_vsim1_reg>;
pwr18-supply = <&it6505_pp18_reg>;
reset-gpios = <&pio 179 1>;
extcon = <&usbc_extcon>;
port {
it6505_in: endpoint {
remote-endpoint = <&dpi_out>;
};
};
};
};

View File

@ -0,0 +1,68 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/bridge/snps,dw-mipi-dsi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Synopsys DesignWare MIPI DSI host controller
maintainers:
- Philippe CORNU <philippe.cornu@st.com>
description: |
This document defines device tree properties for the Synopsys DesignWare MIPI
DSI host controller. It doesn't constitue a device tree binding specification
by itself but is meant to be referenced by platform-specific device tree
bindings.
When referenced from platform device tree bindings the properties defined in
this document are defined as follows. The platform device tree bindings are
responsible for defining whether each property is required or optional.
allOf:
- $ref: ../dsi-controller.yaml#
properties:
reg:
maxItems: 1
clocks:
items:
- description: Module clock
- description: DSI bus clock for either AHB and APB
- description: Pixel clock for the DPI/RGB input
minItems: 2
clock-names:
items:
- const: ref
- const: pclk
- const: px_clk
minItems: 2
resets:
maxItems: 1
reset-names:
const: apb
ports:
type: object
properties:
port@0:
type: object
description: Input node to receive pixel data.
port@1:
type: object
description: DSI output node to panel.
required:
- port@0
- port@1
required:
- clock-names
- clocks
- ports
- reg

View File

@ -42,6 +42,8 @@ properties:
# One Stop Displays OSD101T2587-53TS 10.1" 1920x1200 panel
- osddisplays,osd101t2587-53ts
# Panasonic 10" WUXGA TFT LCD panel
- panasonic,vvx10f004b00
# Panasonic 10" WUXGA TFT LCD panel
- panasonic,vvx10f034n00
reg:

View File

@ -53,10 +53,16 @@ properties:
- auo,g101evn010
# AU Optronics Corporation 10.4" (800x600) color TFT LCD panel
- auo,g104sn02
# AU Optronics Corporation 12.1" (1280x800) TFT LCD panel
- auo,g121ean01
# AU Optronics Corporation 13.3" FHD (1920x1080) TFT LCD panel
- auo,g133han01
# AU Optronics Corporation 15.6" (1366x768) TFT LCD panel
- auo,g156xtn01
# AU Optronics Corporation 18.5" FHD (1920x1080) TFT LCD panel
- auo,g185han01
# AU Optronics Corporation 19.0" (1280x1024) TFT LCD panel
- auo,g190ean01
# AU Optronics Corporation 31.5" FHD (1920x1080) TFT LCD panel
- auo,p320hvn03
# AU Optronics Corporation 21.5" FHD (1920x1080) color TFT LCD panel
@ -67,6 +73,8 @@ properties:
- boe,hv070wsa-100
# BOE OPTOELECTRONICS TECHNOLOGY 10.1" WXGA TFT LCD panel
- boe,nv101wxmn51
# BOE NV133FHM-N61 13.3" FHD (1920x1080) TFT LCD Panel
- boe,nv133fhm-n61
# BOE NV140FHM-N49 14.0" FHD a-Si FT panel
- boe,nv140fhmn49
# CDTech(H.K.) Electronics Limited 4.3" 480x272 color TFT-LCD panel
@ -78,6 +86,8 @@ properties:
# Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
- chunghwa,claa101wa01a
# Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
- chunghwa,claa101wb01
# Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
- chunghwa,claa101wb03
# DataImage, Inc. 7" WVGA (800x480) TFT LCD panel with 24-bit parallel interface.
- dataimage,scf0700c48ggu18
@ -123,6 +133,8 @@ properties:
- hannstar,hsd100pxn1
# Hitachi Ltd. Corporation 9" WVGA (800x480) TFT LCD panel
- hit,tx23d38vm0caa
# InfoVision Optoelectronics M133NWF4 R0 13.3" FHD (1920x1080) TFT LCD panel
- ivo,m133nwf4-r0
# Innolux AT043TN24 4.3" WQVGA TFT LCD panel
- innolux,at043tn24
# Innolux AT070TN92 7.0" WQVGA TFT LCD panel

View File

@ -187,6 +187,8 @@ patternProperties:
description: ChipOne
"^chipspark,.*":
description: ChipSPARK
"^chrontel,.*":
description: Chrontel, Inc.
"^chrp,.*":
description: Common Hardware Reference Platform
"^chunghwa,.*":
@ -463,6 +465,8 @@ patternProperties:
description: Infineon Technologies
"^inforce,.*":
description: Inforce Computing
"^ivo,.*":
description: InfoVision Optoelectronics Kunshan Co. Ltd.
"^ingenic,.*":
description: Ingenic Semiconductor
"^innolux,.*":
@ -488,7 +492,7 @@ patternProperties:
"^issi,.*":
description: Integrated Silicon Solutions Inc.
"^ite,.*":
description: ITE Tech, Inc.
description: ITE Tech. Inc.
"^itead,.*":
description: ITEAD Intelligent Systems Co.Ltd
"^iwave,.*":
@ -1039,6 +1043,8 @@ patternProperties:
description: Tronsmart
"^truly,.*":
description: Truly Semiconductors Limited
"^visionox,.*":
description: Visionox
"^tsd,.*":
description: Theobroma Systems Design und Consulting GmbH
"^tyan,.*":

View File

@ -347,18 +347,6 @@ Contact: Sean Paul
Level: Starter
Remove drm_display_mode.hsync
-----------------------------
We have drm_mode_hsync() to calculate this from hsync_start/end, since drivers
shouldn't/don't use this, remove this member to avoid any temptations to use it
in the future. If there is any debug code using drm_display_mode.hsync, convert
it to use drm_mode_hsync() instead.
Contact: Sean Paul
Level: Starter
connector register/unregister fixes
-----------------------------------

View File

@ -5400,7 +5400,7 @@ L: virtualization@lists.linux-foundation.org
S: Obsolete
W: https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/
T: git git://anongit.freedesktop.org/drm/drm-misc
F: drivers/gpu/drm/cirrus/
F: drivers/gpu/drm/tiny/cirrus.c
DRM DRIVER FOR QXL VIRTUAL GPU
M: Dave Airlie <airlied@redhat.com>

View File

@ -310,8 +310,6 @@ source "drivers/gpu/drm/ast/Kconfig"
source "drivers/gpu/drm/mgag200/Kconfig"
source "drivers/gpu/drm/cirrus/Kconfig"
source "drivers/gpu/drm/armada/Kconfig"
source "drivers/gpu/drm/atmel-hlcdc/Kconfig"

View File

@ -74,7 +74,6 @@ obj-$(CONFIG_DRM_I915) += i915/
obj-$(CONFIG_DRM_MGAG200) += mgag200/
obj-$(CONFIG_DRM_V3D) += v3d/
obj-$(CONFIG_DRM_VC4) += vc4/
obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus/
obj-$(CONFIG_DRM_SIS) += sis/
obj-$(CONFIG_DRM_SAVAGE)+= savage/
obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/

View File

@ -129,7 +129,7 @@ static bool dsc_line_buff_depth_from_dpcd(int dpcd_line_buff_bit_depth, int *lin
static bool dsc_throughput_from_dpcd(int dpcd_throughput, int *throughput)
{
switch (dpcd_throughput) {
case DP_DSC_THROUGHPUT_MODE_0_UPSUPPORTED:
case DP_DSC_THROUGHPUT_MODE_0_UNSUPPORTED:
*throughput = 0;
break;
case DP_DSC_THROUGHPUT_MODE_0_170:

View File

@ -261,18 +261,16 @@ static void komeda_kms_mode_config_init(struct komeda_kms_dev *kms,
struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
{
struct komeda_kms_dev *kms = kzalloc(sizeof(*kms), GFP_KERNEL);
struct komeda_kms_dev *kms;
struct drm_device *drm;
int err;
if (!kms)
return ERR_PTR(-ENOMEM);
kms = devm_drm_dev_alloc(mdev->dev, &komeda_kms_driver,
struct komeda_kms_dev, base);
if (IS_ERR(kms))
return kms;
drm = &kms->base;
err = drm_dev_init(drm, &komeda_kms_driver, mdev->dev);
if (err)
goto free_kms;
drmm_add_final_kfree(drm, kms);
drm->dev_private = mdev;
@ -329,9 +327,6 @@ cleanup_mode_config:
drm_mode_config_cleanup(drm);
komeda_kms_cleanup_private_objs(kms);
drm->dev_private = NULL;
drm_dev_put(drm);
free_kms:
kfree(kms);
return ERR_PTR(err);
}
@ -348,5 +343,4 @@ void komeda_kms_detach(struct komeda_kms_dev *kms)
drm_mode_config_cleanup(drm);
komeda_kms_cleanup_private_objs(kms);
drm->dev_private = NULL;
drm_dev_put(drm);
}

View File

@ -5,6 +5,7 @@
#include <drm/drm_simple_kms_helper.h>
struct aspeed_gfx {
struct drm_device drm;
void __iomem *base;
struct clk *clk;
struct reset_control *rst;
@ -12,8 +13,8 @@ struct aspeed_gfx {
struct drm_simple_display_pipe pipe;
struct drm_connector connector;
struct drm_fbdev_cma *fbdev;
};
#define to_aspeed_gfx(x) container_of(x, struct aspeed_gfx, drm)
int aspeed_gfx_create_pipe(struct drm_device *drm);
int aspeed_gfx_create_output(struct drm_device *drm);

View File

@ -231,7 +231,7 @@ static const uint32_t aspeed_gfx_formats[] = {
int aspeed_gfx_create_pipe(struct drm_device *drm)
{
struct aspeed_gfx *priv = drm->dev_private;
struct aspeed_gfx *priv = to_aspeed_gfx(drm);
return drm_simple_display_pipe_init(drm, &priv->pipe, &aspeed_gfx_funcs,
aspeed_gfx_formats,

View File

@ -77,7 +77,7 @@ static void aspeed_gfx_setup_mode_config(struct drm_device *drm)
static irqreturn_t aspeed_gfx_irq_handler(int irq, void *data)
{
struct drm_device *drm = data;
struct aspeed_gfx *priv = drm->dev_private;
struct aspeed_gfx *priv = to_aspeed_gfx(drm);
u32 reg;
reg = readl(priv->base + CRT_CTRL1);
@ -96,15 +96,10 @@ static irqreturn_t aspeed_gfx_irq_handler(int irq, void *data)
static int aspeed_gfx_load(struct drm_device *drm)
{
struct platform_device *pdev = to_platform_device(drm->dev);
struct aspeed_gfx *priv;
struct aspeed_gfx *priv = to_aspeed_gfx(drm);
struct resource *res;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
drm->dev_private = priv;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->base = devm_ioremap_resource(drm->dev, res);
if (IS_ERR(priv->base))
@ -187,8 +182,6 @@ static void aspeed_gfx_unload(struct drm_device *drm)
{
drm_kms_helper_poll_fini(drm);
drm_mode_config_cleanup(drm);
drm->dev_private = NULL;
}
DEFINE_DRM_GEM_CMA_FOPS(fops);
@ -216,27 +209,26 @@ static const struct of_device_id aspeed_gfx_match[] = {
static int aspeed_gfx_probe(struct platform_device *pdev)
{
struct drm_device *drm;
struct aspeed_gfx *priv;
int ret;
drm = drm_dev_alloc(&aspeed_gfx_driver, &pdev->dev);
if (IS_ERR(drm))
return PTR_ERR(drm);
priv = devm_drm_dev_alloc(&pdev->dev, &aspeed_gfx_driver,
struct aspeed_gfx, drm);
if (IS_ERR(priv))
return PTR_ERR(priv);
ret = aspeed_gfx_load(drm);
ret = aspeed_gfx_load(&priv->drm);
if (ret)
goto err_free;
return ret;
ret = drm_dev_register(drm, 0);
ret = drm_dev_register(&priv->drm, 0);
if (ret)
goto err_unload;
return 0;
err_unload:
aspeed_gfx_unload(drm);
err_free:
drm_dev_put(drm);
aspeed_gfx_unload(&priv->drm);
return ret;
}
@ -247,7 +239,6 @@ static int aspeed_gfx_remove(struct platform_device *pdev)
drm_dev_unregister(drm);
aspeed_gfx_unload(drm);
drm_dev_put(drm);
return 0;
}

View File

@ -28,7 +28,7 @@ static const struct drm_connector_funcs aspeed_gfx_connector_funcs = {
int aspeed_gfx_create_output(struct drm_device *drm)
{
struct aspeed_gfx *priv = drm->dev_private;
struct aspeed_gfx *priv = to_aspeed_gfx(drm);
int ret;
priv->connector.dpms = DRM_MODE_DPMS_OFF;

View File

@ -931,7 +931,6 @@ static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc,
static const struct drm_crtc_funcs ast_crtc_funcs = {
.reset = ast_crtc_reset,
.set_config = drm_crtc_helper_set_config,
.gamma_set = drm_atomic_helper_legacy_gamma_set,
.destroy = ast_crtc_destroy,
.set_config = drm_atomic_helper_set_config,
@ -1080,7 +1079,6 @@ static void ast_connector_destroy(struct drm_connector *connector)
{
struct ast_connector *ast_connector = to_ast_connector(connector);
ast_i2c_destroy(ast_connector->i2c);
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
kfree(connector);
}
@ -1123,8 +1121,6 @@ static int ast_connector_init(struct drm_device *dev)
connector->interlace_allowed = 0;
connector->doublescan_allowed = 0;
drm_connector_register(connector);
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
encoder = list_first_entry(&dev->mode_config.encoder_list, struct drm_encoder, head);

View File

@ -104,7 +104,6 @@ static void bochs_connector_init(struct drm_device *dev)
DRM_MODE_CONNECTOR_VIRTUAL);
drm_connector_helper_add(connector,
&bochs_connector_connector_helper_funcs);
drm_connector_register(connector);
bochs_hw_load_edid(bochs);
if (bochs->edid) {

View File

@ -27,6 +27,16 @@ config DRM_CDNS_DSI
Support Cadence DPI to DSI bridge. This is an internal
bridge and is meant to be directly embedded in a SoC.
config DRM_CHRONTEL_CH7033
tristate "Chrontel CH7033 Video Encoder"
depends on OF
select DRM_KMS_HELPER
help
Enable support for the Chrontel CH7033 VGA/DVI/HDMI Encoder, as
found in the Dell Wyse 3020 thin client.
If in doubt, say "N".
config DRM_DISPLAY_CONNECTOR
tristate "Display connector support"
depends on OF

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o
obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o

View File

@ -0,0 +1,620 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Chrontel CH7033 Video Encoder Driver
*
* Copyright (C) 2019,2020 Lubomir Rintel
*/
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
/* Page 0, Register 0x07 */
enum {
DRI_PD = BIT(3),
IO_PD = BIT(5),
};
/* Page 0, Register 0x08 */
enum {
DRI_PDDRI = GENMASK(7, 4),
PDDAC = GENMASK(3, 1),
PANEN = BIT(0),
};
/* Page 0, Register 0x09 */
enum {
DPD = BIT(7),
GCKOFF = BIT(6),
TV_BP = BIT(5),
SCLPD = BIT(4),
SDPD = BIT(3),
VGA_PD = BIT(2),
HDBKPD = BIT(1),
HDMI_PD = BIT(0),
};
/* Page 0, Register 0x0a */
enum {
MEMINIT = BIT(7),
MEMIDLE = BIT(6),
MEMPD = BIT(5),
STOP = BIT(4),
LVDS_PD = BIT(3),
HD_DVIB = BIT(2),
HDCP_PD = BIT(1),
MCU_PD = BIT(0),
};
/* Page 0, Register 0x18 */
enum {
IDF = GENMASK(7, 4),
INTEN = BIT(3),
SWAP = GENMASK(2, 0),
};
enum {
BYTE_SWAP_RGB = 0,
BYTE_SWAP_RBG = 1,
BYTE_SWAP_GRB = 2,
BYTE_SWAP_GBR = 3,
BYTE_SWAP_BRG = 4,
BYTE_SWAP_BGR = 5,
};
/* Page 0, Register 0x19 */
enum {
HPO_I = BIT(5),
VPO_I = BIT(4),
DEPO_I = BIT(3),
CRYS_EN = BIT(2),
GCLKFREQ = GENMASK(2, 0),
};
/* Page 0, Register 0x2e */
enum {
HFLIP = BIT(7),
VFLIP = BIT(6),
DEPO_O = BIT(5),
HPO_O = BIT(4),
VPO_O = BIT(3),
TE = GENMASK(2, 0),
};
/* Page 0, Register 0x2b */
enum {
SWAPS = GENMASK(7, 4),
VFMT = GENMASK(3, 0),
};
/* Page 0, Register 0x54 */
enum {
COMP_BP = BIT(7),
DAC_EN_T = BIT(6),
HWO_HDMI_HI = GENMASK(5, 3),
HOO_HDMI_HI = GENMASK(2, 0),
};
/* Page 0, Register 0x57 */
enum {
FLDSEN = BIT(7),
VWO_HDMI_HI = GENMASK(5, 3),
VOO_HDMI_HI = GENMASK(2, 0),
};
/* Page 0, Register 0x7e */
enum {
HDMI_LVDS_SEL = BIT(7),
DE_GEN = BIT(6),
PWM_INDEX_HI = BIT(5),
USE_DE = BIT(4),
R_INT = GENMASK(3, 0),
};
/* Page 1, Register 0x07 */
enum {
BPCKSEL = BIT(7),
DRI_CMFB_EN = BIT(6),
CEC_PUEN = BIT(5),
CEC_T = BIT(3),
CKINV = BIT(2),
CK_TVINV = BIT(1),
DRI_CKS2 = BIT(0),
};
/* Page 1, Register 0x08 */
enum {
DACG = BIT(6),
DACKTST = BIT(5),
DEDGEB = BIT(4),
SYO = BIT(3),
DRI_IT_LVDS = GENMASK(2, 1),
DISPON = BIT(0),
};
/* Page 1, Register 0x0c */
enum {
DRI_PLL_CP = GENMASK(7, 6),
DRI_PLL_DIVSEL = BIT(5),
DRI_PLL_N1_1 = BIT(4),
DRI_PLL_N1_0 = BIT(3),
DRI_PLL_N3_1 = BIT(2),
DRI_PLL_N3_0 = BIT(1),
DRI_PLL_CKTSTEN = BIT(0),
};
/* Page 1, Register 0x6b */
enum {
VCO3CS = GENMASK(7, 6),
ICPGBK2_0 = GENMASK(5, 3),
DRI_VCO357SC = BIT(2),
PDPLL2 = BIT(1),
DRI_PD_SER = BIT(0),
};
/* Page 1, Register 0x6c */
enum {
PLL2N11 = GENMASK(7, 4),
PLL2N5_4 = BIT(3),
PLL2N5_TOP = BIT(2),
DRI_PLL_PD = BIT(1),
PD_I2CM = BIT(0),
};
/* Page 3, Register 0x28 */
enum {
DIFF_EN = GENMASK(7, 6),
CORREC_EN = GENMASK(5, 4),
VGACLK_BP = BIT(3),
HM_LV_SEL = BIT(2),
HD_VGA_SEL = BIT(1),
};
/* Page 3, Register 0x2a */
enum {
LVDSCLK_BP = BIT(7),
HDTVCLK_BP = BIT(6),
HDMICLK_BP = BIT(5),
HDTV_BP = BIT(4),
HDMI_BP = BIT(3),
THRWL = GENMASK(2, 0),
};
/* Page 4, Register 0x52 */
enum {
PGM_ARSTB = BIT(7),
MCU_ARSTB = BIT(6),
MCU_RETB = BIT(2),
RESETIB = BIT(1),
RESETDB = BIT(0),
};
struct ch7033_priv {
struct regmap *regmap;
struct drm_bridge *next_bridge;
struct drm_bridge bridge;
struct drm_connector connector;
};
#define conn_to_ch7033_priv(x) \
container_of(x, struct ch7033_priv, connector)
#define bridge_to_ch7033_priv(x) \
container_of(x, struct ch7033_priv, bridge)
static enum drm_connector_status ch7033_connector_detect(
struct drm_connector *connector, bool force)
{
struct ch7033_priv *priv = conn_to_ch7033_priv(connector);
return drm_bridge_detect(priv->next_bridge);
}
static const struct drm_connector_funcs ch7033_connector_funcs = {
.reset = drm_atomic_helper_connector_reset,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = ch7033_connector_detect,
.destroy = drm_connector_cleanup,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int ch7033_connector_get_modes(struct drm_connector *connector)
{
struct ch7033_priv *priv = conn_to_ch7033_priv(connector);
struct edid *edid;
int ret;
edid = drm_bridge_get_edid(priv->next_bridge, connector);
drm_connector_update_edid_property(connector, edid);
if (edid) {
ret = drm_add_edid_modes(connector, edid);
kfree(edid);
} else {
ret = drm_add_modes_noedid(connector, 1920, 1080);
drm_set_preferred_mode(connector, 1024, 768);
}
return ret;
}
static struct drm_encoder *ch7033_connector_best_encoder(
struct drm_connector *connector)
{
struct ch7033_priv *priv = conn_to_ch7033_priv(connector);
return priv->bridge.encoder;
}
static const struct drm_connector_helper_funcs ch7033_connector_helper_funcs = {
.get_modes = ch7033_connector_get_modes,
.best_encoder = ch7033_connector_best_encoder,
};
static void ch7033_hpd_event(void *arg, enum drm_connector_status status)
{
struct ch7033_priv *priv = arg;
if (priv->bridge.dev)
drm_helper_hpd_irq_event(priv->connector.dev);
}
static int ch7033_bridge_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
struct drm_connector *connector = &priv->connector;
int ret;
ret = drm_bridge_attach(bridge->encoder, priv->next_bridge, bridge,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret)
return ret;
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
return 0;
if (priv->next_bridge->ops & DRM_BRIDGE_OP_DETECT) {
connector->polled = DRM_CONNECTOR_POLL_HPD;
} else {
connector->polled = DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT;
}
if (priv->next_bridge->ops & DRM_BRIDGE_OP_HPD) {
drm_bridge_hpd_enable(priv->next_bridge, ch7033_hpd_event,
priv);
}
drm_connector_helper_add(connector,
&ch7033_connector_helper_funcs);
ret = drm_connector_init_with_ddc(bridge->dev, &priv->connector,
&ch7033_connector_funcs,
priv->next_bridge->type,
priv->next_bridge->ddc);
if (ret) {
DRM_ERROR("Failed to initialize connector\n");
return ret;
}
return drm_connector_attach_encoder(&priv->connector, bridge->encoder);
}
static void ch7033_bridge_detach(struct drm_bridge *bridge)
{
struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
if (priv->next_bridge->ops & DRM_BRIDGE_OP_HPD)
drm_bridge_hpd_disable(priv->next_bridge);
drm_connector_cleanup(&priv->connector);
}
static enum drm_mode_status ch7033_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_mode *mode)
{
if (mode->clock > 165000)
return MODE_CLOCK_HIGH;
if (mode->hdisplay >= 1920)
return MODE_BAD_HVALUE;
if (mode->vdisplay >= 1080)
return MODE_BAD_VVALUE;
return MODE_OK;
}
static void ch7033_bridge_disable(struct drm_bridge *bridge)
{
struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
regmap_write(priv->regmap, 0x03, 0x04);
regmap_update_bits(priv->regmap, 0x52, RESETDB, 0x00);
}
static void ch7033_bridge_enable(struct drm_bridge *bridge)
{
struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
regmap_write(priv->regmap, 0x03, 0x04);
regmap_update_bits(priv->regmap, 0x52, RESETDB, RESETDB);
}
static void ch7033_bridge_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
const struct drm_display_mode *adjusted_mode)
{
struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
int hbporch = mode->hsync_start - mode->hdisplay;
int hsynclen = mode->hsync_end - mode->hsync_start;
int vbporch = mode->vsync_start - mode->vdisplay;
int vsynclen = mode->vsync_end - mode->vsync_start;
/*
* Page 4
*/
regmap_write(priv->regmap, 0x03, 0x04);
/* Turn everything off to set all the registers to their defaults. */
regmap_write(priv->regmap, 0x52, 0x00);
/* Bring I/O block up. */
regmap_write(priv->regmap, 0x52, RESETIB);
/*
* Page 0
*/
regmap_write(priv->regmap, 0x03, 0x00);
/* Bring up parts we need from the power down. */
regmap_update_bits(priv->regmap, 0x07, DRI_PD | IO_PD, 0);
regmap_update_bits(priv->regmap, 0x08, DRI_PDDRI | PDDAC | PANEN, 0);
regmap_update_bits(priv->regmap, 0x09, DPD | GCKOFF |
HDMI_PD | VGA_PD, 0);
regmap_update_bits(priv->regmap, 0x0a, HD_DVIB, 0);
/* Horizontal input timing. */
regmap_write(priv->regmap, 0x0b, (mode->htotal >> 8) << 3 |
(mode->hdisplay >> 8));
regmap_write(priv->regmap, 0x0c, mode->hdisplay);
regmap_write(priv->regmap, 0x0d, mode->htotal);
regmap_write(priv->regmap, 0x0e, (hsynclen >> 8) << 3 |
(hbporch >> 8));
regmap_write(priv->regmap, 0x0f, hbporch);
regmap_write(priv->regmap, 0x10, hsynclen);
/* Vertical input timing. */
regmap_write(priv->regmap, 0x11, (mode->vtotal >> 8) << 3 |
(mode->vdisplay >> 8));
regmap_write(priv->regmap, 0x12, mode->vdisplay);
regmap_write(priv->regmap, 0x13, mode->vtotal);
regmap_write(priv->regmap, 0x14, ((vsynclen >> 8) << 3) |
(vbporch >> 8));
regmap_write(priv->regmap, 0x15, vbporch);
regmap_write(priv->regmap, 0x16, vsynclen);
/* Input color swap. */
regmap_update_bits(priv->regmap, 0x18, SWAP, BYTE_SWAP_BGR);
/* Input clock and sync polarity. */
regmap_update_bits(priv->regmap, 0x19, 0x1, mode->clock >> 16);
regmap_update_bits(priv->regmap, 0x19, HPO_I | VPO_I | GCLKFREQ,
(mode->flags & DRM_MODE_FLAG_PHSYNC) ? HPO_I : 0 |
(mode->flags & DRM_MODE_FLAG_PVSYNC) ? VPO_I : 0 |
mode->clock >> 16);
regmap_write(priv->regmap, 0x1a, mode->clock >> 8);
regmap_write(priv->regmap, 0x1b, mode->clock);
/* Horizontal output timing. */
regmap_write(priv->regmap, 0x1f, (mode->htotal >> 8) << 3 |
(mode->hdisplay >> 8));
regmap_write(priv->regmap, 0x20, mode->hdisplay);
regmap_write(priv->regmap, 0x21, mode->htotal);
/* Vertical output timing. */
regmap_write(priv->regmap, 0x25, (mode->vtotal >> 8) << 3 |
(mode->vdisplay >> 8));
regmap_write(priv->regmap, 0x26, mode->vdisplay);
regmap_write(priv->regmap, 0x27, mode->vtotal);
/* VGA channel bypass */
regmap_update_bits(priv->regmap, 0x2b, VFMT, 9);
/* Output sync polarity. */
regmap_update_bits(priv->regmap, 0x2e, HPO_O | VPO_O,
(mode->flags & DRM_MODE_FLAG_PHSYNC) ? HPO_O : 0 |
(mode->flags & DRM_MODE_FLAG_PVSYNC) ? VPO_O : 0);
/* HDMI horizontal output timing. */
regmap_update_bits(priv->regmap, 0x54, HWO_HDMI_HI | HOO_HDMI_HI,
(hsynclen >> 8) << 3 |
(hbporch >> 8));
regmap_write(priv->regmap, 0x55, hbporch);
regmap_write(priv->regmap, 0x56, hsynclen);
/* HDMI vertical output timing. */
regmap_update_bits(priv->regmap, 0x57, VWO_HDMI_HI | VOO_HDMI_HI,
(vsynclen >> 8) << 3 |
(vbporch >> 8));
regmap_write(priv->regmap, 0x58, vbporch);
regmap_write(priv->regmap, 0x59, vsynclen);
/* Pick HDMI, not LVDS. */
regmap_update_bits(priv->regmap, 0x7e, HDMI_LVDS_SEL, HDMI_LVDS_SEL);
/*
* Page 1
*/
regmap_write(priv->regmap, 0x03, 0x01);
/* No idea what these do, but VGA is wobbly and blinky without them. */
regmap_update_bits(priv->regmap, 0x07, CKINV, CKINV);
regmap_update_bits(priv->regmap, 0x08, DISPON, DISPON);
/* DRI PLL */
regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_DIVSEL, DRI_PLL_DIVSEL);
if (mode->clock <= 40000) {
regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_N1_1 |
DRI_PLL_N1_0 |
DRI_PLL_N3_1 |
DRI_PLL_N3_0,
0);
} else if (mode->clock < 80000) {
regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_N1_1 |
DRI_PLL_N1_0 |
DRI_PLL_N3_1 |
DRI_PLL_N3_0,
DRI_PLL_N3_0 |
DRI_PLL_N1_0);
} else {
regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_N1_1 |
DRI_PLL_N1_0 |
DRI_PLL_N3_1 |
DRI_PLL_N3_0,
DRI_PLL_N3_1 |
DRI_PLL_N1_1);
}
/* This seems to be color calibration for VGA. */
regmap_write(priv->regmap, 0x64, 0x29); /* LSB Blue */
regmap_write(priv->regmap, 0x65, 0x29); /* LSB Green */
regmap_write(priv->regmap, 0x66, 0x29); /* LSB Red */
regmap_write(priv->regmap, 0x67, 0x00); /* MSB Blue */
regmap_write(priv->regmap, 0x68, 0x00); /* MSB Green */
regmap_write(priv->regmap, 0x69, 0x00); /* MSB Red */
regmap_update_bits(priv->regmap, 0x6b, DRI_PD_SER, 0x00);
regmap_update_bits(priv->regmap, 0x6c, DRI_PLL_PD, 0x00);
/*
* Page 3
*/
regmap_write(priv->regmap, 0x03, 0x03);
/* More bypasses and apparently another HDMI/LVDS selector. */
regmap_update_bits(priv->regmap, 0x28, VGACLK_BP | HM_LV_SEL,
VGACLK_BP | HM_LV_SEL);
regmap_update_bits(priv->regmap, 0x2a, HDMICLK_BP | HDMI_BP,
HDMICLK_BP | HDMI_BP);
/*
* Page 4
*/
regmap_write(priv->regmap, 0x03, 0x04);
/* Output clock. */
regmap_write(priv->regmap, 0x10, mode->clock >> 16);
regmap_write(priv->regmap, 0x11, mode->clock >> 8);
regmap_write(priv->regmap, 0x12, mode->clock);
}
static const struct drm_bridge_funcs ch7033_bridge_funcs = {
.attach = ch7033_bridge_attach,
.detach = ch7033_bridge_detach,
.mode_valid = ch7033_bridge_mode_valid,
.disable = ch7033_bridge_disable,
.enable = ch7033_bridge_enable,
.mode_set = ch7033_bridge_mode_set,
};
static const struct regmap_config ch7033_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x7f,
};
static int ch7033_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct ch7033_priv *priv;
unsigned int val;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
dev_set_drvdata(dev, priv);
ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, NULL,
&priv->next_bridge);
if (ret)
return ret;
priv->regmap = devm_regmap_init_i2c(client, &ch7033_regmap_config);
if (IS_ERR(priv->regmap)) {
dev_err(&client->dev, "regmap init failed\n");
return PTR_ERR(priv->regmap);
}
ret = regmap_read(priv->regmap, 0x00, &val);
if (ret < 0) {
dev_err(&client->dev, "error reading the model id: %d\n", ret);
return ret;
}
if ((val & 0xf7) != 0x56) {
dev_err(&client->dev, "the device is not a ch7033\n");
return -ENODEV;
}
regmap_write(priv->regmap, 0x03, 0x04);
ret = regmap_read(priv->regmap, 0x51, &val);
if (ret < 0) {
dev_err(&client->dev, "error reading the model id: %d\n", ret);
return ret;
}
if ((val & 0x0f) != 3) {
dev_err(&client->dev, "unknown revision %u\n", val);
return -ENODEV;
}
INIT_LIST_HEAD(&priv->bridge.list);
priv->bridge.funcs = &ch7033_bridge_funcs;
priv->bridge.of_node = dev->of_node;
drm_bridge_add(&priv->bridge);
dev_info(dev, "Chrontel CH7033 Video Encoder\n");
return 0;
}
static int ch7033_remove(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct ch7033_priv *priv = dev_get_drvdata(dev);
drm_bridge_remove(&priv->bridge);
return 0;
}
static const struct of_device_id ch7033_dt_ids[] = {
{ .compatible = "chrontel,ch7033", },
{ }
};
MODULE_DEVICE_TABLE(of, ch7033_dt_ids);
static const struct i2c_device_id ch7033_ids[] = {
{ "ch7033", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ch7033_ids);
static struct i2c_driver ch7033_driver = {
.probe = ch7033_probe,
.remove = ch7033_remove,
.driver = {
.name = "ch7033",
.of_match_table = of_match_ptr(ch7033_dt_ids),
},
.id_table = ch7033_ids,
};
module_i2c_driver(ch7033_driver);
MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
MODULE_DESCRIPTION("Chrontel CH7033 Video Encoder Driver");
MODULE_LICENSE("GPL v2");

View File

@ -166,7 +166,7 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
*
* The connector type is set to @panel->connector_type, which must be set to a
* known type. Calling this function with a panel whose connector type is
* DRM_MODE_CONNECTOR_Unknown will return NULL.
* DRM_MODE_CONNECTOR_Unknown will return ERR_PTR(-EINVAL).
*
* See devm_drm_panel_bridge_add() for an automatically managed version of this
* function.
@ -174,7 +174,7 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel)
{
if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
return NULL;
return ERR_PTR(-EINVAL);
return drm_panel_bridge_add_typed(panel, panel->connector_type);
}
@ -265,7 +265,7 @@ struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
struct drm_panel *panel)
{
if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
return NULL;
return ERR_PTR(-EINVAL);
return devm_drm_panel_bridge_add_typed(dev, panel,
panel->connector_type);

View File

@ -268,8 +268,6 @@ static int ps8640_probe(struct i2c_client *client)
if (!panel)
return -ENODEV;
panel->connector_type = DRM_MODE_CONNECTOR_eDP;
ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
if (IS_ERR(ps_bridge->panel_bridge))
return PTR_ERR(ps_bridge->panel_bridge);

View File

@ -178,6 +178,8 @@ static int tc358768_clear_error(struct tc358768_priv *priv)
static void tc358768_write(struct tc358768_priv *priv, u32 reg, u32 val)
{
/* work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
int tmpval = val;
size_t count = 2;
if (priv->error)
@ -187,7 +189,7 @@ static void tc358768_write(struct tc358768_priv *priv, u32 reg, u32 val)
if (reg < 0x100 || reg >= 0x600)
count = 1;
priv->error = regmap_bulk_write(priv->regmap, reg, &val, count);
priv->error = regmap_bulk_write(priv->regmap, reg, &tmpval, count);
}
static void tc358768_read(struct tc358768_priv *priv, u32 reg, u32 *val)

View File

@ -1,19 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
config DRM_CIRRUS_QEMU
tristate "Cirrus driver for QEMU emulated device"
depends on DRM && PCI && MMU
select DRM_KMS_HELPER
select DRM_GEM_SHMEM_HELPER
help
This is a KMS driver for emulated cirrus device in qemu.
It is *NOT* intended for real cirrus devices. This requires
the modesetting userspace X.org driver.
Cirrus is obsolete, the hardware was designed in the 90ies
and can't keep up with todays needs. More background:
https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/
Better alternatives are:
- stdvga (DRM_BOCHS, qemu -vga std, default in qemu 2.2+)
- qxl (DRM_QXL, qemu -vga qxl, works best with spice)
- virtio (DRM_VIRTIO_GPU), qemu -vga virtio)

View File

@ -1,2 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o

View File

@ -1197,14 +1197,8 @@ static int drm_dp_mst_wait_tx_reply(struct drm_dp_mst_branch *mstb,
/* remove from q */
if (txmsg->state == DRM_DP_SIDEBAND_TX_QUEUED ||
txmsg->state == DRM_DP_SIDEBAND_TX_START_SEND) {
txmsg->state == DRM_DP_SIDEBAND_TX_START_SEND)
list_del(&txmsg->next);
}
if (txmsg->state == DRM_DP_SIDEBAND_TX_START_SEND ||
txmsg->state == DRM_DP_SIDEBAND_TX_SENT) {
mstb->tx_slots[txmsg->seqno] = NULL;
}
}
out:
if (unlikely(ret == -EIO) && drm_debug_enabled(DRM_UT_DP)) {
@ -1214,6 +1208,7 @@ out:
}
mutex_unlock(&mgr->qlock);
drm_dp_mst_kick_tx(mgr);
return ret;
}
@ -2682,22 +2677,6 @@ static int set_hdr_from_dst_qlock(struct drm_dp_sideband_msg_hdr *hdr,
struct drm_dp_mst_branch *mstb = txmsg->dst;
u8 req_type;
/* both msg slots are full */
if (txmsg->seqno == -1) {
if (mstb->tx_slots[0] && mstb->tx_slots[1]) {
DRM_DEBUG_KMS("%s: failed to find slot\n", __func__);
return -EAGAIN;
}
if (mstb->tx_slots[0] == NULL && mstb->tx_slots[1] == NULL) {
txmsg->seqno = mstb->last_seqno;
mstb->last_seqno ^= 1;
} else if (mstb->tx_slots[0] == NULL)
txmsg->seqno = 0;
else
txmsg->seqno = 1;
mstb->tx_slots[txmsg->seqno] = txmsg;
}
req_type = txmsg->msg[0] & 0x7f;
if (req_type == DP_CONNECTION_STATUS_NOTIFY ||
req_type == DP_RESOURCE_STATUS_NOTIFY)
@ -2709,7 +2688,7 @@ static int set_hdr_from_dst_qlock(struct drm_dp_sideband_msg_hdr *hdr,
hdr->lcr = mstb->lct - 1;
if (mstb->lct > 1)
memcpy(hdr->rad, mstb->rad, mstb->lct / 2);
hdr->seqno = txmsg->seqno;
return 0;
}
/*
@ -2724,15 +2703,15 @@ static int process_single_tx_qlock(struct drm_dp_mst_topology_mgr *mgr,
int len, space, idx, tosend;
int ret;
if (txmsg->state == DRM_DP_SIDEBAND_TX_SENT)
return 0;
memset(&hdr, 0, sizeof(struct drm_dp_sideband_msg_hdr));
if (txmsg->state == DRM_DP_SIDEBAND_TX_QUEUED) {
txmsg->seqno = -1;
if (txmsg->state == DRM_DP_SIDEBAND_TX_QUEUED)
txmsg->state = DRM_DP_SIDEBAND_TX_START_SEND;
}
/* make hdr from dst mst - for replies use seqno
otherwise assign one */
/* make hdr from dst mst */
ret = set_hdr_from_dst_qlock(&hdr, txmsg);
if (ret < 0)
return ret;
@ -2785,40 +2764,17 @@ static void process_single_down_tx_qlock(struct drm_dp_mst_topology_mgr *mgr)
if (list_empty(&mgr->tx_msg_downq))
return;
txmsg = list_first_entry(&mgr->tx_msg_downq, struct drm_dp_sideband_msg_tx, next);
txmsg = list_first_entry(&mgr->tx_msg_downq,
struct drm_dp_sideband_msg_tx, next);
ret = process_single_tx_qlock(mgr, txmsg, false);
if (ret == 1) {
/* txmsg is sent it should be in the slots now */
list_del(&txmsg->next);
} else if (ret) {
if (ret < 0) {
DRM_DEBUG_KMS("failed to send msg in q %d\n", ret);
list_del(&txmsg->next);
if (txmsg->seqno != -1)
txmsg->dst->tx_slots[txmsg->seqno] = NULL;
txmsg->state = DRM_DP_SIDEBAND_TX_TIMEOUT;
wake_up_all(&mgr->tx_waitq);
}
}
/* called holding qlock */
static void process_single_up_tx_qlock(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_sideband_msg_tx *txmsg)
{
int ret;
/* construct a chunk from the first msg in the tx_msg queue */
ret = process_single_tx_qlock(mgr, txmsg, true);
if (ret != 1)
DRM_DEBUG_KMS("failed to send msg in q %d\n", ret);
if (txmsg->seqno != -1) {
WARN_ON((unsigned int)txmsg->seqno >
ARRAY_SIZE(txmsg->dst->tx_slots));
txmsg->dst->tx_slots[txmsg->seqno] = NULL;
}
}
static void drm_dp_queue_down_tx(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_sideband_msg_tx *txmsg)
{
@ -3451,7 +3407,7 @@ static int drm_dp_encode_up_ack_reply(struct drm_dp_sideband_msg_tx *msg, u8 req
static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_branch *mstb,
int req_type, int seqno, bool broadcast)
int req_type, bool broadcast)
{
struct drm_dp_sideband_msg_tx *txmsg;
@ -3460,13 +3416,11 @@ static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr,
return -ENOMEM;
txmsg->dst = mstb;
txmsg->seqno = seqno;
drm_dp_encode_up_ack_reply(txmsg, req_type);
mutex_lock(&mgr->qlock);
process_single_up_tx_qlock(mgr, txmsg);
/* construct a chunk from the first msg in the tx_msg queue */
process_single_tx_qlock(mgr, txmsg, true);
mutex_unlock(&mgr->qlock);
kfree(txmsg);
@ -3691,8 +3645,9 @@ out_fail:
}
EXPORT_SYMBOL(drm_dp_mst_topology_mgr_resume);
static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up,
struct drm_dp_mst_branch **mstb, int *seqno)
static bool
drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up,
struct drm_dp_mst_branch **mstb)
{
int len;
u8 replyblock[32];
@ -3700,13 +3655,13 @@ static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up,
int ret;
u8 hdrlen;
struct drm_dp_sideband_msg_hdr hdr;
struct drm_dp_sideband_msg_rx *msg;
struct drm_dp_sideband_msg_rx *msg =
up ? &mgr->up_req_recv : &mgr->down_rep_recv;
int basereg = up ? DP_SIDEBAND_MSG_UP_REQ_BASE :
DP_SIDEBAND_MSG_DOWN_REP_BASE;
if (!up)
*mstb = NULL;
*seqno = -1;
len = min(mgr->max_dpcd_transaction_bytes, 16);
ret = drm_dp_dpcd_read(mgr->aux, basereg, replyblock, len);
@ -3723,11 +3678,7 @@ static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up,
return false;
}
*seqno = hdr.seqno;
if (up) {
msg = &mgr->up_req_recv;
} else {
if (!up) {
/* Caller is responsible for giving back this reference */
*mstb = drm_dp_get_mst_branch_device(mgr, hdr.lct, hdr.rad);
if (!*mstb) {
@ -3735,7 +3686,6 @@ static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up,
hdr.lct);
return false;
}
msg = &(*mstb)->down_rep_recv[hdr.seqno];
}
if (!drm_dp_sideband_msg_set_header(msg, &hdr, hdrlen)) {
@ -3779,13 +3729,10 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
{
struct drm_dp_sideband_msg_tx *txmsg;
struct drm_dp_mst_branch *mstb = NULL;
struct drm_dp_sideband_msg_rx *msg = NULL;
int seqno = -1;
struct drm_dp_sideband_msg_rx *msg = &mgr->down_rep_recv;
if (!drm_dp_get_one_sb_msg(mgr, false, &mstb, &seqno))
goto out_clear_reply;
msg = &mstb->down_rep_recv[seqno];
if (!drm_dp_get_one_sb_msg(mgr, false, &mstb))
goto out;
/* Multi-packet message transmission, don't clear the reply */
if (!msg->have_eomt)
@ -3793,11 +3740,12 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
/* find the message */
mutex_lock(&mgr->qlock);
txmsg = mstb->tx_slots[seqno];
/* remove from slots */
txmsg = list_first_entry_or_null(&mgr->tx_msg_downq,
struct drm_dp_sideband_msg_tx, next);
mutex_unlock(&mgr->qlock);
if (!txmsg) {
/* Were we actually expecting a response, and from this mstb? */
if (!txmsg || txmsg->dst != mstb) {
struct drm_dp_sideband_msg_hdr *hdr;
hdr = &msg->initial_hdr;
DRM_DEBUG_KMS("Got MST reply with no msg %p %d %d %02x %02x\n",
@ -3822,7 +3770,7 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
mutex_lock(&mgr->qlock);
txmsg->state = DRM_DP_SIDEBAND_TX_RX;
mstb->tx_slots[seqno] = NULL;
list_del(&txmsg->next);
mutex_unlock(&mgr->qlock);
wake_up_all(&mgr->tx_waitq);
@ -3830,8 +3778,7 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
return 0;
out_clear_reply:
if (msg)
memset(msg, 0, sizeof(struct drm_dp_sideband_msg_rx));
memset(msg, 0, sizeof(struct drm_dp_sideband_msg_rx));
out:
if (mstb)
drm_dp_mst_topology_put_mstb(mstb);
@ -3911,9 +3858,8 @@ static void drm_dp_mst_up_req_work(struct work_struct *work)
static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
{
struct drm_dp_pending_up_req *up_req;
int seqno;
if (!drm_dp_get_one_sb_msg(mgr, true, NULL, &seqno))
if (!drm_dp_get_one_sb_msg(mgr, true, NULL))
goto out;
if (!mgr->up_req_recv.have_eomt)
@ -3937,7 +3883,7 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
}
drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, up_req->msg.req_type,
seqno, false);
false);
if (up_req->msg.req_type == DP_CONNECTION_STATUS_NOTIFY) {
const struct drm_dp_connection_status_notify *conn_stat =
@ -4703,26 +4649,25 @@ static inline void
drm_dp_delayed_destroy_mstb(struct drm_dp_mst_branch *mstb)
{
struct drm_dp_mst_topology_mgr *mgr = mstb->mgr;
struct drm_dp_mst_port *port, *tmp;
struct drm_dp_mst_port *port, *port_tmp;
struct drm_dp_sideband_msg_tx *txmsg, *txmsg_tmp;
bool wake_tx = false;
mutex_lock(&mgr->lock);
list_for_each_entry_safe(port, tmp, &mstb->ports, next) {
list_for_each_entry_safe(port, port_tmp, &mstb->ports, next) {
list_del(&port->next);
drm_dp_mst_topology_put_port(port);
}
mutex_unlock(&mgr->lock);
/* drop any tx slots msg */
/* drop any tx slot msg */
mutex_lock(&mstb->mgr->qlock);
if (mstb->tx_slots[0]) {
mstb->tx_slots[0]->state = DRM_DP_SIDEBAND_TX_TIMEOUT;
mstb->tx_slots[0] = NULL;
wake_tx = true;
}
if (mstb->tx_slots[1]) {
mstb->tx_slots[1]->state = DRM_DP_SIDEBAND_TX_TIMEOUT;
mstb->tx_slots[1] = NULL;
list_for_each_entry_safe(txmsg, txmsg_tmp, &mgr->tx_msg_downq, next) {
if (txmsg->dst != mstb)
continue;
txmsg->state = DRM_DP_SIDEBAND_TX_TIMEOUT;
list_del(&txmsg->next);
wake_tx = true;
}
mutex_unlock(&mstb->mgr->qlock);

View File

@ -739,6 +739,29 @@ int devm_drm_dev_init(struct device *parent,
}
EXPORT_SYMBOL(devm_drm_dev_init);
void *__devm_drm_dev_alloc(struct device *parent, struct drm_driver *driver,
size_t size, size_t offset)
{
void *container;
struct drm_device *drm;
int ret;
container = kzalloc(size, GFP_KERNEL);
if (!container)
return ERR_PTR(-ENOMEM);
drm = container + offset;
ret = devm_drm_dev_init(parent, drm, driver);
if (ret) {
kfree(container);
return ERR_PTR(ret);
}
drmm_add_final_kfree(drm, container);
return container;
}
EXPORT_SYMBOL(__devm_drm_dev_alloc);
/**
* drm_dev_alloc - Allocate new DRM device
* @driver: DRM driver to allocate device for

View File

@ -2380,6 +2380,14 @@ bad_std_timing(u8 a, u8 b)
(a == 0x20 && b == 0x20);
}
static int drm_mode_hsync(const struct drm_display_mode *mode)
{
if (mode->htotal <= 0)
return 0;
return DIV_ROUND_CLOSEST(mode->clock, mode->htotal);
}
/**
* drm_mode_std - convert standard mode info (width, height, refresh) into mode
* @connector: connector of for the EDID block

View File

@ -613,7 +613,8 @@ put_back_event:
file_priv->event_space -= length;
list_add(&e->link, &file_priv->event_list);
spin_unlock_irq(&dev->event_lock);
wake_up_interruptible(&file_priv->event_wait);
wake_up_interruptible_poll(&file_priv->event_wait,
EPOLLIN | EPOLLRDNORM);
break;
}
@ -809,7 +810,8 @@ void drm_send_event_locked(struct drm_device *dev, struct drm_pending_event *e)
list_del(&e->pending_link);
list_add_tail(&e->link,
&e->file_priv->event_list);
wake_up_interruptible(&e->file_priv->event_wait);
wake_up_interruptible_poll(&e->file_priv->event_wait,
EPOLLIN | EPOLLRDNORM);
}
EXPORT_SYMBOL(drm_send_event_locked);

View File

@ -212,20 +212,6 @@ static void drm_mm_interval_tree_add_node(struct drm_mm_node *hole_node,
&drm_mm_interval_tree_augment);
}
#define RB_INSERT(root, member, expr) do { \
struct rb_node **link = &root.rb_node, *rb = NULL; \
u64 x = expr(node); \
while (*link) { \
rb = *link; \
if (x < expr(rb_entry(rb, struct drm_mm_node, member))) \
link = &rb->rb_left; \
else \
link = &rb->rb_right; \
} \
rb_link_node(&node->member, rb, link); \
rb_insert_color(&node->member, &root); \
} while (0)
#define HOLE_SIZE(NODE) ((NODE)->hole_size)
#define HOLE_ADDR(NODE) (__drm_mm_hole_node_start(NODE))
@ -255,16 +241,42 @@ static void insert_hole_size(struct rb_root_cached *root,
rb_insert_color_cached(&node->rb_hole_size, root, first);
}
RB_DECLARE_CALLBACKS_MAX(static, augment_callbacks,
struct drm_mm_node, rb_hole_addr,
u64, subtree_max_hole, HOLE_SIZE)
static void insert_hole_addr(struct rb_root *root, struct drm_mm_node *node)
{
struct rb_node **link = &root->rb_node, *rb_parent = NULL;
u64 start = HOLE_ADDR(node), subtree_max_hole = node->subtree_max_hole;
struct drm_mm_node *parent;
while (*link) {
rb_parent = *link;
parent = rb_entry(rb_parent, struct drm_mm_node, rb_hole_addr);
if (parent->subtree_max_hole < subtree_max_hole)
parent->subtree_max_hole = subtree_max_hole;
if (start < HOLE_ADDR(parent))
link = &parent->rb_hole_addr.rb_left;
else
link = &parent->rb_hole_addr.rb_right;
}
rb_link_node(&node->rb_hole_addr, rb_parent, link);
rb_insert_augmented(&node->rb_hole_addr, root, &augment_callbacks);
}
static void add_hole(struct drm_mm_node *node)
{
struct drm_mm *mm = node->mm;
node->hole_size =
__drm_mm_hole_node_end(node) - __drm_mm_hole_node_start(node);
node->subtree_max_hole = node->hole_size;
DRM_MM_BUG_ON(!drm_mm_hole_follows(node));
insert_hole_size(&mm->holes_size, node);
RB_INSERT(mm->holes_addr, rb_hole_addr, HOLE_ADDR);
insert_hole_addr(&mm->holes_addr, node);
list_add(&node->hole_stack, &mm->hole_stack);
}
@ -275,8 +287,10 @@ static void rm_hole(struct drm_mm_node *node)
list_del(&node->hole_stack);
rb_erase_cached(&node->rb_hole_size, &node->mm->holes_size);
rb_erase(&node->rb_hole_addr, &node->mm->holes_addr);
rb_erase_augmented(&node->rb_hole_addr, &node->mm->holes_addr,
&augment_callbacks);
node->hole_size = 0;
node->subtree_max_hole = 0;
DRM_MM_BUG_ON(drm_mm_hole_follows(node));
}
@ -361,9 +375,90 @@ first_hole(struct drm_mm *mm,
}
}
/**
* next_hole_high_addr - returns next hole for a DRM_MM_INSERT_HIGH mode request
* @entry: previously selected drm_mm_node
* @size: size of the a hole needed for the request
*
* This function will verify whether left subtree of @entry has hole big enough
* to fit the requtested size. If so, it will return previous node of @entry or
* else it will return parent node of @entry
*
* It will also skip the complete left subtree if subtree_max_hole of that
* subtree is same as the subtree_max_hole of the @entry.
*
* Returns:
* previous node of @entry if left subtree of @entry can serve the request or
* else return parent of @entry
*/
static struct drm_mm_node *
next_hole_high_addr(struct drm_mm_node *entry, u64 size)
{
struct rb_node *rb_node, *left_rb_node, *parent_rb_node;
struct drm_mm_node *left_node;
if (!entry)
return NULL;
rb_node = &entry->rb_hole_addr;
if (rb_node->rb_left) {
left_rb_node = rb_node->rb_left;
parent_rb_node = rb_parent(rb_node);
left_node = rb_entry(left_rb_node,
struct drm_mm_node, rb_hole_addr);
if ((left_node->subtree_max_hole < size ||
entry->size == entry->subtree_max_hole) &&
parent_rb_node && parent_rb_node->rb_left != rb_node)
return rb_hole_addr_to_node(parent_rb_node);
}
return rb_hole_addr_to_node(rb_prev(rb_node));
}
/**
* next_hole_low_addr - returns next hole for a DRM_MM_INSERT_LOW mode request
* @entry: previously selected drm_mm_node
* @size: size of the a hole needed for the request
*
* This function will verify whether right subtree of @entry has hole big enough
* to fit the requtested size. If so, it will return next node of @entry or
* else it will return parent node of @entry
*
* It will also skip the complete right subtree if subtree_max_hole of that
* subtree is same as the subtree_max_hole of the @entry.
*
* Returns:
* next node of @entry if right subtree of @entry can serve the request or
* else return parent of @entry
*/
static struct drm_mm_node *
next_hole_low_addr(struct drm_mm_node *entry, u64 size)
{
struct rb_node *rb_node, *right_rb_node, *parent_rb_node;
struct drm_mm_node *right_node;
if (!entry)
return NULL;
rb_node = &entry->rb_hole_addr;
if (rb_node->rb_right) {
right_rb_node = rb_node->rb_right;
parent_rb_node = rb_parent(rb_node);
right_node = rb_entry(right_rb_node,
struct drm_mm_node, rb_hole_addr);
if ((right_node->subtree_max_hole < size ||
entry->size == entry->subtree_max_hole) &&
parent_rb_node && parent_rb_node->rb_right != rb_node)
return rb_hole_addr_to_node(parent_rb_node);
}
return rb_hole_addr_to_node(rb_next(rb_node));
}
static struct drm_mm_node *
next_hole(struct drm_mm *mm,
struct drm_mm_node *node,
u64 size,
enum drm_mm_insert_mode mode)
{
switch (mode) {
@ -372,10 +467,10 @@ next_hole(struct drm_mm *mm,
return rb_hole_size_to_node(rb_prev(&node->rb_hole_size));
case DRM_MM_INSERT_LOW:
return rb_hole_addr_to_node(rb_next(&node->rb_hole_addr));
return next_hole_low_addr(node, size);
case DRM_MM_INSERT_HIGH:
return rb_hole_addr_to_node(rb_prev(&node->rb_hole_addr));
return next_hole_high_addr(node, size);
case DRM_MM_INSERT_EVICT:
node = list_next_entry(node, hole_stack);
@ -489,7 +584,7 @@ int drm_mm_insert_node_in_range(struct drm_mm * const mm,
remainder_mask = is_power_of_2(alignment) ? alignment - 1 : 0;
for (hole = first_hole(mm, range_start, range_end, size, mode);
hole;
hole = once ? NULL : next_hole(mm, hole, mode)) {
hole = once ? NULL : next_hole(mm, hole, size, mode)) {
u64 hole_start = __drm_mm_hole_node_start(hole);
u64 hole_end = hole_start + hole->hole_size;
u64 adj_start, adj_end;

View File

@ -402,12 +402,13 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
{
struct drm_mode_obj_get_properties *arg = data;
struct drm_mode_object *obj;
struct drm_modeset_acquire_ctx ctx;
int ret = 0;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EOPNOTSUPP;
drm_modeset_lock_all(dev);
DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type);
if (!obj) {
@ -427,7 +428,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
out_unref:
drm_mode_object_put(obj);
out:
drm_modeset_unlock_all(dev);
DRM_MODESET_LOCK_ALL_END(ctx, ret);
return ret;
}
@ -449,12 +450,13 @@ static int set_property_legacy(struct drm_mode_object *obj,
{
struct drm_device *dev = prop->dev;
struct drm_mode_object *ref;
struct drm_modeset_acquire_ctx ctx;
int ret = -EINVAL;
if (!drm_property_change_valid_get(prop, prop_value, &ref))
return -EINVAL;
drm_modeset_lock_all(dev);
DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
switch (obj->type) {
case DRM_MODE_OBJECT_CONNECTOR:
ret = drm_connector_set_obj_prop(obj, prop, prop_value);
@ -468,7 +470,7 @@ static int set_property_legacy(struct drm_mode_object *obj,
break;
}
drm_property_change_valid_put(prop, ref);
drm_modeset_unlock_all(dev);
DRM_MODESET_LOCK_ALL_END(ctx, ret);
return ret;
}

View File

@ -747,32 +747,6 @@ void drm_mode_set_name(struct drm_display_mode *mode)
}
EXPORT_SYMBOL(drm_mode_set_name);
/**
* drm_mode_hsync - get the hsync of a mode
* @mode: mode
*
* Returns:
* @modes's hsync rate in kHz, rounded to the nearest integer. Calculates the
* value first if it is not yet set.
*/
int drm_mode_hsync(const struct drm_display_mode *mode)
{
unsigned int calc_val;
if (mode->hsync)
return mode->hsync;
if (mode->htotal <= 0)
return 0;
calc_val = (mode->clock * 1000) / mode->htotal; /* hsync in Hz */
calc_val += 500; /* round to 1000Hz */
calc_val /= 1000; /* truncate to kHz */
return calc_val;
}
EXPORT_SYMBOL(drm_mode_hsync);
/**
* drm_mode_vrefresh - get the vrefresh of a mode
* @mode: mode

View File

@ -8875,7 +8875,6 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
mode->clock = pipe_config->hw.adjusted_mode.crtc_clock;
mode->hsync = drm_mode_hsync(mode);
mode->vrefresh = drm_mode_vrefresh(mode);
drm_mode_set_name(mode);
}

View File

@ -877,19 +877,11 @@ i915_driver_create(struct pci_dev *pdev, const struct pci_device_id *ent)
(struct intel_device_info *)ent->driver_data;
struct intel_device_info *device_info;
struct drm_i915_private *i915;
int err;
i915 = kzalloc(sizeof(*i915), GFP_KERNEL);
if (!i915)
return ERR_PTR(-ENOMEM);
err = drm_dev_init(&i915->drm, &driver, &pdev->dev);
if (err) {
kfree(i915);
return ERR_PTR(err);
}
drmm_add_final_kfree(&i915->drm, i915);
i915 = devm_drm_dev_alloc(&pdev->dev, &driver,
struct drm_i915_private, drm);
if (IS_ERR(i915))
return i915;
i915->drm.pdev = pdev;
pci_set_drvdata(pdev, i915);
@ -1006,7 +998,6 @@ out_pci_disable:
pci_disable_device(pdev);
out_fini:
i915_probe_error(i915, "Device initialization failed (%d)\n", ret);
drm_dev_put(&i915->drm);
return ret;
}

View File

@ -941,8 +941,6 @@ static void i915_pci_remove(struct pci_dev *pdev)
i915_driver_remove(i915);
pci_set_drvdata(pdev, NULL);
drm_dev_put(&i915->drm);
}
/* is device_id present in comma separated list of ids */

View File

@ -611,24 +611,17 @@ static int ingenic_drm_probe(struct platform_device *pdev)
return -EINVAL;
}
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv = devm_drm_dev_alloc(dev, &ingenic_drm_driver_data,
struct ingenic_drm, drm);
if (IS_ERR(priv))
return PTR_ERR(priv);
priv->soc_info = soc_info;
priv->dev = dev;
drm = &priv->drm;
drm->dev_private = priv;
platform_set_drvdata(pdev, priv);
ret = devm_drm_dev_init(dev, drm, &ingenic_drm_driver_data);
if (ret) {
kfree(priv);
return ret;
}
drmm_add_final_kfree(drm, priv);
ret = drmm_mode_config_init(drm);
if (ret)
return ret;

View File

@ -26,18 +26,33 @@ void lima_bcast_enable(struct lima_device *dev, int num_pp)
bcast_write(LIMA_BCAST_BROADCAST_MASK, mask);
}
static int lima_bcast_hw_init(struct lima_ip *ip)
{
bcast_write(LIMA_BCAST_BROADCAST_MASK, ip->data.mask << 16);
bcast_write(LIMA_BCAST_INTERRUPT_MASK, ip->data.mask);
return 0;
}
int lima_bcast_resume(struct lima_ip *ip)
{
return lima_bcast_hw_init(ip);
}
void lima_bcast_suspend(struct lima_ip *ip)
{
}
int lima_bcast_init(struct lima_ip *ip)
{
int i, mask = 0;
int i;
for (i = lima_ip_pp0; i <= lima_ip_pp7; i++) {
if (ip->dev->ip[i].present)
mask |= 1 << (i - lima_ip_pp0);
ip->data.mask |= 1 << (i - lima_ip_pp0);
}
bcast_write(LIMA_BCAST_BROADCAST_MASK, mask << 16);
bcast_write(LIMA_BCAST_INTERRUPT_MASK, mask);
return 0;
return lima_bcast_hw_init(ip);
}
void lima_bcast_fini(struct lima_ip *ip)

View File

@ -6,6 +6,8 @@
struct lima_ip;
int lima_bcast_resume(struct lima_ip *ip);
void lima_bcast_suspend(struct lima_ip *ip);
int lima_bcast_init(struct lima_ip *ip);
void lima_bcast_fini(struct lima_ip *ip);

View File

@ -101,13 +101,12 @@ void lima_devfreq_fini(struct lima_device *ldev)
}
if (devfreq->devfreq) {
devm_devfreq_remove_device(&ldev->pdev->dev,
devfreq->devfreq);
devm_devfreq_remove_device(ldev->dev, devfreq->devfreq);
devfreq->devfreq = NULL;
}
if (devfreq->opp_of_table_added) {
dev_pm_opp_of_remove_table(&ldev->pdev->dev);
dev_pm_opp_of_remove_table(ldev->dev);
devfreq->opp_of_table_added = false;
}
@ -125,7 +124,7 @@ void lima_devfreq_fini(struct lima_device *ldev)
int lima_devfreq_init(struct lima_device *ldev)
{
struct thermal_cooling_device *cooling;
struct device *dev = &ldev->pdev->dev;
struct device *dev = ldev->dev;
struct opp_table *opp_table;
struct devfreq *devfreq;
struct lima_devfreq *ldevfreq = &ldev->devfreq;
@ -232,3 +231,27 @@ void lima_devfreq_record_idle(struct lima_devfreq *devfreq)
spin_unlock_irqrestore(&devfreq->lock, irqflags);
}
int lima_devfreq_resume(struct lima_devfreq *devfreq)
{
unsigned long irqflags;
if (!devfreq->devfreq)
return 0;
spin_lock_irqsave(&devfreq->lock, irqflags);
lima_devfreq_reset(devfreq);
spin_unlock_irqrestore(&devfreq->lock, irqflags);
return devfreq_resume_device(devfreq->devfreq);
}
int lima_devfreq_suspend(struct lima_devfreq *devfreq)
{
if (!devfreq->devfreq)
return 0;
return devfreq_suspend_device(devfreq->devfreq);
}

View File

@ -38,4 +38,7 @@ void lima_devfreq_fini(struct lima_device *ldev);
void lima_devfreq_record_busy(struct lima_devfreq *devfreq);
void lima_devfreq_record_idle(struct lima_devfreq *devfreq);
int lima_devfreq_resume(struct lima_devfreq *devfreq);
int lima_devfreq_suspend(struct lima_devfreq *devfreq);
#endif

View File

@ -25,6 +25,8 @@ struct lima_ip_desc {
int (*init)(struct lima_ip *ip);
void (*fini)(struct lima_ip *ip);
int (*resume)(struct lima_ip *ip);
void (*suspend)(struct lima_ip *ip);
};
#define LIMA_IP_DESC(ipname, mst0, mst1, off0, off1, func, irq) \
@ -41,6 +43,8 @@ struct lima_ip_desc {
}, \
.init = lima_##func##_init, \
.fini = lima_##func##_fini, \
.resume = lima_##func##_resume, \
.suspend = lima_##func##_suspend, \
}
static struct lima_ip_desc lima_ip_desc[lima_ip_num] = {
@ -77,26 +81,10 @@ const char *lima_ip_name(struct lima_ip *ip)
return lima_ip_desc[ip->id].name;
}
static int lima_clk_init(struct lima_device *dev)
static int lima_clk_enable(struct lima_device *dev)
{
int err;
dev->clk_bus = devm_clk_get(dev->dev, "bus");
if (IS_ERR(dev->clk_bus)) {
err = PTR_ERR(dev->clk_bus);
if (err != -EPROBE_DEFER)
dev_err(dev->dev, "get bus clk failed %d\n", err);
return err;
}
dev->clk_gpu = devm_clk_get(dev->dev, "core");
if (IS_ERR(dev->clk_gpu)) {
err = PTR_ERR(dev->clk_gpu);
if (err != -EPROBE_DEFER)
dev_err(dev->dev, "get core clk failed %d\n", err);
return err;
}
err = clk_prepare_enable(dev->clk_bus);
if (err)
return err;
@ -105,15 +93,7 @@ static int lima_clk_init(struct lima_device *dev)
if (err)
goto error_out0;
dev->reset = devm_reset_control_array_get_optional_shared(dev->dev);
if (IS_ERR(dev->reset)) {
err = PTR_ERR(dev->reset);
if (err != -EPROBE_DEFER)
dev_err(dev->dev, "get reset controller failed %d\n",
err);
goto error_out1;
} else if (dev->reset != NULL) {
if (dev->reset) {
err = reset_control_deassert(dev->reset);
if (err) {
dev_err(dev->dev,
@ -131,14 +111,76 @@ error_out0:
return err;
}
static void lima_clk_fini(struct lima_device *dev)
static void lima_clk_disable(struct lima_device *dev)
{
if (dev->reset != NULL)
if (dev->reset)
reset_control_assert(dev->reset);
clk_disable_unprepare(dev->clk_gpu);
clk_disable_unprepare(dev->clk_bus);
}
static int lima_clk_init(struct lima_device *dev)
{
int err;
dev->clk_bus = devm_clk_get(dev->dev, "bus");
if (IS_ERR(dev->clk_bus)) {
err = PTR_ERR(dev->clk_bus);
if (err != -EPROBE_DEFER)
dev_err(dev->dev, "get bus clk failed %d\n", err);
dev->clk_bus = NULL;
return err;
}
dev->clk_gpu = devm_clk_get(dev->dev, "core");
if (IS_ERR(dev->clk_gpu)) {
err = PTR_ERR(dev->clk_gpu);
if (err != -EPROBE_DEFER)
dev_err(dev->dev, "get core clk failed %d\n", err);
dev->clk_gpu = NULL;
return err;
}
dev->reset = devm_reset_control_array_get_optional_shared(dev->dev);
if (IS_ERR(dev->reset)) {
err = PTR_ERR(dev->reset);
if (err != -EPROBE_DEFER)
dev_err(dev->dev, "get reset controller failed %d\n",
err);
dev->reset = NULL;
return err;
}
return lima_clk_enable(dev);
}
static void lima_clk_fini(struct lima_device *dev)
{
lima_clk_disable(dev);
}
static int lima_regulator_enable(struct lima_device *dev)
{
int ret;
if (!dev->regulator)
return 0;
ret = regulator_enable(dev->regulator);
if (ret < 0) {
dev_err(dev->dev, "failed to enable regulator: %d\n", ret);
return ret;
}
return 0;
}
static void lima_regulator_disable(struct lima_device *dev)
{
if (dev->regulator)
regulator_disable(dev->regulator);
}
static int lima_regulator_init(struct lima_device *dev)
{
int ret;
@ -154,25 +196,20 @@ static int lima_regulator_init(struct lima_device *dev)
return ret;
}
ret = regulator_enable(dev->regulator);
if (ret < 0) {
dev_err(dev->dev, "failed to enable regulator: %d\n", ret);
return ret;
}
return 0;
return lima_regulator_enable(dev);
}
static void lima_regulator_fini(struct lima_device *dev)
{
if (dev->regulator)
regulator_disable(dev->regulator);
lima_regulator_disable(dev);
}
static int lima_init_ip(struct lima_device *dev, int index)
{
struct platform_device *pdev = to_platform_device(dev->dev);
struct lima_ip_desc *desc = lima_ip_desc + index;
struct lima_ip *ip = dev->ip + index;
const char *irq_name = desc->irq_name;
int offset = desc->offset[dev->id];
bool must = desc->must_have[dev->id];
int err;
@ -183,8 +220,9 @@ static int lima_init_ip(struct lima_device *dev, int index)
ip->dev = dev;
ip->id = index;
ip->iomem = dev->iomem + offset;
if (desc->irq_name) {
err = platform_get_irq_byname(dev->pdev, desc->irq_name);
if (irq_name) {
err = must ? platform_get_irq_byname(pdev, irq_name) :
platform_get_irq_byname_optional(pdev, irq_name);
if (err < 0)
goto out;
ip->irq = err;
@ -209,6 +247,27 @@ static void lima_fini_ip(struct lima_device *ldev, int index)
desc->fini(ip);
}
static int lima_resume_ip(struct lima_device *ldev, int index)
{
struct lima_ip_desc *desc = lima_ip_desc + index;
struct lima_ip *ip = ldev->ip + index;
int ret = 0;
if (ip->present)
ret = desc->resume(ip);
return ret;
}
static void lima_suspend_ip(struct lima_device *ldev, int index)
{
struct lima_ip_desc *desc = lima_ip_desc + index;
struct lima_ip *ip = ldev->ip + index;
if (ip->present)
desc->suspend(ip);
}
static int lima_init_gp_pipe(struct lima_device *dev)
{
struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp;
@ -294,8 +353,8 @@ static void lima_fini_pp_pipe(struct lima_device *dev)
int lima_device_init(struct lima_device *ldev)
{
struct platform_device *pdev = to_platform_device(ldev->dev);
int err, i;
struct resource *res;
dma_set_coherent_mask(ldev->dev, DMA_BIT_MASK(32));
@ -326,8 +385,7 @@ int lima_device_init(struct lima_device *ldev)
} else
ldev->va_end = LIMA_VA_RESERVE_END;
res = platform_get_resource(ldev->pdev, IORESOURCE_MEM, 0);
ldev->iomem = devm_ioremap_resource(ldev->dev, res);
ldev->iomem = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ldev->iomem)) {
dev_err(ldev->dev, "fail to ioremap iomem\n");
err = PTR_ERR(ldev->iomem);
@ -404,3 +462,72 @@ void lima_device_fini(struct lima_device *ldev)
lima_clk_fini(ldev);
}
int lima_device_resume(struct device *dev)
{
struct lima_device *ldev = dev_get_drvdata(dev);
int i, err;
err = lima_clk_enable(ldev);
if (err) {
dev_err(dev, "resume clk fail %d\n", err);
return err;
}
err = lima_regulator_enable(ldev);
if (err) {
dev_err(dev, "resume regulator fail %d\n", err);
goto err_out0;
}
for (i = 0; i < lima_ip_num; i++) {
err = lima_resume_ip(ldev, i);
if (err) {
dev_err(dev, "resume ip %d fail\n", i);
goto err_out1;
}
}
err = lima_devfreq_resume(&ldev->devfreq);
if (err) {
dev_err(dev, "devfreq resume fail\n");
goto err_out1;
}
return 0;
err_out1:
while (--i >= 0)
lima_suspend_ip(ldev, i);
lima_regulator_disable(ldev);
err_out0:
lima_clk_disable(ldev);
return err;
}
int lima_device_suspend(struct device *dev)
{
struct lima_device *ldev = dev_get_drvdata(dev);
int i, err;
/* check any task running */
for (i = 0; i < lima_pipe_num; i++) {
if (atomic_read(&ldev->pipe[i].base.hw_rq_count))
return -EBUSY;
}
err = lima_devfreq_suspend(&ldev->devfreq);
if (err) {
dev_err(dev, "devfreq suspend fail\n");
return err;
}
for (i = lima_ip_num - 1; i >= 0; i--)
lima_suspend_ip(ldev, i);
lima_regulator_disable(ldev);
lima_clk_disable(ldev);
return 0;
}

View File

@ -64,6 +64,8 @@ struct lima_ip {
bool async_reset;
/* l2 cache */
spinlock_t lock;
/* pmu/bcast */
u32 mask;
} data;
};
@ -76,7 +78,6 @@ enum lima_pipe_id {
struct lima_device {
struct device *dev;
struct drm_device *ddev;
struct platform_device *pdev;
enum lima_gpu_id id;
u32 gp_version;
@ -139,4 +140,7 @@ static inline int lima_poll_timeout(struct lima_ip *ip, lima_poll_func_t func,
return 0;
}
int lima_device_suspend(struct device *dev);
int lima_device_resume(struct device *dev);
#endif

View File

@ -42,7 +42,7 @@ void lima_dlbu_set_reg(struct lima_ip *ip, u32 *reg)
dlbu_write(LIMA_DLBU_START_TILE_POS, reg[3]);
}
int lima_dlbu_init(struct lima_ip *ip)
static int lima_dlbu_hw_init(struct lima_ip *ip)
{
struct lima_device *dev = ip->dev;
@ -52,6 +52,21 @@ int lima_dlbu_init(struct lima_ip *ip)
return 0;
}
int lima_dlbu_resume(struct lima_ip *ip)
{
return lima_dlbu_hw_init(ip);
}
void lima_dlbu_suspend(struct lima_ip *ip)
{
}
int lima_dlbu_init(struct lima_ip *ip)
{
return lima_dlbu_hw_init(ip);
}
void lima_dlbu_fini(struct lima_ip *ip)
{

View File

@ -12,6 +12,8 @@ void lima_dlbu_disable(struct lima_device *dev);
void lima_dlbu_set_reg(struct lima_ip *ip, u32 *reg);
int lima_dlbu_resume(struct lima_ip *ip);
void lima_dlbu_suspend(struct lima_ip *ip);
int lima_dlbu_init(struct lima_ip *ip);
void lima_dlbu_fini(struct lima_ip *ip);

View File

@ -5,6 +5,7 @@
#include <linux/of_platform.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_drv.h>
#include <drm/drm_prime.h>
@ -380,7 +381,6 @@ static int lima_pdev_probe(struct platform_device *pdev)
goto err_out0;
}
ldev->pdev = pdev;
ldev->dev = &pdev->dev;
ldev->id = (enum lima_gpu_id)of_device_get_match_data(&pdev->dev);
@ -404,6 +404,12 @@ static int lima_pdev_probe(struct platform_device *pdev)
goto err_out2;
}
pm_runtime_set_active(ldev->dev);
pm_runtime_mark_last_busy(ldev->dev);
pm_runtime_set_autosuspend_delay(ldev->dev, 200);
pm_runtime_use_autosuspend(ldev->dev);
pm_runtime_enable(ldev->dev);
/*
* Register the DRM device with the core and the connectors with
* sysfs.
@ -412,17 +418,16 @@ static int lima_pdev_probe(struct platform_device *pdev)
if (err < 0)
goto err_out3;
platform_set_drvdata(pdev, ldev);
if (sysfs_create_bin_file(&ldev->dev->kobj, &lima_error_state_attr))
dev_warn(ldev->dev, "fail to create error state sysfs\n");
return 0;
err_out3:
lima_device_fini(ldev);
err_out2:
pm_runtime_disable(ldev->dev);
lima_devfreq_fini(ldev);
err_out2:
lima_device_fini(ldev);
err_out1:
drm_dev_put(ddev);
err_out0:
@ -436,10 +441,16 @@ static int lima_pdev_remove(struct platform_device *pdev)
struct drm_device *ddev = ldev->ddev;
sysfs_remove_bin_file(&ldev->dev->kobj, &lima_error_state_attr);
platform_set_drvdata(pdev, NULL);
drm_dev_unregister(ddev);
/* stop autosuspend to make sure device is in active state */
pm_runtime_set_autosuspend_delay(ldev->dev, -1);
pm_runtime_disable(ldev->dev);
lima_devfreq_fini(ldev);
lima_device_fini(ldev);
drm_dev_put(ddev);
lima_sched_slab_fini();
return 0;
@ -452,26 +463,22 @@ static const struct of_device_id dt_match[] = {
};
MODULE_DEVICE_TABLE(of, dt_match);
static const struct dev_pm_ops lima_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(lima_device_suspend, lima_device_resume, NULL)
};
static struct platform_driver lima_platform_driver = {
.probe = lima_pdev_probe,
.remove = lima_pdev_remove,
.driver = {
.name = "lima",
.pm = &lima_pm_ops,
.of_match_table = dt_match,
},
};
static int __init lima_init(void)
{
return platform_driver_register(&lima_platform_driver);
}
module_init(lima_init);
static void __exit lima_exit(void)
{
platform_driver_unregister(&lima_platform_driver);
}
module_exit(lima_exit);
module_platform_driver(lima_platform_driver);
MODULE_AUTHOR("Lima Project Developers");
MODULE_DESCRIPTION("Lima DRM Driver");

View File

@ -274,6 +274,23 @@ static void lima_gp_print_version(struct lima_ip *ip)
static struct kmem_cache *lima_gp_task_slab;
static int lima_gp_task_slab_refcnt;
static int lima_gp_hw_init(struct lima_ip *ip)
{
ip->data.async_reset = false;
lima_gp_soft_reset_async(ip);
return lima_gp_soft_reset_async_wait(ip);
}
int lima_gp_resume(struct lima_ip *ip)
{
return lima_gp_hw_init(ip);
}
void lima_gp_suspend(struct lima_ip *ip)
{
}
int lima_gp_init(struct lima_ip *ip)
{
struct lima_device *dev = ip->dev;
@ -281,9 +298,7 @@ int lima_gp_init(struct lima_ip *ip)
lima_gp_print_version(ip);
ip->data.async_reset = false;
lima_gp_soft_reset_async(ip);
err = lima_gp_soft_reset_async_wait(ip);
err = lima_gp_hw_init(ip);
if (err)
return err;

View File

@ -7,6 +7,8 @@
struct lima_ip;
struct lima_device;
int lima_gp_resume(struct lima_ip *ip);
void lima_gp_suspend(struct lima_ip *ip);
int lima_gp_init(struct lima_ip *ip);
void lima_gp_fini(struct lima_ip *ip);

View File

@ -38,9 +38,35 @@ int lima_l2_cache_flush(struct lima_ip *ip)
return ret;
}
static int lima_l2_cache_hw_init(struct lima_ip *ip)
{
int err;
err = lima_l2_cache_flush(ip);
if (err)
return err;
l2_cache_write(LIMA_L2_CACHE_ENABLE,
LIMA_L2_CACHE_ENABLE_ACCESS |
LIMA_L2_CACHE_ENABLE_READ_ALLOCATE);
l2_cache_write(LIMA_L2_CACHE_MAX_READS, 0x1c);
return 0;
}
int lima_l2_cache_resume(struct lima_ip *ip)
{
return lima_l2_cache_hw_init(ip);
}
void lima_l2_cache_suspend(struct lima_ip *ip)
{
}
int lima_l2_cache_init(struct lima_ip *ip)
{
int i, err;
int i;
u32 size;
struct lima_device *dev = ip->dev;
@ -63,15 +89,7 @@ int lima_l2_cache_init(struct lima_ip *ip)
1 << (size & 0xff),
1 << ((size >> 24) & 0xff));
err = lima_l2_cache_flush(ip);
if (err)
return err;
l2_cache_write(LIMA_L2_CACHE_ENABLE,
LIMA_L2_CACHE_ENABLE_ACCESS|LIMA_L2_CACHE_ENABLE_READ_ALLOCATE);
l2_cache_write(LIMA_L2_CACHE_MAX_READS, 0x1c);
return 0;
return lima_l2_cache_hw_init(ip);
}
void lima_l2_cache_fini(struct lima_ip *ip)

View File

@ -6,6 +6,8 @@
struct lima_ip;
int lima_l2_cache_resume(struct lima_ip *ip);
void lima_l2_cache_suspend(struct lima_ip *ip);
int lima_l2_cache_init(struct lima_ip *ip);
void lima_l2_cache_fini(struct lima_ip *ip);

View File

@ -59,12 +59,44 @@ static irqreturn_t lima_mmu_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
int lima_mmu_init(struct lima_ip *ip)
static int lima_mmu_hw_init(struct lima_ip *ip)
{
struct lima_device *dev = ip->dev;
int err;
u32 v;
mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_HARD_RESET);
err = lima_mmu_send_command(LIMA_MMU_COMMAND_HARD_RESET,
LIMA_MMU_DTE_ADDR, v, v == 0);
if (err)
return err;
mmu_write(LIMA_MMU_INT_MASK,
LIMA_MMU_INT_PAGE_FAULT | LIMA_MMU_INT_READ_BUS_ERROR);
mmu_write(LIMA_MMU_DTE_ADDR, dev->empty_vm->pd.dma);
return lima_mmu_send_command(LIMA_MMU_COMMAND_ENABLE_PAGING,
LIMA_MMU_STATUS, v,
v & LIMA_MMU_STATUS_PAGING_ENABLED);
}
int lima_mmu_resume(struct lima_ip *ip)
{
if (ip->id == lima_ip_ppmmu_bcast)
return 0;
return lima_mmu_hw_init(ip);
}
void lima_mmu_suspend(struct lima_ip *ip)
{
}
int lima_mmu_init(struct lima_ip *ip)
{
struct lima_device *dev = ip->dev;
int err;
if (ip->id == lima_ip_ppmmu_bcast)
return 0;
@ -74,12 +106,6 @@ int lima_mmu_init(struct lima_ip *ip)
return -EIO;
}
mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_HARD_RESET);
err = lima_mmu_send_command(LIMA_MMU_COMMAND_HARD_RESET,
LIMA_MMU_DTE_ADDR, v, v == 0);
if (err)
return err;
err = devm_request_irq(dev->dev, ip->irq, lima_mmu_irq_handler,
IRQF_SHARED, lima_ip_name(ip), ip);
if (err) {
@ -87,11 +113,7 @@ int lima_mmu_init(struct lima_ip *ip)
return err;
}
mmu_write(LIMA_MMU_INT_MASK, LIMA_MMU_INT_PAGE_FAULT | LIMA_MMU_INT_READ_BUS_ERROR);
mmu_write(LIMA_MMU_DTE_ADDR, dev->empty_vm->pd.dma);
return lima_mmu_send_command(LIMA_MMU_COMMAND_ENABLE_PAGING,
LIMA_MMU_STATUS, v,
v & LIMA_MMU_STATUS_PAGING_ENABLED);
return lima_mmu_hw_init(ip);
}
void lima_mmu_fini(struct lima_ip *ip)
@ -113,8 +135,7 @@ void lima_mmu_switch_vm(struct lima_ip *ip, struct lima_vm *vm)
LIMA_MMU_STATUS, v,
v & LIMA_MMU_STATUS_STALL_ACTIVE);
if (vm)
mmu_write(LIMA_MMU_DTE_ADDR, vm->pd.dma);
mmu_write(LIMA_MMU_DTE_ADDR, vm->pd.dma);
/* flush the TLB */
mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_ZAP_CACHE);

View File

@ -7,6 +7,8 @@
struct lima_ip;
struct lima_vm;
int lima_mmu_resume(struct lima_ip *ip);
void lima_mmu_suspend(struct lima_ip *ip);
int lima_mmu_init(struct lima_ip *ip);
void lima_mmu_fini(struct lima_ip *ip);

View File

@ -21,7 +21,7 @@ static int lima_pmu_wait_cmd(struct lima_ip *ip)
v, v & LIMA_PMU_INT_CMD_MASK,
100, 100000);
if (err) {
dev_err(dev->dev, "timeout wait pmd cmd\n");
dev_err(dev->dev, "timeout wait pmu cmd\n");
return err;
}
@ -29,7 +29,41 @@ static int lima_pmu_wait_cmd(struct lima_ip *ip)
return 0;
}
int lima_pmu_init(struct lima_ip *ip)
static u32 lima_pmu_get_ip_mask(struct lima_ip *ip)
{
struct lima_device *dev = ip->dev;
u32 ret = 0;
int i;
ret |= LIMA_PMU_POWER_GP0_MASK;
if (dev->id == lima_gpu_mali400) {
ret |= LIMA_PMU_POWER_L2_MASK;
for (i = 0; i < 4; i++) {
if (dev->ip[lima_ip_pp0 + i].present)
ret |= LIMA_PMU_POWER_PP_MASK(i);
}
} else {
if (dev->ip[lima_ip_pp0].present)
ret |= LIMA450_PMU_POWER_PP0_MASK;
for (i = lima_ip_pp1; i <= lima_ip_pp3; i++) {
if (dev->ip[i].present) {
ret |= LIMA450_PMU_POWER_PP13_MASK;
break;
}
}
for (i = lima_ip_pp4; i <= lima_ip_pp7; i++) {
if (dev->ip[i].present) {
ret |= LIMA450_PMU_POWER_PP47_MASK;
break;
}
}
}
return ret;
}
static int lima_pmu_hw_init(struct lima_ip *ip)
{
int err;
u32 stat;
@ -54,7 +88,44 @@ int lima_pmu_init(struct lima_ip *ip)
return 0;
}
static void lima_pmu_hw_fini(struct lima_ip *ip)
{
u32 stat;
if (!ip->data.mask)
ip->data.mask = lima_pmu_get_ip_mask(ip);
stat = ~pmu_read(LIMA_PMU_STATUS) & ip->data.mask;
if (stat) {
pmu_write(LIMA_PMU_POWER_DOWN, stat);
/* Don't wait for interrupt on Mali400 if all domains are
* powered off because the HW won't generate an interrupt
* in this case.
*/
if (ip->dev->id == lima_gpu_mali400)
pmu_write(LIMA_PMU_INT_CLEAR, LIMA_PMU_INT_CMD_MASK);
else
lima_pmu_wait_cmd(ip);
}
}
int lima_pmu_resume(struct lima_ip *ip)
{
return lima_pmu_hw_init(ip);
}
void lima_pmu_suspend(struct lima_ip *ip)
{
lima_pmu_hw_fini(ip);
}
int lima_pmu_init(struct lima_ip *ip)
{
return lima_pmu_hw_init(ip);
}
void lima_pmu_fini(struct lima_ip *ip)
{
lima_pmu_hw_fini(ip);
}

View File

@ -6,6 +6,8 @@
struct lima_ip;
int lima_pmu_resume(struct lima_ip *ip);
void lima_pmu_suspend(struct lima_ip *ip);
int lima_pmu_init(struct lima_ip *ip);
void lima_pmu_fini(struct lima_ip *ip);

View File

@ -223,6 +223,23 @@ static void lima_pp_print_version(struct lima_ip *ip)
lima_ip_name(ip), name, major, minor);
}
static int lima_pp_hw_init(struct lima_ip *ip)
{
ip->data.async_reset = false;
lima_pp_soft_reset_async(ip);
return lima_pp_soft_reset_async_wait(ip);
}
int lima_pp_resume(struct lima_ip *ip)
{
return lima_pp_hw_init(ip);
}
void lima_pp_suspend(struct lima_ip *ip)
{
}
int lima_pp_init(struct lima_ip *ip)
{
struct lima_device *dev = ip->dev;
@ -230,9 +247,7 @@ int lima_pp_init(struct lima_ip *ip)
lima_pp_print_version(ip);
ip->data.async_reset = false;
lima_pp_soft_reset_async(ip);
err = lima_pp_soft_reset_async_wait(ip);
err = lima_pp_hw_init(ip);
if (err)
return err;
@ -254,6 +269,16 @@ void lima_pp_fini(struct lima_ip *ip)
}
int lima_pp_bcast_resume(struct lima_ip *ip)
{
return 0;
}
void lima_pp_bcast_suspend(struct lima_ip *ip)
{
}
int lima_pp_bcast_init(struct lima_ip *ip)
{
struct lima_device *dev = ip->dev;

View File

@ -7,9 +7,13 @@
struct lima_ip;
struct lima_device;
int lima_pp_resume(struct lima_ip *ip);
void lima_pp_suspend(struct lima_ip *ip);
int lima_pp_init(struct lima_ip *ip);
void lima_pp_fini(struct lima_ip *ip);
int lima_pp_bcast_resume(struct lima_ip *ip);
void lima_pp_bcast_suspend(struct lima_ip *ip);
int lima_pp_bcast_init(struct lima_ip *ip);
void lima_pp_bcast_fini(struct lima_ip *ip);

View File

@ -4,6 +4,7 @@
#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/pm_runtime.h>
#include "lima_devfreq.h"
#include "lima_drv.h"
@ -194,14 +195,36 @@ static struct dma_fence *lima_sched_dependency(struct drm_sched_job *job,
return NULL;
}
static int lima_pm_busy(struct lima_device *ldev)
{
int ret;
/* resume GPU if it has been suspended by runtime PM */
ret = pm_runtime_get_sync(ldev->dev);
if (ret < 0)
return ret;
lima_devfreq_record_busy(&ldev->devfreq);
return 0;
}
static void lima_pm_idle(struct lima_device *ldev)
{
lima_devfreq_record_idle(&ldev->devfreq);
/* GPU can do auto runtime suspend */
pm_runtime_mark_last_busy(ldev->dev);
pm_runtime_put_autosuspend(ldev->dev);
}
static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job)
{
struct lima_sched_task *task = to_lima_task(job);
struct lima_sched_pipe *pipe = to_lima_pipe(job->sched);
struct lima_device *ldev = pipe->ldev;
struct lima_fence *fence;
struct dma_fence *ret;
struct lima_vm *vm = NULL, *last_vm = NULL;
int i;
int i, err;
/* after GPU reset */
if (job->s_fence->finished.error < 0)
@ -210,6 +233,13 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job)
fence = lima_fence_create(pipe);
if (!fence)
return NULL;
err = lima_pm_busy(ldev);
if (err < 0) {
dma_fence_put(&fence->base);
return NULL;
}
task->fence = &fence->base;
/* for caller usage of the fence, otherwise irq handler
@ -217,8 +247,6 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job)
*/
ret = dma_fence_get(task->fence);
lima_devfreq_record_busy(&pipe->ldev->devfreq);
pipe->current_task = task;
/* this is needed for MMU to work correctly, otherwise GP/PP
@ -239,22 +267,16 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job)
for (i = 0; i < pipe->num_l2_cache; i++)
lima_l2_cache_flush(pipe->l2_cache[i]);
if (task->vm != pipe->current_vm) {
vm = lima_vm_get(task->vm);
last_vm = pipe->current_vm;
pipe->current_vm = task->vm;
}
lima_vm_put(pipe->current_vm);
pipe->current_vm = lima_vm_get(task->vm);
if (pipe->bcast_mmu)
lima_mmu_switch_vm(pipe->bcast_mmu, vm);
lima_mmu_switch_vm(pipe->bcast_mmu, pipe->current_vm);
else {
for (i = 0; i < pipe->num_mmu; i++)
lima_mmu_switch_vm(pipe->mmu[i], vm);
lima_mmu_switch_vm(pipe->mmu[i], pipe->current_vm);
}
if (last_vm)
lima_vm_put(last_vm);
trace_lima_task_run(task);
pipe->error = false;
@ -285,7 +307,8 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task)
mutex_lock(&dev->error_task_list_lock);
if (dev->dump.num_tasks >= lima_max_error_tasks) {
dev_info(dev->dev, "fail to save task state: error task list is full\n");
dev_info(dev->dev, "fail to save task state from %s pid %d: "
"error task list is full\n", ctx->pname, ctx->pid);
goto out;
}
@ -394,6 +417,7 @@ static void lima_sched_timedout_job(struct drm_sched_job *job)
{
struct lima_sched_pipe *pipe = to_lima_pipe(job->sched);
struct lima_sched_task *task = to_lima_task(job);
struct lima_device *ldev = pipe->ldev;
if (!pipe->error)
DRM_ERROR("lima job timeout\n");
@ -415,13 +439,11 @@ static void lima_sched_timedout_job(struct drm_sched_job *job)
lima_mmu_page_fault_resume(pipe->mmu[i]);
}
if (pipe->current_vm)
lima_vm_put(pipe->current_vm);
lima_vm_put(pipe->current_vm);
pipe->current_vm = NULL;
pipe->current_task = NULL;
lima_devfreq_record_idle(&pipe->ldev->devfreq);
lima_pm_idle(ldev);
drm_sched_resubmit_jobs(&pipe->base);
drm_sched_start(&pipe->base, true);
@ -493,6 +515,7 @@ void lima_sched_pipe_fini(struct lima_sched_pipe *pipe)
void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe)
{
struct lima_sched_task *task = pipe->current_task;
struct lima_device *ldev = pipe->ldev;
if (pipe->error) {
if (task && task->recoverable)
@ -503,6 +526,6 @@ void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe)
pipe->task_fini(pipe);
dma_fence_signal(task->fence);
lima_devfreq_record_idle(&pipe->ldev->devfreq);
lima_pm_idle(ldev);
}
}

View File

@ -54,7 +54,8 @@ static inline struct lima_vm *lima_vm_get(struct lima_vm *vm)
static inline void lima_vm_put(struct lima_vm *vm)
{
kref_put(&vm->refcount, lima_vm_release);
if (vm)
kref_put(&vm->refcount, lima_vm_release);
}
void lima_vm_print(struct lima_vm *vm);

View File

@ -948,7 +948,7 @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe)
{
struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *drm = crtc->dev;
struct mcde *mcde = drm->dev_private;
struct mcde *mcde = to_mcde(drm);
struct drm_pending_vblank_event *event;
drm_crtc_vblank_off(crtc);
@ -1020,7 +1020,7 @@ static void mcde_display_update(struct drm_simple_display_pipe *pipe,
{
struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *drm = crtc->dev;
struct mcde *mcde = drm->dev_private;
struct mcde *mcde = to_mcde(drm);
struct drm_pending_vblank_event *event = crtc->state->event;
struct drm_plane *plane = &pipe->plane;
struct drm_plane_state *pstate = plane->state;
@ -1078,7 +1078,7 @@ static int mcde_display_enable_vblank(struct drm_simple_display_pipe *pipe)
{
struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *drm = crtc->dev;
struct mcde *mcde = drm->dev_private;
struct mcde *mcde = to_mcde(drm);
u32 val;
/* Enable all VBLANK IRQs */
@ -1097,7 +1097,7 @@ static void mcde_display_disable_vblank(struct drm_simple_display_pipe *pipe)
{
struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *drm = crtc->dev;
struct mcde *mcde = drm->dev_private;
struct mcde *mcde = to_mcde(drm);
/* Disable all VBLANK IRQs */
writel(0, mcde->regs + MCDE_IMSCPP);
@ -1117,7 +1117,7 @@ static struct drm_simple_display_pipe_funcs mcde_display_funcs = {
int mcde_display_init(struct drm_device *drm)
{
struct mcde *mcde = drm->dev_private;
struct mcde *mcde = to_mcde(drm);
int ret;
static const u32 formats[] = {
DRM_FORMAT_ARGB8888,

View File

@ -34,6 +34,8 @@ struct mcde {
struct regulator *vana;
};
#define to_mcde(dev) container_of(dev, struct mcde, drm)
bool mcde_dsi_irq(struct mipi_dsi_device *mdsi);
void mcde_dsi_te_request(struct mipi_dsi_device *mdsi);
extern struct platform_driver mcde_dsi_driver;

View File

@ -164,7 +164,7 @@ static irqreturn_t mcde_irq(int irq, void *data)
static int mcde_modeset_init(struct drm_device *drm)
{
struct drm_mode_config *mode_config;
struct mcde *mcde = drm->dev_private;
struct mcde *mcde = to_mcde(drm);
int ret;
if (!mcde->bridge) {
@ -307,24 +307,15 @@ static int mcde_probe(struct platform_device *pdev)
int ret;
int i;
mcde = kzalloc(sizeof(*mcde), GFP_KERNEL);
if (!mcde)
return -ENOMEM;
mcde->dev = dev;
ret = devm_drm_dev_init(dev, &mcde->drm, &mcde_drm_driver);
if (ret) {
kfree(mcde);
return ret;
}
mcde = devm_drm_dev_alloc(dev, &mcde_drm_driver, struct mcde, drm);
if (IS_ERR(mcde))
return PTR_ERR(mcde);
drm = &mcde->drm;
drm->dev_private = mcde;
drmm_add_final_kfree(drm, mcde);
mcde->dev = dev;
platform_set_drvdata(pdev, drm);
/* Enable continuous updates: this is what Linux' framebuffer expects */
mcde->oneshot_mode = false;
drm->dev_private = mcde;
/* First obtain and turn on the main power */
mcde->epod = devm_regulator_get(dev, "epod");
@ -494,7 +485,7 @@ regulator_epod_off:
static int mcde_remove(struct platform_device *pdev)
{
struct drm_device *drm = platform_get_drvdata(pdev);
struct mcde *mcde = drm->dev_private;
struct mcde *mcde = to_mcde(drm);
component_master_del(&pdev->dev, &mcde_drm_comp_ops);
clk_disable_unprepare(mcde->mcde_clk);

View File

@ -1020,7 +1020,7 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
void *data)
{
struct drm_device *drm = data;
struct mcde *mcde = drm->dev_private;
struct mcde *mcde = to_mcde(drm);
struct mcde_dsi *d = dev_get_drvdata(dev);
struct device_node *child;
struct drm_panel *panel = NULL;

View File

@ -11,6 +11,7 @@
#include <linux/component.h>
#include <linux/module.h>
#include <linux/of_graph.h>
#include <linux/sys_soc.h>
#include <linux/platform_device.h>
#include <linux/soc/amlogic/meson-canvas.h>
@ -183,6 +184,24 @@ static void meson_remove_framebuffers(void)
kfree(ap);
}
struct meson_drm_soc_attr {
struct meson_drm_soc_limits limits;
const struct soc_device_attribute *attrs;
};
static const struct meson_drm_soc_attr meson_drm_soc_attrs[] = {
/* S805X/S805Y HDMI PLL won't lock for HDMI PHY freq > 1,65GHz */
{
.limits = {
.max_hdmi_phy_freq = 1650000,
},
.attrs = (const struct soc_device_attribute []) {
{ .soc_id = "GXL (S805*)", },
{ /* sentinel */ },
}
},
};
static int meson_drv_bind_master(struct device *dev, bool has_components)
{
struct platform_device *pdev = to_platform_device(dev);
@ -191,7 +210,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
struct drm_device *drm;
struct resource *res;
void __iomem *regs;
int ret;
int ret, i;
/* Checks if an output connector is available */
if (!meson_vpu_has_available_connectors(dev)) {
@ -281,6 +300,14 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
if (ret)
goto free_drm;
/* Assign limits per soc revision/package */
for (i = 0 ; i < ARRAY_SIZE(meson_drm_soc_attrs) ; ++i) {
if (soc_device_match(meson_drm_soc_attrs[i].attrs)) {
priv->limits = &meson_drm_soc_attrs[i].limits;
break;
}
}
/* Remove early framebuffers (ie. simplefb) */
meson_remove_framebuffers();

View File

@ -30,6 +30,10 @@ struct meson_drm_match_data {
struct meson_afbcd_ops *afbcd_ops;
};
struct meson_drm_soc_limits {
unsigned int max_hdmi_phy_freq;
};
struct meson_drm {
struct device *dev;
enum vpu_compatible compat;
@ -48,6 +52,8 @@ struct meson_drm {
struct drm_plane *primary_plane;
struct drm_plane *overlay_plane;
const struct meson_drm_soc_limits *limits;
/* Components Data */
struct {
bool osd1_enabled;

View File

@ -695,7 +695,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
dev_dbg(connector->dev->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n",
__func__, phy_freq, vclk_freq, venc_freq, hdmi_freq);
return meson_vclk_vic_supported_freq(phy_freq, vclk_freq);
return meson_vclk_vic_supported_freq(priv, phy_freq, vclk_freq);
}
/* Encoder */

View File

@ -223,7 +223,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_16 |
OSD_COLOR_MATRIX_16_RGB565;
break;
};
}
}
switch (fb->format->format) {

View File

@ -725,6 +725,13 @@ meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq)
/* In DMT mode, path after PLL is always /10 */
freq *= 10;
/* Check against soc revision/package limits */
if (priv->limits) {
if (priv->limits->max_hdmi_phy_freq &&
freq > priv->limits->max_hdmi_phy_freq)
return MODE_CLOCK_HIGH;
}
if (meson_hdmi_pll_find_params(priv, freq, &m, &frac, &od))
return MODE_OK;
@ -762,7 +769,7 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
}
enum drm_mode_status
meson_vclk_vic_supported_freq(unsigned int phy_freq,
meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq,
unsigned int vclk_freq)
{
int i;
@ -770,6 +777,13 @@ meson_vclk_vic_supported_freq(unsigned int phy_freq,
DRM_DEBUG_DRIVER("phy_freq = %d vclk_freq = %d\n",
phy_freq, vclk_freq);
/* Check against soc revision/package limits */
if (priv->limits) {
if (priv->limits->max_hdmi_phy_freq &&
phy_freq > priv->limits->max_hdmi_phy_freq)
return MODE_CLOCK_HIGH;
}
for (i = 0 ; params[i].pixel_freq ; ++i) {
DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",
i, params[i].pixel_freq,

View File

@ -25,7 +25,8 @@ enum {
enum drm_mode_status
meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq);
enum drm_mode_status
meson_vclk_vic_supported_freq(unsigned int phy_freq, unsigned int vclk_freq);
meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq,
unsigned int vclk_freq);
void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
unsigned int phy_freq, unsigned int vclk_freq,

View File

@ -3137,33 +3137,12 @@ static void _dispc_mgr_set_lcd_timings(struct dispc_device *dispc,
dispc_write_reg(dispc, DISPC_TIMING_H(channel), timing_h);
dispc_write_reg(dispc, DISPC_TIMING_V(channel), timing_v);
if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
vs = false;
else
vs = true;
if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
hs = false;
else
hs = true;
if (vm->flags & DISPLAY_FLAGS_DE_HIGH)
de = false;
else
de = true;
if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
ipc = false;
else
ipc = true;
/* always use the 'rf' setting */
onoff = true;
if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE)
rf = true;
else
rf = false;
vs = !!(vm->flags & DISPLAY_FLAGS_VSYNC_LOW);
hs = !!(vm->flags & DISPLAY_FLAGS_HSYNC_LOW);
de = !!(vm->flags & DISPLAY_FLAGS_DE_LOW);
ipc = !!(vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE);
onoff = true; /* always use the 'rf' setting */
rf = !!(vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE);
l = FLD_VAL(onoff, 17, 17) |
FLD_VAL(rf, 16, 16) |

View File

@ -208,49 +208,6 @@ static const struct venc_config venc_config_ntsc_trm = {
.gen_ctrl = 0x00F90000,
};
static const struct venc_config venc_config_pal_bdghi = {
.f_control = 0,
.vidout_ctrl = 0,
.sync_ctrl = 0,
.hfltr_ctrl = 0,
.x_color = 0,
.line21 = 0,
.ln_sel = 21,
.htrigger_vtrigger = 0,
.tvdetgp_int_start_stop_x = 0x00140001,
.tvdetgp_int_start_stop_y = 0x00010001,
.gen_ctrl = 0x00FB0000,
.llen = 864-1,
.flens = 625-1,
.cc_carr_wss_carr = 0x2F7625ED,
.c_phase = 0xDF,
.gain_u = 0x111,
.gain_v = 0x181,
.gain_y = 0x140,
.black_level = 0x3e,
.blank_level = 0x3e,
.m_control = 0<<2 | 1<<1,
.bstamp_wss_data = 0x42,
.s_carr = 0x2a098acb,
.l21__wc_ctl = 0<<13 | 0x16<<8 | 0<<0,
.savid__eavid = 0x06A70108,
.flen__fal = 23<<16 | 624<<0,
.lal__phase_reset = 2<<17 | 310<<0,
.hs_int_start_stop_x = 0x00920358,
.hs_ext_start_stop_x = 0x000F035F,
.vs_int_start_x = 0x1a7<<16,
.vs_int_stop_x__vs_int_start_y = 0x000601A7,
.vs_int_stop_y__vs_ext_start_x = 0x01AF0036,
.vs_ext_stop_x__vs_ext_start_y = 0x27101af,
.vs_ext_stop_y = 0x05,
.avid_start_stop_x = 0x03530082,
.avid_start_stop_y = 0x0270002E,
.fid_int_start_x__fid_int_start_y = 0x0005008A,
.fid_int_offset_y__fid_ext_start_x = 0x002E0138,
.fid_ext_start_y__fid_ext_offset_y = 0x01380005,
};
enum venc_videomode {
VENC_MODE_UNKNOWN,
VENC_MODE_PAL,

View File

@ -444,6 +444,14 @@ config DRM_PANEL_TRULY_NT35597_WQXGA
Say Y here if you want to enable support for Truly NT35597 WQXGA Dual DSI
Video Mode panel
config DRM_PANEL_VISIONOX_RM69299
tristate "Visionox RM69299"
depends on OF
depends on DRM_MIPI_DSI
help
Say Y here if you want to enable support for Visionox
RM69299 DSI Video Mode panel.
config DRM_PANEL_XINPENG_XPP055C272
tristate "Xinpeng XPP055C272 panel driver"
depends on OF

View File

@ -47,4 +47,5 @@ obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o
obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o
obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o
obj-$(CONFIG_DRM_PANEL_VISIONOX_RM69299) += panel-visionox-rm69299.o
obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o

View File

@ -697,15 +697,15 @@ static const struct panel_desc auo_b101uan08_3_desc = {
};
static const struct drm_display_mode boe_tv105wum_nw0_default_mode = {
.clock = 159260,
.clock = 159916,
.hdisplay = 1200,
.hsync_start = 1200 + 80,
.hsync_end = 1200 + 80 + 24,
.htotal = 1200 + 80 + 24 + 60,
.vdisplay = 1920,
.vsync_start = 1920 + 10,
.vsync_end = 1920 + 10 + 2,
.vtotal = 1920 + 10 + 2 + 14,
.vsync_start = 1920 + 20,
.vsync_end = 1920 + 20 + 4,
.vtotal = 1920 + 20 + 4 + 10,
.vrefresh = 60,
.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
};

View File

@ -379,7 +379,7 @@ static int ili9322_init(struct drm_panel *panel, struct ili9322 *ili)
"can't set up VCOM amplitude (%d)\n", ret);
return ret;
}
};
}
if (ili->vcom_high != U8_MAX) {
ret = regmap_write(ili->regmap, ILI9322_VCOM_HIGH,
@ -388,7 +388,7 @@ static int ili9322_init(struct drm_panel *panel, struct ili9322 *ili)
dev_err(ili->dev, "can't set up VCOM high (%d)\n", ret);
return ret;
}
};
}
/* Set up gamma correction */
for (i = 0; i < ARRAY_SIZE(ili->gamma); i++) {

View File

@ -836,7 +836,8 @@ static const struct panel_desc auo_g101evn010 = {
.width = 216,
.height = 135,
},
.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
.bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct drm_display_mode auo_g104sn02_mode = {
@ -862,6 +863,31 @@ static const struct panel_desc auo_g104sn02 = {
},
};
static const struct drm_display_mode auo_g121ean01_mode = {
.clock = 66700,
.hdisplay = 1280,
.hsync_start = 1280 + 58,
.hsync_end = 1280 + 58 + 8,
.htotal = 1280 + 58 + 8 + 70,
.vdisplay = 800,
.vsync_start = 800 + 6,
.vsync_end = 800 + 6 + 4,
.vtotal = 800 + 6 + 4 + 10,
.vrefresh = 60,
};
static const struct panel_desc auo_g121ean01 = {
.modes = &auo_g121ean01_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 261,
.height = 163,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct display_timing auo_g133han01_timings = {
.pixelclock = { 134000000, 141200000, 149000000 },
.hactive = { 1920, 1920, 1920 },
@ -892,6 +918,31 @@ static const struct panel_desc auo_g133han01 = {
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct drm_display_mode auo_g156xtn01_mode = {
.clock = 76000,
.hdisplay = 1366,
.hsync_start = 1366 + 33,
.hsync_end = 1366 + 33 + 67,
.htotal = 1560,
.vdisplay = 768,
.vsync_start = 768 + 4,
.vsync_end = 768 + 4 + 4,
.vtotal = 806,
.vrefresh = 60,
};
static const struct panel_desc auo_g156xtn01 = {
.modes = &auo_g156xtn01_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 344,
.height = 194,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct display_timing auo_g185han01_timings = {
.pixelclock = { 120000000, 144000000, 175000000 },
.hactive = { 1920, 1920, 1920 },
@ -922,6 +973,36 @@ static const struct panel_desc auo_g185han01 = {
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct display_timing auo_g190ean01_timings = {
.pixelclock = { 90000000, 108000000, 135000000 },
.hactive = { 1280, 1280, 1280 },
.hfront_porch = { 126, 184, 1266 },
.hback_porch = { 84, 122, 844 },
.hsync_len = { 70, 102, 704 },
.vactive = { 1024, 1024, 1024 },
.vfront_porch = { 4, 26, 76 },
.vback_porch = { 2, 8, 25 },
.vsync_len = { 2, 8, 25 },
};
static const struct panel_desc auo_g190ean01 = {
.timings = &auo_g190ean01_timings,
.num_timings = 1,
.bpc = 8,
.size = {
.width = 376,
.height = 301,
},
.delay = {
.prepare = 50,
.enable = 200,
.disable = 110,
.unprepare = 1000,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct display_timing auo_p320hvn03_timings = {
.pixelclock = { 106000000, 148500000, 164000000 },
.hactive = { 1920, 1920, 1920 },
@ -1092,6 +1173,36 @@ static const struct panel_desc boe_nv101wxmn51 = {
},
};
static const struct drm_display_mode boe_nv133fhm_n61_modes = {
.clock = 147840,
.hdisplay = 1920,
.hsync_start = 1920 + 48,
.hsync_end = 1920 + 48 + 32,
.htotal = 1920 + 48 + 32 + 200,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 6,
.vtotal = 1080 + 3 + 6 + 31,
.vrefresh = 60,
};
static const struct panel_desc boe_nv133fhm_n61 = {
.modes = &boe_nv133fhm_n61_modes,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 300,
.height = 187,
},
.delay = {
.hpd_absent_delay = 200,
.unprepare = 500,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_flags = DRM_BUS_FLAG_DATA_MSB_TO_LSB,
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
static const struct drm_display_mode boe_nv140fhmn49_modes[] = {
{
.clock = 148500,
@ -1980,6 +2091,37 @@ static const struct panel_desc innolux_zj070na_01p = {
},
};
static const struct drm_display_mode ivo_m133nwf4_r0_mode = {
.clock = 138778,
.hdisplay = 1920,
.hsync_start = 1920 + 24,
.hsync_end = 1920 + 24 + 48,
.htotal = 1920 + 24 + 48 + 88,
.vdisplay = 1080,
.vsync_start = 1080 + 3,
.vsync_end = 1080 + 3 + 12,
.vtotal = 1080 + 3 + 12 + 17,
.vrefresh = 60,
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
};
static const struct panel_desc ivo_m133nwf4_r0 = {
.modes = &ivo_m133nwf4_r0_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 294,
.height = 165,
},
.delay = {
.hpd_absent_delay = 200,
.unprepare = 500,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_flags = DRM_BUS_FLAG_DATA_MSB_TO_LSB,
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
static const struct display_timing koe_tx14d24vm1bpa_timing = {
.pixelclock = { 5580000, 5850000, 6200000 },
.hactive = { 320, 320, 320 },
@ -2168,6 +2310,7 @@ static const struct panel_desc lg_lp120up1 = {
.width = 267,
.height = 183,
},
.connector_type = DRM_MODE_CONNECTOR_eDP,
};
static const struct drm_display_mode lg_lp129qe_mode = {
@ -3480,12 +3623,21 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "auo,g104sn02",
.data = &auo_g104sn02,
}, {
.compatible = "auo,g121ean01",
.data = &auo_g121ean01,
}, {
.compatible = "auo,g133han01",
.data = &auo_g133han01,
}, {
.compatible = "auo,g156xtn01",
.data = &auo_g156xtn01,
}, {
.compatible = "auo,g185han01",
.data = &auo_g185han01,
}, {
.compatible = "auo,g190ean01",
.data = &auo_g190ean01,
}, {
.compatible = "auo,p320hvn03",
.data = &auo_p320hvn03,
@ -3504,6 +3656,9 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "boe,nv101wxmn51",
.data = &boe_nv101wxmn51,
}, {
.compatible = "boe,nv133fhm-n61",
.data = &boe_nv133fhm_n61,
}, {
.compatible = "boe,nv140fhmn49",
.data = &boe_nv140fhmn49,
@ -3612,6 +3767,9 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "innolux,zj070na-01p",
.data = &innolux_zj070na_01p,
}, {
.compatible = "ivo,m133nwf4-r0",
.data = &ivo_m133nwf4_r0,
}, {
.compatible = "koe,tx14d24vm1bpa",
.data = &koe_tx14d24vm1bpa,

View File

@ -490,9 +490,7 @@ static int truly_nt35597_panel_add(struct truly_nt35597 *ctx)
{
struct device *dev = ctx->dev;
int ret, i;
const struct nt35597_config *config;
config = ctx->config;
for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++)
ctx->supplies[i].supply = regulator_names[i];

View File

@ -0,0 +1,302 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
struct visionox_rm69299 {
struct drm_panel panel;
struct regulator_bulk_data supplies[2];
struct gpio_desc *reset_gpio;
struct mipi_dsi_device *dsi;
bool prepared;
bool enabled;
};
static inline struct visionox_rm69299 *panel_to_ctx(struct drm_panel *panel)
{
return container_of(panel, struct visionox_rm69299, panel);
}
static int visionox_rm69299_power_on(struct visionox_rm69299 *ctx)
{
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
if (ret < 0)
return ret;
/*
* Reset sequence of visionox panel requires the panel to be
* out of reset for 10ms, followed by being held in reset
* for 10ms and then out again
*/
gpiod_set_value(ctx->reset_gpio, 1);
usleep_range(10000, 20000);
gpiod_set_value(ctx->reset_gpio, 0);
usleep_range(10000, 20000);
gpiod_set_value(ctx->reset_gpio, 1);
usleep_range(10000, 20000);
return 0;
}
static int visionox_rm69299_power_off(struct visionox_rm69299 *ctx)
{
gpiod_set_value(ctx->reset_gpio, 0);
return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
}
static int visionox_rm69299_unprepare(struct drm_panel *panel)
{
struct visionox_rm69299 *ctx = panel_to_ctx(panel);
int ret;
ctx->dsi->mode_flags = 0;
ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0);
if (ret < 0)
DRM_DEV_ERROR(ctx->panel.dev,
"set_display_off cmd failed ret = %d\n", ret);
/* 120ms delay required here as per DCS spec */
msleep(120);
ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0);
if (ret < 0) {
DRM_DEV_ERROR(ctx->panel.dev,
"enter_sleep cmd failed ret = %d\n", ret);
}
ret = visionox_rm69299_power_off(ctx);
ctx->prepared = false;
return ret;
}
static int visionox_rm69299_prepare(struct drm_panel *panel)
{
struct visionox_rm69299 *ctx = panel_to_ctx(panel);
int ret;
if (ctx->prepared)
return 0;
ret = visionox_rm69299_power_on(ctx);
if (ret < 0)
return ret;
ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xfe, 0x00 }, 2);
if (ret < 0) {
DRM_DEV_ERROR(ctx->panel.dev,
"cmd set tx 0 failed, ret = %d\n", ret);
goto power_off;
}
ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xc2, 0x08 }, 2);
if (ret < 0) {
DRM_DEV_ERROR(ctx->panel.dev,
"cmd set tx 1 failed, ret = %d\n", ret);
goto power_off;
}
ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x35, 0x00 }, 2);
if (ret < 0) {
DRM_DEV_ERROR(ctx->panel.dev,
"cmd set tx 2 failed, ret = %d\n", ret);
goto power_off;
}
ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x51, 0xff }, 2);
if (ret < 0) {
DRM_DEV_ERROR(ctx->panel.dev,
"cmd set tx 3 failed, ret = %d\n", ret);
goto power_off;
}
ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0);
if (ret < 0) {
DRM_DEV_ERROR(ctx->panel.dev,
"exit_sleep_mode cmd failed ret = %d\n", ret);
goto power_off;
}
/* Per DSI spec wait 120ms after sending exit sleep DCS command */
msleep(120);
ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);
if (ret < 0) {
DRM_DEV_ERROR(ctx->panel.dev,
"set_display_on cmd failed ret = %d\n", ret);
goto power_off;
}
/* Per DSI spec wait 120ms after sending set_display_on DCS command */
msleep(120);
ctx->prepared = true;
return 0;
power_off:
return ret;
}
static const struct drm_display_mode visionox_rm69299_1080x2248_60hz = {
.name = "1080x2248",
.clock = 158695,
.hdisplay = 1080,
.hsync_start = 1080 + 26,
.hsync_end = 1080 + 26 + 2,
.htotal = 1080 + 26 + 2 + 36,
.vdisplay = 2248,
.vsync_start = 2248 + 56,
.vsync_end = 2248 + 56 + 4,
.vtotal = 2248 + 56 + 4 + 4,
.vrefresh = 60,
.flags = 0,
};
static int visionox_rm69299_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct visionox_rm69299 *ctx = panel_to_ctx(panel);
struct drm_display_mode *mode;
mode = drm_mode_create(connector->dev);
if (!mode) {
DRM_DEV_ERROR(ctx->panel.dev,
"failed to create a new display mode\n");
return 0;
}
connector->display_info.width_mm = 74;
connector->display_info.height_mm = 131;
drm_mode_copy(mode, &visionox_rm69299_1080x2248_60hz);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode);
return 1;
}
static const struct drm_panel_funcs visionox_rm69299_drm_funcs = {
.unprepare = visionox_rm69299_unprepare,
.prepare = visionox_rm69299_prepare,
.get_modes = visionox_rm69299_get_modes,
};
static int visionox_rm69299_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct visionox_rm69299 *ctx;
int ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
mipi_dsi_set_drvdata(dsi, ctx);
ctx->panel.dev = dev;
ctx->dsi = dsi;
ctx->supplies[0].supply = "vdda";
ctx->supplies[1].supply = "vdd3p3";
ret = devm_regulator_bulk_get(ctx->panel.dev, ARRAY_SIZE(ctx->supplies),
ctx->supplies);
if (ret < 0)
return ret;
ctx->reset_gpio = devm_gpiod_get(ctx->panel.dev,
"reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset_gpio)) {
DRM_DEV_ERROR(dev, "cannot get reset gpio %ld\n",
PTR_ERR(ctx->reset_gpio));
return PTR_ERR(ctx->reset_gpio);
}
drm_panel_init(&ctx->panel, dev, &visionox_rm69299_drm_funcs,
DRM_MODE_CONNECTOR_DSI);
ctx->panel.dev = dev;
ctx->panel.funcs = &visionox_rm69299_drm_funcs;
drm_panel_add(&ctx->panel);
dsi->lanes = 4;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM |
MIPI_DSI_CLOCK_NON_CONTINUOUS;
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
DRM_DEV_ERROR(dev, "dsi attach failed ret = %d\n", ret);
goto err_dsi_attach;
}
ret = regulator_set_load(ctx->supplies[0].consumer, 32000);
if (ret) {
DRM_DEV_ERROR(dev,
"regulator set load failed for vdda supply ret = %d\n",
ret);
goto err_set_load;
}
ret = regulator_set_load(ctx->supplies[1].consumer, 13200);
if (ret) {
DRM_DEV_ERROR(dev,
"regulator set load failed for vdd3p3 supply ret = %d\n",
ret);
goto err_set_load;
}
return 0;
err_set_load:
mipi_dsi_detach(dsi);
err_dsi_attach:
drm_panel_remove(&ctx->panel);
return ret;
}
static int visionox_rm69299_remove(struct mipi_dsi_device *dsi)
{
struct visionox_rm69299 *ctx = mipi_dsi_get_drvdata(dsi);
mipi_dsi_detach(ctx->dsi);
mipi_dsi_device_unregister(ctx->dsi);
drm_panel_remove(&ctx->panel);
return 0;
}
static const struct of_device_id visionox_rm69299_of_match[] = {
{ .compatible = "visionox,rm69299-1080p-display", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, visionox_rm69299_of_match);
static struct mipi_dsi_driver visionox_rm69299_driver = {
.driver = {
.name = "panel-visionox-rm69299",
.of_match_table = visionox_rm69299_of_match,
},
.probe = visionox_rm69299_probe,
.remove = visionox_rm69299_remove,
};
module_mipi_dsi_driver(visionox_rm69299_driver);
MODULE_DESCRIPTION("Visionox RM69299 DSI Panel Driver");

View File

@ -3,7 +3,6 @@ pl111_drm-y += pl111_display.o \
pl111_versatile.o \
pl111_drv.o
pl111_drm-$(CONFIG_ARCH_VEXPRESS) += pl111_vexpress.o
pl111_drm-$(CONFIG_ARCH_NOMADIK) += pl111_nomadik.o
pl111_drm-$(CONFIG_DEBUG_FS) += pl111_debugfs.o

View File

@ -444,6 +444,7 @@ static const struct amba_id pl111_id_table[] = {
},
{0, 0},
};
MODULE_DEVICE_TABLE(amba, pl111_id_table);
static struct amba_driver pl111_amba_driver __maybe_unused = {
.drv = {

View File

@ -8,9 +8,9 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <linux/vexpress.h>
#include "pl111_versatile.h"
#include "pl111_vexpress.h"
#include "pl111_drm.h"
static struct regmap *versatile_syscon_map;
@ -361,13 +361,110 @@ static const struct pl111_variant_data pl111_vexpress = {
.broken_clockdivider = true,
};
#define VEXPRESS_FPGAMUX_MOTHERBOARD 0x00
#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_1 0x01
#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_2 0x02
static int pl111_vexpress_clcd_init(struct device *dev, struct device_node *np,
struct pl111_drm_dev_private *priv)
{
struct platform_device *pdev;
struct device_node *root;
struct device_node *child;
struct device_node *ct_clcd = NULL;
struct regmap *map;
bool has_coretile_clcd = false;
bool has_coretile_hdlcd = false;
bool mux_motherboard = true;
u32 val;
int ret;
if (!IS_ENABLED(CONFIG_VEXPRESS_CONFIG))
return -ENODEV;
/*
* Check if we have a CLCD or HDLCD on the core tile by checking if a
* CLCD or HDLCD is available in the root of the device tree.
*/
root = of_find_node_by_path("/");
if (!root)
return -EINVAL;
for_each_available_child_of_node(root, child) {
if (of_device_is_compatible(child, "arm,pl111")) {
has_coretile_clcd = true;
ct_clcd = child;
break;
}
if (of_device_is_compatible(child, "arm,hdlcd")) {
has_coretile_hdlcd = true;
of_node_put(child);
break;
}
}
of_node_put(root);
/*
* If there is a coretile HDLCD and it has a driver,
* do not mux the CLCD on the motherboard to the DVI.
*/
if (has_coretile_hdlcd && IS_ENABLED(CONFIG_DRM_HDLCD))
mux_motherboard = false;
/*
* On the Vexpress CA9 we let the CLCD on the coretile
* take precedence, so also in this case do not mux the
* motherboard to the DVI.
*/
if (has_coretile_clcd)
mux_motherboard = false;
if (mux_motherboard) {
dev_info(dev, "DVI muxed to motherboard CLCD\n");
val = VEXPRESS_FPGAMUX_MOTHERBOARD;
} else if (ct_clcd == dev->of_node) {
dev_info(dev,
"DVI muxed to daughterboard 1 (core tile) CLCD\n");
val = VEXPRESS_FPGAMUX_DAUGHTERBOARD_1;
} else {
dev_info(dev, "core tile graphics present\n");
dev_info(dev, "this device will be deactivated\n");
return -ENODEV;
}
/* Call into deep Vexpress configuration API */
pdev = of_find_device_by_node(np);
if (!pdev) {
dev_err(dev, "can't find the sysreg device, deferring\n");
return -EPROBE_DEFER;
}
map = devm_regmap_init_vexpress_config(&pdev->dev);
if (IS_ERR(map)) {
platform_device_put(pdev);
return PTR_ERR(map);
}
ret = regmap_write(map, 0, val);
platform_device_put(pdev);
if (ret) {
dev_err(dev, "error setting DVI muxmode\n");
return -ENODEV;
}
priv->variant = &pl111_vexpress;
dev_info(dev, "initializing Versatile Express PL111\n");
return 0;
}
int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
{
const struct of_device_id *clcd_id;
enum versatile_clcd versatile_clcd_type;
struct device_node *np;
struct regmap *map;
int ret;
np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match,
&clcd_id);
@ -378,6 +475,15 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
versatile_clcd_type = (enum versatile_clcd)clcd_id->data;
/* Versatile Express special handling */
if (versatile_clcd_type == VEXPRESS_CLCD_V2M) {
int ret = pl111_vexpress_clcd_init(dev, np, priv);
of_node_put(np);
if (ret)
dev_err(dev, "Versatile Express init failed - %d", ret);
return ret;
}
/*
* On the Integrator, check if we should use the IM-PD1 instead,
* if we find it, it will take precedence. This is on the Integrator/AP
@ -390,37 +496,8 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
versatile_clcd_type = (enum versatile_clcd)clcd_id->data;
}
/* Versatile Express special handling */
if (versatile_clcd_type == VEXPRESS_CLCD_V2M) {
struct platform_device *pdev;
/* Registers a driver for the muxfpga */
ret = vexpress_muxfpga_init();
if (ret) {
dev_err(dev, "unable to initialize muxfpga driver\n");
of_node_put(np);
return ret;
}
/* Call into deep Vexpress configuration API */
pdev = of_find_device_by_node(np);
if (!pdev) {
dev_err(dev, "can't find the sysreg device, deferring\n");
of_node_put(np);
return -EPROBE_DEFER;
}
map = dev_get_drvdata(&pdev->dev);
if (!map) {
dev_err(dev, "sysreg has not yet probed\n");
platform_device_put(pdev);
of_node_put(np);
return -EPROBE_DEFER;
}
} else {
map = syscon_node_to_regmap(np);
}
map = syscon_node_to_regmap(np);
of_node_put(np);
if (IS_ERR(map)) {
dev_err(dev, "no Versatile syscon regmap\n");
return PTR_ERR(map);
@ -466,13 +543,6 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
priv->variant_display_disable = pl111_realview_clcd_disable;
dev_info(dev, "set up callbacks for RealView PL111\n");
break;
case VEXPRESS_CLCD_V2M:
priv->variant = &pl111_vexpress;
dev_info(dev, "initializing Versatile Express PL111\n");
ret = pl111_vexpress_clcd_init(dev, priv, map);
if (ret)
return ret;
break;
default:
dev_info(dev, "unknown Versatile system controller\n");
break;

View File

@ -1,138 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Versatile Express PL111 handling
* Copyright (C) 2018 Linus Walleij
*
* This module binds to the "arm,vexpress-muxfpga" device on the
* Versatile Express configuration bus and sets up which CLCD instance
* gets muxed out on the DVI bridge.
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/vexpress.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include "pl111_drm.h"
#include "pl111_vexpress.h"
#define VEXPRESS_FPGAMUX_MOTHERBOARD 0x00
#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_1 0x01
#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_2 0x02
int pl111_vexpress_clcd_init(struct device *dev,
struct pl111_drm_dev_private *priv,
struct regmap *map)
{
struct device_node *root;
struct device_node *child;
struct device_node *ct_clcd = NULL;
bool has_coretile_clcd = false;
bool has_coretile_hdlcd = false;
bool mux_motherboard = true;
u32 val;
int ret;
/*
* Check if we have a CLCD or HDLCD on the core tile by checking if a
* CLCD or HDLCD is available in the root of the device tree.
*/
root = of_find_node_by_path("/");
if (!root)
return -EINVAL;
for_each_available_child_of_node(root, child) {
if (of_device_is_compatible(child, "arm,pl111")) {
has_coretile_clcd = true;
ct_clcd = child;
break;
}
if (of_device_is_compatible(child, "arm,hdlcd")) {
has_coretile_hdlcd = true;
of_node_put(child);
break;
}
}
of_node_put(root);
/*
* If there is a coretile HDLCD and it has a driver,
* do not mux the CLCD on the motherboard to the DVI.
*/
if (has_coretile_hdlcd && IS_ENABLED(CONFIG_DRM_HDLCD))
mux_motherboard = false;
/*
* On the Vexpress CA9 we let the CLCD on the coretile
* take precedence, so also in this case do not mux the
* motherboard to the DVI.
*/
if (has_coretile_clcd)
mux_motherboard = false;
if (mux_motherboard) {
dev_info(dev, "DVI muxed to motherboard CLCD\n");
val = VEXPRESS_FPGAMUX_MOTHERBOARD;
} else if (ct_clcd == dev->of_node) {
dev_info(dev,
"DVI muxed to daughterboard 1 (core tile) CLCD\n");
val = VEXPRESS_FPGAMUX_DAUGHTERBOARD_1;
} else {
dev_info(dev, "core tile graphics present\n");
dev_info(dev, "this device will be deactivated\n");
return -ENODEV;
}
ret = regmap_write(map, 0, val);
if (ret) {
dev_err(dev, "error setting DVI muxmode\n");
return -ENODEV;
}
return 0;
}
/*
* This sets up the regmap pointer that will then be retrieved by
* the detection code in pl111_versatile.c and passed in to the
* pl111_vexpress_clcd_init() function above.
*/
static int vexpress_muxfpga_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct regmap *map;
map = devm_regmap_init_vexpress_config(&pdev->dev);
if (IS_ERR(map))
return PTR_ERR(map);
dev_set_drvdata(dev, map);
return 0;
}
static const struct of_device_id vexpress_muxfpga_match[] = {
{ .compatible = "arm,vexpress-muxfpga", },
{}
};
static struct platform_driver vexpress_muxfpga_driver = {
.driver = {
.name = "vexpress-muxfpga",
.of_match_table = of_match_ptr(vexpress_muxfpga_match),
},
.probe = vexpress_muxfpga_probe,
};
int vexpress_muxfpga_init(void)
{
int ret;
ret = platform_driver_register(&vexpress_muxfpga_driver);
/* -EBUSY just means this driver is already registered */
if (ret == -EBUSY)
ret = 0;
return ret;
}

View File

@ -1,29 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
struct device;
struct pl111_drm_dev_private;
struct regmap;
#ifdef CONFIG_ARCH_VEXPRESS
int pl111_vexpress_clcd_init(struct device *dev,
struct pl111_drm_dev_private *priv,
struct regmap *map);
int vexpress_muxfpga_init(void);
#else
static inline int pl111_vexpress_clcd_init(struct device *dev,
struct pl111_drm_dev_private *priv,
struct regmap *map)
{
return -ENODEV;
}
static inline int vexpress_muxfpga_init(void)
{
return 0;
}
#endif

View File

@ -39,7 +39,7 @@ static int
qxl_debugfs_irq_received(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct qxl_device *qdev = node->minor->dev->dev_private;
struct qxl_device *qdev = to_qxl(node->minor->dev);
seq_printf(m, "%d\n", atomic_read(&qdev->irq_received));
seq_printf(m, "%d\n", atomic_read(&qdev->irq_received_display));
@ -53,7 +53,7 @@ static int
qxl_debugfs_buffers_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct qxl_device *qdev = node->minor->dev->dev_private;
struct qxl_device *qdev = to_qxl(node->minor->dev);
struct qxl_bo *bo;
list_for_each_entry(bo, &qdev->gem.objects, list) {
@ -83,8 +83,7 @@ void
qxl_debugfs_init(struct drm_minor *minor)
{
#if defined(CONFIG_DEBUG_FS)
struct qxl_device *dev =
(struct qxl_device *) minor->dev->dev_private;
struct qxl_device *dev = to_qxl(minor->dev);
drm_debugfs_create_files(qxl_debugfs_list, QXL_DEBUGFS_ENTRIES,
minor->debugfs_root, minor);

View File

@ -221,7 +221,7 @@ static int qxl_add_mode(struct drm_connector *connector,
bool preferred)
{
struct drm_device *dev = connector->dev;
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
struct drm_display_mode *mode = NULL;
int rc;
@ -242,7 +242,7 @@ static int qxl_add_mode(struct drm_connector *connector,
static int qxl_add_monitors_config_modes(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
struct qxl_output *output = drm_connector_to_qxl_output(connector);
int h = output->index;
struct qxl_head *head;
@ -310,7 +310,7 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc,
const char *reason)
{
struct drm_device *dev = crtc->dev;
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
struct qxl_head head;
int oldcount, i = qcrtc->index;
@ -400,7 +400,7 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
unsigned int num_clips)
{
/* TODO: vmwgfx where this was cribbed from had locking. Why? */
struct qxl_device *qdev = fb->dev->dev_private;
struct qxl_device *qdev = to_qxl(fb->dev);
struct drm_clip_rect norect;
struct qxl_bo *qobj;
bool is_primary;
@ -462,7 +462,7 @@ static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = {
static int qxl_primary_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct qxl_device *qdev = plane->dev->dev_private;
struct qxl_device *qdev = to_qxl(plane->dev);
struct qxl_bo *bo;
if (!state->crtc || !state->fb)
@ -476,7 +476,7 @@ static int qxl_primary_atomic_check(struct drm_plane *plane,
static int qxl_primary_apply_cursor(struct drm_plane *plane)
{
struct drm_device *dev = plane->dev;
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
struct drm_framebuffer *fb = plane->state->fb;
struct qxl_crtc *qcrtc = to_qxl_crtc(plane->state->crtc);
struct qxl_cursor_cmd *cmd;
@ -523,7 +523,7 @@ out_free_release:
static void qxl_primary_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct qxl_device *qdev = plane->dev->dev_private;
struct qxl_device *qdev = to_qxl(plane->dev);
struct qxl_bo *bo = gem_to_qxl_bo(plane->state->fb->obj[0]);
struct qxl_bo *primary;
struct drm_clip_rect norect = {
@ -554,7 +554,7 @@ static void qxl_primary_atomic_update(struct drm_plane *plane,
static void qxl_primary_atomic_disable(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct qxl_device *qdev = plane->dev->dev_private;
struct qxl_device *qdev = to_qxl(plane->dev);
if (old_state->fb) {
struct qxl_bo *bo = gem_to_qxl_bo(old_state->fb->obj[0]);
@ -570,7 +570,7 @@ static void qxl_cursor_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct drm_device *dev = plane->dev;
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
struct drm_framebuffer *fb = plane->state->fb;
struct qxl_crtc *qcrtc = to_qxl_crtc(plane->state->crtc);
struct qxl_release *release;
@ -679,7 +679,7 @@ out_free_release:
static void qxl_cursor_atomic_disable(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct qxl_device *qdev = plane->dev->dev_private;
struct qxl_device *qdev = to_qxl(plane->dev);
struct qxl_release *release;
struct qxl_cursor_cmd *cmd;
int ret;
@ -762,7 +762,7 @@ static void qxl_calc_dumb_shadow(struct qxl_device *qdev,
static int qxl_plane_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *new_state)
{
struct qxl_device *qdev = plane->dev->dev_private;
struct qxl_device *qdev = to_qxl(plane->dev);
struct drm_gem_object *obj;
struct qxl_bo *user_bo;
struct qxl_surface surf;
@ -923,7 +923,7 @@ static int qdev_crtc_init(struct drm_device *dev, int crtc_id)
{
struct qxl_crtc *qxl_crtc;
struct drm_plane *primary, *cursor;
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
int r;
qxl_crtc = kzalloc(sizeof(struct qxl_crtc), GFP_KERNEL);
@ -965,7 +965,7 @@ free_mem:
static int qxl_conn_get_modes(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
struct qxl_output *output = drm_connector_to_qxl_output(connector);
unsigned int pwidth = 1024;
unsigned int pheight = 768;
@ -991,7 +991,7 @@ static enum drm_mode_status qxl_conn_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
struct drm_device *ddev = connector->dev;
struct qxl_device *qdev = ddev->dev_private;
struct qxl_device *qdev = to_qxl(ddev);
if (qxl_check_mode(qdev, mode->hdisplay, mode->vdisplay) != 0)
return MODE_BAD;
@ -1021,7 +1021,7 @@ static enum drm_connector_status qxl_conn_detect(
struct qxl_output *output =
drm_connector_to_qxl_output(connector);
struct drm_device *ddev = connector->dev;
struct qxl_device *qdev = ddev->dev_private;
struct qxl_device *qdev = to_qxl(ddev);
bool connected = false;
/* The first monitor is always connected */
@ -1071,7 +1071,7 @@ static int qxl_mode_create_hotplug_mode_update_property(struct qxl_device *qdev)
static int qdev_output_init(struct drm_device *dev, int num_output)
{
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
struct qxl_output *qxl_output;
struct drm_connector *connector;
struct drm_encoder *encoder;

View File

@ -81,13 +81,16 @@ qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return -EINVAL; /* TODO: ENODEV ? */
}
qdev = kzalloc(sizeof(struct qxl_device), GFP_KERNEL);
if (!qdev)
qdev = devm_drm_dev_alloc(&pdev->dev, &qxl_driver,
struct qxl_device, ddev);
if (IS_ERR(qdev)) {
pr_err("Unable to init drm dev");
return -ENOMEM;
}
ret = pci_enable_device(pdev);
if (ret)
goto free_dev;
return ret;
ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "qxl");
if (ret)
@ -101,7 +104,7 @@ qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
ret = qxl_device_init(qdev, &qxl_driver, pdev);
ret = qxl_device_init(qdev, pdev);
if (ret)
goto put_vga;
@ -128,14 +131,13 @@ put_vga:
vga_put(pdev, VGA_RSRC_LEGACY_IO);
disable_pci:
pci_disable_device(pdev);
free_dev:
kfree(qdev);
return ret;
}
static void qxl_drm_release(struct drm_device *dev)
{
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
/*
* TODO: qxl_device_fini() call should be in qxl_pci_remove(),
@ -155,7 +157,6 @@ qxl_pci_remove(struct pci_dev *pdev)
drm_atomic_helper_shutdown(dev);
if (is_vga(pdev))
vga_put(pdev, VGA_RSRC_LEGACY_IO);
drm_dev_put(dev);
}
DEFINE_DRM_GEM_FOPS(qxl_fops);
@ -163,7 +164,7 @@ DEFINE_DRM_GEM_FOPS(qxl_fops);
static int qxl_drm_freeze(struct drm_device *dev)
{
struct pci_dev *pdev = dev->pdev;
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
int ret;
ret = drm_mode_config_helper_suspend(dev);
@ -185,7 +186,7 @@ static int qxl_drm_freeze(struct drm_device *dev)
static int qxl_drm_resume(struct drm_device *dev, bool thaw)
{
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
qdev->ram_header->int_mask = QXL_INTERRUPT_MASK;
if (!thaw) {
@ -244,7 +245,7 @@ static int qxl_pm_restore(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
struct qxl_device *qdev = drm_dev->dev_private;
struct qxl_device *qdev = to_qxl(drm_dev);
qxl_io_reset(qdev);
return qxl_drm_resume(drm_dev, false);

View File

@ -192,8 +192,6 @@ struct qxl_debugfs {
int qxl_debugfs_fence_init(struct qxl_device *rdev);
struct qxl_device;
struct qxl_device {
struct drm_device ddev;
@ -273,11 +271,12 @@ struct qxl_device {
int monitors_config_height;
};
#define to_qxl(dev) container_of(dev, struct qxl_device, ddev)
extern const struct drm_ioctl_desc qxl_ioctls[];
extern int qxl_max_ioctl;
int qxl_device_init(struct qxl_device *qdev, struct drm_driver *drv,
struct pci_dev *pdev);
int qxl_device_init(struct qxl_device *qdev, struct pci_dev *pdev);
void qxl_device_fini(struct qxl_device *qdev);
int qxl_modeset_init(struct qxl_device *qdev);

View File

@ -32,7 +32,7 @@ int qxl_mode_dumb_create(struct drm_file *file_priv,
struct drm_device *dev,
struct drm_mode_create_dumb *args)
{
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
struct qxl_bo *qobj;
uint32_t handle;
int r;

View File

@ -34,7 +34,7 @@ void qxl_gem_object_free(struct drm_gem_object *gobj)
struct qxl_device *qdev;
struct ttm_buffer_object *tbo;
qdev = (struct qxl_device *)gobj->dev->dev_private;
qdev = to_qxl(gobj->dev);
qxl_surface_evict(qdev, qobj, false);

View File

@ -36,7 +36,7 @@
static int qxl_alloc_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
struct drm_qxl_alloc *qxl_alloc = data;
int ret;
struct qxl_bo *qobj;
@ -64,7 +64,7 @@ static int qxl_alloc_ioctl(struct drm_device *dev, void *data,
static int qxl_map_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
struct drm_qxl_map *qxl_map = data;
return qxl_mode_dumb_mmap(file_priv, &qdev->ddev, qxl_map->handle,
@ -279,7 +279,7 @@ out_free_reloc:
static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
struct drm_qxl_execbuffer *execbuffer = data;
struct drm_qxl_command user_cmd;
int cmd_num;
@ -304,7 +304,7 @@ static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data,
static int qxl_update_area_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
{
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
struct drm_qxl_update_area *update_area = data;
struct qxl_rect area = {.left = update_area->left,
.top = update_area->top,
@ -354,7 +354,7 @@ out:
static int qxl_getparam_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
struct drm_qxl_getparam *param = data;
switch (param->param) {
@ -373,7 +373,7 @@ static int qxl_getparam_ioctl(struct drm_device *dev, void *data,
static int qxl_clientcap_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
struct drm_qxl_clientcap *param = data;
int byte, idx;
@ -394,7 +394,7 @@ static int qxl_clientcap_ioctl(struct drm_device *dev, void *data,
static int qxl_alloc_surf_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
{
struct qxl_device *qdev = dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
struct drm_qxl_alloc_surf *param = data;
struct qxl_bo *qobj;
int handle;

View File

@ -32,7 +32,7 @@
irqreturn_t qxl_irq_handler(int irq, void *arg)
{
struct drm_device *dev = (struct drm_device *) arg;
struct qxl_device *qdev = (struct qxl_device *)dev->dev_private;
struct qxl_device *qdev = to_qxl(dev);
uint32_t pending;
pending = xchg(&qdev->ram_header->int_pending, 0);

View File

@ -108,21 +108,12 @@ static void qxl_gc_work(struct work_struct *work)
}
int qxl_device_init(struct qxl_device *qdev,
struct drm_driver *drv,
struct pci_dev *pdev)
{
int r, sb;
r = drm_dev_init(&qdev->ddev, drv, &pdev->dev);
if (r) {
pr_err("Unable to init drm dev");
goto error;
}
qdev->ddev.pdev = pdev;
pci_set_drvdata(pdev, &qdev->ddev);
qdev->ddev.dev_private = qdev;
drmm_add_final_kfree(&qdev->ddev, qdev);
mutex_init(&qdev->gem.mutex);
mutex_init(&qdev->update_area_mutex);
@ -138,8 +129,7 @@ int qxl_device_init(struct qxl_device *qdev,
qdev->vram_mapping = io_mapping_create_wc(qdev->vram_base, pci_resource_len(pdev, 0));
if (!qdev->vram_mapping) {
pr_err("Unable to create vram_mapping");
r = -ENOMEM;
goto error;
return -ENOMEM;
}
if (pci_resource_len(pdev, 4) > 0) {
@ -293,7 +283,6 @@ surface_mapping_free:
io_mapping_free(qdev->surface_mapping);
vram_mapping_free:
io_mapping_free(qdev->vram_mapping);
error:
return r;
}

View File

@ -33,7 +33,7 @@ static void qxl_ttm_bo_destroy(struct ttm_buffer_object *tbo)
struct qxl_device *qdev;
bo = to_qxl_bo(tbo);
qdev = (struct qxl_device *)bo->tbo.base.dev->dev_private;
qdev = to_qxl(bo->tbo.base.dev);
qxl_surface_evict(qdev, bo, false);
WARN_ON_ONCE(bo->map_count > 0);

View File

@ -243,7 +243,7 @@ static int qxl_release_validate_bo(struct qxl_bo *bo)
return ret;
/* allocate a surface for reserved + validated buffers */
ret = qxl_bo_check_id(bo->tbo.base.dev->dev_private, bo);
ret = qxl_bo_check_id(to_qxl(bo->tbo.base.dev), bo);
if (ret)
return ret;
return 0;

View File

@ -243,7 +243,7 @@ static void qxl_bo_move_notify(struct ttm_buffer_object *bo,
if (!qxl_ttm_bo_is_qxl_bo(bo))
return;
qbo = to_qxl_bo(bo);
qdev = qbo->tbo.base.dev->dev_private;
qdev = to_qxl(qbo->tbo.base.dev);
if (bo->mem.mem_type == TTM_PL_PRIV && qbo->surface_id)
qxl_surface_evict(qdev, qbo, new_mem ? true : false);

View File

@ -1106,7 +1106,7 @@ static const struct component_ops cdn_dp_component_ops = {
.unbind = cdn_dp_unbind,
};
int cdn_dp_suspend(struct device *dev)
static int cdn_dp_suspend(struct device *dev)
{
struct cdn_dp_device *dp = dev_get_drvdata(dev);
int ret = 0;
@ -1120,7 +1120,7 @@ int cdn_dp_suspend(struct device *dev)
return ret;
}
int cdn_dp_resume(struct device *dev)
static int cdn_dp_resume(struct device *dev)
{
struct cdn_dp_device *dp = dev_get_drvdata(dev);

View File

@ -601,7 +601,7 @@ static int cdn_dp_get_msa_misc(struct video_info *video,
case YCBCR_4_2_0:
val[0] = 5;
break;
};
}
switch (video->color_depth) {
case 6:
@ -619,7 +619,7 @@ static int cdn_dp_get_msa_misc(struct video_info *video,
case 16:
val[1] = 4;
break;
};
}
msa_misc = 2 * val[0] + 32 * val[1] +
((video->color_fmt == Y_ONLY) ? (1 << 14) : 0);
@ -700,7 +700,7 @@ int cdn_dp_config_video(struct cdn_dp_device *dp)
case 16:
val = BCS_16;
break;
};
}
val += video->color_fmt << 8;
ret = cdn_dp_reg_write(dp, DP_FRAMER_PXL_REPR, val);

View File

@ -42,8 +42,6 @@
#define MAX_IRQ 4
#define MAX_ENDPOINTS 2
#define HWVER_10200 0x010200
#define HWVER_10300 0x010300
#define HWVER_20101 0x020101
@ -1201,36 +1199,20 @@ int ltdc_load(struct drm_device *ddev)
struct ltdc_device *ldev = ddev->dev_private;
struct device *dev = ddev->dev;
struct device_node *np = dev->of_node;
struct drm_bridge *bridge[MAX_ENDPOINTS] = {NULL};
struct drm_panel *panel[MAX_ENDPOINTS] = {NULL};
struct drm_bridge *bridge;
struct drm_panel *panel;
struct drm_crtc *crtc;
struct reset_control *rstc;
struct resource *res;
int irq, ret, i, endpoint_not_ready = -ENODEV;
int irq, i, nb_endpoints;
int ret = -ENODEV;
DRM_DEBUG_DRIVER("\n");
/* Get endpoints if any */
for (i = 0; i < MAX_ENDPOINTS; i++) {
ret = drm_of_find_panel_or_bridge(np, 0, i, &panel[i],
&bridge[i]);
/*
* If at least one endpoint is -EPROBE_DEFER, defer probing,
* else if at least one endpoint is ready, continue probing.
*/
if (ret == -EPROBE_DEFER)
return ret;
else if (!ret)
endpoint_not_ready = 0;
}
if (endpoint_not_ready)
return endpoint_not_ready;
rstc = devm_reset_control_get_exclusive(dev, NULL);
mutex_init(&ldev->err_lock);
/* Get number of endpoints */
nb_endpoints = of_graph_get_endpoint_count(np);
if (!nb_endpoints)
return -ENODEV;
ldev->pixel_clk = devm_clk_get(dev, "lcd");
if (IS_ERR(ldev->pixel_clk)) {
@ -1244,6 +1226,43 @@ int ltdc_load(struct drm_device *ddev)
return -ENODEV;
}
/* Get endpoints if any */
for (i = 0; i < nb_endpoints; i++) {
ret = drm_of_find_panel_or_bridge(np, 0, i, &panel, &bridge);
/*
* If at least one endpoint is -ENODEV, continue probing,
* else if at least one endpoint returned an error
* (ie -EPROBE_DEFER) then stop probing.
*/
if (ret == -ENODEV)
continue;
else if (ret)
goto err;
if (panel) {
bridge = drm_panel_bridge_add_typed(panel,
DRM_MODE_CONNECTOR_DPI);
if (IS_ERR(bridge)) {
DRM_ERROR("panel-bridge endpoint %d\n", i);
ret = PTR_ERR(bridge);
goto err;
}
}
if (bridge) {
ret = ltdc_encoder_init(ddev, bridge);
if (ret) {
DRM_ERROR("init encoder endpoint %d\n", i);
goto err;
}
}
}
rstc = devm_reset_control_get_exclusive(dev, NULL);
mutex_init(&ldev->err_lock);
if (!IS_ERR(rstc)) {
reset_control_assert(rstc);
usleep_range(10, 20);
@ -1285,27 +1304,7 @@ int ltdc_load(struct drm_device *ddev)
DRM_ERROR("Failed to register LTDC interrupt\n");
goto err;
}
}
/* Add endpoints panels or bridges if any */
for (i = 0; i < MAX_ENDPOINTS; i++) {
if (panel[i]) {
bridge[i] = drm_panel_bridge_add_typed(panel[i],
DRM_MODE_CONNECTOR_DPI);
if (IS_ERR(bridge[i])) {
DRM_ERROR("panel-bridge endpoint %d\n", i);
ret = PTR_ERR(bridge[i]);
goto err;
}
}
if (bridge[i]) {
ret = ltdc_encoder_init(ddev, bridge[i]);
if (ret) {
DRM_ERROR("init encoder endpoint %d\n", i);
goto err;
}
}
}
crtc = devm_kzalloc(dev, sizeof(*crtc), GFP_KERNEL);
@ -1340,8 +1339,8 @@ int ltdc_load(struct drm_device *ddev)
return 0;
err:
for (i = 0; i < MAX_ENDPOINTS; i++)
drm_panel_bridge_remove(bridge[i]);
for (i = 0; i < nb_endpoints; i++)
drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i);
clk_disable_unprepare(ldev->pixel_clk);
@ -1350,11 +1349,14 @@ err:
void ltdc_unload(struct drm_device *ddev)
{
int i;
struct device *dev = ddev->dev;
int nb_endpoints, i;
DRM_DEBUG_DRIVER("\n");
for (i = 0; i < MAX_ENDPOINTS; i++)
nb_endpoints = of_graph_get_endpoint_count(dev->of_node);
for (i = 0; i < nb_endpoints; i++)
drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i);
pm_runtime_disable(ddev->dev);

View File

@ -24,7 +24,7 @@
static void tidss_crtc_finish_page_flip(struct tidss_crtc *tcrtc)
{
struct drm_device *ddev = tcrtc->crtc.dev;
struct tidss_device *tidss = ddev->dev_private;
struct tidss_device *tidss = to_tidss(ddev);
struct drm_pending_vblank_event *event;
unsigned long flags;
bool busy;
@ -88,7 +88,7 @@ static int tidss_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
struct drm_device *ddev = crtc->dev;
struct tidss_device *tidss = ddev->dev_private;
struct tidss_device *tidss = to_tidss(ddev);
struct dispc_device *dispc = tidss->dispc;
struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
u32 hw_videoport = tcrtc->hw_videoport;
@ -165,7 +165,7 @@ static void tidss_crtc_atomic_flush(struct drm_crtc *crtc,
{
struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
struct drm_device *ddev = crtc->dev;
struct tidss_device *tidss = ddev->dev_private;
struct tidss_device *tidss = to_tidss(ddev);
unsigned long flags;
dev_dbg(ddev->dev,
@ -216,7 +216,7 @@ static void tidss_crtc_atomic_enable(struct drm_crtc *crtc,
{
struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
struct drm_device *ddev = crtc->dev;
struct tidss_device *tidss = ddev->dev_private;
struct tidss_device *tidss = to_tidss(ddev);
const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
unsigned long flags;
int r;
@ -259,7 +259,7 @@ static void tidss_crtc_atomic_disable(struct drm_crtc *crtc,
{
struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
struct drm_device *ddev = crtc->dev;
struct tidss_device *tidss = ddev->dev_private;
struct tidss_device *tidss = to_tidss(ddev);
unsigned long flags;
dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event);
@ -295,7 +295,7 @@ enum drm_mode_status tidss_crtc_mode_valid(struct drm_crtc *crtc,
{
struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
struct drm_device *ddev = crtc->dev;
struct tidss_device *tidss = ddev->dev_private;
struct tidss_device *tidss = to_tidss(ddev);
return dispc_vp_mode_valid(tidss->dispc, tcrtc->hw_videoport, mode);
}
@ -314,7 +314,7 @@ static const struct drm_crtc_helper_funcs tidss_crtc_helper_funcs = {
static int tidss_crtc_enable_vblank(struct drm_crtc *crtc)
{
struct drm_device *ddev = crtc->dev;
struct tidss_device *tidss = ddev->dev_private;
struct tidss_device *tidss = to_tidss(ddev);
dev_dbg(ddev->dev, "%s\n", __func__);
@ -328,7 +328,7 @@ static int tidss_crtc_enable_vblank(struct drm_crtc *crtc)
static void tidss_crtc_disable_vblank(struct drm_crtc *crtc)
{
struct drm_device *ddev = crtc->dev;
struct tidss_device *tidss = ddev->dev_private;
struct tidss_device *tidss = to_tidss(ddev);
dev_dbg(ddev->dev, "%s\n", __func__);

View File

@ -181,10 +181,6 @@ const struct dispc_features dispc_am65x_feats = {
.vid_name = { "vid", "vidl1" },
.vid_lite = { false, true, },
.vid_order = { 1, 0 },
.errata = {
.i2000 = true,
},
};
static const u16 tidss_j721e_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
@ -2674,12 +2670,9 @@ int dispc_init(struct tidss_device *tidss)
return -ENOMEM;
num_fourccs = 0;
for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i) {
if (feat->errata.i2000 &&
dispc_fourcc_is_yuv(dispc_color_formats[i].fourcc))
continue;
for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i)
dispc->fourccs[num_fourccs++] = dispc_color_formats[i].fourcc;
}
dispc->num_fourccs = num_fourccs;
dispc->tidss = tidss;
dispc->dev = dev;

Some files were not shown because too many files have changed in this diff Show More