drm-misc-next for 5.1:
UAPI Changes: - New fourcc identifier for ARM Framebuffer Compression v1.3 Cross-subsystem Changes: Core Changes: - Reorganisation of drm_device and drm_framebuffer headers - Cleanup of the drmP inclusion - Fix leaks in the fb-helpers - Allow for depth different from bpp in fb-helper fbdev emulation - Remove drm_mode_object from drm_display_mode Driver Changes: - Add reflection properties to rockchip - a bunch of fixes for virtio - a bunch of fixes for dp_mst and drivers using it, and introduction of a new refcounting scheme - Convertion of bochs to atomic and generic fbdev emulation - Allow meson to remove the firmware framebuffers -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQRcEzekXsqa64kGDp7j7w1vZxhRxQUCXD+OHgAKCRDj7w1vZxhR xe3IAP4s59sFVMZseVJpwSe41OJ1ipD/cyIbtXU94X6nFd6zCAD+Jm4q+XIIS+uv 7ElmJ2BD7rwicqSViWNG8tteHYfjrAU= =XPsb -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2019-01-16' of git://anongit.freedesktop.org/drm/drm-misc into drm-next drm-misc-next for 5.1: UAPI Changes: - New fourcc identifier for ARM Framebuffer Compression v1.3 Cross-subsystem Changes: Core Changes: - Reorganisation of drm_device and drm_framebuffer headers - Cleanup of the drmP inclusion - Fix leaks in the fb-helpers - Allow for depth different from bpp in fb-helper fbdev emulation - Remove drm_mode_object from drm_display_mode Driver Changes: - Add reflection properties to rockchip - a bunch of fixes for virtio - a bunch of fixes for dp_mst and drivers using it, and introduction of a new refcounting scheme - Convertion of bochs to atomic and generic fbdev emulation - Allow meson to remove the firmware framebuffers [airlied: patch rcar-du to add drm_modes.h] Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20190116200428.u2n4jbk4mzza7n6e@flea
This commit is contained in:
Коммит
f164a94c2c
|
@ -10,6 +10,7 @@ Required properties:
|
|||
"rockchip,rk3126-vop";
|
||||
"rockchip,px30-vop-lit";
|
||||
"rockchip,px30-vop-big";
|
||||
"rockchip,rk3066-vop";
|
||||
"rockchip,rk3188-vop";
|
||||
"rockchip,rk3288-vop";
|
||||
"rockchip,rk3368-vop";
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
digraph T {
|
||||
/* Make sure our payloads are always drawn below the driver node */
|
||||
subgraph cluster_driver {
|
||||
fillcolor = grey;
|
||||
style = filled;
|
||||
driver -> {payload1, payload2} [dir=none];
|
||||
}
|
||||
|
||||
/* Driver malloc references */
|
||||
edge [style=dashed];
|
||||
driver -> port1;
|
||||
driver -> port2;
|
||||
driver -> port3:e;
|
||||
driver -> port4;
|
||||
|
||||
payload1:s -> port1:e;
|
||||
payload2:s -> port3:e;
|
||||
edge [style=""];
|
||||
|
||||
subgraph cluster_topology {
|
||||
label="Topology Manager";
|
||||
labelloc=bottom;
|
||||
|
||||
/* Topology references */
|
||||
mstb1 -> {port1, port2};
|
||||
port1 -> mstb2;
|
||||
port2 -> mstb3 -> {port3, port4};
|
||||
port3 -> mstb4;
|
||||
|
||||
/* Malloc references */
|
||||
edge [style=dashed;dir=back];
|
||||
mstb1 -> {port1, port2};
|
||||
port1 -> mstb2;
|
||||
port2 -> mstb3 -> {port3, port4};
|
||||
port3 -> mstb4;
|
||||
}
|
||||
|
||||
driver [label="DRM driver";style=filled;shape=box;fillcolor=lightblue];
|
||||
|
||||
payload1 [label="Payload #1";style=filled;shape=box;fillcolor=lightblue];
|
||||
payload2 [label="Payload #2";style=filled;shape=box;fillcolor=lightblue];
|
||||
|
||||
mstb1 [label="MSTB #1";style=filled;fillcolor=palegreen;shape=oval];
|
||||
mstb2 [label="MSTB #2";style=filled;fillcolor=palegreen;shape=oval];
|
||||
mstb3 [label="MSTB #3";style=filled;fillcolor=palegreen;shape=oval];
|
||||
mstb4 [label="MSTB #4";style=filled;fillcolor=palegreen;shape=oval];
|
||||
|
||||
port1 [label="Port #1";shape=oval];
|
||||
port2 [label="Port #2";shape=oval];
|
||||
port3 [label="Port #3";shape=oval];
|
||||
port4 [label="Port #4";shape=oval];
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
digraph T {
|
||||
/* Make sure our payloads are always drawn below the driver node */
|
||||
subgraph cluster_driver {
|
||||
fillcolor = grey;
|
||||
style = filled;
|
||||
driver -> {payload1, payload2} [dir=none];
|
||||
}
|
||||
|
||||
/* Driver malloc references */
|
||||
edge [style=dashed];
|
||||
driver -> port1;
|
||||
driver -> port2;
|
||||
driver -> port3:e;
|
||||
driver -> port4 [color=red];
|
||||
|
||||
payload1:s -> port1:e;
|
||||
payload2:s -> port3:e;
|
||||
edge [style=""];
|
||||
|
||||
subgraph cluster_topology {
|
||||
label="Topology Manager";
|
||||
labelloc=bottom;
|
||||
|
||||
/* Topology references */
|
||||
mstb1 -> {port1, port2};
|
||||
port1 -> mstb2;
|
||||
edge [color=red];
|
||||
port2 -> mstb3 -> {port3, port4};
|
||||
port3 -> mstb4;
|
||||
edge [color=""];
|
||||
|
||||
/* Malloc references */
|
||||
edge [style=dashed;dir=back];
|
||||
mstb1 -> {port1, port2};
|
||||
port1 -> mstb2;
|
||||
port2 -> mstb3 -> port3;
|
||||
edge [color=red];
|
||||
mstb3 -> port4;
|
||||
port3 -> mstb4;
|
||||
}
|
||||
|
||||
mstb1 [label="MSTB #1";style=filled;fillcolor=palegreen];
|
||||
mstb2 [label="MSTB #2";style=filled;fillcolor=palegreen];
|
||||
mstb3 [label="MSTB #3";style=filled;fillcolor=palegreen];
|
||||
mstb4 [label="MSTB #4";style=filled;fillcolor=grey];
|
||||
|
||||
port1 [label="Port #1"];
|
||||
port2 [label="Port #2"];
|
||||
port3 [label="Port #3"];
|
||||
port4 [label="Port #4";style=filled;fillcolor=grey];
|
||||
|
||||
driver [label="DRM driver";style=filled;shape=box;fillcolor=lightblue];
|
||||
|
||||
payload1 [label="Payload #1";style=filled;shape=box;fillcolor=lightblue];
|
||||
payload2 [label="Payload #2";style=filled;shape=box;fillcolor=lightblue];
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
digraph T {
|
||||
/* Make sure our payloads are always drawn below the driver node */
|
||||
subgraph cluster_driver {
|
||||
fillcolor = grey;
|
||||
style = filled;
|
||||
edge [dir=none];
|
||||
driver -> payload1;
|
||||
driver -> payload2 [penwidth=3];
|
||||
edge [dir=""];
|
||||
}
|
||||
|
||||
/* Driver malloc references */
|
||||
edge [style=dashed];
|
||||
driver -> port1;
|
||||
driver -> port2;
|
||||
driver -> port3:e;
|
||||
driver -> port4 [color=grey];
|
||||
payload1:s -> port1:e;
|
||||
payload2:s -> port3:e [penwidth=3];
|
||||
edge [style=""];
|
||||
|
||||
subgraph cluster_topology {
|
||||
label="Topology Manager";
|
||||
labelloc=bottom;
|
||||
|
||||
/* Topology references */
|
||||
mstb1 -> {port1, port2};
|
||||
port1 -> mstb2;
|
||||
edge [color=grey];
|
||||
port2 -> mstb3 -> {port3, port4};
|
||||
port3 -> mstb4;
|
||||
edge [color=""];
|
||||
|
||||
/* Malloc references */
|
||||
edge [style=dashed;dir=back];
|
||||
mstb1 -> {port1, port2};
|
||||
port1 -> mstb2;
|
||||
port2 -> mstb3 [penwidth=3];
|
||||
mstb3 -> port3 [penwidth=3];
|
||||
edge [color=grey];
|
||||
mstb3 -> port4;
|
||||
port3 -> mstb4;
|
||||
}
|
||||
|
||||
mstb1 [label="MSTB #1";style=filled;fillcolor=palegreen];
|
||||
mstb2 [label="MSTB #2";style=filled;fillcolor=palegreen];
|
||||
mstb3 [label="MSTB #3";style=filled;fillcolor=palegreen;penwidth=3];
|
||||
mstb4 [label="MSTB #4";style=filled;fillcolor=grey];
|
||||
|
||||
port1 [label="Port #1"];
|
||||
port2 [label="Port #2";penwidth=5];
|
||||
port3 [label="Port #3";penwidth=3];
|
||||
port4 [label="Port #4";style=filled;fillcolor=grey];
|
||||
|
||||
driver [label="DRM driver";style=filled;shape=box;fillcolor=lightblue];
|
||||
|
||||
payload1 [label="Payload #1";style=filled;shape=box;fillcolor=lightblue];
|
||||
payload2 [label="Payload #2";style=filled;shape=box;fillcolor=lightblue;penwidth=3];
|
||||
}
|
|
@ -143,6 +143,9 @@ Device Instance and Driver Handling
|
|||
.. kernel-doc:: drivers/gpu/drm/drm_drv.c
|
||||
:doc: driver instance overview
|
||||
|
||||
.. kernel-doc:: include/drm/drm_device.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: include/drm/drm_drv.h
|
||||
:internal:
|
||||
|
||||
|
@ -230,6 +233,15 @@ Printer
|
|||
.. kernel-doc:: drivers/gpu/drm/drm_print.c
|
||||
:export:
|
||||
|
||||
Utilities
|
||||
---------
|
||||
|
||||
.. kernel-doc:: include/drm/drm_util.h
|
||||
:doc: drm utils
|
||||
|
||||
.. kernel-doc:: include/drm/drm_util.h
|
||||
:internal:
|
||||
|
||||
|
||||
Legacy Support Code
|
||||
===================
|
||||
|
|
|
@ -116,8 +116,6 @@ Framebuffer CMA Helper Functions Reference
|
|||
.. kernel-doc:: drivers/gpu/drm/drm_fb_cma_helper.c
|
||||
:export:
|
||||
|
||||
.. _drm_bridges:
|
||||
|
||||
Framebuffer GEM Helper Reference
|
||||
================================
|
||||
|
||||
|
@ -127,6 +125,8 @@ Framebuffer GEM Helper Reference
|
|||
.. kernel-doc:: drivers/gpu/drm/drm_gem_framebuffer_helper.c
|
||||
:export:
|
||||
|
||||
.. _drm_bridges:
|
||||
|
||||
Bridges
|
||||
=======
|
||||
|
||||
|
@ -208,18 +208,40 @@ Display Port Dual Mode Adaptor Helper Functions Reference
|
|||
.. kernel-doc:: drivers/gpu/drm/drm_dp_dual_mode_helper.c
|
||||
:export:
|
||||
|
||||
Display Port MST Helper Functions Reference
|
||||
===========================================
|
||||
Display Port MST Helpers
|
||||
========================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c
|
||||
:doc: dp mst helper
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c
|
||||
:doc: Branch device and port refcounting
|
||||
|
||||
Functions Reference
|
||||
-------------------
|
||||
|
||||
.. kernel-doc:: include/drm/drm_dp_mst_helper.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c
|
||||
:export:
|
||||
|
||||
Topology Lifetime Internals
|
||||
---------------------------
|
||||
|
||||
These functions aren't exported to drivers, but are documented here to help make
|
||||
the MST topology helpers easier to understand
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c
|
||||
:functions: drm_dp_mst_topology_try_get_mstb drm_dp_mst_topology_get_mstb
|
||||
drm_dp_mst_topology_put_mstb
|
||||
drm_dp_mst_topology_try_get_port drm_dp_mst_topology_get_port
|
||||
drm_dp_mst_topology_put_port
|
||||
drm_dp_mst_get_mstb_malloc drm_dp_mst_put_mstb_malloc
|
||||
|
||||
MIPI DSI Helper Functions Reference
|
||||
===================================
|
||||
|
||||
|
|
|
@ -209,6 +209,36 @@ Would be great to refactor this all into a set of small common helpers.
|
|||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Generic fbdev defio support
|
||||
---------------------------
|
||||
|
||||
The defio support code in the fbdev core has some very specific requirements,
|
||||
which means drivers need to have a special framebuffer for fbdev. Which prevents
|
||||
us from using the generic fbdev emulation code everywhere. The main issue is
|
||||
that it uses some fields in struct page itself, which breaks shmem gem objects
|
||||
(and other things).
|
||||
|
||||
Possible solution would be to write our own defio mmap code in the drm fbdev
|
||||
emulation. It would need to fully wrap the existing mmap ops, forwarding
|
||||
everything after it has done the write-protect/mkwrite trickery:
|
||||
|
||||
- In the drm_fbdev_fb_mmap helper, if we need defio, change the
|
||||
default page prots to write-protected with something like this::
|
||||
|
||||
vma->vm_page_prot = pgprot_wrprotect(vma->vm_page_prot);
|
||||
|
||||
- Set the mkwrite and fsync callbacks with similar implementions to the core
|
||||
fbdev defio stuff. These should all work on plain ptes, they don't actually
|
||||
require a struct page. uff. These should all work on plain ptes, they don't
|
||||
actually require a struct page.
|
||||
|
||||
- Track the dirty pages in a separate structure (bitfield with one bit per page
|
||||
should work) to avoid clobbering struct page.
|
||||
|
||||
Might be good to also have some igt testcases for this.
|
||||
|
||||
Contact: Daniel Vetter, Noralf Tronnes
|
||||
|
||||
Put a reservation_object into drm_gem_object
|
||||
--------------------------------------------
|
||||
|
||||
|
|
17
MAINTAINERS
17
MAINTAINERS
|
@ -4910,6 +4910,13 @@ DRM DRIVER FOR TDFX VIDEO CARDS
|
|||
S: Orphan / Obsolete
|
||||
F: drivers/gpu/drm/tdfx/
|
||||
|
||||
DRM DRIVER FOR TPO TPG110 PANELS
|
||||
M: Linus Walleij <linus.walleij@linaro.org>
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/panel/panel-tpo-tpg110.c
|
||||
F: Documentation/devicetree/bindings/display/panel/tpo,tpg110.txt
|
||||
|
||||
DRM DRIVER FOR USB DISPLAYLINK VIDEO ADAPTERS
|
||||
M: Dave Airlie <airlied@redhat.com>
|
||||
R: Sean Paul <sean@poorly.run>
|
||||
|
@ -4918,6 +4925,16 @@ S: Odd Fixes
|
|||
F: drivers/gpu/drm/udl/
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
|
||||
DRM DRIVER FOR VIRTUAL KERNEL MODESETTING (VKMS)
|
||||
M: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
|
||||
R: Haneen Mohammed <hamohammed.sa@gmail.com>
|
||||
R: Daniel Vetter <daniel@ffwll.ch>
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
S: Maintained
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
F: drivers/gpu/drm/vkms/
|
||||
F: Documentation/gpu/vkms.rst
|
||||
|
||||
DRM DRIVER FOR VMWARE VIRTUAL GPU
|
||||
M: "VMware Graphics" <linux-graphics-maintainer@vmware.com>
|
||||
M: Thomas Hellstrom <thellstrom@vmware.com>
|
||||
|
|
|
@ -2708,7 +2708,7 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
|
|||
amdgpu_irq_disable_all(adev);
|
||||
if (adev->mode_info.mode_config_initialized){
|
||||
if (!amdgpu_device_has_dc_support(adev))
|
||||
drm_crtc_force_disable_all(adev->ddev);
|
||||
drm_helper_force_disable_all(adev->ddev);
|
||||
else
|
||||
drm_atomic_helper_shutdown(adev->ddev);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include <linux/slab.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <drm/drm_util.h>
|
||||
|
||||
#define ATOM_DEBUG
|
||||
|
||||
#include "atom.h"
|
||||
|
|
|
@ -1682,7 +1682,7 @@ static void dce_v10_0_afmt_setmode(struct drm_encoder *encoder,
|
|||
dce_v10_0_audio_write_sad_regs(encoder);
|
||||
dce_v10_0_audio_write_latency_fields(encoder, mode);
|
||||
|
||||
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
|
||||
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode);
|
||||
if (err < 0) {
|
||||
DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
|
||||
return;
|
||||
|
|
|
@ -1724,7 +1724,7 @@ static void dce_v11_0_afmt_setmode(struct drm_encoder *encoder,
|
|||
dce_v11_0_audio_write_sad_regs(encoder);
|
||||
dce_v11_0_audio_write_latency_fields(encoder, mode);
|
||||
|
||||
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
|
||||
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode);
|
||||
if (err < 0) {
|
||||
DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
|
||||
return;
|
||||
|
|
|
@ -1423,6 +1423,7 @@ static void dce_v6_0_audio_set_avi_infoframe(struct drm_encoder *encoder,
|
|||
struct amdgpu_device *adev = dev->dev_private;
|
||||
struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
|
||||
struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
|
||||
struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
|
||||
struct hdmi_avi_infoframe frame;
|
||||
u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
|
||||
uint8_t *payload = buffer + 3;
|
||||
|
@ -1430,7 +1431,7 @@ static void dce_v6_0_audio_set_avi_infoframe(struct drm_encoder *encoder,
|
|||
ssize_t err;
|
||||
u32 tmp;
|
||||
|
||||
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
|
||||
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode);
|
||||
if (err < 0) {
|
||||
DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
|
||||
return;
|
||||
|
|
|
@ -1616,7 +1616,7 @@ static void dce_v8_0_afmt_setmode(struct drm_encoder *encoder,
|
|||
dce_v8_0_audio_write_sad_regs(encoder);
|
||||
dce_v8_0_audio_write_latency_fields(encoder, mode);
|
||||
|
||||
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
|
||||
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode);
|
||||
if (err < 0) {
|
||||
DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
|
||||
return;
|
||||
|
|
|
@ -191,6 +191,7 @@ dm_dp_mst_connector_destroy(struct drm_connector *connector)
|
|||
drm_encoder_cleanup(&amdgpu_encoder->base);
|
||||
kfree(amdgpu_encoder);
|
||||
drm_connector_cleanup(connector);
|
||||
drm_dp_mst_put_port_malloc(amdgpu_dm_connector->port);
|
||||
kfree(amdgpu_dm_connector);
|
||||
}
|
||||
|
||||
|
@ -363,7 +364,9 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
|
|||
amdgpu_dm_connector_funcs_reset(connector);
|
||||
|
||||
DRM_INFO("DM_MST: added connector: %p [id: %d] [master: %p]\n",
|
||||
aconnector, connector->base.id, aconnector->mst_port);
|
||||
aconnector, connector->base.id, aconnector->mst_port);
|
||||
|
||||
drm_dp_mst_get_port_malloc(port);
|
||||
|
||||
DRM_DEBUG_KMS(":%d\n", connector->base.id);
|
||||
|
||||
|
@ -379,12 +382,12 @@ static void dm_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
|
|||
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
|
||||
|
||||
DRM_INFO("DM_MST: Disabling connector: %p [id: %d] [master: %p]\n",
|
||||
aconnector, connector->base.id, aconnector->mst_port);
|
||||
aconnector, connector->base.id, aconnector->mst_port);
|
||||
|
||||
aconnector->port = NULL;
|
||||
if (aconnector->dc_sink) {
|
||||
amdgpu_dm_update_freesync_caps(connector, NULL);
|
||||
dc_link_remove_remote_sink(aconnector->dc_link, aconnector->dc_sink);
|
||||
dc_link_remove_remote_sink(aconnector->dc_link,
|
||||
aconnector->dc_sink);
|
||||
dc_sink_release(aconnector->dc_sink);
|
||||
aconnector->dc_sink = NULL;
|
||||
}
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_data/simplefb.h>
|
||||
|
|
|
@ -16,12 +16,18 @@
|
|||
|
||||
#include <linux/clk.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_debugfs.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "arcpgu.h"
|
||||
#include "arcpgu_regs.h"
|
||||
|
|
|
@ -51,7 +51,6 @@ arcpgu_drm_connector_helper_funcs = {
|
|||
};
|
||||
|
||||
static const struct drm_connector_funcs arcpgu_drm_connector_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = arcpgu_drm_connector_destroy,
|
||||
|
|
|
@ -270,13 +270,7 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
|||
tm = adj->crtc_vtotal - adj->crtc_vsync_end;
|
||||
|
||||
DRM_DEBUG_KMS("[CRTC:%d:%s] mode " DRM_MODE_FMT "\n",
|
||||
crtc->base.id, crtc->name,
|
||||
adj->base.id, adj->name, adj->vrefresh, adj->clock,
|
||||
adj->crtc_hdisplay, adj->crtc_hsync_start,
|
||||
adj->crtc_hsync_end, adj->crtc_htotal,
|
||||
adj->crtc_vdisplay, adj->crtc_vsync_start,
|
||||
adj->crtc_vsync_end, adj->crtc_vtotal,
|
||||
adj->type, adj->flags);
|
||||
crtc->base.id, crtc->name, DRM_MODE_ARG(adj));
|
||||
DRM_DEBUG_KMS("lm %d rm %d tm %d bm %d\n", lm, rm, tm, bm);
|
||||
|
||||
/* Now compute the divider for real */
|
||||
|
|
|
@ -39,7 +39,9 @@
|
|||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_util.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
||||
#include "ast_drv.h"
|
||||
|
||||
static void ast_dirty_update(struct ast_fbdev *afbdev,
|
||||
|
@ -261,7 +263,7 @@ static void ast_fbdev_destroy(struct drm_device *dev,
|
|||
{
|
||||
struct ast_framebuffer *afb = &afbdev->afb;
|
||||
|
||||
drm_crtc_force_disable_all(dev);
|
||||
drm_helper_force_disable_all(dev);
|
||||
drm_fb_helper_unregister_fbi(&afbdev->helper);
|
||||
|
||||
if (afb->obj) {
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
bochs-drm-y := bochs_drv.o bochs_mm.o bochs_kms.o bochs_fbdev.o bochs_hw.o
|
||||
bochs-drm-y := bochs_drv.o bochs_mm.o bochs_kms.o bochs_hw.o
|
||||
|
||||
obj-$(CONFIG_DRM_BOCHS) += bochs-drm.o
|
||||
|
|
|
@ -80,12 +80,6 @@ struct bochs_device {
|
|||
struct ttm_bo_device bdev;
|
||||
bool initialized;
|
||||
} ttm;
|
||||
|
||||
/* fbdev */
|
||||
struct {
|
||||
struct drm_framebuffer *fb;
|
||||
struct drm_fb_helper helper;
|
||||
} fb;
|
||||
};
|
||||
|
||||
struct bochs_bo {
|
||||
|
@ -121,8 +115,9 @@ int bochs_hw_init(struct drm_device *dev);
|
|||
void bochs_hw_fini(struct drm_device *dev);
|
||||
|
||||
void bochs_hw_setmode(struct bochs_device *bochs,
|
||||
struct drm_display_mode *mode,
|
||||
const struct drm_format_info *format);
|
||||
struct drm_display_mode *mode);
|
||||
void bochs_hw_setformat(struct bochs_device *bochs,
|
||||
const struct drm_format_info *format);
|
||||
void bochs_hw_setbase(struct bochs_device *bochs,
|
||||
int x, int y, u64 addr);
|
||||
int bochs_hw_load_edid(struct bochs_device *bochs);
|
||||
|
@ -141,15 +136,19 @@ int bochs_dumb_create(struct drm_file *file, struct drm_device *dev,
|
|||
int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
|
||||
uint32_t handle, uint64_t *offset);
|
||||
|
||||
int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr);
|
||||
int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag);
|
||||
int bochs_bo_unpin(struct bochs_bo *bo);
|
||||
|
||||
int bochs_gem_prime_pin(struct drm_gem_object *obj);
|
||||
void bochs_gem_prime_unpin(struct drm_gem_object *obj);
|
||||
void *bochs_gem_prime_vmap(struct drm_gem_object *obj);
|
||||
void bochs_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
|
||||
int bochs_gem_prime_mmap(struct drm_gem_object *obj,
|
||||
struct vm_area_struct *vma);
|
||||
|
||||
/* bochs_kms.c */
|
||||
int bochs_kms_init(struct bochs_device *bochs);
|
||||
void bochs_kms_fini(struct bochs_device *bochs);
|
||||
|
||||
/* bochs_fbdev.c */
|
||||
int bochs_fbdev_init(struct bochs_device *bochs);
|
||||
void bochs_fbdev_fini(struct bochs_device *bochs);
|
||||
|
||||
extern const struct drm_mode_config_funcs bochs_mode_funcs;
|
||||
|
|
|
@ -16,10 +16,6 @@ static int bochs_modeset = -1;
|
|||
module_param_named(modeset, bochs_modeset, int, 0444);
|
||||
MODULE_PARM_DESC(modeset, "enable/disable kernel modesetting");
|
||||
|
||||
static bool enable_fbdev = true;
|
||||
module_param_named(fbdev, enable_fbdev, bool, 0444);
|
||||
MODULE_PARM_DESC(fbdev, "register fbdev device");
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* drm interface */
|
||||
|
||||
|
@ -27,7 +23,6 @@ static void bochs_unload(struct drm_device *dev)
|
|||
{
|
||||
struct bochs_device *bochs = dev->dev_private;
|
||||
|
||||
bochs_fbdev_fini(bochs);
|
||||
bochs_kms_fini(bochs);
|
||||
bochs_mm_fini(bochs);
|
||||
bochs_hw_fini(dev);
|
||||
|
@ -58,9 +53,6 @@ static int bochs_load(struct drm_device *dev)
|
|||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (enable_fbdev)
|
||||
bochs_fbdev_init(bochs);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
|
@ -81,7 +73,8 @@ static const struct file_operations bochs_fops = {
|
|||
};
|
||||
|
||||
static struct drm_driver bochs_driver = {
|
||||
.driver_features = DRIVER_GEM | DRIVER_MODESET,
|
||||
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
|
||||
DRIVER_PRIME,
|
||||
.fops = &bochs_fops,
|
||||
.name = "bochs-drm",
|
||||
.desc = "bochs dispi vga interface (qemu stdvga)",
|
||||
|
@ -91,6 +84,14 @@ static struct drm_driver bochs_driver = {
|
|||
.gem_free_object_unlocked = bochs_gem_free_object,
|
||||
.dumb_create = bochs_dumb_create,
|
||||
.dumb_map_offset = bochs_dumb_mmap_offset,
|
||||
|
||||
.gem_prime_export = drm_gem_prime_export,
|
||||
.gem_prime_import = drm_gem_prime_import,
|
||||
.gem_prime_pin = bochs_gem_prime_pin,
|
||||
.gem_prime_unpin = bochs_gem_prime_unpin,
|
||||
.gem_prime_vmap = bochs_gem_prime_vmap,
|
||||
.gem_prime_vunmap = bochs_gem_prime_vunmap,
|
||||
.gem_prime_mmap = bochs_gem_prime_mmap,
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
@ -101,27 +102,16 @@ static int bochs_pm_suspend(struct device *dev)
|
|||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
struct bochs_device *bochs = drm_dev->dev_private;
|
||||
|
||||
drm_kms_helper_poll_disable(drm_dev);
|
||||
|
||||
drm_fb_helper_set_suspend_unlocked(&bochs->fb.helper, 1);
|
||||
|
||||
return 0;
|
||||
return drm_mode_config_helper_suspend(drm_dev);
|
||||
}
|
||||
|
||||
static int bochs_pm_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
struct bochs_device *bochs = drm_dev->dev_private;
|
||||
|
||||
drm_helper_resume_force_mode(drm_dev);
|
||||
|
||||
drm_fb_helper_set_suspend_unlocked(&bochs->fb.helper, 0);
|
||||
|
||||
drm_kms_helper_poll_enable(drm_dev);
|
||||
return 0;
|
||||
return drm_mode_config_helper_resume(drm_dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -165,6 +155,7 @@ static int bochs_pci_probe(struct pci_dev *pdev,
|
|||
if (ret)
|
||||
goto err_unload;
|
||||
|
||||
drm_fbdev_generic_setup(dev, 32);
|
||||
return ret;
|
||||
|
||||
err_unload:
|
||||
|
|
|
@ -1,163 +0,0 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "bochs.h"
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static int bochsfb_mmap(struct fb_info *info,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct drm_fb_helper *fb_helper = info->par;
|
||||
struct bochs_bo *bo = gem_to_bochs_bo(fb_helper->fb->obj[0]);
|
||||
|
||||
return ttm_fbdev_mmap(vma, &bo->bo);
|
||||
}
|
||||
|
||||
static struct fb_ops bochsfb_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
DRM_FB_HELPER_DEFAULT_OPS,
|
||||
.fb_fillrect = drm_fb_helper_cfb_fillrect,
|
||||
.fb_copyarea = drm_fb_helper_cfb_copyarea,
|
||||
.fb_imageblit = drm_fb_helper_cfb_imageblit,
|
||||
.fb_mmap = bochsfb_mmap,
|
||||
};
|
||||
|
||||
static int bochsfb_create_object(struct bochs_device *bochs,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object **gobj_p)
|
||||
{
|
||||
struct drm_device *dev = bochs->dev;
|
||||
struct drm_gem_object *gobj;
|
||||
u32 size;
|
||||
int ret = 0;
|
||||
|
||||
size = mode_cmd->pitches[0] * mode_cmd->height;
|
||||
ret = bochs_gem_create(dev, size, true, &gobj);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*gobj_p = gobj;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bochsfb_create(struct drm_fb_helper *helper,
|
||||
struct drm_fb_helper_surface_size *sizes)
|
||||
{
|
||||
struct bochs_device *bochs =
|
||||
container_of(helper, struct bochs_device, fb.helper);
|
||||
struct fb_info *info;
|
||||
struct drm_framebuffer *fb;
|
||||
struct drm_mode_fb_cmd2 mode_cmd;
|
||||
struct drm_gem_object *gobj = NULL;
|
||||
struct bochs_bo *bo = NULL;
|
||||
int size, ret;
|
||||
|
||||
if (sizes->surface_bpp != 32)
|
||||
return -EINVAL;
|
||||
|
||||
mode_cmd.width = sizes->surface_width;
|
||||
mode_cmd.height = sizes->surface_height;
|
||||
mode_cmd.pitches[0] = sizes->surface_width * 4;
|
||||
mode_cmd.pixel_format = DRM_FORMAT_HOST_XRGB8888;
|
||||
size = mode_cmd.pitches[0] * mode_cmd.height;
|
||||
|
||||
/* alloc, pin & map bo */
|
||||
ret = bochsfb_create_object(bochs, &mode_cmd, &gobj);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to create fbcon backing object %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bo = gem_to_bochs_bo(gobj);
|
||||
|
||||
ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to pin fbcon\n");
|
||||
ttm_bo_unreserve(&bo->bo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages,
|
||||
&bo->kmap);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to kmap fbcon\n");
|
||||
ttm_bo_unreserve(&bo->bo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ttm_bo_unreserve(&bo->bo);
|
||||
|
||||
/* init fb device */
|
||||
info = drm_fb_helper_alloc_fbi(helper);
|
||||
if (IS_ERR(info)) {
|
||||
DRM_ERROR("Failed to allocate fbi: %ld\n", PTR_ERR(info));
|
||||
return PTR_ERR(info);
|
||||
}
|
||||
|
||||
info->par = &bochs->fb.helper;
|
||||
|
||||
fb = drm_gem_fbdev_fb_create(bochs->dev, sizes, 0, gobj, NULL);
|
||||
if (IS_ERR(fb)) {
|
||||
DRM_ERROR("Failed to create framebuffer: %ld\n", PTR_ERR(fb));
|
||||
return PTR_ERR(fb);
|
||||
}
|
||||
|
||||
/* setup helper */
|
||||
bochs->fb.helper.fb = fb;
|
||||
|
||||
strcpy(info->fix.id, "bochsdrmfb");
|
||||
|
||||
info->fbops = &bochsfb_ops;
|
||||
|
||||
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
|
||||
drm_fb_helper_fill_var(info, &bochs->fb.helper, sizes->fb_width,
|
||||
sizes->fb_height);
|
||||
|
||||
info->screen_base = bo->kmap.virtual;
|
||||
info->screen_size = size;
|
||||
|
||||
drm_vma_offset_remove(&bo->bo.bdev->vma_manager, &bo->bo.vma_node);
|
||||
info->fix.smem_start = 0;
|
||||
info->fix.smem_len = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_fb_helper_funcs bochs_fb_helper_funcs = {
|
||||
.fb_probe = bochsfb_create,
|
||||
};
|
||||
|
||||
static struct drm_framebuffer *
|
||||
bochs_gem_fb_create(struct drm_device *dev, struct drm_file *file,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd)
|
||||
{
|
||||
if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888 &&
|
||||
mode_cmd->pixel_format != DRM_FORMAT_BGRX8888)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return drm_gem_fb_create(dev, file, mode_cmd);
|
||||
}
|
||||
|
||||
const struct drm_mode_config_funcs bochs_mode_funcs = {
|
||||
.fb_create = bochs_gem_fb_create,
|
||||
};
|
||||
|
||||
int bochs_fbdev_init(struct bochs_device *bochs)
|
||||
{
|
||||
return drm_fb_helper_fbdev_setup(bochs->dev, &bochs->fb.helper,
|
||||
&bochs_fb_helper_funcs, 32, 1);
|
||||
}
|
||||
|
||||
void bochs_fbdev_fini(struct bochs_device *bochs)
|
||||
{
|
||||
drm_fb_helper_fbdev_teardown(bochs->dev);
|
||||
}
|
|
@ -204,8 +204,7 @@ void bochs_hw_fini(struct drm_device *dev)
|
|||
}
|
||||
|
||||
void bochs_hw_setmode(struct bochs_device *bochs,
|
||||
struct drm_display_mode *mode,
|
||||
const struct drm_format_info *format)
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
bochs->xres = mode->hdisplay;
|
||||
bochs->yres = mode->vdisplay;
|
||||
|
@ -213,12 +212,8 @@ void bochs_hw_setmode(struct bochs_device *bochs,
|
|||
bochs->stride = mode->hdisplay * (bochs->bpp / 8);
|
||||
bochs->yres_virtual = bochs->fb_size / bochs->stride;
|
||||
|
||||
DRM_DEBUG_DRIVER("%dx%d @ %d bpp, format %c%c%c%c, vy %d\n",
|
||||
DRM_DEBUG_DRIVER("%dx%d @ %d bpp, vy %d\n",
|
||||
bochs->xres, bochs->yres, bochs->bpp,
|
||||
(format->format >> 0) & 0xff,
|
||||
(format->format >> 8) & 0xff,
|
||||
(format->format >> 16) & 0xff,
|
||||
(format->format >> 24) & 0xff,
|
||||
bochs->yres_virtual);
|
||||
|
||||
bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */
|
||||
|
@ -236,6 +231,16 @@ void bochs_hw_setmode(struct bochs_device *bochs,
|
|||
|
||||
bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,
|
||||
VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
|
||||
}
|
||||
|
||||
void bochs_hw_setformat(struct bochs_device *bochs,
|
||||
const struct drm_format_info *format)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("format %c%c%c%c\n",
|
||||
(format->format >> 0) & 0xff,
|
||||
(format->format >> 8) & 0xff,
|
||||
(format->format >> 16) & 0xff,
|
||||
(format->format >> 24) & 0xff);
|
||||
|
||||
switch (format->format) {
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
*/
|
||||
|
||||
#include "bochs.h"
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <drm/drm_atomic_uapi.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
|
||||
static int defx = 1024;
|
||||
static int defy = 768;
|
||||
|
@ -18,115 +21,51 @@ MODULE_PARM_DESC(defy, "default y resolution");
|
|||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static void bochs_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case DRM_MODE_DPMS_ON:
|
||||
case DRM_MODE_DPMS_STANDBY:
|
||||
case DRM_MODE_DPMS_SUSPEND:
|
||||
case DRM_MODE_DPMS_OFF:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
{
|
||||
struct bochs_device *bochs =
|
||||
container_of(crtc, struct bochs_device, crtc);
|
||||
struct bochs_bo *bo;
|
||||
u64 gpu_addr = 0;
|
||||
int ret;
|
||||
|
||||
if (old_fb) {
|
||||
bo = gem_to_bochs_bo(old_fb->obj[0]);
|
||||
ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to reserve old_fb bo\n");
|
||||
} else {
|
||||
bochs_bo_unpin(bo);
|
||||
ttm_bo_unreserve(&bo->bo);
|
||||
}
|
||||
}
|
||||
|
||||
if (WARN_ON(crtc->primary->fb == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
bo = gem_to_bochs_bo(crtc->primary->fb->obj[0]);
|
||||
ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
|
||||
if (ret) {
|
||||
ttm_bo_unreserve(&bo->bo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ttm_bo_unreserve(&bo->bo);
|
||||
bochs_hw_setbase(bochs, x, y, gpu_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bochs_crtc_mode_set(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode,
|
||||
int x, int y, struct drm_framebuffer *old_fb)
|
||||
static void bochs_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
||||
{
|
||||
struct bochs_device *bochs =
|
||||
container_of(crtc, struct bochs_device, crtc);
|
||||
|
||||
if (WARN_ON(crtc->primary->fb == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
bochs_hw_setmode(bochs, mode, crtc->primary->fb->format);
|
||||
bochs_crtc_mode_set_base(crtc, x, y, old_fb);
|
||||
return 0;
|
||||
bochs_hw_setmode(bochs, &crtc->mode);
|
||||
}
|
||||
|
||||
static void bochs_crtc_prepare(struct drm_crtc *crtc)
|
||||
static void bochs_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_crtc_state)
|
||||
{
|
||||
}
|
||||
|
||||
static void bochs_crtc_commit(struct drm_crtc *crtc)
|
||||
static void bochs_crtc_atomic_flush(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_crtc_state)
|
||||
{
|
||||
}
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_pending_vblank_event *event;
|
||||
|
||||
static int bochs_crtc_page_flip(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_pending_vblank_event *event,
|
||||
uint32_t page_flip_flags,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
struct bochs_device *bochs =
|
||||
container_of(crtc, struct bochs_device, crtc);
|
||||
struct drm_framebuffer *old_fb = crtc->primary->fb;
|
||||
unsigned long irqflags;
|
||||
if (crtc->state && crtc->state->event) {
|
||||
unsigned long irqflags;
|
||||
|
||||
crtc->primary->fb = fb;
|
||||
bochs_crtc_mode_set_base(crtc, 0, 0, old_fb);
|
||||
if (event) {
|
||||
spin_lock_irqsave(&bochs->dev->event_lock, irqflags);
|
||||
spin_lock_irqsave(&dev->event_lock, irqflags);
|
||||
event = crtc->state->event;
|
||||
crtc->state->event = NULL;
|
||||
drm_crtc_send_vblank_event(crtc, event);
|
||||
spin_unlock_irqrestore(&bochs->dev->event_lock, irqflags);
|
||||
spin_unlock_irqrestore(&dev->event_lock, irqflags);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* These provide the minimum set of functions required to handle a CRTC */
|
||||
static const struct drm_crtc_funcs bochs_crtc_funcs = {
|
||||
.set_config = drm_crtc_helper_set_config,
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
.destroy = drm_crtc_cleanup,
|
||||
.page_flip = bochs_crtc_page_flip,
|
||||
.page_flip = drm_atomic_helper_page_flip,
|
||||
.reset = drm_atomic_helper_crtc_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_helper_funcs bochs_helper_funcs = {
|
||||
.dpms = bochs_crtc_dpms,
|
||||
.mode_set = bochs_crtc_mode_set,
|
||||
.mode_set_base = bochs_crtc_mode_set_base,
|
||||
.prepare = bochs_crtc_prepare,
|
||||
.commit = bochs_crtc_commit,
|
||||
.mode_set_nofb = bochs_crtc_mode_set_nofb,
|
||||
.atomic_enable = bochs_crtc_atomic_enable,
|
||||
.atomic_flush = bochs_crtc_atomic_flush,
|
||||
};
|
||||
|
||||
static const uint32_t bochs_formats[] = {
|
||||
|
@ -134,6 +73,59 @@ static const uint32_t bochs_formats[] = {
|
|||
DRM_FORMAT_BGRX8888,
|
||||
};
|
||||
|
||||
static void bochs_plane_atomic_update(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct bochs_device *bochs = plane->dev->dev_private;
|
||||
struct bochs_bo *bo;
|
||||
|
||||
if (!plane->state->fb)
|
||||
return;
|
||||
bo = gem_to_bochs_bo(plane->state->fb->obj[0]);
|
||||
bochs_hw_setbase(bochs,
|
||||
plane->state->crtc_x,
|
||||
plane->state->crtc_y,
|
||||
bo->bo.offset);
|
||||
bochs_hw_setformat(bochs, plane->state->fb->format);
|
||||
}
|
||||
|
||||
static int bochs_plane_prepare_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *new_state)
|
||||
{
|
||||
struct bochs_bo *bo;
|
||||
|
||||
if (!new_state->fb)
|
||||
return 0;
|
||||
bo = gem_to_bochs_bo(new_state->fb->obj[0]);
|
||||
return bochs_bo_pin(bo, TTM_PL_FLAG_VRAM);
|
||||
}
|
||||
|
||||
static void bochs_plane_cleanup_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct bochs_bo *bo;
|
||||
|
||||
if (!old_state->fb)
|
||||
return;
|
||||
bo = gem_to_bochs_bo(old_state->fb->obj[0]);
|
||||
bochs_bo_unpin(bo);
|
||||
}
|
||||
|
||||
static const struct drm_plane_helper_funcs bochs_plane_helper_funcs = {
|
||||
.atomic_update = bochs_plane_atomic_update,
|
||||
.prepare_fb = bochs_plane_prepare_fb,
|
||||
.cleanup_fb = bochs_plane_cleanup_fb,
|
||||
};
|
||||
|
||||
static const struct drm_plane_funcs bochs_plane_funcs = {
|
||||
.update_plane = drm_atomic_helper_update_plane,
|
||||
.disable_plane = drm_atomic_helper_disable_plane,
|
||||
.destroy = drm_primary_helper_destroy,
|
||||
.reset = drm_atomic_helper_plane_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
|
||||
};
|
||||
|
||||
static struct drm_plane *bochs_primary_plane(struct drm_device *dev)
|
||||
{
|
||||
struct drm_plane *primary;
|
||||
|
@ -146,16 +138,17 @@ static struct drm_plane *bochs_primary_plane(struct drm_device *dev)
|
|||
}
|
||||
|
||||
ret = drm_universal_plane_init(dev, primary, 0,
|
||||
&drm_primary_helper_funcs,
|
||||
&bochs_plane_funcs,
|
||||
bochs_formats,
|
||||
ARRAY_SIZE(bochs_formats),
|
||||
NULL,
|
||||
DRM_PLANE_TYPE_PRIMARY, NULL);
|
||||
if (ret) {
|
||||
kfree(primary);
|
||||
primary = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drm_plane_helper_add(primary, &bochs_plane_helper_funcs);
|
||||
return primary;
|
||||
}
|
||||
|
||||
|
@ -170,31 +163,6 @@ static void bochs_crtc_init(struct drm_device *dev)
|
|||
drm_crtc_helper_add(crtc, &bochs_helper_funcs);
|
||||
}
|
||||
|
||||
static void bochs_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
}
|
||||
|
||||
static void bochs_encoder_dpms(struct drm_encoder *encoder, int state)
|
||||
{
|
||||
}
|
||||
|
||||
static void bochs_encoder_prepare(struct drm_encoder *encoder)
|
||||
{
|
||||
}
|
||||
|
||||
static void bochs_encoder_commit(struct drm_encoder *encoder)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs bochs_encoder_helper_funcs = {
|
||||
.dpms = bochs_encoder_dpms,
|
||||
.mode_set = bochs_encoder_mode_set,
|
||||
.prepare = bochs_encoder_prepare,
|
||||
.commit = bochs_encoder_commit,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_funcs bochs_encoder_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
@ -207,7 +175,6 @@ static void bochs_encoder_init(struct drm_device *dev)
|
|||
encoder->possible_crtcs = 0x1;
|
||||
drm_encoder_init(dev, encoder, &bochs_encoder_encoder_funcs,
|
||||
DRM_MODE_ENCODER_DAC, NULL);
|
||||
drm_encoder_helper_add(encoder, &bochs_encoder_helper_funcs);
|
||||
}
|
||||
|
||||
|
||||
|
@ -266,6 +233,9 @@ static const struct drm_connector_funcs bochs_connector_connector_funcs = {
|
|||
.dpms = drm_helper_connector_dpms,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = drm_connector_cleanup,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
static void bochs_connector_init(struct drm_device *dev)
|
||||
|
@ -287,6 +257,22 @@ static void bochs_connector_init(struct drm_device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
static struct drm_framebuffer *
|
||||
bochs_gem_fb_create(struct drm_device *dev, struct drm_file *file,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd)
|
||||
{
|
||||
if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888 &&
|
||||
mode_cmd->pixel_format != DRM_FORMAT_BGRX8888)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return drm_gem_fb_create(dev, file, mode_cmd);
|
||||
}
|
||||
|
||||
const struct drm_mode_config_funcs bochs_mode_funcs = {
|
||||
.fb_create = bochs_gem_fb_create,
|
||||
.atomic_check = drm_atomic_helper_check,
|
||||
.atomic_commit = drm_atomic_helper_commit,
|
||||
};
|
||||
|
||||
int bochs_kms_init(struct bochs_device *bochs)
|
||||
{
|
||||
|
@ -309,6 +295,8 @@ int bochs_kms_init(struct bochs_device *bochs)
|
|||
drm_connector_attach_encoder(&bochs->connector,
|
||||
&bochs->encoder);
|
||||
|
||||
drm_mode_config_reset(bochs->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -210,33 +210,28 @@ static void bochs_ttm_placement(struct bochs_bo *bo, int domain)
|
|||
bo->placement.num_busy_placement = c;
|
||||
}
|
||||
|
||||
static inline u64 bochs_bo_gpu_offset(struct bochs_bo *bo)
|
||||
{
|
||||
return bo->bo.offset;
|
||||
}
|
||||
|
||||
int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr)
|
||||
int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag)
|
||||
{
|
||||
struct ttm_operation_ctx ctx = { false, false };
|
||||
int i, ret;
|
||||
|
||||
if (bo->pin_count) {
|
||||
bo->pin_count++;
|
||||
if (gpu_addr)
|
||||
*gpu_addr = bochs_bo_gpu_offset(bo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bochs_ttm_placement(bo, pl_flag);
|
||||
for (i = 0; i < bo->placement.num_placement; i++)
|
||||
bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
|
||||
ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx);
|
||||
ttm_bo_unreserve(&bo->bo);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bo->pin_count = 1;
|
||||
if (gpu_addr)
|
||||
*gpu_addr = bochs_bo_gpu_offset(bo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -256,7 +251,11 @@ int bochs_bo_unpin(struct bochs_bo *bo)
|
|||
|
||||
for (i = 0; i < bo->placement.num_placement; i++)
|
||||
bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
|
||||
ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx);
|
||||
ttm_bo_unreserve(&bo->bo);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -396,3 +395,52 @@ int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
|
|||
drm_gem_object_put_unlocked(obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
int bochs_gem_prime_pin(struct drm_gem_object *obj)
|
||||
{
|
||||
struct bochs_bo *bo = gem_to_bochs_bo(obj);
|
||||
|
||||
return bochs_bo_pin(bo, TTM_PL_FLAG_VRAM);
|
||||
}
|
||||
|
||||
void bochs_gem_prime_unpin(struct drm_gem_object *obj)
|
||||
{
|
||||
struct bochs_bo *bo = gem_to_bochs_bo(obj);
|
||||
|
||||
bochs_bo_unpin(bo);
|
||||
}
|
||||
|
||||
void *bochs_gem_prime_vmap(struct drm_gem_object *obj)
|
||||
{
|
||||
struct bochs_bo *bo = gem_to_bochs_bo(obj);
|
||||
bool is_iomem;
|
||||
int ret;
|
||||
|
||||
ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM);
|
||||
if (ret)
|
||||
return NULL;
|
||||
ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
|
||||
if (ret) {
|
||||
bochs_bo_unpin(bo);
|
||||
return NULL;
|
||||
}
|
||||
return ttm_kmap_obj_virtual(&bo->kmap, &is_iomem);
|
||||
}
|
||||
|
||||
void bochs_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
|
||||
{
|
||||
struct bochs_bo *bo = gem_to_bochs_bo(obj);
|
||||
|
||||
ttm_bo_kunmap(&bo->kmap);
|
||||
bochs_bo_unpin(bo);
|
||||
}
|
||||
|
||||
int bochs_gem_prime_mmap(struct drm_gem_object *obj,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct bochs_bo *bo = gem_to_bochs_bo(obj);
|
||||
|
||||
return ttm_fbdev_mmap(vma, &bo->bo);
|
||||
}
|
||||
|
|
|
@ -1094,8 +1094,9 @@ static void anx78xx_bridge_mode_set(struct drm_bridge *bridge,
|
|||
|
||||
mutex_lock(&anx78xx->lock);
|
||||
|
||||
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, adjusted_mode,
|
||||
false);
|
||||
err = drm_hdmi_avi_infoframe_from_display_mode(&frame,
|
||||
&anx78xx->connector,
|
||||
adjusted_mode);
|
||||
if (err) {
|
||||
DRM_ERROR("Failed to setup AVI infoframe: %d\n", err);
|
||||
goto unlock;
|
||||
|
|
|
@ -134,8 +134,8 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
|
|||
};
|
||||
|
||||
/**
|
||||
* drm_panel_bridge_add - Creates a drm_bridge and drm_connector that
|
||||
* just calls the appropriate functions from drm_panel.
|
||||
* drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that
|
||||
* just calls the appropriate functions from &drm_panel.
|
||||
*
|
||||
* @panel: The drm_panel being wrapped. Must be non-NULL.
|
||||
* @connector_type: The DRM_MODE_CONNECTOR_* for the connector to be
|
||||
|
@ -149,9 +149,12 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
|
|||
* passed to drm_bridge_attach(). The drm_panel_prepare() and related
|
||||
* functions can be dropped from the encoder driver (they're now
|
||||
* called by the KMS helpers before calling into the encoder), along
|
||||
* with connector creation. When done with the bridge,
|
||||
* drm_bridge_detach() should be called as normal, then
|
||||
* with connector creation. When done with the bridge (after
|
||||
* drm_mode_config_cleanup() if the bridge has already been attached), then
|
||||
* drm_panel_bridge_remove() to free it.
|
||||
*
|
||||
* See devm_drm_panel_bridge_add() for an automatically manged version of this
|
||||
* function.
|
||||
*/
|
||||
struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
|
||||
u32 connector_type)
|
||||
|
@ -210,6 +213,17 @@ static void devm_drm_panel_bridge_release(struct device *dev, void *res)
|
|||
drm_panel_bridge_remove(*bridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector
|
||||
* that just calls the appropriate functions from &drm_panel.
|
||||
* @dev: device to tie the bridge lifetime to
|
||||
* @panel: The drm_panel being wrapped. Must be non-NULL.
|
||||
* @connector_type: The DRM_MODE_CONNECTOR_* for the connector to be
|
||||
* created.
|
||||
*
|
||||
* This is the managed version of drm_panel_bridge_add() which automatically
|
||||
* calls drm_panel_bridge_remove() when @dev is unbound.
|
||||
*/
|
||||
struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
|
||||
struct drm_panel *panel,
|
||||
u32 connector_type)
|
||||
|
|
|
@ -258,7 +258,8 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge,
|
|||
if (ret)
|
||||
return;
|
||||
|
||||
ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, adj, false);
|
||||
ret = drm_hdmi_avi_infoframe_from_display_mode(&frame,
|
||||
&sii902x->connector, adj);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("couldn't fill AVI infoframe\n");
|
||||
return;
|
||||
|
|
|
@ -1104,8 +1104,7 @@ static void sii8620_set_infoframes(struct sii8620 *ctx,
|
|||
int ret;
|
||||
|
||||
ret = drm_hdmi_avi_infoframe_from_display_mode(&frm.avi,
|
||||
mode,
|
||||
true);
|
||||
NULL, mode);
|
||||
if (ctx->use_packed_pixel)
|
||||
frm.avi.colorspace = HDMI_COLORSPACE_YUV422;
|
||||
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
* Copyright (c) 2017 Renesas Solutions Corp.
|
||||
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
*/
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <drm/bridge/dw_hdmi.h>
|
||||
|
||||
#include <sound/hdmi-codec.h>
|
||||
|
|
|
@ -1344,7 +1344,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
|
|||
u8 val;
|
||||
|
||||
/* Initialise info frame from DRM mode */
|
||||
drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
|
||||
drm_hdmi_avi_infoframe_from_display_mode(&frame,
|
||||
&hdmi->connector, mode);
|
||||
|
||||
if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
|
||||
frame.colorspace = HDMI_COLORSPACE_YUV444;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*/
|
||||
#include <linux/module.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_util.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
||||
|
@ -256,6 +257,8 @@ static int cirrus_fbdev_destroy(struct drm_device *dev,
|
|||
{
|
||||
struct drm_framebuffer *gfb = gfbdev->gfb;
|
||||
|
||||
drm_helper_force_disable_all(dev);
|
||||
|
||||
drm_fb_helper_unregister_fbi(&gfbdev->helper);
|
||||
|
||||
vfree(gfbdev->sysram);
|
||||
|
|
|
@ -93,15 +93,6 @@ struct drm_crtc *drm_crtc_from_index(struct drm_device *dev, int idx)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_crtc_from_index);
|
||||
|
||||
/**
|
||||
* drm_crtc_force_disable - Forcibly turn off a CRTC
|
||||
* @crtc: CRTC to turn off
|
||||
*
|
||||
* Note: This should only be used by non-atomic legacy drivers.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, error code on failure.
|
||||
*/
|
||||
int drm_crtc_force_disable(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_mode_set set = {
|
||||
|
@ -112,38 +103,6 @@ int drm_crtc_force_disable(struct drm_crtc *crtc)
|
|||
|
||||
return drm_mode_set_config_internal(&set);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_crtc_force_disable);
|
||||
|
||||
/**
|
||||
* drm_crtc_force_disable_all - Forcibly turn off all enabled CRTCs
|
||||
* @dev: DRM device whose CRTCs to turn off
|
||||
*
|
||||
* Drivers may want to call this on unload to ensure that all displays are
|
||||
* unlit and the GPU is in a consistent, low power state. Takes modeset locks.
|
||||
*
|
||||
* Note: This should only be used by non-atomic legacy drivers. For an atomic
|
||||
* version look at drm_atomic_helper_shutdown().
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, error code on failure.
|
||||
*/
|
||||
int drm_crtc_force_disable_all(struct drm_device *dev)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
int ret = 0;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
drm_for_each_crtc(crtc, dev)
|
||||
if (crtc->enabled) {
|
||||
ret = drm_crtc_force_disable(crtc);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
drm_modeset_unlock_all(dev);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_crtc_force_disable_all);
|
||||
|
||||
static unsigned int drm_num_crtcs(struct drm_device *dev)
|
||||
{
|
||||
|
|
|
@ -93,6 +93,8 @@ bool drm_helper_encoder_in_use(struct drm_encoder *encoder)
|
|||
struct drm_connector_list_iter conn_iter;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
|
||||
WARN_ON(drm_drv_uses_atomic_modeset(dev));
|
||||
|
||||
/*
|
||||
* We can expect this mutex to be locked if we are not panicking.
|
||||
* Locking is currently fubar in the panic handler.
|
||||
|
@ -131,6 +133,8 @@ bool drm_helper_crtc_in_use(struct drm_crtc *crtc)
|
|||
struct drm_encoder *encoder;
|
||||
struct drm_device *dev = crtc->dev;
|
||||
|
||||
WARN_ON(drm_drv_uses_atomic_modeset(dev));
|
||||
|
||||
/*
|
||||
* We can expect this mutex to be locked if we are not panicking.
|
||||
* Locking is currently fubar in the panic handler.
|
||||
|
@ -212,8 +216,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev)
|
|||
*/
|
||||
void drm_helper_disable_unused_functions(struct drm_device *dev)
|
||||
{
|
||||
if (drm_core_check_feature(dev, DRIVER_ATOMIC))
|
||||
DRM_ERROR("Called for atomic driver, this is not what you want.\n");
|
||||
WARN_ON(drm_drv_uses_atomic_modeset(dev));
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
__drm_helper_disable_unused_functions(dev);
|
||||
|
@ -281,6 +284,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
|||
struct drm_encoder *encoder;
|
||||
bool ret = true;
|
||||
|
||||
WARN_ON(drm_drv_uses_atomic_modeset(dev));
|
||||
|
||||
drm_warn_on_modeset_not_all_locked(dev);
|
||||
|
||||
saved_enabled = crtc->enabled;
|
||||
|
@ -386,9 +391,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
|||
if (!encoder_funcs)
|
||||
continue;
|
||||
|
||||
DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n",
|
||||
encoder->base.id, encoder->name,
|
||||
mode->base.id, mode->name);
|
||||
DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%s]\n",
|
||||
encoder->base.id, encoder->name, mode->name);
|
||||
if (encoder_funcs->mode_set)
|
||||
encoder_funcs->mode_set(encoder, mode, adjusted_mode);
|
||||
|
||||
|
@ -540,6 +544,9 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set,
|
|||
|
||||
crtc_funcs = set->crtc->helper_private;
|
||||
|
||||
dev = set->crtc->dev;
|
||||
WARN_ON(drm_drv_uses_atomic_modeset(dev));
|
||||
|
||||
if (!set->mode)
|
||||
set->fb = NULL;
|
||||
|
||||
|
@ -555,8 +562,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set,
|
|||
return 0;
|
||||
}
|
||||
|
||||
dev = set->crtc->dev;
|
||||
|
||||
drm_warn_on_modeset_not_all_locked(dev);
|
||||
|
||||
/*
|
||||
|
@ -875,6 +880,8 @@ int drm_helper_connector_dpms(struct drm_connector *connector, int mode)
|
|||
struct drm_crtc *crtc = encoder ? encoder->crtc : NULL;
|
||||
int old_dpms, encoder_dpms = DRM_MODE_DPMS_OFF;
|
||||
|
||||
WARN_ON(drm_drv_uses_atomic_modeset(connector->dev));
|
||||
|
||||
if (mode == connector->dpms)
|
||||
return 0;
|
||||
|
||||
|
@ -946,6 +953,8 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
|
|||
int encoder_dpms;
|
||||
bool ret;
|
||||
|
||||
WARN_ON(drm_drv_uses_atomic_modeset(dev));
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
drm_for_each_crtc(crtc, dev) {
|
||||
|
||||
|
@ -984,3 +993,38 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
|
|||
drm_modeset_unlock_all(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_helper_resume_force_mode);
|
||||
|
||||
/**
|
||||
* drm_helper_force_disable_all - Forcibly turn off all enabled CRTCs
|
||||
* @dev: DRM device whose CRTCs to turn off
|
||||
*
|
||||
* Drivers may want to call this on unload to ensure that all displays are
|
||||
* unlit and the GPU is in a consistent, low power state. Takes modeset locks.
|
||||
*
|
||||
* Note: This should only be used by non-atomic legacy drivers. For an atomic
|
||||
* version look at drm_atomic_helper_shutdown().
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, error code on failure.
|
||||
*/
|
||||
int drm_helper_force_disable_all(struct drm_device *dev)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
int ret = 0;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
drm_for_each_crtc(crtc, dev)
|
||||
if (crtc->enabled) {
|
||||
struct drm_mode_set set = {
|
||||
.crtc = crtc,
|
||||
};
|
||||
|
||||
ret = drm_mode_set_config_internal(&set);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
drm_modeset_unlock_all(dev);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_helper_force_disable_all);
|
||||
|
|
|
@ -50,6 +50,7 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc,
|
|||
const struct drm_framebuffer *fb);
|
||||
int drm_crtc_register_all(struct drm_device *dev);
|
||||
void drm_crtc_unregister_all(struct drm_device *dev);
|
||||
int drm_crtc_force_disable(struct drm_crtc *crtc);
|
||||
|
||||
struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc);
|
||||
|
||||
|
|
|
@ -154,6 +154,7 @@ u8 drm_dp_link_rate_to_bw_code(int link_rate)
|
|||
default:
|
||||
WARN(1, "unknown DP link rate %d, using %x\n", link_rate,
|
||||
DP_LINK_BW_1_62);
|
||||
/* fall through */
|
||||
case 162000:
|
||||
return DP_LINK_BW_1_62;
|
||||
case 270000:
|
||||
|
@ -171,6 +172,7 @@ int drm_dp_bw_code_to_link_rate(u8 link_bw)
|
|||
switch (link_bw) {
|
||||
default:
|
||||
WARN(1, "unknown DP link BW code %x, using 162000\n", link_bw);
|
||||
/* fall through */
|
||||
case DP_LINK_BW_1_62:
|
||||
return 162000;
|
||||
case DP_LINK_BW_2_7:
|
||||
|
@ -552,6 +554,7 @@ int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
|||
case DP_DS_16BPC:
|
||||
return 16;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -264,14 +264,13 @@ void drm_minor_release(struct drm_minor *minor)
|
|||
* DOC: driver instance overview
|
||||
*
|
||||
* A device instance for a drm driver is represented by &struct drm_device. This
|
||||
* is allocated with drm_dev_alloc(), usually from bus-specific ->probe()
|
||||
* is initialized with drm_dev_init(), usually from bus-specific ->probe()
|
||||
* callbacks implemented by the driver. The driver then needs to initialize all
|
||||
* the various subsystems for the drm device like memory management, vblank
|
||||
* handling, modesetting support and intial output configuration plus obviously
|
||||
* initialize all the corresponding hardware bits. An important part of this is
|
||||
* also calling drm_dev_set_unique() to set the userspace-visible unique name of
|
||||
* this device instance. Finally when everything is up and running and ready for
|
||||
* userspace the device instance can be published using drm_dev_register().
|
||||
* initialize all the corresponding hardware bits. Finally when everything is up
|
||||
* and running and ready for userspace the device instance can be published
|
||||
* using drm_dev_register().
|
||||
*
|
||||
* There is also deprecated support for initalizing device instances using
|
||||
* bus-specific helpers and the &drm_driver.load callback. But due to
|
||||
|
@ -287,9 +286,6 @@ void drm_minor_release(struct drm_minor *minor)
|
|||
* Note that the lifetime rules for &drm_device instance has still a lot of
|
||||
* historical baggage. Hence use the reference counting provided by
|
||||
* drm_dev_get() and drm_dev_put() only carefully.
|
||||
*
|
||||
* It is recommended that drivers embed &struct drm_device into their own device
|
||||
* structure, which is supported through drm_dev_init().
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -475,6 +471,9 @@ static void drm_fs_inode_free(struct inode *inode)
|
|||
* The initial ref-count of the object is 1. Use drm_dev_get() and
|
||||
* drm_dev_put() to take and drop further ref-counts.
|
||||
*
|
||||
* It is recommended that drivers embed &struct drm_device into their own device
|
||||
* structure.
|
||||
*
|
||||
* Drivers that do not want to allocate their own device struct
|
||||
* embedding &struct drm_device can call drm_dev_alloc() instead. For drivers
|
||||
* that do embed &struct drm_device it must be placed first in the overall
|
||||
|
@ -765,7 +764,7 @@ static void remove_compat_control_link(struct drm_device *dev)
|
|||
* @flags: Flags passed to the driver's .load() function
|
||||
*
|
||||
* Register the DRM device @dev with the system, advertise device to user-space
|
||||
* and start normal device operation. @dev must be allocated via drm_dev_alloc()
|
||||
* and start normal device operation. @dev must be initialized via drm_dev_init()
|
||||
* previously.
|
||||
*
|
||||
* Never call this twice on any device!
|
||||
|
@ -877,9 +876,9 @@ EXPORT_SYMBOL(drm_dev_unregister);
|
|||
* @dev: device of which to set the unique name
|
||||
* @name: unique name
|
||||
*
|
||||
* Sets the unique name of a DRM device using the specified string. Drivers
|
||||
* can use this at driver probe time if the unique name of the devices they
|
||||
* drive is static.
|
||||
* Sets the unique name of a DRM device using the specified string. This is
|
||||
* already done by drm_dev_init(), drivers should only override the default
|
||||
* unique name for backwards compatibility reasons.
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
|
|
|
@ -3641,6 +3641,20 @@ static bool cea_db_is_hdmi_forum_vsdb(const u8 *db)
|
|||
return oui == HDMI_FORUM_IEEE_OUI;
|
||||
}
|
||||
|
||||
static bool cea_db_is_vcdb(const u8 *db)
|
||||
{
|
||||
if (cea_db_tag(db) != USE_EXTENDED_TAG)
|
||||
return false;
|
||||
|
||||
if (cea_db_payload_len(db) != 2)
|
||||
return false;
|
||||
|
||||
if (cea_db_extended_tag(db) != EXT_VIDEO_CAPABILITY_BLOCK)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool cea_db_is_y420cmdb(const u8 *db)
|
||||
{
|
||||
if (cea_db_tag(db) != USE_EXTENDED_TAG)
|
||||
|
@ -4223,41 +4237,6 @@ end:
|
|||
}
|
||||
EXPORT_SYMBOL(drm_detect_monitor_audio);
|
||||
|
||||
/**
|
||||
* drm_rgb_quant_range_selectable - is RGB quantization range selectable?
|
||||
* @edid: EDID block to scan
|
||||
*
|
||||
* Check whether the monitor reports the RGB quantization range selection
|
||||
* as supported. The AVI infoframe can then be used to inform the monitor
|
||||
* which quantization range (full or limited) is used.
|
||||
*
|
||||
* Return: True if the RGB quantization range is selectable, false otherwise.
|
||||
*/
|
||||
bool drm_rgb_quant_range_selectable(struct edid *edid)
|
||||
{
|
||||
u8 *edid_ext;
|
||||
int i, start, end;
|
||||
|
||||
edid_ext = drm_find_cea_extension(edid);
|
||||
if (!edid_ext)
|
||||
return false;
|
||||
|
||||
if (cea_db_offsets(edid_ext, &start, &end))
|
||||
return false;
|
||||
|
||||
for_each_cea_db(edid_ext, i, start, end) {
|
||||
if (cea_db_tag(&edid_ext[i]) == USE_EXTENDED_TAG &&
|
||||
cea_db_payload_len(&edid_ext[i]) == 2 &&
|
||||
cea_db_extended_tag(&edid_ext[i]) ==
|
||||
EXT_VIDEO_CAPABILITY_BLOCK) {
|
||||
DRM_DEBUG_KMS("CEA VCDB 0x%02x\n", edid_ext[i + 2]);
|
||||
return edid_ext[i + 2] & EDID_CEA_VCDB_QS;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
|
||||
|
||||
/**
|
||||
* drm_default_rgb_quant_range - default RGB quantization range
|
||||
|
@ -4278,6 +4257,16 @@ drm_default_rgb_quant_range(const struct drm_display_mode *mode)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_default_rgb_quant_range);
|
||||
|
||||
static void drm_parse_vcdb(struct drm_connector *connector, const u8 *db)
|
||||
{
|
||||
struct drm_display_info *info = &connector->display_info;
|
||||
|
||||
DRM_DEBUG_KMS("CEA VCDB 0x%02x\n", db[2]);
|
||||
|
||||
if (db[2] & EDID_CEA_VCDB_QS)
|
||||
info->rgb_quant_range_selectable = true;
|
||||
}
|
||||
|
||||
static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector,
|
||||
const u8 *db)
|
||||
{
|
||||
|
@ -4452,6 +4441,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
|
|||
drm_parse_hdmi_forum_vsdb(connector, db);
|
||||
if (cea_db_is_y420cmdb(db))
|
||||
drm_parse_y420cmdb_bitmap(connector, db);
|
||||
if (cea_db_is_vcdb(db))
|
||||
drm_parse_vcdb(connector, db);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4472,6 +4463,7 @@ drm_reset_display_info(struct drm_connector *connector)
|
|||
info->max_tmds_clock = 0;
|
||||
info->dvi_dual = false;
|
||||
info->has_hdmi_infoframe = false;
|
||||
info->rgb_quant_range_selectable = false;
|
||||
memset(&info->hdmi, 0, sizeof(info->hdmi));
|
||||
|
||||
info->non_desktop = 0;
|
||||
|
@ -4830,19 +4822,32 @@ void drm_set_preferred_mode(struct drm_connector *connector,
|
|||
}
|
||||
EXPORT_SYMBOL(drm_set_preferred_mode);
|
||||
|
||||
static bool is_hdmi2_sink(struct drm_connector *connector)
|
||||
{
|
||||
/*
|
||||
* FIXME: sil-sii8620 doesn't have a connector around when
|
||||
* we need one, so we have to be prepared for a NULL connector.
|
||||
*/
|
||||
if (!connector)
|
||||
return true;
|
||||
|
||||
return connector->display_info.hdmi.scdc.supported ||
|
||||
connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with
|
||||
* data from a DRM display mode
|
||||
* @frame: HDMI AVI infoframe
|
||||
* @connector: the connector
|
||||
* @mode: DRM display mode
|
||||
* @is_hdmi2_sink: Sink is HDMI 2.0 compliant
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int
|
||||
drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
|
||||
const struct drm_display_mode *mode,
|
||||
bool is_hdmi2_sink)
|
||||
struct drm_connector *connector,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
enum hdmi_picture_aspect picture_aspect;
|
||||
int err;
|
||||
|
@ -4864,7 +4869,7 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
|
|||
* HDMI 2.0 VIC range: 1 <= VIC <= 107 (CEA-861-F). So we
|
||||
* have to make sure we dont break HDMI 1.4 sinks.
|
||||
*/
|
||||
if (!is_hdmi2_sink && frame->video_code > 64)
|
||||
if (!is_hdmi2_sink(connector) && frame->video_code > 64)
|
||||
frame->video_code = 0;
|
||||
|
||||
/*
|
||||
|
@ -4923,22 +4928,18 @@ EXPORT_SYMBOL(drm_hdmi_avi_infoframe_from_display_mode);
|
|||
* drm_hdmi_avi_infoframe_quant_range() - fill the HDMI AVI infoframe
|
||||
* quantization range information
|
||||
* @frame: HDMI AVI infoframe
|
||||
* @connector: the connector
|
||||
* @mode: DRM display mode
|
||||
* @rgb_quant_range: RGB quantization range (Q)
|
||||
* @rgb_quant_range_selectable: Sink support selectable RGB quantization range (QS)
|
||||
* @is_hdmi2_sink: HDMI 2.0 sink, which has different default recommendations
|
||||
*
|
||||
* Note that @is_hdmi2_sink can be derived by looking at the
|
||||
* &drm_scdc.supported flag stored in &drm_hdmi_info.scdc,
|
||||
* &drm_display_info.hdmi, which can be found in &drm_connector.display_info.
|
||||
*/
|
||||
void
|
||||
drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame,
|
||||
struct drm_connector *connector,
|
||||
const struct drm_display_mode *mode,
|
||||
enum hdmi_quantization_range rgb_quant_range,
|
||||
bool rgb_quant_range_selectable,
|
||||
bool is_hdmi2_sink)
|
||||
enum hdmi_quantization_range rgb_quant_range)
|
||||
{
|
||||
const struct drm_display_info *info = &connector->display_info;
|
||||
|
||||
/*
|
||||
* CEA-861:
|
||||
* "A Source shall not send a non-zero Q value that does not correspond
|
||||
|
@ -4949,7 +4950,7 @@ drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame,
|
|||
* HDMI 2.0 recommends sending non-zero Q when it does match the
|
||||
* default RGB quantization range for the mode, even when QS=0.
|
||||
*/
|
||||
if (rgb_quant_range_selectable ||
|
||||
if (info->rgb_quant_range_selectable ||
|
||||
rgb_quant_range == drm_default_rgb_quant_range(mode))
|
||||
frame->quantization_range = rgb_quant_range;
|
||||
else
|
||||
|
@ -4968,7 +4969,7 @@ drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame,
|
|||
* we limit non-zero YQ to HDMI 2.0 sinks only as HDMI 2.0 is based
|
||||
* on on CEA-861-F.
|
||||
*/
|
||||
if (!is_hdmi2_sink ||
|
||||
if (!is_hdmi2_sink(connector) ||
|
||||
rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED)
|
||||
frame->ycc_quantization_range =
|
||||
HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
|
||||
|
|
|
@ -1797,6 +1797,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
|||
int i;
|
||||
struct drm_fb_helper_surface_size sizes;
|
||||
int gamma_size = 0;
|
||||
int best_depth = 0;
|
||||
|
||||
memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
|
||||
sizes.surface_depth = 24;
|
||||
|
@ -1804,7 +1805,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
|||
sizes.fb_width = (u32)-1;
|
||||
sizes.fb_height = (u32)-1;
|
||||
|
||||
/* if driver picks 8 or 16 by default use that for both depth/bpp */
|
||||
/*
|
||||
* If driver picks 8 or 16 by default use that for both depth/bpp
|
||||
* to begin with
|
||||
*/
|
||||
if (preferred_bpp != sizes.surface_bpp)
|
||||
sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
|
||||
|
||||
|
@ -1839,6 +1843,55 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we run into a situation where, for example, the primary plane
|
||||
* supports RGBA5551 (16 bpp, depth 15) but not RGB565 (16 bpp, depth
|
||||
* 16) we need to scale down the depth of the sizes we request.
|
||||
*/
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
|
||||
struct drm_crtc *crtc = mode_set->crtc;
|
||||
struct drm_plane *plane = crtc->primary;
|
||||
int j;
|
||||
|
||||
DRM_DEBUG("test CRTC %d primary plane\n", i);
|
||||
|
||||
for (j = 0; j < plane->format_count; j++) {
|
||||
const struct drm_format_info *fmt;
|
||||
|
||||
fmt = drm_format_info(plane->format_types[j]);
|
||||
|
||||
/*
|
||||
* Do not consider YUV or other complicated formats
|
||||
* for framebuffers. This means only legacy formats
|
||||
* are supported (fmt->depth is a legacy field) but
|
||||
* the framebuffer emulation can only deal with such
|
||||
* formats, specifically RGB/BGA formats.
|
||||
*/
|
||||
if (fmt->depth == 0)
|
||||
continue;
|
||||
|
||||
/* We found a perfect fit, great */
|
||||
if (fmt->depth == sizes.surface_depth) {
|
||||
best_depth = fmt->depth;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Skip depths above what we're looking for */
|
||||
if (fmt->depth > sizes.surface_depth)
|
||||
continue;
|
||||
|
||||
/* Best depth found so far */
|
||||
if (fmt->depth > best_depth)
|
||||
best_depth = fmt->depth;
|
||||
}
|
||||
}
|
||||
if (sizes.surface_depth != best_depth) {
|
||||
DRM_INFO("requested bpp %d, scaled depth down to %d",
|
||||
sizes.surface_bpp, best_depth);
|
||||
sizes.surface_depth = best_depth;
|
||||
}
|
||||
|
||||
crtc_count = 0;
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
struct drm_display_mode *desired_mode;
|
||||
|
@ -2866,7 +2919,7 @@ int drm_fb_helper_fbdev_setup(struct drm_device *dev,
|
|||
return 0;
|
||||
|
||||
err_drm_fb_helper_fini:
|
||||
drm_fb_helper_fini(fb_helper);
|
||||
drm_fb_helper_fbdev_teardown(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -2961,18 +3014,16 @@ static int drm_fbdev_fb_release(struct fb_info *info, int user)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fb_ops.fb_destroy is called by the last put_fb_info() call at the end of
|
||||
* unregister_framebuffer() or fb_release().
|
||||
*/
|
||||
static void drm_fbdev_fb_destroy(struct fb_info *info)
|
||||
static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper)
|
||||
{
|
||||
struct drm_fb_helper *fb_helper = info->par;
|
||||
struct fb_info *fbi = fb_helper->fbdev;
|
||||
struct fb_ops *fbops = NULL;
|
||||
void *shadow = NULL;
|
||||
|
||||
if (fbi->fbdefio) {
|
||||
if (!fb_helper->dev)
|
||||
return;
|
||||
|
||||
if (fbi && fbi->fbdefio) {
|
||||
fb_deferred_io_cleanup(fbi);
|
||||
shadow = fbi->screen_buffer;
|
||||
fbops = fbi->fbops;
|
||||
|
@ -2986,6 +3037,12 @@ static void drm_fbdev_fb_destroy(struct fb_info *info)
|
|||
}
|
||||
|
||||
drm_client_framebuffer_delete(fb_helper->buffer);
|
||||
}
|
||||
|
||||
static void drm_fbdev_release(struct drm_fb_helper *fb_helper)
|
||||
{
|
||||
drm_fbdev_cleanup(fb_helper);
|
||||
|
||||
/*
|
||||
* FIXME:
|
||||
* Remove conditional when all CMA drivers have been moved over to using
|
||||
|
@ -2997,6 +3054,15 @@ static void drm_fbdev_fb_destroy(struct fb_info *info)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fb_ops.fb_destroy is called by the last put_fb_info() call at the end of
|
||||
* unregister_framebuffer() or fb_release().
|
||||
*/
|
||||
static void drm_fbdev_fb_destroy(struct fb_info *info)
|
||||
{
|
||||
drm_fbdev_release(info->par);
|
||||
}
|
||||
|
||||
static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
|
||||
{
|
||||
struct drm_fb_helper *fb_helper = info->par;
|
||||
|
@ -3047,7 +3113,6 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
|
|||
struct drm_framebuffer *fb;
|
||||
struct fb_info *fbi;
|
||||
u32 format;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
|
||||
sizes->surface_width, sizes->surface_height,
|
||||
|
@ -3064,10 +3129,8 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
|
|||
fb = buffer->fb;
|
||||
|
||||
fbi = drm_fb_helper_alloc_fbi(fb_helper);
|
||||
if (IS_ERR(fbi)) {
|
||||
ret = PTR_ERR(fbi);
|
||||
goto err_free_buffer;
|
||||
}
|
||||
if (IS_ERR(fbi))
|
||||
return PTR_ERR(fbi);
|
||||
|
||||
fbi->par = fb_helper;
|
||||
fbi->fbops = &drm_fbdev_fb_ops;
|
||||
|
@ -3098,8 +3161,7 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
|
|||
if (!fbops || !shadow) {
|
||||
kfree(fbops);
|
||||
vfree(shadow);
|
||||
ret = -ENOMEM;
|
||||
goto err_fb_info_destroy;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*fbops = *fbi->fbops;
|
||||
|
@ -3111,13 +3173,6 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_fb_info_destroy:
|
||||
drm_fb_helper_fini(fb_helper);
|
||||
err_free_buffer:
|
||||
drm_client_framebuffer_delete(buffer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_generic_probe);
|
||||
|
||||
|
@ -3129,18 +3184,11 @@ static void drm_fbdev_client_unregister(struct drm_client_dev *client)
|
|||
{
|
||||
struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
|
||||
|
||||
if (fb_helper->fbdev) {
|
||||
drm_fb_helper_unregister_fbi(fb_helper);
|
||||
if (fb_helper->fbdev)
|
||||
/* drm_fbdev_fb_destroy() takes care of cleanup */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Did drm_fb_helper_fbdev_setup() run? */
|
||||
if (fb_helper->dev)
|
||||
drm_fb_helper_fini(fb_helper);
|
||||
|
||||
drm_client_release(client);
|
||||
kfree(fb_helper);
|
||||
drm_fb_helper_unregister_fbi(fb_helper);
|
||||
else
|
||||
drm_fbdev_release(fb_helper);
|
||||
}
|
||||
|
||||
static int drm_fbdev_client_restore(struct drm_client_dev *client)
|
||||
|
@ -3158,7 +3206,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
|
|||
struct drm_device *dev = client->dev;
|
||||
int ret;
|
||||
|
||||
/* If drm_fb_helper_fbdev_setup() failed, we only try once */
|
||||
/* Setup is not retried if it has failed */
|
||||
if (!fb_helper->dev && fb_helper->funcs)
|
||||
return 0;
|
||||
|
||||
|
@ -3170,15 +3218,34 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
|
|||
return 0;
|
||||
}
|
||||
|
||||
ret = drm_fb_helper_fbdev_setup(dev, fb_helper, &drm_fb_helper_generic_funcs,
|
||||
fb_helper->preferred_bpp, 0);
|
||||
if (ret) {
|
||||
fb_helper->dev = NULL;
|
||||
fb_helper->fbdev = NULL;
|
||||
return ret;
|
||||
}
|
||||
drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs);
|
||||
|
||||
ret = drm_fb_helper_init(dev, fb_helper, dev->mode_config.num_connector);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = drm_fb_helper_single_add_all_connectors(fb_helper);
|
||||
if (ret)
|
||||
goto err_cleanup;
|
||||
|
||||
if (!drm_drv_uses_atomic_modeset(dev))
|
||||
drm_helper_disable_unused_functions(dev);
|
||||
|
||||
ret = drm_fb_helper_initial_config(fb_helper, fb_helper->preferred_bpp);
|
||||
if (ret)
|
||||
goto err_cleanup;
|
||||
|
||||
return 0;
|
||||
|
||||
err_cleanup:
|
||||
drm_fbdev_cleanup(fb_helper);
|
||||
err:
|
||||
fb_helper->dev = NULL;
|
||||
fb_helper->fbdev = NULL;
|
||||
|
||||
DRM_DEV_ERROR(dev->dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_client_funcs drm_fbdev_client_funcs = {
|
||||
|
@ -3237,6 +3304,10 @@ int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
|
|||
|
||||
drm_client_add(&fb_helper->client);
|
||||
|
||||
if (!preferred_bpp)
|
||||
preferred_bpp = dev->mode_config.preferred_depth;
|
||||
if (!preferred_bpp)
|
||||
preferred_bpp = 32;
|
||||
fb_helper->preferred_bpp = preferred_bpp;
|
||||
|
||||
ret = drm_fbdev_client_hotplug(&fb_helper->client);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_util.h>
|
||||
#include <drm/drm_flip_work.h>
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_uapi.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_util.h>
|
||||
|
||||
#include "drm_internal.h"
|
||||
#include "drm_crtc_internal.h"
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <linux/shmem_fs.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/mem_encrypt.h>
|
||||
#include <linux/pagevec.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_vma_manager.h>
|
||||
#include <drm/drm_gem.h>
|
||||
|
@ -526,6 +527,17 @@ int drm_gem_create_mmap_offset(struct drm_gem_object *obj)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_gem_create_mmap_offset);
|
||||
|
||||
/*
|
||||
* Move pages to appropriate lru and release the pagevec, decrementing the
|
||||
* ref count of those pages.
|
||||
*/
|
||||
static void drm_gem_check_release_pagevec(struct pagevec *pvec)
|
||||
{
|
||||
check_move_unevictable_pages(pvec);
|
||||
__pagevec_release(pvec);
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_gem_get_pages - helper to allocate backing pages for a GEM object
|
||||
* from shmem
|
||||
|
@ -551,6 +563,7 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj)
|
|||
{
|
||||
struct address_space *mapping;
|
||||
struct page *p, **pages;
|
||||
struct pagevec pvec;
|
||||
int i, npages;
|
||||
|
||||
/* This is the shared memory object that backs the GEM resource */
|
||||
|
@ -568,6 +581,8 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj)
|
|||
if (pages == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mapping_set_unevictable(mapping);
|
||||
|
||||
for (i = 0; i < npages; i++) {
|
||||
p = shmem_read_mapping_page(mapping, i);
|
||||
if (IS_ERR(p))
|
||||
|
@ -586,8 +601,14 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj)
|
|||
return pages;
|
||||
|
||||
fail:
|
||||
while (i--)
|
||||
put_page(pages[i]);
|
||||
mapping_clear_unevictable(mapping);
|
||||
pagevec_init(&pvec);
|
||||
while (i--) {
|
||||
if (!pagevec_add(&pvec, pages[i]))
|
||||
drm_gem_check_release_pagevec(&pvec);
|
||||
}
|
||||
if (pagevec_count(&pvec))
|
||||
drm_gem_check_release_pagevec(&pvec);
|
||||
|
||||
kvfree(pages);
|
||||
return ERR_CAST(p);
|
||||
|
@ -605,6 +626,11 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages,
|
|||
bool dirty, bool accessed)
|
||||
{
|
||||
int i, npages;
|
||||
struct address_space *mapping;
|
||||
struct pagevec pvec;
|
||||
|
||||
mapping = file_inode(obj->filp)->i_mapping;
|
||||
mapping_clear_unevictable(mapping);
|
||||
|
||||
/* We already BUG_ON() for non-page-aligned sizes in
|
||||
* drm_gem_object_init(), so we should never hit this unless
|
||||
|
@ -614,6 +640,7 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages,
|
|||
|
||||
npages = obj->size >> PAGE_SHIFT;
|
||||
|
||||
pagevec_init(&pvec);
|
||||
for (i = 0; i < npages; i++) {
|
||||
if (dirty)
|
||||
set_page_dirty(pages[i]);
|
||||
|
@ -622,8 +649,11 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages,
|
|||
mark_page_accessed(pages[i]);
|
||||
|
||||
/* Undo the reference we took when populating the table */
|
||||
put_page(pages[i]);
|
||||
if (!pagevec_add(&pvec, pages[i]))
|
||||
drm_gem_check_release_pagevec(&pvec);
|
||||
}
|
||||
if (pagevec_count(&pvec))
|
||||
drm_gem_check_release_pagevec(&pvec);
|
||||
|
||||
kvfree(pages);
|
||||
}
|
||||
|
|
|
@ -71,11 +71,6 @@ struct drm_display_mode *drm_mode_create(struct drm_device *dev)
|
|||
if (!nmode)
|
||||
return NULL;
|
||||
|
||||
if (drm_mode_object_add(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) {
|
||||
kfree(nmode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return nmode;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_create);
|
||||
|
@ -92,8 +87,6 @@ void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
|
|||
if (!mode)
|
||||
return;
|
||||
|
||||
drm_mode_object_unregister(dev, &mode->base);
|
||||
|
||||
kfree(mode);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_destroy);
|
||||
|
@ -911,11 +904,9 @@ EXPORT_SYMBOL(drm_mode_set_crtcinfo);
|
|||
*/
|
||||
void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
|
||||
{
|
||||
int id = dst->base.id;
|
||||
struct list_head head = dst->head;
|
||||
|
||||
*dst = *src;
|
||||
dst->base.id = id;
|
||||
dst->head = head;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_copy);
|
||||
|
|
|
@ -217,9 +217,11 @@ int drm_of_encoder_active_endpoint(struct device_node *node,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint);
|
||||
|
||||
/*
|
||||
/**
|
||||
* drm_of_find_panel_or_bridge - return connected panel or bridge device
|
||||
* @np: device tree node containing encoder output ports
|
||||
* @port: port in the device tree node
|
||||
* @endpoint: endpoint in the device tree node
|
||||
* @panel: pointer to hold returned drm_panel
|
||||
* @bridge: pointer to hold returned drm_bridge
|
||||
*
|
||||
|
|
|
@ -36,6 +36,9 @@ static LIST_HEAD(panel_list);
|
|||
* The DRM panel helpers allow drivers to register panel objects with a
|
||||
* central registry and provide functions to retrieve those panels in display
|
||||
* drivers.
|
||||
*
|
||||
* For easy integration into drivers using the &drm_bridge infrastructure please
|
||||
* take look at drm_panel_bridge_add() and devm_drm_panel_bridge_add().
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
|
@ -220,6 +220,9 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
|
|||
format_modifier_count++;
|
||||
}
|
||||
|
||||
if (format_modifier_count)
|
||||
config->allow_fb_modifiers = true;
|
||||
|
||||
plane->modifier_count = format_modifier_count;
|
||||
plane->modifiers = kmalloc_array(format_modifier_count,
|
||||
sizeof(format_modifiers[0]),
|
||||
|
|
|
@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
|
|||
write_sequnlock(&vblank->seqlock);
|
||||
}
|
||||
|
||||
static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
|
||||
{
|
||||
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
|
||||
|
||||
return vblank->max_vblank_count ?: dev->max_vblank_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* "No hw counter" fallback implementation of .get_vblank_counter() hook,
|
||||
* if there is no useable hardware frame counter available.
|
||||
*/
|
||||
static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
|
||||
{
|
||||
WARN_ON_ONCE(dev->max_vblank_count != 0);
|
||||
WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
|
|||
ktime_t t_vblank;
|
||||
int count = DRM_TIMESTAMP_MAXRETRIES;
|
||||
int framedur_ns = vblank->framedur_ns;
|
||||
u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
|
||||
|
||||
/*
|
||||
* Interrupts were disabled prior to this call, so deal with counter
|
||||
|
@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
|
|||
rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
|
||||
} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
|
||||
|
||||
if (dev->max_vblank_count != 0) {
|
||||
if (max_vblank_count) {
|
||||
/* trust the hw counter when it's around */
|
||||
diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
|
||||
diff = (cur_vblank - vblank->last) & max_vblank_count;
|
||||
} else if (rc && framedur_ns) {
|
||||
u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
|
||||
|
||||
|
@ -1204,6 +1212,37 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_crtc_vblank_reset);
|
||||
|
||||
/**
|
||||
* drm_crtc_set_max_vblank_count - configure the hw max vblank counter value
|
||||
* @crtc: CRTC in question
|
||||
* @max_vblank_count: max hardware vblank counter value
|
||||
*
|
||||
* Update the maximum hardware vblank counter value for @crtc
|
||||
* at runtime. Useful for hardware where the operation of the
|
||||
* hardware vblank counter depends on the currently active
|
||||
* display configuration.
|
||||
*
|
||||
* For example, if the hardware vblank counter does not work
|
||||
* when a specific connector is active the maximum can be set
|
||||
* to zero. And when that specific connector isn't active the
|
||||
* maximum can again be set to the appropriate non-zero value.
|
||||
*
|
||||
* If used, must be called before drm_vblank_on().
|
||||
*/
|
||||
void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
|
||||
u32 max_vblank_count)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned int pipe = drm_crtc_index(crtc);
|
||||
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
|
||||
|
||||
WARN_ON(dev->max_vblank_count);
|
||||
WARN_ON(!READ_ONCE(vblank->inmodeset));
|
||||
|
||||
vblank->max_vblank_count = max_vblank_count;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_crtc_set_max_vblank_count);
|
||||
|
||||
/**
|
||||
* drm_crtc_vblank_on - enable vblank events on a CRTC
|
||||
* @crtc: CRTC in question
|
||||
|
|
|
@ -819,7 +819,8 @@ static void hdmi_reg_infoframes(struct hdmi_context *hdata)
|
|||
return;
|
||||
}
|
||||
|
||||
ret = drm_hdmi_avi_infoframe_from_display_mode(&frm.avi, m, false);
|
||||
ret = drm_hdmi_avi_infoframe_from_display_mode(&frm.avi,
|
||||
&hdata->connector, m);
|
||||
if (!ret)
|
||||
ret = hdmi_avi_infoframe_pack(&frm.avi, buf, sizeof(buf));
|
||||
if (ret > 0) {
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <drm/drmP.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
@ -33,32 +34,15 @@ static struct kirin_dc_ops *dc_ops;
|
|||
|
||||
static int kirin_drm_kms_cleanup(struct drm_device *dev)
|
||||
{
|
||||
struct kirin_drm_private *priv = dev->dev_private;
|
||||
|
||||
if (priv->fbdev) {
|
||||
drm_fbdev_cma_fini(priv->fbdev);
|
||||
priv->fbdev = NULL;
|
||||
}
|
||||
|
||||
drm_kms_helper_poll_fini(dev);
|
||||
dc_ops->cleanup(to_platform_device(dev->dev));
|
||||
drm_mode_config_cleanup(dev);
|
||||
devm_kfree(dev->dev, priv);
|
||||
dev->dev_private = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kirin_fbdev_output_poll_changed(struct drm_device *dev)
|
||||
{
|
||||
struct kirin_drm_private *priv = dev->dev_private;
|
||||
|
||||
drm_fbdev_cma_hotplug_event(priv->fbdev);
|
||||
}
|
||||
|
||||
static const struct drm_mode_config_funcs kirin_drm_mode_config_funcs = {
|
||||
.fb_create = drm_gem_fb_create,
|
||||
.output_poll_changed = kirin_fbdev_output_poll_changed,
|
||||
.atomic_check = drm_atomic_helper_check,
|
||||
.atomic_commit = drm_atomic_helper_commit,
|
||||
};
|
||||
|
@ -76,14 +60,8 @@ static void kirin_drm_mode_config_init(struct drm_device *dev)
|
|||
|
||||
static int kirin_drm_kms_init(struct drm_device *dev)
|
||||
{
|
||||
struct kirin_drm_private *priv;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->dev_private = priv;
|
||||
dev_set_drvdata(dev->dev, dev);
|
||||
|
||||
/* dev->mode_config initialization */
|
||||
|
@ -117,26 +95,14 @@ static int kirin_drm_kms_init(struct drm_device *dev)
|
|||
/* init kms poll for handling hpd */
|
||||
drm_kms_helper_poll_init(dev);
|
||||
|
||||
priv->fbdev = drm_fbdev_cma_init(dev, 32,
|
||||
dev->mode_config.num_connector);
|
||||
|
||||
if (IS_ERR(priv->fbdev)) {
|
||||
DRM_ERROR("failed to initialize fbdev.\n");
|
||||
ret = PTR_ERR(priv->fbdev);
|
||||
goto err_cleanup_poll;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_cleanup_poll:
|
||||
drm_kms_helper_poll_fini(dev);
|
||||
err_unbind_all:
|
||||
component_unbind_all(dev->dev, dev);
|
||||
err_dc_cleanup:
|
||||
dc_ops->cleanup(to_platform_device(dev->dev));
|
||||
err_mode_config_cleanup:
|
||||
drm_mode_config_cleanup(dev);
|
||||
devm_kfree(dev->dev, priv);
|
||||
dev->dev_private = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -199,6 +165,8 @@ static int kirin_drm_bind(struct device *dev)
|
|||
if (ret)
|
||||
goto err_kms_cleanup;
|
||||
|
||||
drm_fbdev_generic_setup(drm_dev, 32);
|
||||
|
||||
return 0;
|
||||
|
||||
err_kms_cleanup:
|
||||
|
|
|
@ -19,10 +19,6 @@ struct kirin_dc_ops {
|
|||
void (*cleanup)(struct platform_device *pdev);
|
||||
};
|
||||
|
||||
struct kirin_drm_private {
|
||||
struct drm_fbdev_cma *fbdev;
|
||||
};
|
||||
|
||||
extern const struct kirin_dc_ops ade_dc_ops;
|
||||
|
||||
#endif /* __KIRIN_DRM_DRV_H__ */
|
||||
|
|
|
@ -359,10 +359,10 @@ static int ch7006_encoder_set_property(struct drm_encoder *encoder,
|
|||
if (modes_changed) {
|
||||
drm_helper_probe_single_connector_modes(connector, 0, 0);
|
||||
|
||||
/* Disable the crtc to ensure a full modeset is
|
||||
* performed whenever it's turned on again. */
|
||||
if (crtc)
|
||||
drm_crtc_force_disable(crtc);
|
||||
drm_crtc_helper_set_mode(crtc, &crtc->mode,
|
||||
crtc->x, crtc->y,
|
||||
crtc->primary->fb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -849,7 +849,8 @@ tda998x_write_avi(struct tda998x_priv *priv, const struct drm_display_mode *mode
|
|||
{
|
||||
union hdmi_infoframe frame;
|
||||
|
||||
drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false);
|
||||
drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
|
||||
&priv->connector, mode);
|
||||
frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_FULL;
|
||||
|
||||
tda998x_write_if(priv, DIP_IF_FLAGS_IF2, REG_IF2_HB0, &frame);
|
||||
|
@ -1122,7 +1123,6 @@ static void tda998x_connector_destroy(struct drm_connector *connector)
|
|||
}
|
||||
|
||||
static const struct drm_connector_funcs tda998x_connector_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.detect = tda998x_connector_detect,
|
||||
|
|
|
@ -2948,14 +2948,7 @@ static void intel_seq_print_mode(struct seq_file *m, int tabs,
|
|||
for (i = 0; i < tabs; i++)
|
||||
seq_putc(m, '\t');
|
||||
|
||||
seq_printf(m, "id %d:\"%s\" freq %d clock %d hdisp %d hss %d hse %d htot %d vdisp %d vss %d vse %d vtot %d type 0x%x flags 0x%x\n",
|
||||
mode->base.id, mode->name,
|
||||
mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start,
|
||||
mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start,
|
||||
mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
seq_printf(m, DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
|
||||
}
|
||||
|
||||
static void intel_encoder_info(struct seq_file *m,
|
||||
|
|
|
@ -1178,9 +1178,9 @@ static void gen11_dsi_get_config(struct intel_encoder *encoder,
|
|||
pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI);
|
||||
}
|
||||
|
||||
static bool gen11_dsi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
static int gen11_dsi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi,
|
||||
base);
|
||||
|
@ -1205,7 +1205,7 @@ static bool gen11_dsi_compute_config(struct intel_encoder *encoder,
|
|||
pipe_config->clock_set = true;
|
||||
pipe_config->port_clock = intel_dsi_bitrate(intel_dsi) / 5;
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 gen11_dsi_get_power_domains(struct intel_encoder *encoder,
|
||||
|
|
|
@ -95,6 +95,10 @@ void intel_connector_destroy(struct drm_connector *connector)
|
|||
intel_panel_fini(&intel_connector->panel);
|
||||
|
||||
drm_connector_cleanup(connector);
|
||||
|
||||
if (intel_connector->port)
|
||||
drm_dp_mst_put_port_malloc(intel_connector->port);
|
||||
|
||||
kfree(connector);
|
||||
}
|
||||
|
||||
|
|
|
@ -344,51 +344,52 @@ intel_crt_mode_valid(struct drm_connector *connector,
|
|||
return MODE_OK;
|
||||
}
|
||||
|
||||
static bool intel_crt_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
static int intel_crt_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_display_mode *adjusted_mode =
|
||||
&pipe_config->base.adjusted_mode;
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
|
||||
return true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool pch_crt_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
static int pch_crt_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_display_mode *adjusted_mode =
|
||||
&pipe_config->base.adjusted_mode;
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
pipe_config->has_pch_encoder = true;
|
||||
pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool hsw_crt_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
static int hsw_crt_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct drm_display_mode *adjusted_mode =
|
||||
&pipe_config->base.adjusted_mode;
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
/* HSW/BDW FDI limited to 4k */
|
||||
if (adjusted_mode->crtc_hdisplay > 4096 ||
|
||||
adjusted_mode->crtc_hblank_start > 4096)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
pipe_config->has_pch_encoder = true;
|
||||
pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
|
||||
|
@ -397,7 +398,7 @@ static bool hsw_crt_compute_config(struct intel_encoder *encoder,
|
|||
if (HAS_PCH_LPT(dev_priv)) {
|
||||
if (pipe_config->bw_constrained && pipe_config->pipe_bpp < 24) {
|
||||
DRM_DEBUG_KMS("LPT only supports 24bpp\n");
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pipe_config->pipe_bpp = 24;
|
||||
|
@ -406,7 +407,7 @@ static bool hsw_crt_compute_config(struct intel_encoder *encoder,
|
|||
/* FDI must always be 2.7 GHz */
|
||||
pipe_config->port_clock = 135000 * 2;
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
|
||||
|
|
|
@ -3875,9 +3875,9 @@ intel_ddi_compute_output_type(struct intel_encoder *encoder,
|
|||
}
|
||||
}
|
||||
|
||||
static bool intel_ddi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
static int intel_ddi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
enum port port = encoder->port;
|
||||
|
|
|
@ -11517,10 +11517,13 @@ encoder_retry:
|
|||
continue;
|
||||
|
||||
encoder = to_intel_encoder(connector_state->best_encoder);
|
||||
|
||||
if (!(encoder->compute_config(encoder, pipe_config, connector_state))) {
|
||||
DRM_DEBUG_KMS("Encoder config failure\n");
|
||||
return -EINVAL;
|
||||
ret = encoder->compute_config(encoder, pipe_config,
|
||||
connector_state);
|
||||
if (ret < 0) {
|
||||
if (ret != -EDEADLK)
|
||||
DRM_DEBUG_KMS("Encoder config failure: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12695,6 +12698,10 @@ static int intel_atomic_check(struct drm_device *dev,
|
|||
"[modeset]" : "[fastset]");
|
||||
}
|
||||
|
||||
ret = drm_dp_mst_atomic_check(state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (any_ms) {
|
||||
ret = intel_modeset_checks(state);
|
||||
|
||||
|
|
|
@ -1808,7 +1808,7 @@ intel_dp_adjust_compliance_config(struct intel_dp *intel_dp,
|
|||
}
|
||||
|
||||
/* Optimize link config in order: max bpp, min clock, min lanes */
|
||||
static bool
|
||||
static int
|
||||
intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
const struct link_config_limits *limits)
|
||||
|
@ -1834,17 +1834,17 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
|
|||
pipe_config->pipe_bpp = bpp;
|
||||
pipe_config->port_clock = link_clock;
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Optimize link config in order: max bpp, min lanes, min clock */
|
||||
static bool
|
||||
static int
|
||||
intel_dp_compute_link_config_fast(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
const struct link_config_limits *limits)
|
||||
|
@ -1870,13 +1870,13 @@ intel_dp_compute_link_config_fast(struct intel_dp *intel_dp,
|
|||
pipe_config->pipe_bpp = bpp;
|
||||
pipe_config->port_clock = link_clock;
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc)
|
||||
|
@ -1894,19 +1894,20 @@ static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state,
|
||||
struct link_config_limits *limits)
|
||||
static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state,
|
||||
struct link_config_limits *limits)
|
||||
{
|
||||
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||
struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
|
||||
struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
|
||||
u8 dsc_max_bpc;
|
||||
int pipe_bpp;
|
||||
int ret;
|
||||
|
||||
if (!intel_dp_supports_dsc(intel_dp, pipe_config))
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
dsc_max_bpc = min_t(u8, DP_DSC_MAX_SUPPORTED_BPC,
|
||||
conn_state->max_requested_bpc);
|
||||
|
@ -1914,7 +1915,7 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
|
|||
pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, dsc_max_bpc);
|
||||
if (pipe_bpp < DP_DSC_MIN_SUPPORTED_BPC * 3) {
|
||||
DRM_DEBUG_KMS("No DSC support for less than 8bpc\n");
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1948,7 +1949,7 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
|
|||
adjusted_mode->crtc_hdisplay);
|
||||
if (!dsc_max_output_bpp || !dsc_dp_slice_count) {
|
||||
DRM_DEBUG_KMS("Compressed BPP/Slice Count not supported\n");
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
pipe_config->dsc_params.compressed_bpp = min_t(u16,
|
||||
dsc_max_output_bpp >> 4,
|
||||
|
@ -1965,16 +1966,19 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
|
|||
pipe_config->dsc_params.dsc_split = true;
|
||||
} else {
|
||||
DRM_DEBUG_KMS("Cannot split stream to use 2 VDSC instances\n");
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
if (intel_dp_compute_dsc_params(intel_dp, pipe_config) < 0) {
|
||||
|
||||
ret = intel_dp_compute_dsc_params(intel_dp, pipe_config);
|
||||
if (ret < 0) {
|
||||
DRM_DEBUG_KMS("Cannot compute valid DSC parameters for Input Bpp = %d "
|
||||
"Compressed BPP = %d\n",
|
||||
pipe_config->pipe_bpp,
|
||||
pipe_config->dsc_params.compressed_bpp);
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
pipe_config->dsc_params.compression_enable = true;
|
||||
DRM_DEBUG_KMS("DP DSC computed with Input Bpp = %d "
|
||||
"Compressed Bpp = %d Slice Count = %d\n",
|
||||
|
@ -1982,10 +1986,10 @@ static bool intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
|
|||
pipe_config->dsc_params.compressed_bpp,
|
||||
pipe_config->dsc_params.slice_count);
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
static int
|
||||
intel_dp_compute_link_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
|
@ -1994,7 +1998,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
|
|||
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
|
||||
struct link_config_limits limits;
|
||||
int common_len;
|
||||
bool ret;
|
||||
int ret;
|
||||
|
||||
common_len = intel_dp_common_len_rate_limit(intel_dp,
|
||||
intel_dp->max_link_rate);
|
||||
|
@ -2051,10 +2055,11 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
|
|||
&limits);
|
||||
|
||||
/* enable compression if the mode doesn't fit available BW */
|
||||
if (!ret) {
|
||||
if (!intel_dp_dsc_compute_config(intel_dp, pipe_config,
|
||||
conn_state, &limits))
|
||||
return false;
|
||||
if (ret) {
|
||||
ret = intel_dp_dsc_compute_config(intel_dp, pipe_config,
|
||||
conn_state, &limits);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pipe_config->dsc_params.compression_enable) {
|
||||
|
@ -2079,10 +2084,10 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
|
|||
intel_dp_max_data_rate(pipe_config->port_clock,
|
||||
pipe_config->lane_count));
|
||||
}
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
int
|
||||
intel_dp_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
|
@ -2098,6 +2103,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
|
|||
to_intel_digital_connector_state(conn_state);
|
||||
bool constant_n = drm_dp_has_quirk(&intel_dp->desc,
|
||||
DP_DPCD_QUIRK_CONSTANT_N);
|
||||
int ret;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A)
|
||||
pipe_config->has_pch_encoder = true;
|
||||
|
@ -2119,8 +2125,6 @@ intel_dp_compute_config(struct intel_encoder *encoder,
|
|||
adjusted_mode);
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 9) {
|
||||
int ret;
|
||||
|
||||
ret = skl_update_scaler_crtc(pipe_config);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -2135,20 +2139,21 @@ intel_dp_compute_config(struct intel_encoder *encoder,
|
|||
}
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
if (HAS_GMCH_DISPLAY(dev_priv) &&
|
||||
adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
pipe_config->fec_enable = !intel_dp_is_edp(intel_dp) &&
|
||||
intel_dp_supports_fec(intel_dp, pipe_config);
|
||||
|
||||
if (!intel_dp_compute_link_config(encoder, pipe_config, conn_state))
|
||||
return false;
|
||||
ret = intel_dp_compute_link_config(encoder, pipe_config, conn_state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) {
|
||||
/*
|
||||
|
@ -2196,7 +2201,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
|
|||
|
||||
intel_psr_compute_config(intel_dp, pipe_config);
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_dp_set_link_params(struct intel_dp *intel_dp,
|
||||
|
|
|
@ -30,9 +30,9 @@
|
|||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
|
||||
static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
|
||||
|
@ -41,15 +41,19 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
|
|||
struct drm_connector *connector = conn_state->connector;
|
||||
void *port = to_intel_connector(connector)->port;
|
||||
struct drm_atomic_state *state = pipe_config->base.state;
|
||||
struct drm_crtc *crtc = pipe_config->base.crtc;
|
||||
struct drm_crtc_state *old_crtc_state =
|
||||
drm_atomic_get_old_crtc_state(state, crtc);
|
||||
int bpp;
|
||||
int lane_count, slots = 0;
|
||||
int lane_count, slots =
|
||||
to_intel_crtc_state(old_crtc_state)->dp_m_n.tu;
|
||||
const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
|
||||
int mst_pbn;
|
||||
bool constant_n = drm_dp_has_quirk(&intel_dp->desc,
|
||||
DP_DPCD_QUIRK_CONSTANT_N);
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
|
||||
pipe_config->has_pch_encoder = false;
|
||||
|
@ -86,7 +90,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
|
|||
if (slots < 0) {
|
||||
DRM_DEBUG_KMS("failed finding vcpi slots:%d\n",
|
||||
slots);
|
||||
return false;
|
||||
return slots;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,38 +108,42 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
|
|||
|
||||
intel_ddi_compute_min_voltage_level(dev_priv, pipe_config);
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_dp_mst_atomic_check(struct drm_connector *connector,
|
||||
struct drm_connector_state *new_conn_state)
|
||||
static int
|
||||
intel_dp_mst_atomic_check(struct drm_connector *connector,
|
||||
struct drm_connector_state *new_conn_state)
|
||||
{
|
||||
struct drm_atomic_state *state = new_conn_state->state;
|
||||
struct drm_connector_state *old_conn_state;
|
||||
struct drm_crtc *old_crtc;
|
||||
struct drm_connector_state *old_conn_state =
|
||||
drm_atomic_get_old_connector_state(state, connector);
|
||||
struct intel_connector *intel_connector =
|
||||
to_intel_connector(connector);
|
||||
struct drm_crtc *new_crtc = new_conn_state->crtc;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
int slots, ret = 0;
|
||||
struct drm_dp_mst_topology_mgr *mgr;
|
||||
int ret = 0;
|
||||
|
||||
old_conn_state = drm_atomic_get_old_connector_state(state, connector);
|
||||
old_crtc = old_conn_state->crtc;
|
||||
if (!old_crtc)
|
||||
return ret;
|
||||
if (!old_conn_state->crtc)
|
||||
return 0;
|
||||
|
||||
crtc_state = drm_atomic_get_new_crtc_state(state, old_crtc);
|
||||
slots = to_intel_crtc_state(crtc_state)->dp_m_n.tu;
|
||||
if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) {
|
||||
struct drm_dp_mst_topology_mgr *mgr;
|
||||
struct drm_encoder *old_encoder;
|
||||
/* We only want to free VCPI if this state disables the CRTC on this
|
||||
* connector
|
||||
*/
|
||||
if (new_crtc) {
|
||||
crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
|
||||
|
||||
old_encoder = old_conn_state->best_encoder;
|
||||
mgr = &enc_to_mst(old_encoder)->primary->dp.mst_mgr;
|
||||
|
||||
ret = drm_dp_atomic_release_vcpi_slots(state, mgr, slots);
|
||||
if (ret)
|
||||
DRM_DEBUG_KMS("failed releasing %d vcpi slots:%d\n", slots, ret);
|
||||
else
|
||||
to_intel_crtc_state(crtc_state)->dp_m_n.tu = 0;
|
||||
if (!crtc_state ||
|
||||
!drm_atomic_crtc_needs_modeset(crtc_state) ||
|
||||
crtc_state->enable)
|
||||
return 0;
|
||||
}
|
||||
|
||||
mgr = &enc_to_mst(old_conn_state->best_encoder)->primary->dp.mst_mgr;
|
||||
ret = drm_dp_atomic_release_vcpi_slots(state, mgr,
|
||||
intel_connector->port);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -457,6 +465,7 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
|
|||
intel_connector->get_hw_state = intel_dp_mst_get_hw_state;
|
||||
intel_connector->mst_port = intel_dp;
|
||||
intel_connector->port = port;
|
||||
drm_dp_mst_get_port_malloc(port);
|
||||
|
||||
connector = &intel_connector->base;
|
||||
ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs,
|
||||
|
|
|
@ -222,9 +222,9 @@ struct intel_encoder {
|
|||
enum intel_output_type (*compute_output_type)(struct intel_encoder *,
|
||||
struct intel_crtc_state *,
|
||||
struct drm_connector_state *);
|
||||
bool (*compute_config)(struct intel_encoder *,
|
||||
struct intel_crtc_state *,
|
||||
struct drm_connector_state *);
|
||||
int (*compute_config)(struct intel_encoder *,
|
||||
struct intel_crtc_state *,
|
||||
struct drm_connector_state *);
|
||||
void (*pre_pll_enable)(struct intel_encoder *,
|
||||
const struct intel_crtc_state *,
|
||||
const struct drm_connector_state *);
|
||||
|
@ -1074,7 +1074,6 @@ struct intel_hdmi {
|
|||
} dp_dual_mode;
|
||||
bool has_hdmi_sink;
|
||||
bool has_audio;
|
||||
bool rgb_quant_range_selectable;
|
||||
struct intel_connector *attached_connector;
|
||||
struct cec_notifier *cec_notifier;
|
||||
};
|
||||
|
@ -1807,9 +1806,9 @@ void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp,
|
|||
void intel_dp_encoder_reset(struct drm_encoder *encoder);
|
||||
void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
|
||||
void intel_dp_encoder_destroy(struct drm_encoder *encoder);
|
||||
bool intel_dp_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state);
|
||||
int intel_dp_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state);
|
||||
bool intel_dp_is_edp(struct intel_dp *intel_dp);
|
||||
bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port);
|
||||
enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port,
|
||||
|
@ -1967,9 +1966,9 @@ void intel_hdmi_init(struct drm_i915_private *dev_priv, i915_reg_t hdmi_reg,
|
|||
void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
|
||||
struct intel_connector *intel_connector);
|
||||
struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
|
||||
bool intel_hdmi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state);
|
||||
int intel_hdmi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state);
|
||||
bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder,
|
||||
struct drm_connector *connector,
|
||||
bool high_tmds_clock_ratio,
|
||||
|
|
|
@ -235,9 +235,9 @@ intel_dvo_mode_valid(struct drm_connector *connector,
|
|||
return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode);
|
||||
}
|
||||
|
||||
static bool intel_dvo_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
static int intel_dvo_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
|
||||
const struct drm_display_mode *fixed_mode =
|
||||
|
@ -254,10 +254,11 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder,
|
|||
intel_fixed_panel_mode(fixed_mode, adjusted_mode);
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
|
||||
return true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void intel_dvo_pre_enable(struct intel_encoder *encoder,
|
||||
|
|
|
@ -479,18 +479,14 @@ static void intel_hdmi_set_avi_infoframe(struct intel_encoder *encoder,
|
|||
const struct intel_crtc_state *crtc_state,
|
||||
const struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
|
||||
const struct drm_display_mode *adjusted_mode =
|
||||
&crtc_state->base.adjusted_mode;
|
||||
struct drm_connector *connector = &intel_hdmi->attached_connector->base;
|
||||
bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported ||
|
||||
connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420;
|
||||
union hdmi_infoframe frame;
|
||||
int ret;
|
||||
|
||||
ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
|
||||
adjusted_mode,
|
||||
is_hdmi2_sink);
|
||||
conn_state->connector,
|
||||
adjusted_mode);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("couldn't fill AVI infoframe\n");
|
||||
return;
|
||||
|
@ -503,12 +499,12 @@ static void intel_hdmi_set_avi_infoframe(struct intel_encoder *encoder,
|
|||
else
|
||||
frame.avi.colorspace = HDMI_COLORSPACE_RGB;
|
||||
|
||||
drm_hdmi_avi_infoframe_quant_range(&frame.avi, adjusted_mode,
|
||||
drm_hdmi_avi_infoframe_quant_range(&frame.avi,
|
||||
conn_state->connector,
|
||||
adjusted_mode,
|
||||
crtc_state->limited_color_range ?
|
||||
HDMI_QUANTIZATION_RANGE_LIMITED :
|
||||
HDMI_QUANTIZATION_RANGE_FULL,
|
||||
intel_hdmi->rgb_quant_range_selectable,
|
||||
is_hdmi2_sink);
|
||||
HDMI_QUANTIZATION_RANGE_FULL);
|
||||
|
||||
drm_hdmi_avi_infoframe_content_type(&frame.avi,
|
||||
conn_state);
|
||||
|
@ -1707,9 +1703,9 @@ intel_hdmi_ycbcr420_config(struct drm_connector *connector,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool intel_hdmi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
int intel_hdmi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
|
@ -1725,7 +1721,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
|
|||
bool force_dvi = intel_conn_state->force_audio == HDMI_AUDIO_OFF_DVI;
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
|
||||
pipe_config->has_hdmi_sink = !force_dvi && intel_hdmi->has_hdmi_sink;
|
||||
|
@ -1756,7 +1752,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
|
|||
&clock_12bpc, &clock_10bpc,
|
||||
&clock_8bpc)) {
|
||||
DRM_ERROR("Can't support YCBCR420 output\n");
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1806,7 +1802,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
|
|||
if (hdmi_port_clock_valid(intel_hdmi, pipe_config->port_clock,
|
||||
false, force_dvi) != MODE_OK) {
|
||||
DRM_DEBUG_KMS("unsupported HDMI clock, rejecting mode\n");
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set user selected PAR to incoming mode's member */
|
||||
|
@ -1825,7 +1821,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
|
|||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1835,7 +1831,6 @@ intel_hdmi_unset_edid(struct drm_connector *connector)
|
|||
|
||||
intel_hdmi->has_hdmi_sink = false;
|
||||
intel_hdmi->has_audio = false;
|
||||
intel_hdmi->rgb_quant_range_selectable = false;
|
||||
|
||||
intel_hdmi->dp_dual_mode.type = DRM_DP_DUAL_MODE_NONE;
|
||||
intel_hdmi->dp_dual_mode.max_tmds_clock = 0;
|
||||
|
@ -1919,9 +1914,6 @@ intel_hdmi_set_edid(struct drm_connector *connector)
|
|||
|
||||
to_intel_connector(connector)->detect_edid = edid;
|
||||
if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
|
||||
intel_hdmi->rgb_quant_range_selectable =
|
||||
drm_rgb_quant_range_selectable(edid);
|
||||
|
||||
intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
|
||||
intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
|
||||
|
||||
|
|
|
@ -462,10 +462,8 @@ void lspcon_set_infoframes(struct intel_encoder *encoder,
|
|||
uint8_t buf[VIDEO_DIP_DATA_SIZE];
|
||||
struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
|
||||
struct intel_lspcon *lspcon = &dig_port->lspcon;
|
||||
struct intel_dp *intel_dp = &dig_port->dp;
|
||||
struct drm_connector *connector = &intel_dp->attached_connector->base;
|
||||
const struct drm_display_mode *mode = &crtc_state->base.adjusted_mode;
|
||||
bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported;
|
||||
const struct drm_display_mode *adjusted_mode =
|
||||
&crtc_state->base.adjusted_mode;
|
||||
|
||||
if (!lspcon->active) {
|
||||
DRM_ERROR("Writing infoframes while LSPCON disabled ?\n");
|
||||
|
@ -473,7 +471,8 @@ void lspcon_set_infoframes(struct intel_encoder *encoder,
|
|||
}
|
||||
|
||||
ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
|
||||
mode, is_hdmi2_sink);
|
||||
conn_state->connector,
|
||||
adjusted_mode);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("couldn't fill AVI infoframe\n");
|
||||
return;
|
||||
|
@ -488,11 +487,12 @@ void lspcon_set_infoframes(struct intel_encoder *encoder,
|
|||
frame.avi.colorspace = HDMI_COLORSPACE_RGB;
|
||||
}
|
||||
|
||||
drm_hdmi_avi_infoframe_quant_range(&frame.avi, mode,
|
||||
drm_hdmi_avi_infoframe_quant_range(&frame.avi,
|
||||
conn_state->connector,
|
||||
adjusted_mode,
|
||||
crtc_state->limited_color_range ?
|
||||
HDMI_QUANTIZATION_RANGE_LIMITED :
|
||||
HDMI_QUANTIZATION_RANGE_FULL,
|
||||
false, is_hdmi2_sink);
|
||||
HDMI_QUANTIZATION_RANGE_FULL);
|
||||
|
||||
ret = hdmi_infoframe_pack(&frame, buf, sizeof(buf));
|
||||
if (ret < 0) {
|
||||
|
|
|
@ -379,9 +379,9 @@ intel_lvds_mode_valid(struct drm_connector *connector,
|
|||
return MODE_OK;
|
||||
}
|
||||
|
||||
static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
static int intel_lvds_compute_config(struct intel_encoder *intel_encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
|
||||
struct intel_lvds_encoder *lvds_encoder =
|
||||
|
@ -395,7 +395,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
|
|||
/* Should never happen!! */
|
||||
if (INTEL_GEN(dev_priv) < 4 && intel_crtc->pipe == 0) {
|
||||
DRM_ERROR("Can't support LVDS on pipe A\n");
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (lvds_encoder->a3_power == LVDS_A3_POWER_UP)
|
||||
|
@ -421,7 +421,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
|
|||
adjusted_mode);
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev_priv)) {
|
||||
pipe_config->has_pch_encoder = true;
|
||||
|
@ -440,7 +440,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
|
|||
* user's requested refresh rate.
|
||||
*/
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
|
|
|
@ -103,7 +103,6 @@ struct intel_sdvo {
|
|||
|
||||
bool has_hdmi_monitor;
|
||||
bool has_hdmi_audio;
|
||||
bool rgb_quant_range_selectable;
|
||||
|
||||
/* DDC bus used by this SDVO encoder */
|
||||
uint8_t ddc_bus;
|
||||
|
@ -981,29 +980,30 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
|
|||
}
|
||||
|
||||
static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
|
||||
const struct intel_crtc_state *pipe_config)
|
||||
const struct intel_crtc_state *pipe_config,
|
||||
const struct drm_connector_state *conn_state)
|
||||
{
|
||||
const struct drm_display_mode *adjusted_mode =
|
||||
&pipe_config->base.adjusted_mode;
|
||||
uint8_t sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
|
||||
union hdmi_infoframe frame;
|
||||
int ret;
|
||||
ssize_t len;
|
||||
|
||||
ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
|
||||
&pipe_config->base.adjusted_mode,
|
||||
false);
|
||||
conn_state->connector,
|
||||
adjusted_mode);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("couldn't fill AVI infoframe\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (intel_sdvo->rgb_quant_range_selectable) {
|
||||
if (pipe_config->limited_color_range)
|
||||
frame.avi.quantization_range =
|
||||
HDMI_QUANTIZATION_RANGE_LIMITED;
|
||||
else
|
||||
frame.avi.quantization_range =
|
||||
HDMI_QUANTIZATION_RANGE_FULL;
|
||||
}
|
||||
drm_hdmi_avi_infoframe_quant_range(&frame.avi,
|
||||
conn_state->connector,
|
||||
adjusted_mode,
|
||||
pipe_config->limited_color_range ?
|
||||
HDMI_QUANTIZATION_RANGE_LIMITED :
|
||||
HDMI_QUANTIZATION_RANGE_FULL);
|
||||
|
||||
len = hdmi_infoframe_pack(&frame, sdvo_data, sizeof(sdvo_data));
|
||||
if (len < 0)
|
||||
|
@ -1108,9 +1108,9 @@ static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config)
|
|||
pipe_config->clock_set = true;
|
||||
}
|
||||
|
||||
static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
static int intel_sdvo_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
|
||||
struct intel_sdvo_connector_state *intel_sdvo_state =
|
||||
|
@ -1135,7 +1135,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
|
|||
*/
|
||||
if (IS_TV(intel_sdvo_connector)) {
|
||||
if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode))
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
(void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
|
||||
intel_sdvo_connector,
|
||||
|
@ -1145,7 +1145,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
|
|||
} else if (IS_LVDS(intel_sdvo_connector)) {
|
||||
if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
|
||||
intel_sdvo_connector->base.panel.fixed_mode))
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
(void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
|
||||
intel_sdvo_connector,
|
||||
|
@ -1154,7 +1154,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
|
|||
}
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Make the CRTC code factor in the SDVO pixel multiplier. The
|
||||
|
@ -1194,7 +1194,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
|
|||
if (intel_sdvo_connector->is_hdmi)
|
||||
adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio;
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define UPDATE_PROPERTY(input, NAME) \
|
||||
|
@ -1316,7 +1316,8 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
|
|||
intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
|
||||
intel_sdvo_set_colorimetry(intel_sdvo,
|
||||
SDVO_COLORIMETRY_RGB256);
|
||||
intel_sdvo_set_avi_infoframe(intel_sdvo, crtc_state);
|
||||
intel_sdvo_set_avi_infoframe(intel_sdvo,
|
||||
crtc_state, conn_state);
|
||||
} else
|
||||
intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI);
|
||||
|
||||
|
@ -1802,8 +1803,6 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector)
|
|||
if (intel_sdvo_connector->is_hdmi) {
|
||||
intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);
|
||||
intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid);
|
||||
intel_sdvo->rgb_quant_range_selectable =
|
||||
drm_rgb_quant_range_selectable(edid);
|
||||
}
|
||||
} else
|
||||
status = connector_status_disconnected;
|
||||
|
@ -1852,7 +1851,6 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
|
|||
|
||||
intel_sdvo->has_hdmi_monitor = false;
|
||||
intel_sdvo->has_hdmi_audio = false;
|
||||
intel_sdvo->rgb_quant_range_selectable = false;
|
||||
|
||||
if ((intel_sdvo_connector->output_flag & response) == 0)
|
||||
ret = connector_status_disconnected;
|
||||
|
|
|
@ -870,7 +870,7 @@ intel_tv_get_config(struct intel_encoder *encoder,
|
|||
pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
|
||||
}
|
||||
|
||||
static bool
|
||||
static int
|
||||
intel_tv_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
|
@ -880,10 +880,10 @@ intel_tv_compute_config(struct intel_encoder *encoder,
|
|||
&pipe_config->base.adjusted_mode;
|
||||
|
||||
if (!tv_mode)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
|
||||
adjusted_mode->crtc_clock = tv_mode->clock;
|
||||
|
@ -898,7 +898,7 @@ intel_tv_compute_config(struct intel_encoder *encoder,
|
|||
* or whether userspace is doing something stupid.
|
||||
*/
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -257,9 +257,9 @@ static void band_gap_reset(struct drm_i915_private *dev_priv)
|
|||
mutex_unlock(&dev_priv->sb_lock);
|
||||
}
|
||||
|
||||
static bool intel_dsi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
static int intel_dsi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi,
|
||||
|
@ -285,7 +285,7 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder,
|
|||
}
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
/* DSI uses short packets for sync events, so clear mode flags for DSI */
|
||||
adjusted_mode->flags = 0;
|
||||
|
@ -303,16 +303,16 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder,
|
|||
|
||||
ret = bxt_dsi_pll_compute(encoder, pipe_config);
|
||||
if (ret)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
} else {
|
||||
ret = vlv_dsi_pll_compute(encoder, pipe_config);
|
||||
if (ret)
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pipe_config->clock_set = true;
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool glk_dsi_enable_io(struct intel_encoder *encoder)
|
||||
|
|
|
@ -981,7 +981,8 @@ static int mtk_hdmi_setup_avi_infoframe(struct mtk_hdmi *hdmi,
|
|||
u8 buffer[17];
|
||||
ssize_t err;
|
||||
|
||||
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
|
||||
err = drm_hdmi_avi_infoframe_from_display_mode(&frame,
|
||||
&hdmi->conn, mode);
|
||||
if (err < 0) {
|
||||
dev_err(hdmi->dev,
|
||||
"Failed to get AVI infoframe from mode: %zd\n", err);
|
||||
|
|
|
@ -152,6 +152,23 @@ static void meson_vpu_init(struct meson_drm *priv)
|
|||
writel_relaxed(0x20000, priv->io_base + _REG(VPU_WRARB_MODE_L2C1));
|
||||
}
|
||||
|
||||
static void meson_remove_framebuffers(void)
|
||||
{
|
||||
struct apertures_struct *ap;
|
||||
|
||||
ap = alloc_apertures(1);
|
||||
if (!ap)
|
||||
return;
|
||||
|
||||
/* The framebuffer can be located anywhere in RAM */
|
||||
ap->ranges[0].base = 0;
|
||||
ap->ranges[0].size = ~0;
|
||||
|
||||
drm_fb_helper_remove_conflicting_framebuffers(ap, "meson-drm-fb",
|
||||
false);
|
||||
kfree(ap);
|
||||
}
|
||||
|
||||
static int meson_drv_bind_master(struct device *dev, bool has_components)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
@ -262,6 +279,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
|
|||
if (ret)
|
||||
goto free_drm;
|
||||
|
||||
/* Remove early framebuffers (ie. simplefb) */
|
||||
meson_remove_framebuffers();
|
||||
|
||||
drm_mode_config_init(drm);
|
||||
drm->mode_config.max_width = 3840;
|
||||
drm->mode_config.max_height = 2160;
|
||||
|
|
|
@ -365,7 +365,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
|
|||
unsigned int wr_clk =
|
||||
readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING));
|
||||
|
||||
DRM_DEBUG_DRIVER("%d:\"%s\"\n", mode->base.id, mode->name);
|
||||
DRM_DEBUG_DRIVER("\"%s\"\n", mode->name);
|
||||
|
||||
/* Enable clocks */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
|
||||
|
@ -555,12 +555,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
|
|||
int vic = drm_match_cea_mode(mode);
|
||||
enum drm_mode_status status;
|
||||
|
||||
DRM_DEBUG_DRIVER("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
|
||||
mode->base.id, mode->name, mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start,
|
||||
mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start,
|
||||
mode->vsync_end, mode->vtotal, mode->type, mode->flags);
|
||||
DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
|
||||
|
||||
/* Check against non-VIC supported modes */
|
||||
if (!vic) {
|
||||
|
@ -650,8 +645,7 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
|
|||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
int vic = drm_match_cea_mode(mode);
|
||||
|
||||
DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n",
|
||||
mode->base.id, mode->name, vic);
|
||||
DRM_DEBUG_DRIVER("\"%s\" vic %d\n", mode->name, vic);
|
||||
|
||||
/* VENC + VENC-DVI Mode setup */
|
||||
meson_venc_hdmi_mode_set(priv, vic, mode);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
#include <linux/module.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_util.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
||||
|
|
|
@ -244,14 +244,8 @@ static void mdp4_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
|||
|
||||
mode = &crtc->state->adjusted_mode;
|
||||
|
||||
DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
mdp4_crtc->name, mode->base.id, mode->name,
|
||||
mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start,
|
||||
mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start,
|
||||
mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
DBG("%s: set mode: " DRM_MODE_FMT,
|
||||
mdp4_crtc->name, DRM_MODE_ARG(mode));
|
||||
|
||||
mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma),
|
||||
MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) |
|
||||
|
|
|
@ -58,14 +58,7 @@ static void mdp4_dsi_encoder_mode_set(struct drm_encoder *encoder,
|
|||
|
||||
mode = adjusted_mode;
|
||||
|
||||
DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
mode->base.id, mode->name,
|
||||
mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start,
|
||||
mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start,
|
||||
mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode));
|
||||
|
||||
ctrl_pol = 0;
|
||||
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
|
||||
|
|
|
@ -104,14 +104,7 @@ static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder,
|
|||
|
||||
mode = adjusted_mode;
|
||||
|
||||
DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
mode->base.id, mode->name,
|
||||
mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start,
|
||||
mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start,
|
||||
mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode));
|
||||
|
||||
mdp4_dtv_encoder->pixclock = mode->clock * 1000;
|
||||
|
||||
|
|
|
@ -273,14 +273,7 @@ static void mdp4_lcdc_encoder_mode_set(struct drm_encoder *encoder,
|
|||
|
||||
mode = adjusted_mode;
|
||||
|
||||
DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
mode->base.id, mode->name,
|
||||
mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start,
|
||||
mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start,
|
||||
mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode));
|
||||
|
||||
mdp4_lcdc_encoder->pixclock = mode->clock * 1000;
|
||||
|
||||
|
|
|
@ -134,14 +134,7 @@ void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
|
|||
{
|
||||
mode = adjusted_mode;
|
||||
|
||||
DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
mode->base.id, mode->name,
|
||||
mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start,
|
||||
mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start,
|
||||
mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode));
|
||||
pingpong_tearcheck_setup(encoder, mode);
|
||||
mdp5_crtc_set_pipeline(encoder->crtc);
|
||||
}
|
||||
|
|
|
@ -384,14 +384,7 @@ static void mdp5_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
|||
|
||||
mode = &crtc->state->adjusted_mode;
|
||||
|
||||
DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
crtc->name, mode->base.id, mode->name,
|
||||
mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start,
|
||||
mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start,
|
||||
mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
DBG("%s: set mode: " DRM_MODE_FMT, crtc->name, DRM_MODE_ARG(mode));
|
||||
|
||||
mixer_width = mode->hdisplay;
|
||||
if (r_mixer)
|
||||
|
|
|
@ -118,14 +118,7 @@ static void mdp5_vid_encoder_mode_set(struct drm_encoder *encoder,
|
|||
|
||||
mode = adjusted_mode;
|
||||
|
||||
DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
mode->base.id, mode->name,
|
||||
mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start,
|
||||
mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start,
|
||||
mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode));
|
||||
|
||||
ctrl_pol = 0;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <drm/drm_util.h>
|
||||
|
||||
#include "mdp5_kms.h"
|
||||
#include "mdp5_smp.h"
|
||||
|
|
|
@ -536,14 +536,7 @@ static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge,
|
|||
struct mipi_dsi_host *host = msm_dsi->host;
|
||||
bool is_dual_dsi = IS_DUAL_DSI();
|
||||
|
||||
DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
mode->base.id, mode->name,
|
||||
mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start,
|
||||
mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start,
|
||||
mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode));
|
||||
|
||||
if (is_dual_dsi && !IS_MASTER_DSI_LINK(id))
|
||||
return;
|
||||
|
|
|
@ -60,14 +60,7 @@ static void edp_bridge_mode_set(struct drm_bridge *bridge,
|
|||
struct edp_bridge *edp_bridge = to_edp_bridge(bridge);
|
||||
struct msm_edp *edp = edp_bridge->edp;
|
||||
|
||||
DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
mode->base.id, mode->name,
|
||||
mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start,
|
||||
mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start,
|
||||
mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode));
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if ((connector->encoder != NULL) &&
|
||||
|
|
|
@ -101,7 +101,8 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
|
|||
u32 val;
|
||||
int len;
|
||||
|
||||
drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode, false);
|
||||
drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
|
||||
hdmi->connector, mode);
|
||||
|
||||
len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer));
|
||||
if (len < 0) {
|
||||
|
|
|
@ -263,23 +263,12 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags)
|
|||
|
||||
drm_kms_helper_poll_init(drm);
|
||||
|
||||
mxsfb->fbdev = drm_fbdev_cma_init(drm, 32,
|
||||
drm->mode_config.num_connector);
|
||||
if (IS_ERR(mxsfb->fbdev)) {
|
||||
ret = PTR_ERR(mxsfb->fbdev);
|
||||
mxsfb->fbdev = NULL;
|
||||
dev_err(drm->dev, "Failed to init FB CMA area\n");
|
||||
goto err_cma;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, drm);
|
||||
|
||||
drm_helper_hpd_irq_event(drm);
|
||||
|
||||
return 0;
|
||||
|
||||
err_cma:
|
||||
drm_irq_uninstall(drm);
|
||||
err_irq:
|
||||
drm_panel_detach(mxsfb->panel);
|
||||
err_vblank:
|
||||
|
@ -290,11 +279,6 @@ err_vblank:
|
|||
|
||||
static void mxsfb_unload(struct drm_device *drm)
|
||||
{
|
||||
struct mxsfb_drm_private *mxsfb = drm->dev_private;
|
||||
|
||||
if (mxsfb->fbdev)
|
||||
drm_fbdev_cma_fini(mxsfb->fbdev);
|
||||
|
||||
drm_kms_helper_poll_fini(drm);
|
||||
drm_mode_config_cleanup(drm);
|
||||
|
||||
|
@ -307,13 +291,6 @@ static void mxsfb_unload(struct drm_device *drm)
|
|||
pm_runtime_disable(drm->dev);
|
||||
}
|
||||
|
||||
static void mxsfb_lastclose(struct drm_device *drm)
|
||||
{
|
||||
struct mxsfb_drm_private *mxsfb = drm->dev_private;
|
||||
|
||||
drm_fbdev_cma_restore_mode(mxsfb->fbdev);
|
||||
}
|
||||
|
||||
static void mxsfb_irq_preinstall(struct drm_device *drm)
|
||||
{
|
||||
struct mxsfb_drm_private *mxsfb = drm->dev_private;
|
||||
|
@ -347,7 +324,6 @@ static struct drm_driver mxsfb_driver = {
|
|||
.driver_features = DRIVER_GEM | DRIVER_MODESET |
|
||||
DRIVER_PRIME | DRIVER_ATOMIC |
|
||||
DRIVER_HAVE_IRQ,
|
||||
.lastclose = mxsfb_lastclose,
|
||||
.irq_handler = mxsfb_irq_handler,
|
||||
.irq_preinstall = mxsfb_irq_preinstall,
|
||||
.irq_uninstall = mxsfb_irq_preinstall,
|
||||
|
@ -412,6 +388,8 @@ static int mxsfb_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_unload;
|
||||
|
||||
drm_fbdev_generic_setup(drm, 32);
|
||||
|
||||
return 0;
|
||||
|
||||
err_unload:
|
||||
|
|
|
@ -37,7 +37,6 @@ struct mxsfb_drm_private {
|
|||
struct drm_simple_display_pipe pipe;
|
||||
struct drm_connector connector;
|
||||
struct drm_panel *panel;
|
||||
struct drm_fbdev_cma *fbdev;
|
||||
};
|
||||
|
||||
int mxsfb_setup_crtc(struct drm_device *dev);
|
||||
|
|
|
@ -750,7 +750,9 @@ static int nv17_tv_set_property(struct drm_encoder *encoder,
|
|||
/* Disable the crtc to ensure a full modeset is
|
||||
* performed whenever it's turned on again. */
|
||||
if (crtc)
|
||||
drm_crtc_force_disable(crtc);
|
||||
drm_crtc_helper_set_mode(crtc, &crtc->mode,
|
||||
crtc->x, crtc->y,
|
||||
crtc->primary->fb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -561,7 +561,7 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode)
|
|||
u32 max_ac_packet;
|
||||
union hdmi_infoframe avi_frame;
|
||||
union hdmi_infoframe vendor_frame;
|
||||
bool scdc_supported, high_tmds_clock_ratio = false, scrambling = false;
|
||||
bool high_tmds_clock_ratio = false, scrambling = false;
|
||||
u8 config;
|
||||
int ret;
|
||||
int size;
|
||||
|
@ -571,10 +571,9 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode)
|
|||
return;
|
||||
|
||||
hdmi = &nv_connector->base.display_info.hdmi;
|
||||
scdc_supported = hdmi->scdc.supported;
|
||||
|
||||
ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, mode,
|
||||
scdc_supported);
|
||||
ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi,
|
||||
&nv_connector->base, mode);
|
||||
if (!ret) {
|
||||
/* We have an AVI InfoFrame, populate it to the display */
|
||||
args.pwr.avi_infoframe_length
|
||||
|
@ -680,6 +679,8 @@ nv50_msto_payload(struct nv50_msto *msto)
|
|||
struct nv50_mstm *mstm = mstc->mstm;
|
||||
int vcpi = mstc->port->vcpi.vcpi, i;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&mstm->mgr.payload_lock));
|
||||
|
||||
NV_ATOMIC(drm, "%s: vcpi %d\n", msto->encoder.name, vcpi);
|
||||
for (i = 0; i < mstm->mgr.max_payloads; i++) {
|
||||
struct drm_dp_payload *payload = &mstm->mgr.payloads[i];
|
||||
|
@ -704,14 +705,16 @@ nv50_msto_cleanup(struct nv50_msto *msto)
|
|||
struct nv50_mstc *mstc = msto->mstc;
|
||||
struct nv50_mstm *mstm = mstc->mstm;
|
||||
|
||||
if (!msto->disabled)
|
||||
return;
|
||||
|
||||
NV_ATOMIC(drm, "%s: msto cleanup\n", msto->encoder.name);
|
||||
if (mstc->port && mstc->port->vcpi.vcpi > 0 && !nv50_msto_payload(msto))
|
||||
drm_dp_mst_deallocate_vcpi(&mstm->mgr, mstc->port);
|
||||
if (msto->disabled) {
|
||||
msto->mstc = NULL;
|
||||
msto->head = NULL;
|
||||
msto->disabled = false;
|
||||
}
|
||||
|
||||
drm_dp_mst_deallocate_vcpi(&mstm->mgr, mstc->port);
|
||||
|
||||
msto->mstc = NULL;
|
||||
msto->head = NULL;
|
||||
msto->disabled = false;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -731,8 +734,10 @@ nv50_msto_prepare(struct nv50_msto *msto)
|
|||
(0x0100 << msto->head->base.index),
|
||||
};
|
||||
|
||||
mutex_lock(&mstm->mgr.payload_lock);
|
||||
|
||||
NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name);
|
||||
if (mstc->port && mstc->port->vcpi.vcpi > 0) {
|
||||
if (mstc->port->vcpi.vcpi > 0) {
|
||||
struct drm_dp_payload *payload = nv50_msto_payload(msto);
|
||||
if (payload) {
|
||||
args.vcpi.start_slot = payload->start_slot;
|
||||
|
@ -746,7 +751,9 @@ nv50_msto_prepare(struct nv50_msto *msto)
|
|||
msto->encoder.name, msto->head->base.base.name,
|
||||
args.vcpi.start_slot, args.vcpi.num_slots,
|
||||
args.vcpi.pbn, args.vcpi.aligned_pbn);
|
||||
|
||||
nvif_mthd(&drm->display->disp.object, 0, &args, sizeof(args));
|
||||
mutex_unlock(&mstm->mgr.payload_lock);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -754,16 +761,23 @@ nv50_msto_atomic_check(struct drm_encoder *encoder,
|
|||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct nv50_mstc *mstc = nv50_mstc(conn_state->connector);
|
||||
struct drm_atomic_state *state = crtc_state->state;
|
||||
struct drm_connector *connector = conn_state->connector;
|
||||
struct nv50_mstc *mstc = nv50_mstc(connector);
|
||||
struct nv50_mstm *mstm = mstc->mstm;
|
||||
int bpp = conn_state->connector->display_info.bpc * 3;
|
||||
int bpp = connector->display_info.bpc * 3;
|
||||
int slots;
|
||||
|
||||
mstc->pbn = drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock, bpp);
|
||||
mstc->pbn = drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock,
|
||||
bpp);
|
||||
|
||||
slots = drm_dp_find_vcpi_slots(&mstm->mgr, mstc->pbn);
|
||||
if (slots < 0)
|
||||
return slots;
|
||||
if (drm_atomic_crtc_needs_modeset(crtc_state) &&
|
||||
!drm_connector_is_unregistered(connector)) {
|
||||
slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr,
|
||||
mstc->port, mstc->pbn);
|
||||
if (slots < 0)
|
||||
return slots;
|
||||
}
|
||||
|
||||
return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state,
|
||||
mstc->native);
|
||||
|
@ -829,8 +843,7 @@ nv50_msto_disable(struct drm_encoder *encoder)
|
|||
struct nv50_mstc *mstc = msto->mstc;
|
||||
struct nv50_mstm *mstm = mstc->mstm;
|
||||
|
||||
if (mstc->port)
|
||||
drm_dp_mst_reset_vcpi_slots(&mstm->mgr, mstc->port);
|
||||
drm_dp_mst_reset_vcpi_slots(&mstm->mgr, mstc->port);
|
||||
|
||||
mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0);
|
||||
mstm->modified = true;
|
||||
|
@ -927,12 +940,43 @@ nv50_mstc_get_modes(struct drm_connector *connector)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_mstc_atomic_check(struct drm_connector *connector,
|
||||
struct drm_connector_state *new_conn_state)
|
||||
{
|
||||
struct drm_atomic_state *state = new_conn_state->state;
|
||||
struct nv50_mstc *mstc = nv50_mstc(connector);
|
||||
struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr;
|
||||
struct drm_connector_state *old_conn_state =
|
||||
drm_atomic_get_old_connector_state(state, connector);
|
||||
struct drm_crtc_state *crtc_state;
|
||||
struct drm_crtc *new_crtc = new_conn_state->crtc;
|
||||
|
||||
if (!old_conn_state->crtc)
|
||||
return 0;
|
||||
|
||||
/* We only want to free VCPI if this state disables the CRTC on this
|
||||
* connector
|
||||
*/
|
||||
if (new_crtc) {
|
||||
crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
|
||||
|
||||
if (!crtc_state ||
|
||||
!drm_atomic_crtc_needs_modeset(crtc_state) ||
|
||||
crtc_state->enable)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return drm_dp_atomic_release_vcpi_slots(state, mgr, mstc->port);
|
||||
}
|
||||
|
||||
static const struct drm_connector_helper_funcs
|
||||
nv50_mstc_help = {
|
||||
.get_modes = nv50_mstc_get_modes,
|
||||
.mode_valid = nv50_mstc_mode_valid,
|
||||
.best_encoder = nv50_mstc_best_encoder,
|
||||
.atomic_best_encoder = nv50_mstc_atomic_best_encoder,
|
||||
.atomic_check = nv50_mstc_atomic_check,
|
||||
};
|
||||
|
||||
static enum drm_connector_status
|
||||
|
@ -942,7 +986,7 @@ nv50_mstc_detect(struct drm_connector *connector, bool force)
|
|||
enum drm_connector_status conn_status;
|
||||
int ret;
|
||||
|
||||
if (!mstc->port)
|
||||
if (drm_connector_is_unregistered(connector))
|
||||
return connector_status_disconnected;
|
||||
|
||||
ret = pm_runtime_get_sync(connector->dev->dev);
|
||||
|
@ -961,7 +1005,10 @@ static void
|
|||
nv50_mstc_destroy(struct drm_connector *connector)
|
||||
{
|
||||
struct nv50_mstc *mstc = nv50_mstc(connector);
|
||||
|
||||
drm_connector_cleanup(&mstc->connector);
|
||||
drm_dp_mst_put_port_malloc(mstc->port);
|
||||
|
||||
kfree(mstc);
|
||||
}
|
||||
|
||||
|
@ -1009,6 +1056,7 @@ nv50_mstc_new(struct nv50_mstm *mstm, struct drm_dp_mst_port *port,
|
|||
drm_object_attach_property(&mstc->connector.base, dev->mode_config.path_property, 0);
|
||||
drm_object_attach_property(&mstc->connector.base, dev->mode_config.tile_property, 0);
|
||||
drm_connector_set_path_property(&mstc->connector, path);
|
||||
drm_dp_mst_get_port_malloc(port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1073,10 +1121,6 @@ nv50_mstm_destroy_connector(struct drm_dp_mst_topology_mgr *mgr,
|
|||
|
||||
drm_fb_helper_remove_one_connector(&drm->fbcon->helper, &mstc->connector);
|
||||
|
||||
drm_modeset_lock(&drm->dev->mode_config.connection_mutex, NULL);
|
||||
mstc->port = NULL;
|
||||
drm_modeset_unlock(&drm->dev->mode_config.connection_mutex);
|
||||
|
||||
drm_connector_put(&mstc->connector);
|
||||
}
|
||||
|
||||
|
@ -1099,11 +1143,8 @@ nv50_mstm_add_connector(struct drm_dp_mst_topology_mgr *mgr,
|
|||
int ret;
|
||||
|
||||
ret = nv50_mstc_new(mstm, port, path, &mstc);
|
||||
if (ret) {
|
||||
if (mstc)
|
||||
mstc->connector.funcs->destroy(&mstc->connector);
|
||||
if (ret)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &mstc->connector;
|
||||
}
|
||||
|
@ -2117,6 +2158,10 @@ nv50_disp_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = drm_dp_mst_atomic_check(state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -453,7 +453,7 @@ nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime)
|
|||
if (drm_drv_uses_atomic_modeset(dev))
|
||||
drm_atomic_helper_shutdown(dev);
|
||||
else
|
||||
drm_crtc_force_disable_all(dev);
|
||||
drm_helper_force_disable_all(dev);
|
||||
}
|
||||
|
||||
/* disable flip completion events */
|
||||
|
|
|
@ -305,14 +305,9 @@ static int omap_connector_mode_valid(struct drm_connector *connector,
|
|||
drm_mode_destroy(dev, new_mode);
|
||||
|
||||
done:
|
||||
DBG("connector: mode %s: "
|
||||
"%d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
DBG("connector: mode %s: " DRM_MODE_FMT,
|
||||
(ret == MODE_OK) ? "valid" : "invalid",
|
||||
mode->base.id, mode->name, mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start,
|
||||
mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start,
|
||||
mode->vsync_end, mode->vtotal, mode->type, mode->flags);
|
||||
DRM_MODE_ARG(mode));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -427,12 +427,8 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
|||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||
struct drm_display_mode *mode = &crtc->state->adjusted_mode;
|
||||
|
||||
DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
omap_crtc->name, mode->base.id, mode->name,
|
||||
mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
DBG("%s: set mode: " DRM_MODE_FMT,
|
||||
omap_crtc->name, DRM_MODE_ARG(mode));
|
||||
|
||||
drm_display_mode_to_videomode(mode, &omap_crtc->vm);
|
||||
}
|
||||
|
|
|
@ -76,8 +76,8 @@ static void omap_encoder_hdmi_mode_set(struct drm_encoder *encoder,
|
|||
struct hdmi_avi_infoframe avi;
|
||||
int r;
|
||||
|
||||
r = drm_hdmi_avi_infoframe_from_display_mode(&avi, adjusted_mode,
|
||||
false);
|
||||
r = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector,
|
||||
adjusted_mode);
|
||||
if (r == 0)
|
||||
dssdev->ops->hdmi.set_infoframe(dssdev, &avi);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_util.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
|
||||
#include "omap_drv.h"
|
||||
|
|
|
@ -204,6 +204,15 @@ config DRM_PANEL_SITRONIX_ST7789V
|
|||
Say Y here if you want to enable support for the Sitronix
|
||||
ST7789V controller for 240x320 LCD panels
|
||||
|
||||
config DRM_PANEL_TPO_TPG110
|
||||
tristate "TPO TPG 800x400 panel"
|
||||
depends on OF && SPI && GPIOLIB
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
help
|
||||
Say Y here if you want to enable support for TPO TPG110
|
||||
400CH LTPS TFT LCD Single Chip Digital Driver for up to
|
||||
800x400 LCD panels.
|
||||
|
||||
config DRM_PANEL_TRULY_NT35597_WQXGA
|
||||
tristate "Truly WQXGA"
|
||||
depends on OF
|
||||
|
|
|
@ -21,4 +21,5 @@ obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o
|
|||
obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
|
||||
obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
|
||||
obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o
|
||||
obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o
|
||||
obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o
|
||||
|
|
|
@ -0,0 +1,496 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Panel driver for the TPO TPG110 400CH LTPS TFT LCD Single Chip
|
||||
* Digital Driver.
|
||||
*
|
||||
* This chip drives a TFT LCD, so it does not know what kind of
|
||||
* display is actually connected to it, so the width and height of that
|
||||
* display needs to be supplied from the machine configuration.
|
||||
*
|
||||
* Author:
|
||||
* Linus Walleij <linus.walleij@linaro.org>
|
||||
*/
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#define TPG110_TEST 0x00
|
||||
#define TPG110_CHIPID 0x01
|
||||
#define TPG110_CTRL1 0x02
|
||||
#define TPG110_RES_MASK GENMASK(2, 0)
|
||||
#define TPG110_RES_800X480 0x07
|
||||
#define TPG110_RES_640X480 0x06
|
||||
#define TPG110_RES_480X272 0x05
|
||||
#define TPG110_RES_480X640 0x04
|
||||
#define TPG110_RES_480X272_D 0x01 /* Dual scan: outputs 800x480 */
|
||||
#define TPG110_RES_400X240_D 0x00 /* Dual scan: outputs 800x480 */
|
||||
#define TPG110_CTRL2 0x03
|
||||
#define TPG110_CTRL2_PM BIT(0)
|
||||
#define TPG110_CTRL2_RES_PM_CTRL BIT(7)
|
||||
|
||||
/**
|
||||
* struct tpg110_panel_mode - lookup struct for the supported modes
|
||||
*/
|
||||
struct tpg110_panel_mode {
|
||||
/**
|
||||
* @name: the name of this panel
|
||||
*/
|
||||
const char *name;
|
||||
/**
|
||||
* @magic: the magic value from the detection register
|
||||
*/
|
||||
u32 magic;
|
||||
/**
|
||||
* @mode: the DRM display mode for this panel
|
||||
*/
|
||||
struct drm_display_mode mode;
|
||||
/**
|
||||
* @bus_flags: the DRM bus flags for this panel e.g. inverted clock
|
||||
*/
|
||||
u32 bus_flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tpg110 - state container for the TPG110 panel
|
||||
*/
|
||||
struct tpg110 {
|
||||
/**
|
||||
* @dev: the container device
|
||||
*/
|
||||
struct device *dev;
|
||||
/**
|
||||
* @spi: the corresponding SPI device
|
||||
*/
|
||||
struct spi_device *spi;
|
||||
/**
|
||||
* @panel: the DRM panel instance for this device
|
||||
*/
|
||||
struct drm_panel panel;
|
||||
/**
|
||||
* @backlight: backlight for this panel
|
||||
*/
|
||||
struct backlight_device *backlight;
|
||||
/**
|
||||
* @panel_type: the panel mode as detected
|
||||
*/
|
||||
const struct tpg110_panel_mode *panel_mode;
|
||||
/**
|
||||
* @width: the width of this panel in mm
|
||||
*/
|
||||
u32 width;
|
||||
/**
|
||||
* @height: the height of this panel in mm
|
||||
*/
|
||||
u32 height;
|
||||
/**
|
||||
* @grestb: reset GPIO line
|
||||
*/
|
||||
struct gpio_desc *grestb;
|
||||
};
|
||||
|
||||
/*
|
||||
* TPG110 modes, these are the simple modes, the dualscan modes that
|
||||
* take 400x240 or 480x272 in and display as 800x480 are not listed.
|
||||
*/
|
||||
static const struct tpg110_panel_mode tpg110_modes[] = {
|
||||
{
|
||||
.name = "800x480 RGB",
|
||||
.magic = TPG110_RES_800X480,
|
||||
.mode = {
|
||||
.clock = 33200,
|
||||
.hdisplay = 800,
|
||||
.hsync_start = 800 + 40,
|
||||
.hsync_end = 800 + 40 + 1,
|
||||
.htotal = 800 + 40 + 1 + 216,
|
||||
.vdisplay = 480,
|
||||
.vsync_start = 480 + 10,
|
||||
.vsync_end = 480 + 10 + 1,
|
||||
.vtotal = 480 + 10 + 1 + 35,
|
||||
.vrefresh = 60,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
},
|
||||
{
|
||||
.name = "640x480 RGB",
|
||||
.magic = TPG110_RES_640X480,
|
||||
.mode = {
|
||||
.clock = 25200,
|
||||
.hdisplay = 640,
|
||||
.hsync_start = 640 + 24,
|
||||
.hsync_end = 640 + 24 + 1,
|
||||
.htotal = 640 + 24 + 1 + 136,
|
||||
.vdisplay = 480,
|
||||
.vsync_start = 480 + 18,
|
||||
.vsync_end = 480 + 18 + 1,
|
||||
.vtotal = 480 + 18 + 1 + 27,
|
||||
.vrefresh = 60,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
},
|
||||
{
|
||||
.name = "480x272 RGB",
|
||||
.magic = TPG110_RES_480X272,
|
||||
.mode = {
|
||||
.clock = 9000,
|
||||
.hdisplay = 480,
|
||||
.hsync_start = 480 + 2,
|
||||
.hsync_end = 480 + 2 + 1,
|
||||
.htotal = 480 + 2 + 1 + 43,
|
||||
.vdisplay = 272,
|
||||
.vsync_start = 272 + 2,
|
||||
.vsync_end = 272 + 2 + 1,
|
||||
.vtotal = 272 + 2 + 1 + 12,
|
||||
.vrefresh = 60,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
},
|
||||
{
|
||||
.name = "480x640 RGB",
|
||||
.magic = TPG110_RES_480X640,
|
||||
.mode = {
|
||||
.clock = 20500,
|
||||
.hdisplay = 480,
|
||||
.hsync_start = 480 + 2,
|
||||
.hsync_end = 480 + 2 + 1,
|
||||
.htotal = 480 + 2 + 1 + 43,
|
||||
.vdisplay = 640,
|
||||
.vsync_start = 640 + 4,
|
||||
.vsync_end = 640 + 4 + 1,
|
||||
.vtotal = 640 + 4 + 1 + 8,
|
||||
.vrefresh = 60,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
},
|
||||
{
|
||||
.name = "400x240 RGB",
|
||||
.magic = TPG110_RES_400X240_D,
|
||||
.mode = {
|
||||
.clock = 8300,
|
||||
.hdisplay = 400,
|
||||
.hsync_start = 400 + 20,
|
||||
.hsync_end = 400 + 20 + 1,
|
||||
.htotal = 400 + 20 + 1 + 108,
|
||||
.vdisplay = 240,
|
||||
.vsync_start = 240 + 2,
|
||||
.vsync_end = 240 + 2 + 1,
|
||||
.vtotal = 240 + 2 + 1 + 20,
|
||||
.vrefresh = 60,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
},
|
||||
};
|
||||
|
||||
static inline struct tpg110 *
|
||||
to_tpg110(struct drm_panel *panel)
|
||||
{
|
||||
return container_of(panel, struct tpg110, panel);
|
||||
}
|
||||
|
||||
static u8 tpg110_readwrite_reg(struct tpg110 *tpg, bool write,
|
||||
u8 address, u8 outval)
|
||||
{
|
||||
struct spi_message m;
|
||||
struct spi_transfer t[2];
|
||||
u8 buf[2];
|
||||
int ret;
|
||||
|
||||
spi_message_init(&m);
|
||||
memset(t, 0, sizeof(t));
|
||||
|
||||
if (write) {
|
||||
/*
|
||||
* Clear address bit 0, 1 when writing, just to be sure
|
||||
* The actual bit indicating a write here is bit 1, bit
|
||||
* 0 is just surplus to pad it up to 8 bits.
|
||||
*/
|
||||
buf[0] = address << 2;
|
||||
buf[0] &= ~0x03;
|
||||
buf[1] = outval;
|
||||
|
||||
t[0].bits_per_word = 8;
|
||||
t[0].tx_buf = &buf[0];
|
||||
t[0].len = 1;
|
||||
|
||||
t[1].tx_buf = &buf[1];
|
||||
t[1].len = 1;
|
||||
t[1].bits_per_word = 8;
|
||||
} else {
|
||||
/* Set address bit 0 to 1 to read */
|
||||
buf[0] = address << 1;
|
||||
buf[0] |= 0x01;
|
||||
|
||||
/*
|
||||
* The last bit/clock is Hi-Z turnaround cycle, so we need
|
||||
* to send only 7 bits here. The 8th bit is the high impedance
|
||||
* turn-around cycle.
|
||||
*/
|
||||
t[0].bits_per_word = 7;
|
||||
t[0].tx_buf = &buf[0];
|
||||
t[0].len = 1;
|
||||
|
||||
t[1].rx_buf = &buf[1];
|
||||
t[1].len = 1;
|
||||
t[1].bits_per_word = 8;
|
||||
}
|
||||
|
||||
spi_message_add_tail(&t[0], &m);
|
||||
spi_message_add_tail(&t[1], &m);
|
||||
ret = spi_sync(tpg->spi, &m);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(tpg->dev, "SPI message error %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (write)
|
||||
return 0;
|
||||
/* Read */
|
||||
return buf[1];
|
||||
}
|
||||
|
||||
static u8 tpg110_read_reg(struct tpg110 *tpg, u8 address)
|
||||
{
|
||||
return tpg110_readwrite_reg(tpg, false, address, 0);
|
||||
}
|
||||
|
||||
static void tpg110_write_reg(struct tpg110 *tpg, u8 address, u8 outval)
|
||||
{
|
||||
tpg110_readwrite_reg(tpg, true, address, outval);
|
||||
}
|
||||
|
||||
static int tpg110_startup(struct tpg110 *tpg)
|
||||
{
|
||||
u8 val;
|
||||
int i;
|
||||
|
||||
/* De-assert the reset signal */
|
||||
gpiod_set_value_cansleep(tpg->grestb, 0);
|
||||
usleep_range(1000, 2000);
|
||||
DRM_DEV_DEBUG(tpg->dev, "de-asserted GRESTB\n");
|
||||
|
||||
/* Test display communication */
|
||||
tpg110_write_reg(tpg, TPG110_TEST, 0x55);
|
||||
val = tpg110_read_reg(tpg, TPG110_TEST);
|
||||
if (val != 0x55) {
|
||||
DRM_DEV_ERROR(tpg->dev, "failed communication test\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
val = tpg110_read_reg(tpg, TPG110_CHIPID);
|
||||
DRM_DEV_INFO(tpg->dev, "TPG110 chip ID: %d version: %d\n",
|
||||
val >> 4, val & 0x0f);
|
||||
|
||||
/* Show display resolution */
|
||||
val = tpg110_read_reg(tpg, TPG110_CTRL1);
|
||||
val &= TPG110_RES_MASK;
|
||||
switch (val) {
|
||||
case TPG110_RES_400X240_D:
|
||||
DRM_DEV_INFO(tpg->dev,
|
||||
"IN 400x240 RGB -> OUT 800x480 RGB (dual scan)\n");
|
||||
break;
|
||||
case TPG110_RES_480X272_D:
|
||||
DRM_DEV_INFO(tpg->dev,
|
||||
"IN 480x272 RGB -> OUT 800x480 RGB (dual scan)\n");
|
||||
break;
|
||||
case TPG110_RES_480X640:
|
||||
DRM_DEV_INFO(tpg->dev, "480x640 RGB\n");
|
||||
break;
|
||||
case TPG110_RES_480X272:
|
||||
DRM_DEV_INFO(tpg->dev, "480x272 RGB\n");
|
||||
break;
|
||||
case TPG110_RES_640X480:
|
||||
DRM_DEV_INFO(tpg->dev, "640x480 RGB\n");
|
||||
break;
|
||||
case TPG110_RES_800X480:
|
||||
DRM_DEV_INFO(tpg->dev, "800x480 RGB\n");
|
||||
break;
|
||||
default:
|
||||
DRM_DEV_ERROR(tpg->dev, "ILLEGAL RESOLUTION 0x%02x\n", val);
|
||||
break;
|
||||
}
|
||||
|
||||
/* From the producer side, this is the same resolution */
|
||||
if (val == TPG110_RES_480X272_D)
|
||||
val = TPG110_RES_480X272;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tpg110_modes); i++) {
|
||||
const struct tpg110_panel_mode *pm;
|
||||
|
||||
pm = &tpg110_modes[i];
|
||||
if (pm->magic == val) {
|
||||
tpg->panel_mode = pm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == ARRAY_SIZE(tpg110_modes)) {
|
||||
DRM_DEV_ERROR(tpg->dev, "unsupported mode (%02x) detected\n",
|
||||
val);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
val = tpg110_read_reg(tpg, TPG110_CTRL2);
|
||||
DRM_DEV_INFO(tpg->dev, "resolution and standby is controlled by %s\n",
|
||||
(val & TPG110_CTRL2_RES_PM_CTRL) ? "software" : "hardware");
|
||||
/* Take control over resolution and standby */
|
||||
val |= TPG110_CTRL2_RES_PM_CTRL;
|
||||
tpg110_write_reg(tpg, TPG110_CTRL2, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tpg110_disable(struct drm_panel *panel)
|
||||
{
|
||||
struct tpg110 *tpg = to_tpg110(panel);
|
||||
u8 val;
|
||||
|
||||
/* Put chip into standby */
|
||||
val = tpg110_read_reg(tpg, TPG110_CTRL2_PM);
|
||||
val &= ~TPG110_CTRL2_PM;
|
||||
tpg110_write_reg(tpg, TPG110_CTRL2_PM, val);
|
||||
|
||||
backlight_disable(tpg->backlight);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tpg110_enable(struct drm_panel *panel)
|
||||
{
|
||||
struct tpg110 *tpg = to_tpg110(panel);
|
||||
u8 val;
|
||||
|
||||
backlight_enable(tpg->backlight);
|
||||
|
||||
/* Take chip out of standby */
|
||||
val = tpg110_read_reg(tpg, TPG110_CTRL2_PM);
|
||||
val |= TPG110_CTRL2_PM;
|
||||
tpg110_write_reg(tpg, TPG110_CTRL2_PM, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tpg110_get_modes() - return the appropriate mode
|
||||
* @panel: the panel to get the mode for
|
||||
*
|
||||
* This currently does not present a forest of modes, instead it
|
||||
* presents the mode that is configured for the system under use,
|
||||
* and which is detected by reading the registers of the display.
|
||||
*/
|
||||
static int tpg110_get_modes(struct drm_panel *panel)
|
||||
{
|
||||
struct drm_connector *connector = panel->connector;
|
||||
struct tpg110 *tpg = to_tpg110(panel);
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
strncpy(connector->display_info.name, tpg->panel_mode->name,
|
||||
DRM_DISPLAY_INFO_LEN);
|
||||
connector->display_info.width_mm = tpg->width;
|
||||
connector->display_info.height_mm = tpg->height;
|
||||
connector->display_info.bus_flags = tpg->panel_mode->bus_flags;
|
||||
|
||||
mode = drm_mode_duplicate(panel->drm, &tpg->panel_mode->mode);
|
||||
drm_mode_set_name(mode);
|
||||
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
|
||||
|
||||
mode->width_mm = tpg->width;
|
||||
mode->height_mm = tpg->height;
|
||||
|
||||
drm_mode_probed_add(connector, mode);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct drm_panel_funcs tpg110_drm_funcs = {
|
||||
.disable = tpg110_disable,
|
||||
.enable = tpg110_enable,
|
||||
.get_modes = tpg110_get_modes,
|
||||
};
|
||||
|
||||
static int tpg110_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct tpg110 *tpg;
|
||||
int ret;
|
||||
|
||||
tpg = devm_kzalloc(dev, sizeof(*tpg), GFP_KERNEL);
|
||||
if (!tpg)
|
||||
return -ENOMEM;
|
||||
tpg->dev = dev;
|
||||
|
||||
/* We get the physical display dimensions from the DT */
|
||||
ret = of_property_read_u32(np, "width-mm", &tpg->width);
|
||||
if (ret)
|
||||
DRM_DEV_ERROR(dev, "no panel width specified\n");
|
||||
ret = of_property_read_u32(np, "height-mm", &tpg->height);
|
||||
if (ret)
|
||||
DRM_DEV_ERROR(dev, "no panel height specified\n");
|
||||
|
||||
/* Look for some optional backlight */
|
||||
tpg->backlight = devm_of_find_backlight(dev);
|
||||
if (IS_ERR(tpg->backlight))
|
||||
return PTR_ERR(tpg->backlight);
|
||||
|
||||
/* This asserts the GRESTB signal, putting the display into reset */
|
||||
tpg->grestb = devm_gpiod_get(dev, "grestb", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(tpg->grestb)) {
|
||||
DRM_DEV_ERROR(dev, "no GRESTB GPIO\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
spi->bits_per_word = 8;
|
||||
spi->mode |= SPI_3WIRE_HIZ;
|
||||
ret = spi_setup(spi);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(dev, "spi setup failed.\n");
|
||||
return ret;
|
||||
}
|
||||
tpg->spi = spi;
|
||||
|
||||
ret = tpg110_startup(tpg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drm_panel_init(&tpg->panel);
|
||||
tpg->panel.dev = dev;
|
||||
tpg->panel.funcs = &tpg110_drm_funcs;
|
||||
spi_set_drvdata(spi, tpg);
|
||||
|
||||
return drm_panel_add(&tpg->panel);
|
||||
}
|
||||
|
||||
static int tpg110_remove(struct spi_device *spi)
|
||||
{
|
||||
struct tpg110 *tpg = spi_get_drvdata(spi);
|
||||
|
||||
drm_panel_remove(&tpg->panel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id tpg110_match[] = {
|
||||
{ .compatible = "tpo,tpg110", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tpg110_match);
|
||||
|
||||
static struct spi_driver tpg110_driver = {
|
||||
.probe = tpg110_probe,
|
||||
.remove = tpg110_remove,
|
||||
.driver = {
|
||||
.name = "tpo-tpg110-panel",
|
||||
.of_match_table = tpg110_match,
|
||||
},
|
||||
};
|
||||
module_spi_driver(tpg110_driver);
|
||||
|
||||
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
|
||||
MODULE_DESCRIPTION("TPO TPG110 panel driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
/* QXL cmd/ring handling */
|
||||
|
||||
#include <drm/drm_util.h>
|
||||
|
||||
#include "qxl_drv.h"
|
||||
#include "qxl_object.h"
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче