drm-misc-next for v5.3:

UAPI Changes:
 
 Cross-subsystem Changes:
 - Add devicetree bindings for new panels.
 - Convert allwinner's DT bindings to a schema.
 - Drop video/hdmi static functions from kernel docs.
 - Discard old fence when reserving space in reservation_object_get_fences_rcu.
 
 Core Changes:
 - Add missing -ENOMEM handling in edid loading.
 - Fix null pointer deref in scheduler.
 - Header cleanups, making them self-contained.
 - Remove drmP.h inclusion from core.
 - Fix make htmldocs warning in scheduler and HDR metadata.
 - Fix a few warnings in the uapi header and add a doc section for it.
 - Small MST sideband error handling fix.
 - Clarify userspace review requirements.
 - Clarify implicit/explicit fencing in docs.
 - Flush output polling on shutdown.
 
 Driver Changes:
 - Small cleanups to stm.
 - Add new driver for ST-Ericsson MCDE
 - Kconfig fix for meson HDMI.
 - Add support for Armadeus ST0700 Adapt panel.
 - Add KOE tx14d24vm1bpa panel.
 - Update timings for st7701.
 - Fix compile error in mcde.
 - Big series of tc358767 fixes, and enabling support for IRQ and HPD handling.
 - Assorted fixes to sii902x, and implementing HDMI audio support.
 - Enable HDR metadata support on amdgpu.
 - Assorted fixes to atmel-hlcdc, and add sam9x60 LCD controller support.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAlz3iIMACgkQ/lWMcqZw
 E8NlwA/+NxCaUyuymD7dxw266Y4HlsL+jcba1pYOjuMpknnhb4HgDEgg//UekjSN
 UxskzNh4H4+DD4yphgsFn5wqkivlUxTFS+mt0FdrjT8h2gij4jQQ1k8EIMeuxg5P
 OHjJYwvHN2c/4fiQF9Fo5/nxYciN0erzcA7mFcbMeDIWtyO7BBr/6eXKl68G9FwH
 cXvpshNzVNvvpoaSpZLnxm/YkLDZNj1Io0+sVu2/w0AY0jmGEFFFpXxh42nnh4TL
 CwLzilfstJnXmJuM5nwcpUS1pV9IovauVDD3owGL5J1ZwiFy8j+e9GAA4kv6pf8C
 VsK3FynFt7u1BX26yfLWVLbCFF8wrpz5B3WZXrJLGiSpQi3zshpc/CMnchLfOdYf
 FijrQTrciVsQglxrDqqtaJ54ReF7wr5LWW3PhB1GYZRbQb9pZ4h4zroQQToFSkBa
 uxAEj9khJWgLhY6CeYzVbT1kShqjG7vjskDUbw493tZ+VqvL04Cy47npYi28iYxu
 hl+5maJY5KWnO6YTeJbuox3GjWelURtGhqfxbWhRAn1h74UQNjG8U9x5fWf3f4v7
 YgZn4Z2UvHrs5XQdZE9sZm01vKFtQM7IHqfM5l2ZkKmKY/SQ1fII/XISOoaoLIZl
 X35WwB727OS4vTSCusd5QGKESh0WFtUB8dFM/NfXNQM7SGXtG/c=
 =GrAP
 -----END PGP SIGNATURE-----

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

drm-misc-next for v5.3:

UAPI Changes:

Cross-subsystem Changes:
- Add devicetree bindings for new panels.
- Convert allwinner's DT bindings to a schema.
- Drop video/hdmi static functions from kernel docs.
- Discard old fence when reserving space in reservation_object_get_fences_rcu.

Core Changes:
- Add missing -ENOMEM handling in edid loading.
- Fix null pointer deref in scheduler.
- Header cleanups, making them self-contained.
- Remove drmP.h inclusion from core.
- Fix make htmldocs warning in scheduler and HDR metadata.
- Fix a few warnings in the uapi header and add a doc section for it.
- Small MST sideband error handling fix.
- Clarify userspace review requirements.
- Clarify implicit/explicit fencing in docs.
- Flush output polling on shutdown.

Driver Changes:
- Small cleanups to stm.
- Add new driver for ST-Ericsson MCDE
- Kconfig fix for meson HDMI.
- Add support for Armadeus ST0700 Adapt panel.
- Add KOE tx14d24vm1bpa panel.
- Update timings for st7701.
- Fix compile error in mcde.
- Big series of tc358767 fixes, and enabling support for IRQ and HPD handling.
- Assorted fixes to sii902x, and implementing HDMI audio support.
- Enable HDR metadata support on amdgpu.
- Assorted fixes to atmel-hlcdc, and add sam9x60 LCD controller support.

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

From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/6c43ffa9-11ff-5354-d772-c20fd4d1e3d9@linux.intel.com
This commit is contained in:
Dave Airlie 2019-06-06 12:16:17 +10:00
commit 141de1d46f
152 changed files with 6331 additions and 887 deletions

View File

@ -0,0 +1,100 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/allwinner,sun6i-a31-mipi-dsi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Allwinner A31 MIPI-DSI Controller Device Tree Bindings
maintainers:
- Chen-Yu Tsai <wens@csie.org>
- Maxime Ripard <maxime.ripard@bootlin.com>
properties:
"#address-cells": true
"#size-cells": true
compatible:
const: allwinner,sun6i-a31-mipi-dsi
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: Bus Clock
- description: Module Clock
clock-names:
items:
- const: bus
- const: mod
resets:
maxItems: 1
phys:
maxItems: 1
phy-names:
const: dphy
port:
type: object
description:
A port node with endpoint definitions as defined in
Documentation/devicetree/bindings/media/video-interfaces.txt. That
port should be the input endpoint, usually coming from the
associated TCON.
patternProperties:
"^panel@[0-9]+$": true
required:
- "#address-cells"
- "#size-cells"
- compatible
- reg
- interrupts
- clocks
- clock-names
- phys
- phy-names
- resets
- port
additionalProperties: false
examples:
- |
dsi0: dsi@1ca0000 {
compatible = "allwinner,sun6i-a31-mipi-dsi";
reg = <0x01ca0000 0x1000>;
interrupts = <0 89 4>;
clocks = <&ccu 23>, <&ccu 96>;
clock-names = "bus", "mod";
resets = <&ccu 4>;
phys = <&dphy0>;
phy-names = "dphy";
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "bananapi,lhr050h41", "ilitek,ili9881c";
reg = <0>;
power-gpios = <&pio 1 7 0>; /* PB07 */
reset-gpios = <&r_pio 0 5 1>; /* PL05 */
backlight = <&pwm_bl>;
};
port {
dsi0_in_tcon0: endpoint {
remote-endpoint = <&tcon0_out_dsi0>;
};
};
};
...

View File

@ -5,10 +5,44 @@ Required properties:
- reg: i2c address of the bridge
Optional properties:
- interrupts: describe the interrupt line used to inform the host
- interrupts: describe the interrupt line used to inform the host
about hotplug events.
- reset-gpios: OF device-tree gpio specification for RST_N pin.
HDMI audio properties:
- #sound-dai-cells: <0> or <1>. <0> if only i2s or spdif pin
is wired, <1> if the both are wired. HDMI audio is
configured only if this property is found.
- sil,i2s-data-lanes: Array of up to 4 integers with values of 0-3
Each integer indicates which i2s pin is connected to which
audio fifo. The first integer selects i2s audio pin for the
first audio fifo#0 (HDMI channels 1&2), second for fifo#1
(HDMI channels 3&4), and so on. There is 4 fifos and 4 i2s
pins (SD0 - SD3). Any i2s pin can be connected to any fifo,
but there can be no gaps. E.g. an i2s pin must be mapped to
fifo#0 and fifo#1 before mapping a channel to fifo#2. Default
value is <0>, describing SD0 pin beiging routed to hdmi audio
fifo #0.
- clocks: phandle and clock specifier for each clock listed in
the clock-names property
- clock-names: "mclk"
Describes SII902x MCLK input. MCLK is used to produce
HDMI audio CTS values. This property is required if
"#sound-dai-cells"-property is present. This property follows
Documentation/devicetree/bindings/clock/clock-bindings.txt
consumer binding.
If HDMI audio is configured the sii902x device becomes an I2S
and/or spdif audio codec component (e.g a digital audio sink),
that can be used in configuring a full audio devices with
simple-card or audio-graph-card binding. See their binding
documents on how to describe the way the sii902x device is
connected to the rest of the audio system:
Documentation/devicetree/bindings/sound/simple-card.txt
Documentation/devicetree/bindings/sound/audio-graph-card.txt
Note: In case of the audio-graph-card binding the used port
index should be 3.
Optional subnodes:
- video input: this subnode can contain a video input port node
to connect the bridge to a display controller output (See this
@ -21,6 +55,12 @@ Example:
compatible = "sil,sii9022";
reg = <0x39>;
reset-gpios = <&pioA 1 0>;
#sound-dai-cells = <0>;
sil,i2s-data-lanes = < 0 1 2 >;
clocks = <&mclk>;
clock-names = "mclk";
ports {
#address-cells = <1>;
#size-cells = <0>;

View File

@ -12,6 +12,7 @@ Optional properties:
(active high shutdown input)
- reset-gpios: OF device-tree gpio specification for RSTX pin
(active low system reset)
- toshiba,hpd-pin: TC358767 GPIO pin number to which HPD is connected to (0 or 1)
- ports: the ports node can contain video interface port nodes to connect
to a DPI/DSI source and to an eDP/DP sink according to [1][2]:
- port@0: DSI input port

View File

@ -0,0 +1,9 @@
Armadeus ST0700 Adapt. A Santek ST0700I5Y-RBSLW 7.0" WVGA (800x480) TFT with
an adapter board.
Required properties:
- compatible: "armadeus,st0700-adapt"
- power-supply: see panel-common.txt
Optional properties:
- backlight: see panel-common.txt

View File

@ -0,0 +1,42 @@
Kaohsiung Opto-Electronics Inc. 5.7" QVGA (320 x 240) TFT LCD panel
Required properties:
- compatible: should be "koe,tx14d24vm1bpa"
- backlight: phandle of the backlight device attached to the panel
- power-supply: single regulator to provide the supply voltage
Required nodes:
- port: Parallel port mapping to connect this display
This panel needs single power supply voltage. Its backlight is conntrolled
via PWM signal.
Example:
--------
Example device-tree definition when connected to iMX53 based board
lcd_panel: lcd-panel {
compatible = "koe,tx14d24vm1bpa";
backlight = <&backlight_lcd>;
power-supply = <&reg_3v3>;
port {
lcd_panel_in: endpoint {
remote-endpoint = <&lcd_display_out>;
};
};
};
Then one needs to extend the dispX node:
lcd_display: disp1 {
port@1 {
reg = <1>;
lcd_display_out: endpoint {
remote-endpoint = <&lcd_panel_in>;
};
};
};

View File

@ -1,93 +0,0 @@
Allwinner A31 DSI Encoder
=========================
The DSI pipeline consists of two separate blocks: the DSI controller
itself, and its associated D-PHY.
DSI Encoder
-----------
The DSI Encoder generates the DSI signal from the TCON's.
Required properties:
- compatible: value must be one of:
* allwinner,sun6i-a31-mipi-dsi
- reg: base address and size of memory-mapped region
- interrupts: interrupt associated to this IP
- clocks: phandles to the clocks feeding the DSI encoder
* bus: the DSI interface clock
* mod: the DSI module clock
- clock-names: the clock names mentioned above
- phys: phandle to the D-PHY
- phy-names: must be "dphy"
- resets: phandle to the reset controller driving the encoder
- ports: A ports node with endpoint definitions as defined in
Documentation/devicetree/bindings/media/video-interfaces.txt. The
first port should be the input endpoint, usually coming from the
associated TCON.
Any MIPI-DSI device attached to this should be described according to
the bindings defined in ../mipi-dsi-bus.txt
D-PHY
-----
Required properties:
- compatible: value must be one of:
* allwinner,sun6i-a31-mipi-dphy
- reg: base address and size of memory-mapped region
- clocks: phandles to the clocks feeding the DSI encoder
* bus: the DSI interface clock
* mod: the DSI module clock
- clock-names: the clock names mentioned above
- resets: phandle to the reset controller driving the encoder
Example:
dsi0: dsi@1ca0000 {
compatible = "allwinner,sun6i-a31-mipi-dsi";
reg = <0x01ca0000 0x1000>;
interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_BUS_MIPI_DSI>,
<&ccu CLK_DSI_SCLK>;
clock-names = "bus", "mod";
resets = <&ccu RST_BUS_MIPI_DSI>;
phys = <&dphy0>;
phy-names = "dphy";
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "bananapi,lhr050h41", "ilitek,ili9881c";
reg = <0>;
power-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* PB07 */
reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_LOW>; /* PL05 */
backlight = <&pwm_bl>;
};
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
dsi0_in_tcon0: endpoint {
remote-endpoint = <&tcon0_out_dsi0>;
};
};
};
};
dphy0: d-phy@1ca1000 {
compatible = "allwinner,sun6i-a31-mipi-dphy";
reg = <0x01ca1000 0x1000>;
clocks = <&ccu CLK_BUS_MIPI_DSI>,
<&ccu CLK_DSI_DPHY>;
clock-names = "bus", "mod";
resets = <&ccu RST_BUS_MIPI_DSI>;
#phy-cells = <0>;
};

View File

@ -0,0 +1,57 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/allwinner,sun6i-a31-mipi-dphy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Allwinner A31 MIPI D-PHY Controller Device Tree Bindings
maintainers:
- Chen-Yu Tsai <wens@csie.org>
- Maxime Ripard <maxime.ripard@bootlin.com>
properties:
"#phy-cells":
const: 0
compatible:
const: allwinner,sun6i-a31-mipi-dphy
reg:
maxItems: 1
clocks:
items:
- description: Bus Clock
- description: Module Clock
clock-names:
items:
- const: bus
- const: mod
resets:
maxItems: 1
required:
- "#phy-cells"
- compatible
- reg
- clocks
- clock-names
- resets
additionalProperties: false
examples:
- |
dphy0: d-phy@1ca1000 {
compatible = "allwinner,sun6i-a31-mipi-dphy";
reg = <0x01ca1000 0x1000>;
clocks = <&ccu 23>, <&ccu 97>;
clock-names = "bus", "mod";
resets = <&ccu 4>;
#phy-cells = <0>;
};
...

View File

@ -7,6 +7,7 @@ GPU Driver Documentation
amdgpu
amdgpu-dc
i915
mcde
meson
pl111
tegra

View File

@ -10,3 +10,6 @@ Kernel clients
.. kernel-doc:: drivers/gpu/drm/drm_client.c
:export:
.. kernel-doc:: drivers/gpu/drm/drm_client_modeset.c
:export:

View File

@ -85,9 +85,9 @@ leads to a few additional requirements:
- The userspace side must be fully reviewed and tested to the standards of that
userspace project. For e.g. mesa this means piglit testcases and review on the
mailing list. This is again to ensure that the new interface actually gets the
job done. The userspace-side reviewer should also provide at least an
Acked-by on the kernel uAPI patch indicating that they've looked at how the
kernel side is implementing the new feature being used.
job done. The userspace-side reviewer should also provide an Acked-by on the
kernel uAPI patch indicating that they believe the proposed uAPI is sound and
sufficiently documented and validated for userspace's consumption.
- The userspace patches must be against the canonical upstream, not some vendor
fork. This is to make sure that no one cheats on the review and testing
@ -329,3 +329,12 @@ DRM_IOCTL_MODESET_CTL
mode setting, since on many devices the vertical blank counter is
reset to 0 at some point during modeset. Modern drivers should not
call this any more since with kernel mode setting it is a no-op.
Userspace API Structures
========================
.. kernel-doc:: include/uapi/drm/drm_mode.h
:doc: overview
.. kernel-doc:: include/uapi/drm/drm_mode.h
:internal:

View File

@ -0,0 +1,8 @@
.. SPDX-License-Identifier: GPL-2.0
=======================================================
drm/mcde ST-Ericsson MCDE Multi-channel display engine
=======================================================
.. kernel-doc:: drivers/gpu/drm/mcde/mcde_drv.c
:doc: ST-Ericsson MCDE DRM Driver

View File

@ -289,6 +289,9 @@ drm_fb_helper tasks
these igt tests need to be fixed: kms_fbcon_fbt@psr and
kms_fbcon_fbt@psr-suspend.
- The max connector argument for drm_fb_helper_init() and
drm_fb_helper_fbdev_setup() isn't used anymore and can be removed.
Core refactorings
=================

View File

@ -5128,6 +5128,13 @@ S: Maintained
F: drivers/gpu/drm/tinydrm/st7735r.c
F: Documentation/devicetree/bindings/display/sitronix,st7735r.txt
DRM DRIVER FOR ST-ERICSSON MCDE
M: Linus Walleij <linus.walleij@linaro.org>
T: git git://anongit.freedesktop.org/drm/drm-misc
S: Maintained
F: drivers/gpu/drm/mcde/
F: Documentation/devicetree/bindings/display/ste,mcde.txt
DRM DRIVER FOR TDFX VIDEO CARDS
S: Orphan / Obsolete
F: drivers/gpu/drm/tdfx/

View File

@ -365,6 +365,10 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
GFP_NOWAIT | __GFP_NOWARN);
if (!nshared) {
rcu_read_unlock();
dma_fence_put(fence_excl);
fence_excl = NULL;
nshared = krealloc(shared, sz, GFP_KERNEL);
if (nshared) {
shared = nshared;

View File

@ -350,6 +350,8 @@ source "drivers/gpu/drm/panfrost/Kconfig"
source "drivers/gpu/drm/aspeed/Kconfig"
source "drivers/gpu/drm/mcde/Kconfig"
# Keep legacy drivers last
menuconfig DRM_LEGACY

View File

@ -17,7 +17,7 @@ drm-y := drm_auth.o drm_cache.o \
drm_plane.o drm_color_mgmt.o drm_print.o \
drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \
drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \
drm_atomic_uapi.o drm_hdcp.o
drm_client_modeset.o drm_atomic_uapi.o drm_hdcp.o
drm-$(CONFIG_DRM_LEGACY) += drm_legacy_misc.o drm_bufs.o drm_context.o drm_dma.o drm_scatter.o drm_lock.o
drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
@ -118,3 +118,4 @@ obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo/
obj-$(CONFIG_DRM_LIMA) += lima/
obj-$(CONFIG_DRM_PANFROST) += panfrost/
obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/
obj-$(CONFIG_DRM_MCDE) += mcde/

View File

@ -3875,6 +3875,128 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec
return result;
}
static int fill_hdr_info_packet(const struct drm_connector_state *state,
struct dc_info_packet *out)
{
struct hdmi_drm_infoframe frame;
unsigned char buf[30]; /* 26 + 4 */
ssize_t len;
int ret, i;
memset(out, 0, sizeof(*out));
if (!state->hdr_output_metadata)
return 0;
ret = drm_hdmi_infoframe_set_hdr_metadata(&frame, state);
if (ret)
return ret;
len = hdmi_drm_infoframe_pack_only(&frame, buf, sizeof(buf));
if (len < 0)
return (int)len;
/* Static metadata is a fixed 26 bytes + 4 byte header. */
if (len != 30)
return -EINVAL;
/* Prepare the infopacket for DC. */
switch (state->connector->connector_type) {
case DRM_MODE_CONNECTOR_HDMIA:
out->hb0 = 0x87; /* type */
out->hb1 = 0x01; /* version */
out->hb2 = 0x1A; /* length */
out->sb[0] = buf[3]; /* checksum */
i = 1;
break;
case DRM_MODE_CONNECTOR_DisplayPort:
case DRM_MODE_CONNECTOR_eDP:
out->hb0 = 0x00; /* sdp id, zero */
out->hb1 = 0x87; /* type */
out->hb2 = 0x1D; /* payload len - 1 */
out->hb3 = (0x13 << 2); /* sdp version */
out->sb[0] = 0x01; /* version */
out->sb[1] = 0x1A; /* length */
i = 2;
break;
default:
return -EINVAL;
}
memcpy(&out->sb[i], &buf[4], 26);
out->valid = true;
print_hex_dump(KERN_DEBUG, "HDR SB:", DUMP_PREFIX_NONE, 16, 1, out->sb,
sizeof(out->sb), false);
return 0;
}
static bool
is_hdr_metadata_different(const struct drm_connector_state *old_state,
const struct drm_connector_state *new_state)
{
struct drm_property_blob *old_blob = old_state->hdr_output_metadata;
struct drm_property_blob *new_blob = new_state->hdr_output_metadata;
if (old_blob != new_blob) {
if (old_blob && new_blob &&
old_blob->length == new_blob->length)
return memcmp(old_blob->data, new_blob->data,
old_blob->length);
return true;
}
return false;
}
static int
amdgpu_dm_connector_atomic_check(struct drm_connector *conn,
struct drm_connector_state *new_con_state)
{
struct drm_atomic_state *state = new_con_state->state;
struct drm_connector_state *old_con_state =
drm_atomic_get_old_connector_state(state, conn);
struct drm_crtc *crtc = new_con_state->crtc;
struct drm_crtc_state *new_crtc_state;
int ret;
if (!crtc)
return 0;
if (is_hdr_metadata_different(old_con_state, new_con_state)) {
struct dc_info_packet hdr_infopacket;
ret = fill_hdr_info_packet(new_con_state, &hdr_infopacket);
if (ret)
return ret;
new_crtc_state = drm_atomic_get_crtc_state(state, crtc);
if (IS_ERR(new_crtc_state))
return PTR_ERR(new_crtc_state);
/*
* DC considers the stream backends changed if the
* static metadata changes. Forcing the modeset also
* gives a simple way for userspace to switch from
* 8bpc to 10bpc when setting the metadata to enter
* or exit HDR.
*
* Changing the static metadata after it's been
* set is permissible, however. So only force a
* modeset if we're entering or exiting HDR.
*/
new_crtc_state->mode_changed =
!old_con_state->hdr_output_metadata ||
!new_con_state->hdr_output_metadata;
}
return 0;
}
static const struct drm_connector_helper_funcs
amdgpu_dm_connector_helper_funcs = {
/*
@ -3885,6 +4007,7 @@ amdgpu_dm_connector_helper_funcs = {
*/
.get_modes = get_modes,
.mode_valid = amdgpu_dm_connector_mode_valid,
.atomic_check = amdgpu_dm_connector_atomic_check,
};
static void dm_crtc_helper_disable(struct drm_crtc *crtc)
@ -4693,6 +4816,10 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
if (connector_type == DRM_MODE_CONNECTOR_HDMIA ||
connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
connector_type == DRM_MODE_CONNECTOR_eDP) {
drm_object_attach_property(
&aconnector->base.base,
dm->ddev->mode_config.hdr_output_metadata_property, 0);
drm_connector_attach_vrr_capable_property(
&aconnector->base);
}
@ -5781,7 +5908,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc);
struct dc_surface_update dummy_updates[MAX_SURFACES];
struct dc_stream_update stream_update;
struct dc_info_packet hdr_packet;
struct dc_stream_status *status = NULL;
bool abm_changed, hdr_changed, scaling_changed;
memset(&dummy_updates, 0, sizeof(dummy_updates));
memset(&stream_update, 0, sizeof(stream_update));
@ -5798,11 +5927,19 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
if (!is_scaling_state_different(dm_new_con_state, dm_old_con_state) &&
(dm_new_crtc_state->abm_level == dm_old_crtc_state->abm_level))
scaling_changed = is_scaling_state_different(dm_new_con_state,
dm_old_con_state);
abm_changed = dm_new_crtc_state->abm_level !=
dm_old_crtc_state->abm_level;
hdr_changed =
is_hdr_metadata_different(old_con_state, new_con_state);
if (!scaling_changed && !abm_changed && !hdr_changed)
continue;
if (is_scaling_state_different(dm_new_con_state, dm_old_con_state)) {
if (scaling_changed) {
update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode,
dm_new_con_state, (struct dc_stream_state *)dm_new_crtc_state->stream);
@ -5810,12 +5947,17 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
stream_update.dst = dm_new_crtc_state->stream->dst;
}
if (dm_new_crtc_state->abm_level != dm_old_crtc_state->abm_level) {
if (abm_changed) {
dm_new_crtc_state->stream->abm_level = dm_new_crtc_state->abm_level;
stream_update.abm_level = &dm_new_crtc_state->abm_level;
}
if (hdr_changed) {
fill_hdr_info_packet(new_con_state, &hdr_packet);
stream_update.hdr_static_metadata = &hdr_packet;
}
status = dc_stream_get_status(dm_new_crtc_state->stream);
WARN_ON(!status);
WARN_ON(!status->plane_count);
@ -6161,6 +6303,11 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
dm_new_crtc_state->abm_level = dm_new_conn_state->abm_level;
ret = fill_hdr_info_packet(drm_new_conn_state,
&new_stream->hdr_static_metadata);
if (ret)
goto fail;
if (dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) &&
dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream)) {
new_crtc_state->mode_changed = false;

View File

@ -32,9 +32,12 @@
*/
#include <linux/export.h>
#include <drm/drmP.h>
#include <drm/ati_pcigart.h>
#include <drm/drm_device.h>
#include <drm/drm_os_linux.h>
#include <drm/drm_pci.h>
#include <drm/drm_print.h>
# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */

View File

@ -78,7 +78,8 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
unsigned long mode_rate;
struct videomode vm;
unsigned long prate;
unsigned int cfg;
unsigned int mask = ATMEL_HLCDC_CLKDIV_MASK | ATMEL_HLCDC_CLKPOL;
unsigned int cfg = 0;
int div;
vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay;
@ -101,7 +102,10 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
(adj->crtc_hdisplay - 1) |
((adj->crtc_vdisplay - 1) << 16));
cfg = ATMEL_HLCDC_CLKSEL;
if (!crtc->dc->desc->fixed_clksrc) {
cfg |= ATMEL_HLCDC_CLKSEL;
mask |= ATMEL_HLCDC_CLKSEL;
}
prate = 2 * clk_get_rate(crtc->dc->hlcdc->sys_clk);
mode_rate = adj->crtc_clock * 1000;
@ -132,11 +136,10 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
cfg |= ATMEL_HLCDC_CLKDIV(div);
regmap_update_bits(regmap, ATMEL_HLCDC_CFG(0),
ATMEL_HLCDC_CLKSEL | ATMEL_HLCDC_CLKDIV_MASK |
ATMEL_HLCDC_CLKPOL, cfg);
regmap_update_bits(regmap, ATMEL_HLCDC_CFG(0), mask, cfg);
cfg = 0;
state = drm_crtc_state_to_atmel_hlcdc_crtc_state(c->state);
cfg = state->output_mode << 8;
if (adj->flags & DRM_MODE_FLAG_NVSYNC)
cfg |= ATMEL_HLCDC_VSPOL;
@ -144,9 +147,6 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
if (adj->flags & DRM_MODE_FLAG_NHSYNC)
cfg |= ATMEL_HLCDC_HSPOL;
state = drm_crtc_state_to_atmel_hlcdc_crtc_state(c->state);
cfg |= state->output_mode << 8;
regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5),
ATMEL_HLCDC_HSPOL | ATMEL_HLCDC_VSPOL |
ATMEL_HLCDC_VSPDLYS | ATMEL_HLCDC_VSPDLYE |

View File

@ -364,6 +364,103 @@ static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d4 = {
.nlayers = ARRAY_SIZE(atmel_hlcdc_sama5d4_layers),
.layers = atmel_hlcdc_sama5d4_layers,
};
static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sam9x60_layers[] = {
{
.name = "base",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x60,
.id = 0,
.type = ATMEL_HLCDC_BASE_LAYER,
.cfgs_offset = 0x2c,
.layout = {
.xstride = { 2 },
.default_color = 3,
.general_config = 4,
.disc_pos = 5,
.disc_size = 6,
},
.clut_offset = 0x600,
},
{
.name = "overlay1",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x160,
.id = 1,
.type = ATMEL_HLCDC_OVERLAY_LAYER,
.cfgs_offset = 0x2c,
.layout = {
.pos = 2,
.size = 3,
.xstride = { 4 },
.pstride = { 5 },
.default_color = 6,
.chroma_key = 7,
.chroma_key_mask = 8,
.general_config = 9,
},
.clut_offset = 0xa00,
},
{
.name = "overlay2",
.formats = &atmel_hlcdc_plane_rgb_formats,
.regs_offset = 0x260,
.id = 2,
.type = ATMEL_HLCDC_OVERLAY_LAYER,
.cfgs_offset = 0x2c,
.layout = {
.pos = 2,
.size = 3,
.xstride = { 4 },
.pstride = { 5 },
.default_color = 6,
.chroma_key = 7,
.chroma_key_mask = 8,
.general_config = 9,
},
.clut_offset = 0xe00,
},
{
.name = "high-end-overlay",
.formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
.regs_offset = 0x360,
.id = 3,
.type = ATMEL_HLCDC_OVERLAY_LAYER,
.cfgs_offset = 0x4c,
.layout = {
.pos = 2,
.size = 3,
.memsize = 4,
.xstride = { 5, 7 },
.pstride = { 6, 8 },
.default_color = 9,
.chroma_key = 10,
.chroma_key_mask = 11,
.general_config = 12,
.scaler_config = 13,
.phicoeffs = {
.x = 17,
.y = 33,
},
.csc = 14,
},
.clut_offset = 0x1200,
},
};
static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sam9x60 = {
.min_width = 0,
.min_height = 0,
.max_width = 2048,
.max_height = 2048,
.max_spw = 0xff,
.max_vpw = 0xff,
.max_hpw = 0x3ff,
.fixed_clksrc = true,
.nlayers = ARRAY_SIZE(atmel_hlcdc_sam9x60_layers),
.layers = atmel_hlcdc_sam9x60_layers,
};
static const struct of_device_id atmel_hlcdc_of_match[] = {
{
.compatible = "atmel,at91sam9n12-hlcdc",
@ -385,6 +482,10 @@ static const struct of_device_id atmel_hlcdc_of_match[] = {
.compatible = "atmel,sama5d4-hlcdc",
.data = &atmel_hlcdc_dc_sama5d4,
},
{
.compatible = "microchip,sam9x60-hlcdc",
.data = &atmel_hlcdc_dc_sam9x60,
},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, atmel_hlcdc_of_match);
@ -625,10 +726,18 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
dc->hlcdc = dev_get_drvdata(dev->dev->parent);
dev->dev_private = dc;
if (dc->desc->fixed_clksrc) {
ret = clk_prepare_enable(dc->hlcdc->sys_clk);
if (ret) {
dev_err(dev->dev, "failed to enable sys_clk\n");
goto err_destroy_wq;
}
}
ret = clk_prepare_enable(dc->hlcdc->periph_clk);
if (ret) {
dev_err(dev->dev, "failed to enable periph_clk\n");
goto err_destroy_wq;
goto err_sys_clk_disable;
}
pm_runtime_enable(dev->dev);
@ -664,6 +773,9 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
err_periph_clk_disable:
pm_runtime_disable(dev->dev);
clk_disable_unprepare(dc->hlcdc->periph_clk);
err_sys_clk_disable:
if (dc->desc->fixed_clksrc)
clk_disable_unprepare(dc->hlcdc->sys_clk);
err_destroy_wq:
destroy_workqueue(dc->wq);
@ -688,6 +800,8 @@ static void atmel_hlcdc_dc_unload(struct drm_device *dev)
pm_runtime_disable(dev->dev);
clk_disable_unprepare(dc->hlcdc->periph_clk);
if (dc->desc->fixed_clksrc)
clk_disable_unprepare(dc->hlcdc->sys_clk);
destroy_workqueue(dc->wq);
}
@ -805,6 +919,8 @@ static int atmel_hlcdc_dc_drm_suspend(struct device *dev)
regmap_read(regmap, ATMEL_HLCDC_IMR, &dc->suspend.imr);
regmap_write(regmap, ATMEL_HLCDC_IDR, dc->suspend.imr);
clk_disable_unprepare(dc->hlcdc->periph_clk);
if (dc->desc->fixed_clksrc)
clk_disable_unprepare(dc->hlcdc->sys_clk);
return 0;
}
@ -814,6 +930,8 @@ static int atmel_hlcdc_dc_drm_resume(struct device *dev)
struct drm_device *drm_dev = dev_get_drvdata(dev);
struct atmel_hlcdc_dc *dc = drm_dev->dev_private;
if (dc->desc->fixed_clksrc)
clk_prepare_enable(dc->hlcdc->sys_clk);
clk_prepare_enable(dc->hlcdc->periph_clk);
regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, dc->suspend.imr);

View File

@ -328,6 +328,7 @@ atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *layer)
* @max_hpw: maximum horizontal back/front porch width
* @conflicting_output_formats: true if RGBXXX output formats conflict with
* each other.
* @fixed_clksrc: true if clock source is fixed
* @layers: a layer description table describing available layers
* @nlayers: layer description table size
*/
@ -340,6 +341,7 @@ struct atmel_hlcdc_dc_desc {
int max_vpw;
int max_hpw;
bool conflicting_output_formats;
bool fixed_clksrc;
const struct atmel_hlcdc_layer_desc *layers;
int nlayers;
};

View File

@ -382,7 +382,7 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
cfg |= ATMEL_HLCDC_LAYER_LAEN;
else
cfg |= ATMEL_HLCDC_LAYER_GAEN |
ATMEL_HLCDC_LAYER_GA(state->base.alpha >> 8);
ATMEL_HLCDC_LAYER_GA(state->base.alpha);
}
if (state->disc_h && state->disc_w)

View File

@ -6,21 +6,21 @@
* Licensed under the GPL-2.
*/
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <drm/drmP.h>
#include <media/cec.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <media/cec.h>
#include "adv7511.h"
/* ADI recommended values for proper operation. */

View File

@ -16,23 +16,23 @@
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <linux/types.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include "analogix-anx78xx.h"

View File

@ -10,26 +10,26 @@
* option) any later version.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/component.h>
#include <linux/phy/phy.h>
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
#include <linux/platform_device.h>
#include <drm/bridge/analogix_dp.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include "analogix_dp_core.h"
#include "analogix_dp_reg.h"

View File

@ -15,9 +15,9 @@
#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
struct dumb_vga {

View File

@ -7,13 +7,15 @@
* the License, or (at your option) any later version.
*/
#include <drm/drmP.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <drm/drm_bridge.h>
#include <drm/drm_panel.h>
#include <linux/gpio/consumer.h>
#include <linux/of_graph.h>
struct lvds_encoder {
struct drm_bridge bridge;
struct drm_bridge *panel_bridge;

View File

@ -34,11 +34,12 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
#define EDID_EXT_BLOCK_CNT 0x7E

View File

@ -20,13 +20,14 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
#define PTN3460_EDID_ADDR 0x0
#define PTN3460_EDID_EMULATION_ADDR 0x84

View File

@ -8,12 +8,12 @@
* the License, or (at your option) any later version.
*/
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_connector.h>
#include <drm/drm_encoder.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
struct panel_bridge {

View File

@ -24,12 +24,13 @@
#include <linux/of_device.h>
#include <linux/pm.h>
#include <linux/regulator/consumer.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
/* Brightness scale on the Parade chip */
#define PS8622_MAX_BRIGHTNESS 0xff

View File

@ -27,12 +27,16 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/clk.h>
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <sound/hdmi-codec.h>
#define SII902X_TPI_VIDEO_DATA 0x0
#define SII902X_TPI_PIXEL_REPETITION 0x8
@ -74,6 +78,77 @@
#define SII902X_AVI_POWER_STATE_MSK GENMASK(1, 0)
#define SII902X_AVI_POWER_STATE_D(l) ((l) & SII902X_AVI_POWER_STATE_MSK)
/* Audio */
#define SII902X_TPI_I2S_ENABLE_MAPPING_REG 0x1f
#define SII902X_TPI_I2S_CONFIG_FIFO0 (0 << 0)
#define SII902X_TPI_I2S_CONFIG_FIFO1 (1 << 0)
#define SII902X_TPI_I2S_CONFIG_FIFO2 (2 << 0)
#define SII902X_TPI_I2S_CONFIG_FIFO3 (3 << 0)
#define SII902X_TPI_I2S_LEFT_RIGHT_SWAP (1 << 2)
#define SII902X_TPI_I2S_AUTO_DOWNSAMPLE (1 << 3)
#define SII902X_TPI_I2S_SELECT_SD0 (0 << 4)
#define SII902X_TPI_I2S_SELECT_SD1 (1 << 4)
#define SII902X_TPI_I2S_SELECT_SD2 (2 << 4)
#define SII902X_TPI_I2S_SELECT_SD3 (3 << 4)
#define SII902X_TPI_I2S_FIFO_ENABLE (1 << 7)
#define SII902X_TPI_I2S_INPUT_CONFIG_REG 0x20
#define SII902X_TPI_I2S_FIRST_BIT_SHIFT_YES (0 << 0)
#define SII902X_TPI_I2S_FIRST_BIT_SHIFT_NO (1 << 0)
#define SII902X_TPI_I2S_SD_DIRECTION_MSB_FIRST (0 << 1)
#define SII902X_TPI_I2S_SD_DIRECTION_LSB_FIRST (1 << 1)
#define SII902X_TPI_I2S_SD_JUSTIFY_LEFT (0 << 2)
#define SII902X_TPI_I2S_SD_JUSTIFY_RIGHT (1 << 2)
#define SII902X_TPI_I2S_WS_POLARITY_LOW (0 << 3)
#define SII902X_TPI_I2S_WS_POLARITY_HIGH (1 << 3)
#define SII902X_TPI_I2S_MCLK_MULTIPLIER_128 (0 << 4)
#define SII902X_TPI_I2S_MCLK_MULTIPLIER_256 (1 << 4)
#define SII902X_TPI_I2S_MCLK_MULTIPLIER_384 (2 << 4)
#define SII902X_TPI_I2S_MCLK_MULTIPLIER_512 (3 << 4)
#define SII902X_TPI_I2S_MCLK_MULTIPLIER_768 (4 << 4)
#define SII902X_TPI_I2S_MCLK_MULTIPLIER_1024 (5 << 4)
#define SII902X_TPI_I2S_MCLK_MULTIPLIER_1152 (6 << 4)
#define SII902X_TPI_I2S_MCLK_MULTIPLIER_192 (7 << 4)
#define SII902X_TPI_I2S_SCK_EDGE_FALLING (0 << 7)
#define SII902X_TPI_I2S_SCK_EDGE_RISING (1 << 7)
#define SII902X_TPI_I2S_STRM_HDR_BASE 0x21
#define SII902X_TPI_I2S_STRM_HDR_SIZE 5
#define SII902X_TPI_AUDIO_CONFIG_BYTE2_REG 0x26
#define SII902X_TPI_AUDIO_CODING_STREAM_HEADER (0 << 0)
#define SII902X_TPI_AUDIO_CODING_PCM (1 << 0)
#define SII902X_TPI_AUDIO_CODING_AC3 (2 << 0)
#define SII902X_TPI_AUDIO_CODING_MPEG1 (3 << 0)
#define SII902X_TPI_AUDIO_CODING_MP3 (4 << 0)
#define SII902X_TPI_AUDIO_CODING_MPEG2 (5 << 0)
#define SII902X_TPI_AUDIO_CODING_AAC (6 << 0)
#define SII902X_TPI_AUDIO_CODING_DTS (7 << 0)
#define SII902X_TPI_AUDIO_CODING_ATRAC (8 << 0)
#define SII902X_TPI_AUDIO_MUTE_DISABLE (0 << 4)
#define SII902X_TPI_AUDIO_MUTE_ENABLE (1 << 4)
#define SII902X_TPI_AUDIO_LAYOUT_2_CHANNELS (0 << 5)
#define SII902X_TPI_AUDIO_LAYOUT_8_CHANNELS (1 << 5)
#define SII902X_TPI_AUDIO_INTERFACE_DISABLE (0 << 6)
#define SII902X_TPI_AUDIO_INTERFACE_SPDIF (1 << 6)
#define SII902X_TPI_AUDIO_INTERFACE_I2S (2 << 6)
#define SII902X_TPI_AUDIO_CONFIG_BYTE3_REG 0x27
#define SII902X_TPI_AUDIO_FREQ_STREAM (0 << 3)
#define SII902X_TPI_AUDIO_FREQ_32KHZ (1 << 3)
#define SII902X_TPI_AUDIO_FREQ_44KHZ (2 << 3)
#define SII902X_TPI_AUDIO_FREQ_48KHZ (3 << 3)
#define SII902X_TPI_AUDIO_FREQ_88KHZ (4 << 3)
#define SII902X_TPI_AUDIO_FREQ_96KHZ (5 << 3)
#define SII902X_TPI_AUDIO_FREQ_176KHZ (6 << 3)
#define SII902X_TPI_AUDIO_FREQ_192KHZ (7 << 3)
#define SII902X_TPI_AUDIO_SAMPLE_SIZE_STREAM (0 << 6)
#define SII902X_TPI_AUDIO_SAMPLE_SIZE_16 (1 << 6)
#define SII902X_TPI_AUDIO_SAMPLE_SIZE_20 (2 << 6)
#define SII902X_TPI_AUDIO_SAMPLE_SIZE_24 (3 << 6)
#define SII902X_TPI_AUDIO_CONFIG_BYTE4_REG 0x28
#define SII902X_INT_ENABLE 0x3c
#define SII902X_INT_STATUS 0x3d
#define SII902X_HOTPLUG_EVENT BIT(0)
@ -81,6 +156,16 @@
#define SII902X_REG_TPI_RQB 0xc7
/* Indirect internal register access */
#define SII902X_IND_SET_PAGE 0xbc
#define SII902X_IND_OFFSET 0xbd
#define SII902X_IND_VALUE 0xbe
#define SII902X_TPI_MISC_INFOFRAME_BASE 0xbf
#define SII902X_TPI_MISC_INFOFRAME_END 0xde
#define SII902X_TPI_MISC_INFOFRAME_SIZE \
(SII902X_TPI_MISC_INFOFRAME_END - SII902X_TPI_MISC_INFOFRAME_BASE)
#define SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS 500
struct sii902x {
@ -90,6 +175,16 @@ struct sii902x {
struct drm_connector connector;
struct gpio_desc *reset_gpio;
struct i2c_mux_core *i2cmux;
/*
* Mutex protects audio and video functions from interfering
* each other, by keeping their i2c command sequences atomic.
*/
struct mutex mutex;
struct sii902x_audio {
struct platform_device *pdev;
struct clk *mclk;
u32 i2s_fifo_sequence[4];
} audio;
};
static int sii902x_read_unlocked(struct i2c_client *i2c, u8 reg, u8 *val)
@ -161,8 +256,12 @@ sii902x_connector_detect(struct drm_connector *connector, bool force)
struct sii902x *sii902x = connector_to_sii902x(connector);
unsigned int status;
mutex_lock(&sii902x->mutex);
regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status);
mutex_unlock(&sii902x->mutex);
return (status & SII902X_PLUGGED_STATUS) ?
connector_status_connected : connector_status_disconnected;
}
@ -180,12 +279,18 @@ static int sii902x_get_modes(struct drm_connector *connector)
{
struct sii902x *sii902x = connector_to_sii902x(connector);
u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI;
struct edid *edid;
int num = 0, ret;
mutex_lock(&sii902x->mutex);
edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]);
drm_connector_update_edid_property(connector, edid);
if (edid) {
if (drm_detect_hdmi_monitor(edid))
output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI;
num = drm_add_edid_modes(connector, edid);
kfree(edid);
}
@ -193,9 +298,19 @@ static int sii902x_get_modes(struct drm_connector *connector)
ret = drm_display_info_set_bus_formats(&connector->display_info,
&bus_format, 1);
if (ret)
return ret;
goto error_out;
return num;
ret = regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA,
SII902X_SYS_CTRL_OUTPUT_MODE, output_mode);
if (ret)
goto error_out;
ret = num;
error_out:
mutex_unlock(&sii902x->mutex);
return ret;
}
static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector,
@ -215,20 +330,28 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge)
{
struct sii902x *sii902x = bridge_to_sii902x(bridge);
mutex_lock(&sii902x->mutex);
regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA,
SII902X_SYS_CTRL_PWR_DWN,
SII902X_SYS_CTRL_PWR_DWN);
mutex_unlock(&sii902x->mutex);
}
static void sii902x_bridge_enable(struct drm_bridge *bridge)
{
struct sii902x *sii902x = bridge_to_sii902x(bridge);
mutex_lock(&sii902x->mutex);
regmap_update_bits(sii902x->regmap, SII902X_PWR_STATE_CTRL,
SII902X_AVI_POWER_STATE_MSK,
SII902X_AVI_POWER_STATE_D(0));
regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA,
SII902X_SYS_CTRL_PWR_DWN, 0);
mutex_unlock(&sii902x->mutex);
}
static void sii902x_bridge_mode_set(struct drm_bridge *bridge,
@ -239,10 +362,11 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge,
struct regmap *regmap = sii902x->regmap;
u8 buf[HDMI_INFOFRAME_SIZE(AVI)];
struct hdmi_avi_infoframe frame;
u16 pixel_clock_10kHz = adj->clock / 10;
int ret;
buf[0] = adj->clock;
buf[1] = adj->clock >> 8;
buf[0] = pixel_clock_10kHz & 0xff;
buf[1] = pixel_clock_10kHz >> 8;
buf[2] = adj->vrefresh;
buf[3] = 0x00;
buf[4] = adj->hdisplay;
@ -254,27 +378,32 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge,
buf[9] = SII902X_TPI_AVI_INPUT_RANGE_AUTO |
SII902X_TPI_AVI_INPUT_COLORSPACE_RGB;
mutex_lock(&sii902x->mutex);
ret = regmap_bulk_write(regmap, SII902X_TPI_VIDEO_DATA, buf, 10);
if (ret)
return;
goto out;
ret = drm_hdmi_avi_infoframe_from_display_mode(&frame,
&sii902x->connector, adj);
if (ret < 0) {
DRM_ERROR("couldn't fill AVI infoframe\n");
return;
goto out;
}
ret = hdmi_avi_infoframe_pack(&frame, buf, sizeof(buf));
if (ret < 0) {
DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
return;
goto out;
}
/* Do not send the infoframe header, but keep the CRC field. */
regmap_bulk_write(regmap, SII902X_TPI_AVI_INFOFRAME,
buf + HDMI_INFOFRAME_HEADER_SIZE - 1,
HDMI_AVI_INFOFRAME_SIZE + 1);
out:
mutex_unlock(&sii902x->mutex);
}
static int sii902x_bridge_attach(struct drm_bridge *bridge)
@ -315,6 +444,335 @@ static const struct drm_bridge_funcs sii902x_bridge_funcs = {
.enable = sii902x_bridge_enable,
};
static int sii902x_mute(struct sii902x *sii902x, bool mute)
{
struct device *dev = &sii902x->i2c->dev;
unsigned int val = mute ? SII902X_TPI_AUDIO_MUTE_ENABLE :
SII902X_TPI_AUDIO_MUTE_DISABLE;
dev_dbg(dev, "%s: %s\n", __func__, mute ? "Muted" : "Unmuted");
return regmap_update_bits(sii902x->regmap,
SII902X_TPI_AUDIO_CONFIG_BYTE2_REG,
SII902X_TPI_AUDIO_MUTE_ENABLE, val);
}
static const int sii902x_mclk_div_table[] = {
128, 256, 384, 512, 768, 1024, 1152, 192 };
static int sii902x_select_mclk_div(u8 *i2s_config_reg, unsigned int rate,
unsigned int mclk)
{
int div = mclk / rate;
int distance = 100000;
u8 i, nearest = 0;
for (i = 0; i < ARRAY_SIZE(sii902x_mclk_div_table); i++) {
unsigned int d = abs(div - sii902x_mclk_div_table[i]);
if (d >= distance)
continue;
nearest = i;
distance = d;
if (d == 0)
break;
}
*i2s_config_reg |= nearest << 4;
return sii902x_mclk_div_table[nearest];
}
static const struct sii902x_sample_freq {
u32 freq;
u8 val;
} sii902x_sample_freq[] = {
{ .freq = 32000, .val = SII902X_TPI_AUDIO_FREQ_32KHZ },
{ .freq = 44000, .val = SII902X_TPI_AUDIO_FREQ_44KHZ },
{ .freq = 48000, .val = SII902X_TPI_AUDIO_FREQ_48KHZ },
{ .freq = 88000, .val = SII902X_TPI_AUDIO_FREQ_88KHZ },
{ .freq = 96000, .val = SII902X_TPI_AUDIO_FREQ_96KHZ },
{ .freq = 176000, .val = SII902X_TPI_AUDIO_FREQ_176KHZ },
{ .freq = 192000, .val = SII902X_TPI_AUDIO_FREQ_192KHZ },
};
static int sii902x_audio_hw_params(struct device *dev, void *data,
struct hdmi_codec_daifmt *daifmt,
struct hdmi_codec_params *params)
{
struct sii902x *sii902x = dev_get_drvdata(dev);
u8 i2s_config_reg = SII902X_TPI_I2S_SD_DIRECTION_MSB_FIRST;
u8 config_byte2_reg = (SII902X_TPI_AUDIO_INTERFACE_I2S |
SII902X_TPI_AUDIO_MUTE_ENABLE |
SII902X_TPI_AUDIO_CODING_PCM);
u8 config_byte3_reg = 0;
u8 infoframe_buf[HDMI_INFOFRAME_SIZE(AUDIO)];
unsigned long mclk_rate;
int i, ret;
if (daifmt->bit_clk_master || daifmt->frame_clk_master) {
dev_dbg(dev, "%s: I2S master mode not supported\n", __func__);
return -EINVAL;
}
switch (daifmt->fmt) {
case HDMI_I2S:
i2s_config_reg |= SII902X_TPI_I2S_FIRST_BIT_SHIFT_YES |
SII902X_TPI_I2S_SD_JUSTIFY_LEFT;
break;
case HDMI_RIGHT_J:
i2s_config_reg |= SII902X_TPI_I2S_SD_JUSTIFY_RIGHT;
break;
case HDMI_LEFT_J:
i2s_config_reg |= SII902X_TPI_I2S_SD_JUSTIFY_LEFT;
break;
default:
dev_dbg(dev, "%s: Unsupported i2s format %u\n", __func__,
daifmt->fmt);
return -EINVAL;
}
if (daifmt->bit_clk_inv)
i2s_config_reg |= SII902X_TPI_I2S_SCK_EDGE_FALLING;
else
i2s_config_reg |= SII902X_TPI_I2S_SCK_EDGE_RISING;
if (daifmt->frame_clk_inv)
i2s_config_reg |= SII902X_TPI_I2S_WS_POLARITY_LOW;
else
i2s_config_reg |= SII902X_TPI_I2S_WS_POLARITY_HIGH;
if (params->channels > 2)
config_byte2_reg |= SII902X_TPI_AUDIO_LAYOUT_8_CHANNELS;
else
config_byte2_reg |= SII902X_TPI_AUDIO_LAYOUT_2_CHANNELS;
switch (params->sample_width) {
case 16:
config_byte3_reg |= SII902X_TPI_AUDIO_SAMPLE_SIZE_16;
break;
case 20:
config_byte3_reg |= SII902X_TPI_AUDIO_SAMPLE_SIZE_20;
break;
case 24:
case 32:
config_byte3_reg |= SII902X_TPI_AUDIO_SAMPLE_SIZE_24;
break;
default:
dev_err(dev, "%s: Unsupported sample width %u\n", __func__,
params->sample_width);
return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(sii902x_sample_freq); i++) {
if (params->sample_rate == sii902x_sample_freq[i].freq) {
config_byte3_reg |= sii902x_sample_freq[i].val;
break;
}
}
ret = clk_prepare_enable(sii902x->audio.mclk);
if (ret) {
dev_err(dev, "Enabling mclk failed: %d\n", ret);
return ret;
}
mclk_rate = clk_get_rate(sii902x->audio.mclk);
ret = sii902x_select_mclk_div(&i2s_config_reg, params->sample_rate,
mclk_rate);
if (mclk_rate != ret * params->sample_rate)
dev_dbg(dev, "Inaccurate reference clock (%ld/%d != %u)\n",
mclk_rate, ret, params->sample_rate);
mutex_lock(&sii902x->mutex);
ret = regmap_write(sii902x->regmap,
SII902X_TPI_AUDIO_CONFIG_BYTE2_REG,
config_byte2_reg);
if (ret < 0)
goto out;
ret = regmap_write(sii902x->regmap, SII902X_TPI_I2S_INPUT_CONFIG_REG,
i2s_config_reg);
if (ret)
goto out;
for (i = 0; sii902x->audio.i2s_fifo_sequence[i] &&
i < ARRAY_SIZE(sii902x->audio.i2s_fifo_sequence); i++)
regmap_write(sii902x->regmap,
SII902X_TPI_I2S_ENABLE_MAPPING_REG,
sii902x->audio.i2s_fifo_sequence[i]);
ret = regmap_write(sii902x->regmap, SII902X_TPI_AUDIO_CONFIG_BYTE3_REG,
config_byte3_reg);
if (ret)
goto out;
ret = regmap_bulk_write(sii902x->regmap, SII902X_TPI_I2S_STRM_HDR_BASE,
params->iec.status,
min((size_t) SII902X_TPI_I2S_STRM_HDR_SIZE,
sizeof(params->iec.status)));
if (ret)
goto out;
ret = hdmi_audio_infoframe_pack(&params->cea, infoframe_buf,
sizeof(infoframe_buf));
if (ret < 0) {
dev_err(dev, "%s: Failed to pack audio infoframe: %d\n",
__func__, ret);
goto out;
}
ret = regmap_bulk_write(sii902x->regmap,
SII902X_TPI_MISC_INFOFRAME_BASE,
infoframe_buf,
min(ret, SII902X_TPI_MISC_INFOFRAME_SIZE));
if (ret)
goto out;
/* Decode Level 0 Packets */
ret = regmap_write(sii902x->regmap, SII902X_IND_SET_PAGE, 0x02);
if (ret)
goto out;
ret = regmap_write(sii902x->regmap, SII902X_IND_OFFSET, 0x24);
if (ret)
goto out;
ret = regmap_write(sii902x->regmap, SII902X_IND_VALUE, 0x02);
if (ret)
goto out;
dev_dbg(dev, "%s: hdmi audio enabled\n", __func__);
out:
mutex_unlock(&sii902x->mutex);
if (ret) {
clk_disable_unprepare(sii902x->audio.mclk);
dev_err(dev, "%s: hdmi audio enable failed: %d\n", __func__,
ret);
}
return ret;
}
static void sii902x_audio_shutdown(struct device *dev, void *data)
{
struct sii902x *sii902x = dev_get_drvdata(dev);
mutex_lock(&sii902x->mutex);
regmap_write(sii902x->regmap, SII902X_TPI_AUDIO_CONFIG_BYTE2_REG,
SII902X_TPI_AUDIO_INTERFACE_DISABLE);
mutex_unlock(&sii902x->mutex);
clk_disable_unprepare(sii902x->audio.mclk);
}
int sii902x_audio_digital_mute(struct device *dev, void *data, bool enable)
{
struct sii902x *sii902x = dev_get_drvdata(dev);
mutex_lock(&sii902x->mutex);
sii902x_mute(sii902x, enable);
mutex_unlock(&sii902x->mutex);
return 0;
}
static int sii902x_audio_get_eld(struct device *dev, void *data,
uint8_t *buf, size_t len)
{
struct sii902x *sii902x = dev_get_drvdata(dev);
mutex_lock(&sii902x->mutex);
memcpy(buf, sii902x->connector.eld,
min(sizeof(sii902x->connector.eld), len));
mutex_unlock(&sii902x->mutex);
return 0;
}
static const struct hdmi_codec_ops sii902x_audio_codec_ops = {
.hw_params = sii902x_audio_hw_params,
.audio_shutdown = sii902x_audio_shutdown,
.digital_mute = sii902x_audio_digital_mute,
.get_eld = sii902x_audio_get_eld,
};
static int sii902x_audio_codec_init(struct sii902x *sii902x,
struct device *dev)
{
static const u8 audio_fifo_id[] = {
SII902X_TPI_I2S_CONFIG_FIFO0,
SII902X_TPI_I2S_CONFIG_FIFO1,
SII902X_TPI_I2S_CONFIG_FIFO2,
SII902X_TPI_I2S_CONFIG_FIFO3,
};
static const u8 i2s_lane_id[] = {
SII902X_TPI_I2S_SELECT_SD0,
SII902X_TPI_I2S_SELECT_SD1,
SII902X_TPI_I2S_SELECT_SD2,
SII902X_TPI_I2S_SELECT_SD3,
};
struct hdmi_codec_pdata codec_data = {
.ops = &sii902x_audio_codec_ops,
.i2s = 1, /* Only i2s support for now. */
.spdif = 0,
.max_i2s_channels = 0,
};
u8 lanes[4];
u32 num_lanes, i;
if (!of_property_read_bool(dev->of_node, "#sound-dai-cells")) {
dev_dbg(dev, "%s: No \"#sound-dai-cells\", no audio\n",
__func__);
return 0;
}
num_lanes = of_property_read_variable_u8_array(dev->of_node,
"sil,i2s-data-lanes",
lanes, 1,
ARRAY_SIZE(lanes));
if (num_lanes == -EINVAL) {
dev_dbg(dev,
"%s: No \"sil,i2s-data-lanes\", use default <0>\n",
__func__);
num_lanes = 1;
lanes[0] = 0;
} else if (num_lanes < 0) {
dev_err(dev,
"%s: Error gettin \"sil,i2s-data-lanes\": %d\n",
__func__, num_lanes);
return num_lanes;
}
codec_data.max_i2s_channels = 2 * num_lanes;
for (i = 0; i < num_lanes; i++)
sii902x->audio.i2s_fifo_sequence[i] |= audio_fifo_id[i] |
i2s_lane_id[lanes[i]] | SII902X_TPI_I2S_FIFO_ENABLE;
if (IS_ERR(sii902x->audio.mclk)) {
dev_err(dev, "%s: No clock (audio mclk) found: %ld\n",
__func__, PTR_ERR(sii902x->audio.mclk));
return 0;
}
sii902x->audio.pdev = platform_device_register_data(
dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO,
&codec_data, sizeof(codec_data));
return PTR_ERR_OR_ZERO(sii902x->audio.pdev);
}
static const struct regmap_range sii902x_volatile_ranges[] = {
{ .range_min = 0, .range_max = 0xff },
};
@ -327,6 +785,8 @@ static const struct regmap_access_table sii902x_volatile_table = {
static const struct regmap_config sii902x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.disable_locking = true, /* struct sii902x mutex should be enough */
.max_register = SII902X_TPI_MISC_INFOFRAME_END,
.volatile_table = &sii902x_volatile_table,
.cache_type = REGCACHE_NONE,
};
@ -336,9 +796,13 @@ static irqreturn_t sii902x_interrupt(int irq, void *data)
struct sii902x *sii902x = data;
unsigned int status = 0;
mutex_lock(&sii902x->mutex);
regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status);
regmap_write(sii902x->regmap, SII902X_INT_STATUS, status);
mutex_unlock(&sii902x->mutex);
if ((status & SII902X_HOTPLUG_EVENT) && sii902x->bridge.dev)
drm_helper_hpd_irq_event(sii902x->bridge.dev);
@ -460,6 +924,12 @@ static int sii902x_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id)
return 0;
}
static const struct drm_bridge_timings default_sii902x_timings = {
.input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE
| DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE
| DRM_BUS_FLAG_DE_HIGH,
};
static int sii902x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -493,6 +963,8 @@ static int sii902x_probe(struct i2c_client *client,
return PTR_ERR(sii902x->reset_gpio);
}
mutex_init(&sii902x->mutex);
sii902x_reset(sii902x);
ret = regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x0);
@ -530,8 +1002,11 @@ static int sii902x_probe(struct i2c_client *client,
sii902x->bridge.funcs = &sii902x_bridge_funcs;
sii902x->bridge.of_node = dev->of_node;
sii902x->bridge.timings = &default_sii902x_timings;
drm_bridge_add(&sii902x->bridge);
sii902x_audio_codec_init(sii902x, dev);
i2c_set_clientdata(client, sii902x);
sii902x->i2cmux = i2c_mux_alloc(client->adapter, dev,

View File

@ -11,34 +11,35 @@
* (at your option) any later version.
*
*/
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/hdmi.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
#include <drm/drm_of.h>
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder_slave.h>
#include <drm/drm_scdc_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/bridge/dw_hdmi.h>
#include <media/cec-notifier.h>
#include <uapi/linux/media-bus-format.h>
#include <uapi/linux/videodev2.h>
#include "dw-hdmi.h"
#include <drm/bridge/dw_hdmi.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder_slave.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_scdc_helper.h>
#include "dw-hdmi-audio.h"
#include "dw-hdmi-cec.h"
#include <media/cec-notifier.h>
#include "dw-hdmi.h"
#define DDC_SEGMENT_ADDR 0x30

View File

@ -15,15 +15,18 @@
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <drm/drmP.h>
#include <video/mipi_display.h>
#include <drm/bridge/dw_mipi_dsi.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_crtc.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/bridge/dw_mipi_dsi.h>
#include <video/mipi_display.h>
#define HWVER_131 0x31333100 /* IP version 1.31 */

View File

@ -7,18 +7,22 @@
* Maciej Purski <m.purski@samsung.com>
*/
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drmP.h>
#include <linux/gpio/consumer.h>
#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>
#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))

View File

@ -71,6 +71,7 @@
/* System */
#define TC_IDREG 0x0500
#define SYSSTAT 0x0508
#define SYSCTRL 0x0510
#define DP0_AUDSRC_NO_INPUT (0 << 3)
#define DP0_AUDSRC_I2S_RX (1 << 3)
@ -78,6 +79,19 @@
#define DP0_VIDSRC_DSI_RX (1 << 0)
#define DP0_VIDSRC_DPI_RX (2 << 0)
#define DP0_VIDSRC_COLOR_BAR (3 << 0)
#define GPIOM 0x0540
#define GPIOC 0x0544
#define GPIOO 0x0548
#define GPIOI 0x054c
#define INTCTL_G 0x0560
#define INTSTS_G 0x0564
#define INT_SYSERR BIT(16)
#define INT_GPIO_H(x) (1 << (x == 0 ? 2 : 10))
#define INT_GPIO_LC(x) (1 << (x == 0 ? 3 : 11))
#define INT_GP0_LCNT 0x0584
#define INT_GP1_LCNT 0x0588
/* Control */
#define DP0CTL 0x0600
@ -186,11 +200,8 @@ module_param_named(test, tc_test_pattern, bool, 0644);
struct tc_edp_link {
struct drm_dp_link base;
u8 assr;
int scrambler_dis;
int spread;
int coding8b10b;
u8 swing;
u8 preemp;
bool scrambler_dis;
bool spread;
};
struct tc_data {
@ -208,7 +219,7 @@ struct tc_data {
/* display edid */
struct edid *edid;
/* current mode */
const struct drm_display_mode *mode;
struct drm_display_mode mode;
u32 rev;
u8 assr;
@ -216,6 +227,12 @@ struct tc_data {
struct gpio_desc *sd_gpio;
struct gpio_desc *reset_gpio;
struct clk *refclk;
/* do we have IRQ */
bool have_irq;
/* HPD pin number (0 or 1) or -ENODEV */
int hpd_pin;
};
static inline struct tc_data *aux_to_tc(struct drm_dp_aux *a)
@ -286,14 +303,17 @@ static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
ret = regmap_read(tc->regmap, DP0_AUXSTATUS, &value);
if (ret < 0)
return ret;
if (value & AUX_BUSY) {
if (value & AUX_TIMEOUT) {
dev_err(tc->dev, "i2c access timeout!\n");
return -ETIMEDOUT;
}
dev_err(tc->dev, "aux busy!\n");
return -EBUSY;
}
if (value & AUX_TIMEOUT) {
dev_err(tc->dev, "aux access timeout!\n");
return -ETIMEDOUT;
}
*reply = (value & AUX_STATUS_MASK) >> AUX_STATUS_SHIFT;
return 0;
}
@ -387,13 +407,10 @@ static u32 tc_srcctrl(struct tc_data *tc)
* No training pattern, skew lane 1 data by two LSCLK cycles with
* respect to lane 0 data, AutoCorrect Mode = 0
*/
u32 reg = DP0_SRCCTRL_NOTP | DP0_SRCCTRL_LANESKEW;
u32 reg = DP0_SRCCTRL_NOTP | DP0_SRCCTRL_LANESKEW | DP0_SRCCTRL_EN810B;
if (tc->link.scrambler_dis)
reg |= DP0_SRCCTRL_SCRMBLDIS; /* Scrambler Disabled */
if (tc->link.coding8b10b)
/* Enable 8/10B Encoder (TxData[19:16] not used) */
reg |= DP0_SRCCTRL_EN810B;
if (tc->link.spread)
reg |= DP0_SRCCTRL_SSCG; /* Spread Spectrum Enable */
if (tc->link.base.num_lanes == 2)
@ -545,7 +562,6 @@ static int tc_aux_link_setup(struct tc_data *tc)
unsigned long rate;
u32 value;
int ret;
u32 dp_phy_ctrl;
rate = clk_get_rate(tc->refclk);
switch (rate) {
@ -570,10 +586,7 @@ static int tc_aux_link_setup(struct tc_data *tc)
value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
tc_write(SYS_PLLPARAM, value);
dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_A0_EN;
if (tc->link.base.num_lanes == 2)
dp_phy_ctrl |= PHY_2LANE;
tc_write(DP_PHY_CTRL, dp_phy_ctrl);
tc_write(DP_PHY_CTRL, BGREN | PWR_SW_EN | PHY_A0_EN);
/*
* Initially PLLs are in bypass. Force PLL parameter update,
@ -590,8 +603,9 @@ static int tc_aux_link_setup(struct tc_data *tc)
if (ret == -ETIMEDOUT) {
dev_err(tc->dev, "Timeout waiting for PHY to become ready");
return ret;
} else if (ret)
} else if (ret) {
goto err;
}
/* Setup AUX link */
tc_write(DP0_AUXCFG1, AUX_RX_FILTER_EN |
@ -627,13 +641,13 @@ static int tc_get_display_props(struct tc_data *tc)
ret = drm_dp_dpcd_readb(&tc->aux, DP_MAX_DOWNSPREAD, tmp);
if (ret < 0)
goto err_dpcd_read;
tc->link.spread = tmp[0] & BIT(0); /* 0.5% down spread */
tc->link.spread = tmp[0] & DP_MAX_DOWNSPREAD_0_5;
ret = drm_dp_dpcd_readb(&tc->aux, DP_MAIN_LINK_CHANNEL_CODING, tmp);
if (ret < 0)
goto err_dpcd_read;
tc->link.coding8b10b = tmp[0] & BIT(0);
tc->link.scrambler_dis = 0;
tc->link.scrambler_dis = false;
/* read assr */
ret = drm_dp_dpcd_readb(&tc->aux, DP_EDP_CONFIGURATION_SET, tmp);
if (ret < 0)
@ -646,7 +660,9 @@ static int tc_get_display_props(struct tc_data *tc)
tc->link.base.num_lanes,
(tc->link.base.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) ?
"enhanced" : "non-enhanced");
dev_dbg(tc->dev, "ANSI 8B/10B: %d\n", tc->link.coding8b10b);
dev_dbg(tc->dev, "Downspread: %s, scrambler: %s\n",
tc->link.spread ? "0.5%" : "0.0%",
tc->link.scrambler_dis ? "disabled" : "enabled");
dev_dbg(tc->dev, "Display ASSR: %d, TC358767 ASSR: %d\n",
tc->link.assr, tc->assr);
@ -744,89 +760,29 @@ static int tc_set_video_mode(struct tc_data *tc,
return ret;
}
static int tc_link_training(struct tc_data *tc, int pattern)
static int tc_wait_link_training(struct tc_data *tc)
{
const char * const *errors;
u32 srcctrl = tc_srcctrl(tc) | DP0_SRCCTRL_SCRMBLDIS |
DP0_SRCCTRL_AUTOCORRECT;
int timeout;
int retry;
u32 timeout = 1000;
u32 value;
int ret;
if (pattern == DP_TRAINING_PATTERN_1) {
srcctrl |= DP0_SRCCTRL_TP1;
errors = training_pattern1_errors;
} else {
srcctrl |= DP0_SRCCTRL_TP2;
errors = training_pattern2_errors;
}
/* Set DPCD 0x102 for Training Part 1 or 2 */
tc_write(DP0_SNKLTCTRL, DP_LINK_SCRAMBLING_DISABLE | pattern);
tc_write(DP0_LTLOOPCTRL,
(0x0f << 28) | /* Defer Iteration Count */
(0x0f << 24) | /* Loop Iteration Count */
(0x0d << 0)); /* Loop Timer Delay */
retry = 5;
do {
/* Set DP0 Training Pattern */
tc_write(DP0_SRCCTRL, srcctrl);
udelay(1);
tc_read(DP0_LTSTAT, &value);
} while ((!(value & LT_LOOPDONE)) && (--timeout));
/* Enable DP0 to start Link Training */
tc_write(DP0CTL, DP_EN);
/* wait */
timeout = 1000;
do {
tc_read(DP0_LTSTAT, &value);
udelay(1);
} while ((!(value & LT_LOOPDONE)) && (--timeout));
if (timeout == 0) {
dev_err(tc->dev, "Link training timeout!\n");
} else {
int pattern = (value >> 11) & 0x3;
int error = (value >> 8) & 0x7;
dev_dbg(tc->dev,
"Link training phase %d done after %d uS: %s\n",
pattern, 1000 - timeout, errors[error]);
if (pattern == DP_TRAINING_PATTERN_1 && error == 0)
break;
if (pattern == DP_TRAINING_PATTERN_2) {
value &= LT_CHANNEL1_EQ_BITS |
LT_INTERLANE_ALIGN_DONE |
LT_CHANNEL0_EQ_BITS;
/* in case of two lanes */
if ((tc->link.base.num_lanes == 2) &&
(value == (LT_CHANNEL1_EQ_BITS |
LT_INTERLANE_ALIGN_DONE |
LT_CHANNEL0_EQ_BITS)))
break;
/* in case of one line */
if ((tc->link.base.num_lanes == 1) &&
(value == (LT_INTERLANE_ALIGN_DONE |
LT_CHANNEL0_EQ_BITS)))
break;
}
}
/* restart */
tc_write(DP0CTL, 0);
usleep_range(10, 20);
} while (--retry);
if (retry == 0) {
dev_err(tc->dev, "Failed to finish training phase %d\n",
pattern);
if (timeout == 0) {
dev_err(tc->dev, "Link training timeout waiting for LT_LOOPDONE!\n");
return -ETIMEDOUT;
}
return 0;
return (value >> 8) & 0x7;
err:
return ret;
}
static int tc_main_link_setup(struct tc_data *tc)
static int tc_main_link_enable(struct tc_data *tc)
{
struct drm_dp_aux *aux = &tc->aux;
struct device *dev = tc->dev;
@ -837,9 +793,11 @@ static int tc_main_link_setup(struct tc_data *tc)
int ret;
u8 tmp[8];
/* display mode should be set at this point */
if (!tc->mode)
return -EINVAL;
dev_dbg(tc->dev, "link enable\n");
tc_read(DP0CTL, &value);
if (WARN_ON(value & DP_EN))
tc_write(DP0CTL, 0);
tc_write(DP0_SRCCTRL, tc_srcctrl(tc));
/* SSCG and BW27 on DP1 must be set to the same as on DP0 */
@ -872,7 +830,6 @@ static int tc_main_link_setup(struct tc_data *tc)
if (tc->link.base.num_lanes == 2)
dp_phy_ctrl |= PHY_2LANE;
tc_write(DP_PHY_CTRL, dp_phy_ctrl);
msleep(100);
/* PLL setup */
tc_write(DP0_PLLCTRL, PLLUPDATE | PLLEN);
@ -881,14 +838,6 @@ static int tc_main_link_setup(struct tc_data *tc)
tc_write(DP1_PLLCTRL, PLLUPDATE | PLLEN);
tc_wait_pll_lock(tc);
/* PXL PLL setup */
if (tc_test_pattern) {
ret = tc_pxl_pll_en(tc, clk_get_rate(tc->refclk),
1000 * tc->mode->clock);
if (ret)
goto err;
}
/* Reset/Enable Main Links */
dp_phy_ctrl |= DP_PHY_RST | PHY_M1_RST | PHY_M0_RST;
tc_write(DP_PHY_CTRL, dp_phy_ctrl);
@ -934,9 +883,9 @@ static int tc_main_link_setup(struct tc_data *tc)
if (tmp[0] != tc->assr) {
dev_dbg(dev, "Failed to switch display ASSR to %d, falling back to unscrambled mode\n",
tc->assr);
tc->assr);
/* trying with disabled scrambler */
tc->link.scrambler_dis = 1;
tc->link.scrambler_dis = true;
}
}
@ -948,18 +897,81 @@ static int tc_main_link_setup(struct tc_data *tc)
/* DOWNSPREAD_CTRL */
tmp[0] = tc->link.spread ? DP_SPREAD_AMP_0_5 : 0x00;
/* MAIN_LINK_CHANNEL_CODING_SET */
tmp[1] = tc->link.coding8b10b ? DP_SET_ANSI_8B10B : 0x00;
tmp[1] = DP_SET_ANSI_8B10B;
ret = drm_dp_dpcd_write(aux, DP_DOWNSPREAD_CTRL, tmp, 2);
if (ret < 0)
goto err_dpcd_write;
ret = tc_link_training(tc, DP_TRAINING_PATTERN_1);
if (ret)
/* Reset voltage-swing & pre-emphasis */
tmp[0] = tmp[1] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 |
DP_TRAIN_PRE_EMPH_LEVEL_0;
ret = drm_dp_dpcd_write(aux, DP_TRAINING_LANE0_SET, tmp, 2);
if (ret < 0)
goto err_dpcd_write;
/* Clock-Recovery */
/* Set DPCD 0x102 for Training Pattern 1 */
tc_write(DP0_SNKLTCTRL, DP_LINK_SCRAMBLING_DISABLE |
DP_TRAINING_PATTERN_1);
tc_write(DP0_LTLOOPCTRL,
(15 << 28) | /* Defer Iteration Count */
(15 << 24) | /* Loop Iteration Count */
(0xd << 0)); /* Loop Timer Delay */
tc_write(DP0_SRCCTRL, tc_srcctrl(tc) | DP0_SRCCTRL_SCRMBLDIS |
DP0_SRCCTRL_AUTOCORRECT | DP0_SRCCTRL_TP1);
/* Enable DP0 to start Link Training */
tc_write(DP0CTL,
((tc->link.base.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) ? EF_EN : 0) |
DP_EN);
/* wait */
ret = tc_wait_link_training(tc);
if (ret < 0)
goto err;
ret = tc_link_training(tc, DP_TRAINING_PATTERN_2);
if (ret)
if (ret) {
dev_err(tc->dev, "Link training phase 1 failed: %s\n",
training_pattern1_errors[ret]);
ret = -ENODEV;
goto err;
}
/* Channel Equalization */
/* Set DPCD 0x102 for Training Pattern 2 */
tc_write(DP0_SNKLTCTRL, DP_LINK_SCRAMBLING_DISABLE |
DP_TRAINING_PATTERN_2);
tc_write(DP0_SRCCTRL, tc_srcctrl(tc) | DP0_SRCCTRL_SCRMBLDIS |
DP0_SRCCTRL_AUTOCORRECT | DP0_SRCCTRL_TP2);
/* wait */
ret = tc_wait_link_training(tc);
if (ret < 0)
goto err;
if (ret) {
dev_err(tc->dev, "Link training phase 2 failed: %s\n",
training_pattern2_errors[ret]);
ret = -ENODEV;
goto err;
}
/*
* Toshiba's documentation suggests to first clear DPCD 0x102, then
* clear the training pattern bit in DP0_SRCCTRL. Testing shows
* that the link sometimes drops if those steps are done in that order,
* but if the steps are done in reverse order, the link stays up.
*
* So we do the steps differently than documented here.
*/
/* Clear Training Pattern, set AutoCorrect Mode = 1 */
tc_write(DP0_SRCCTRL, tc_srcctrl(tc) | DP0_SRCCTRL_AUTOCORRECT);
/* Clear DPCD 0x102 */
/* Note: Can Not use DP0_SNKLTCTRL (0x06E4) short cut */
@ -968,47 +980,43 @@ static int tc_main_link_setup(struct tc_data *tc)
if (ret < 0)
goto err_dpcd_write;
/* Clear Training Pattern, set AutoCorrect Mode = 1 */
tc_write(DP0_SRCCTRL, tc_srcctrl(tc) | DP0_SRCCTRL_AUTOCORRECT);
/* Check link status */
ret = drm_dp_dpcd_read_link_status(aux, tmp);
if (ret < 0)
goto err_dpcd_read;
/* Wait */
timeout = 100;
do {
udelay(1);
/* Read DPCD 0x202-0x207 */
ret = drm_dp_dpcd_read_link_status(aux, tmp + 2);
if (ret < 0)
goto err_dpcd_read;
} while ((--timeout) &&
!(drm_dp_channel_eq_ok(tmp + 2, tc->link.base.num_lanes)));
ret = 0;
if (timeout == 0) {
/* Read DPCD 0x200-0x201 */
ret = drm_dp_dpcd_read(aux, DP_SINK_COUNT, tmp, 2);
if (ret < 0)
goto err_dpcd_read;
dev_err(dev, "channel(s) EQ not ok\n");
dev_info(dev, "0x0200 SINK_COUNT: 0x%02x\n", tmp[0]);
dev_info(dev, "0x0201 DEVICE_SERVICE_IRQ_VECTOR: 0x%02x\n",
tmp[1]);
dev_info(dev, "0x0202 LANE0_1_STATUS: 0x%02x\n", tmp[2]);
dev_info(dev, "0x0204 LANE_ALIGN_STATUS_UPDATED: 0x%02x\n",
tmp[4]);
dev_info(dev, "0x0205 SINK_STATUS: 0x%02x\n", tmp[5]);
dev_info(dev, "0x0206 ADJUST_REQUEST_LANE0_1: 0x%02x\n",
tmp[6]);
value = tmp[0] & DP_CHANNEL_EQ_BITS;
return -EAGAIN;
if (value != DP_CHANNEL_EQ_BITS) {
dev_err(tc->dev, "Lane 0 failed: %x\n", value);
ret = -ENODEV;
}
ret = tc_set_video_mode(tc, tc->mode);
if (ret)
goto err;
if (tc->link.base.num_lanes == 2) {
value = (tmp[0] >> 4) & DP_CHANNEL_EQ_BITS;
/* Set M/N */
ret = tc_stream_clock_calc(tc);
if (ret)
if (value != DP_CHANNEL_EQ_BITS) {
dev_err(tc->dev, "Lane 1 failed: %x\n", value);
ret = -ENODEV;
}
if (!(tmp[2] & DP_INTERLANE_ALIGN_DONE)) {
dev_err(tc->dev, "Interlane align failed\n");
ret = -ENODEV;
}
}
if (ret) {
dev_err(dev, "0x0202 LANE0_1_STATUS: 0x%02x\n", tmp[0]);
dev_err(dev, "0x0203 LANE2_3_STATUS 0x%02x\n", tmp[1]);
dev_err(dev, "0x0204 LANE_ALIGN_STATUS_UPDATED: 0x%02x\n", tmp[2]);
dev_err(dev, "0x0205 SINK_STATUS: 0x%02x\n", tmp[3]);
dev_err(dev, "0x0206 ADJUST_REQUEST_LANE0_1: 0x%02x\n", tmp[4]);
dev_err(dev, "0x0207 ADJUST_REQUEST_LANE2_3: 0x%02x\n", tmp[5]);
goto err;
}
return 0;
err_dpcd_read:
@ -1020,39 +1028,84 @@ static int tc_main_link_setup(struct tc_data *tc)
return ret;
}
static int tc_main_link_stream(struct tc_data *tc, int state)
static int tc_main_link_disable(struct tc_data *tc)
{
int ret;
dev_dbg(tc->dev, "link disable\n");
tc_write(DP0_SRCCTRL, 0);
tc_write(DP0CTL, 0);
return 0;
err:
return ret;
}
static int tc_stream_enable(struct tc_data *tc)
{
int ret;
u32 value;
dev_dbg(tc->dev, "stream: %d\n", state);
dev_dbg(tc->dev, "enable video stream\n");
if (state) {
value = VID_MN_GEN | DP_EN;
if (tc->link.base.capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
value |= EF_EN;
tc_write(DP0CTL, value);
/*
* VID_EN assertion should be delayed by at least N * LSCLK
* cycles from the time VID_MN_GEN is enabled in order to
* generate stable values for VID_M. LSCLK is 270 MHz or
* 162 MHz, VID_N is set to 32768 in tc_stream_clock_calc(),
* so a delay of at least 203 us should suffice.
*/
usleep_range(500, 1000);
value |= VID_EN;
tc_write(DP0CTL, value);
/* Set input interface */
value = DP0_AUDSRC_NO_INPUT;
if (tc_test_pattern)
value |= DP0_VIDSRC_COLOR_BAR;
else
value |= DP0_VIDSRC_DPI_RX;
tc_write(SYSCTRL, value);
} else {
tc_write(DP0CTL, 0);
/* PXL PLL setup */
if (tc_test_pattern) {
ret = tc_pxl_pll_en(tc, clk_get_rate(tc->refclk),
1000 * tc->mode.clock);
if (ret)
goto err;
}
ret = tc_set_video_mode(tc, &tc->mode);
if (ret)
return ret;
/* Set M/N */
ret = tc_stream_clock_calc(tc);
if (ret)
return ret;
value = VID_MN_GEN | DP_EN;
if (tc->link.base.capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
value |= EF_EN;
tc_write(DP0CTL, value);
/*
* VID_EN assertion should be delayed by at least N * LSCLK
* cycles from the time VID_MN_GEN is enabled in order to
* generate stable values for VID_M. LSCLK is 270 MHz or
* 162 MHz, VID_N is set to 32768 in tc_stream_clock_calc(),
* so a delay of at least 203 us should suffice.
*/
usleep_range(500, 1000);
value |= VID_EN;
tc_write(DP0CTL, value);
/* Set input interface */
value = DP0_AUDSRC_NO_INPUT;
if (tc_test_pattern)
value |= DP0_VIDSRC_COLOR_BAR;
else
value |= DP0_VIDSRC_DPI_RX;
tc_write(SYSCTRL, value);
return 0;
err:
return ret;
}
static int tc_stream_disable(struct tc_data *tc)
{
int ret;
u32 val;
dev_dbg(tc->dev, "disable video stream\n");
tc_read(DP0CTL, &val);
val &= ~VID_EN;
tc_write(DP0CTL, val);
tc_pxl_pll_dis(tc);
return 0;
err:
return ret;
@ -1070,15 +1123,22 @@ static void tc_bridge_enable(struct drm_bridge *bridge)
struct tc_data *tc = bridge_to_tc(bridge);
int ret;
ret = tc_main_link_setup(tc);
ret = tc_get_display_props(tc);
if (ret < 0) {
dev_err(tc->dev, "main link setup error: %d\n", ret);
dev_err(tc->dev, "failed to read display props: %d\n", ret);
return;
}
ret = tc_main_link_stream(tc, 1);
ret = tc_main_link_enable(tc);
if (ret < 0) {
dev_err(tc->dev, "main link enable error: %d\n", ret);
return;
}
ret = tc_stream_enable(tc);
if (ret < 0) {
dev_err(tc->dev, "main link stream start error: %d\n", ret);
tc_main_link_disable(tc);
return;
}
@ -1092,9 +1152,13 @@ static void tc_bridge_disable(struct drm_bridge *bridge)
drm_panel_disable(tc->panel);
ret = tc_main_link_stream(tc, 0);
ret = tc_stream_disable(tc);
if (ret < 0)
dev_err(tc->dev, "main link stream stop error: %d\n", ret);
ret = tc_main_link_disable(tc);
if (ret < 0)
dev_err(tc->dev, "main link disable error: %d\n", ret);
}
static void tc_bridge_post_disable(struct drm_bridge *bridge)
@ -1116,10 +1180,10 @@ static bool tc_bridge_mode_fixup(struct drm_bridge *bridge,
return true;
}
static enum drm_mode_status tc_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
static enum drm_mode_status tc_mode_valid(struct drm_bridge *bridge,
const struct drm_display_mode *mode)
{
struct tc_data *tc = connector_to_tc(connector);
struct tc_data *tc = bridge_to_tc(bridge);
u32 req, avail;
u32 bits_per_pixel = 24;
@ -1142,7 +1206,7 @@ static void tc_bridge_mode_set(struct drm_bridge *bridge,
{
struct tc_data *tc = bridge_to_tc(bridge);
tc->mode = mode;
tc->mode = *mode;
}
static int tc_connector_get_modes(struct drm_connector *connector)
@ -1150,6 +1214,13 @@ static int tc_connector_get_modes(struct drm_connector *connector)
struct tc_data *tc = connector_to_tc(connector);
struct edid *edid;
unsigned int count;
int ret;
ret = tc_get_display_props(tc);
if (ret < 0) {
dev_err(tc->dev, "failed to read display props: %d\n", ret);
return 0;
}
if (tc->panel && tc->panel->funcs && tc->panel->funcs->get_modes) {
count = tc->panel->funcs->get_modes(tc->panel);
@ -1170,29 +1241,40 @@ static int tc_connector_get_modes(struct drm_connector *connector)
return count;
}
static void tc_connector_set_polling(struct tc_data *tc,
struct drm_connector *connector)
{
/* TODO: add support for HPD */
connector->polled = DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT;
}
static struct drm_encoder *
tc_connector_best_encoder(struct drm_connector *connector)
{
struct tc_data *tc = connector_to_tc(connector);
return tc->bridge.encoder;
}
static const struct drm_connector_helper_funcs tc_connector_helper_funcs = {
.get_modes = tc_connector_get_modes,
.mode_valid = tc_connector_mode_valid,
.best_encoder = tc_connector_best_encoder,
};
static enum drm_connector_status tc_connector_detect(struct drm_connector *connector,
bool force)
{
struct tc_data *tc = connector_to_tc(connector);
bool conn;
u32 val;
int ret;
if (tc->hpd_pin < 0) {
if (tc->panel)
return connector_status_connected;
else
return connector_status_unknown;
}
tc_read(GPIOI, &val);
conn = val & BIT(tc->hpd_pin);
if (conn)
return connector_status_connected;
else
return connector_status_disconnected;
err:
return connector_status_unknown;
}
static const struct drm_connector_funcs tc_connector_funcs = {
.detect = tc_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = drm_connector_cleanup,
.reset = drm_atomic_helper_connector_reset,
@ -1207,7 +1289,7 @@ static int tc_bridge_attach(struct drm_bridge *bridge)
struct drm_device *drm = bridge->dev;
int ret;
/* Create eDP connector */
/* Create DP/eDP connector */
drm_connector_helper_add(&tc->connector, &tc_connector_helper_funcs);
ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs,
tc->panel ? DRM_MODE_CONNECTOR_eDP :
@ -1215,6 +1297,15 @@ static int tc_bridge_attach(struct drm_bridge *bridge)
if (ret)
return ret;
/* Don't poll if don't have HPD connected */
if (tc->hpd_pin >= 0) {
if (tc->have_irq)
tc->connector.polled = DRM_CONNECTOR_POLL_HPD;
else
tc->connector.polled = DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT;
}
if (tc->panel)
drm_panel_attach(tc->panel, &tc->connector);
@ -1231,6 +1322,7 @@ static int tc_bridge_attach(struct drm_bridge *bridge)
static const struct drm_bridge_funcs tc_bridge_funcs = {
.attach = tc_bridge_attach,
.mode_valid = tc_mode_valid,
.mode_set = tc_bridge_mode_set,
.pre_enable = tc_bridge_pre_enable,
.enable = tc_bridge_enable,
@ -1250,6 +1342,8 @@ static const struct regmap_range tc_volatile_ranges[] = {
regmap_reg_range(DP_PHY_CTRL, DP_PHY_CTRL),
regmap_reg_range(DP0_PLLCTRL, PXL_PLLCTRL),
regmap_reg_range(VFUEN0, VFUEN0),
regmap_reg_range(INTSTS_G, INTSTS_G),
regmap_reg_range(GPIOI, GPIOI),
};
static const struct regmap_access_table tc_volatile_table = {
@ -1278,6 +1372,49 @@ static const struct regmap_config tc_regmap_config = {
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static irqreturn_t tc_irq_handler(int irq, void *arg)
{
struct tc_data *tc = arg;
u32 val;
int r;
r = regmap_read(tc->regmap, INTSTS_G, &val);
if (r)
return IRQ_NONE;
if (!val)
return IRQ_NONE;
if (val & INT_SYSERR) {
u32 stat = 0;
regmap_read(tc->regmap, SYSSTAT, &stat);
dev_err(tc->dev, "syserr %x\n", stat);
}
if (tc->hpd_pin >= 0 && tc->bridge.dev) {
/*
* H is triggered when the GPIO goes high.
*
* LC is triggered when the GPIO goes low and stays low for
* the duration of LCNT
*/
bool h = val & INT_GPIO_H(tc->hpd_pin);
bool lc = val & INT_GPIO_LC(tc->hpd_pin);
dev_dbg(tc->dev, "GPIO%d: %s %s\n", tc->hpd_pin,
h ? "H" : "", lc ? "LC" : "");
if (h || lc)
drm_kms_helper_hotplug_event(tc->bridge.dev);
}
regmap_write(tc->regmap, INTSTS_G, val);
return IRQ_HANDLED;
}
static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
@ -1329,6 +1466,33 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
return ret;
}
ret = of_property_read_u32(dev->of_node, "toshiba,hpd-pin",
&tc->hpd_pin);
if (ret) {
tc->hpd_pin = -ENODEV;
} else {
if (tc->hpd_pin < 0 || tc->hpd_pin > 1) {
dev_err(dev, "failed to parse HPD number\n");
return ret;
}
}
if (client->irq > 0) {
/* enable SysErr */
regmap_write(tc->regmap, INTCTL_G, INT_SYSERR);
ret = devm_request_threaded_irq(dev, client->irq,
NULL, tc_irq_handler,
IRQF_ONESHOT,
"tc358767-irq", tc);
if (ret) {
dev_err(dev, "failed to register dp interrupt\n");
return ret;
}
tc->have_irq = true;
}
ret = regmap_read(tc->regmap, TC_IDREG, &tc->rev);
if (ret) {
dev_err(tc->dev, "can not read device ID: %d\n", ret);
@ -1342,6 +1506,22 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
tc->assr = (tc->rev == 0x6601); /* Enable ASSR for eDP panels */
if (tc->hpd_pin >= 0) {
u32 lcnt_reg = tc->hpd_pin == 0 ? INT_GP0_LCNT : INT_GP1_LCNT;
u32 h_lc = INT_GPIO_H(tc->hpd_pin) | INT_GPIO_LC(tc->hpd_pin);
/* Set LCNT to 2ms */
regmap_write(tc->regmap, lcnt_reg,
clk_get_rate(tc->refclk) * 2 / 1000);
/* We need the "alternate" mode for HPD */
regmap_write(tc->regmap, GPIOM, BIT(tc->hpd_pin));
if (tc->have_irq) {
/* enable H & LC */
regmap_update_bits(tc->regmap, INTCTL_G, h_lc, h_lc);
}
}
ret = tc_aux_link_setup(tc);
if (ret)
return ret;
@ -1354,12 +1534,6 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (ret)
return ret;
ret = tc_get_display_props(tc);
if (ret)
goto err_unregister_aux;
tc_connector_set_polling(tc, &tc->connector);
tc->bridge.funcs = &tc_bridge_funcs;
tc->bridge.of_node = dev->of_node;
drm_bridge_add(&tc->bridge);
@ -1367,9 +1541,6 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
i2c_set_clientdata(client, tc);
return 0;
err_unregister_aux:
drm_dp_aux_unregister(&tc->aux);
return ret;
}
static int tc_remove(struct i2c_client *client)
@ -1379,8 +1550,6 @@ static int tc_remove(struct i2c_client *client)
drm_bridge_remove(&tc->bridge);
drm_dp_aux_unregister(&tc->aux);
tc_pxl_pll_dis(tc);
return 0;
}

View File

@ -5,15 +5,17 @@
* Copyright (C) 2018 Jacopo Mondi <jacopo+renesas@jmondi.org>
*/
#include <drm/drmP.h>
#include <drm/drm_bridge.h>
#include <drm/drm_panel.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <drm/drm_bridge.h>
#include <drm/drm_panel.h>
enum thc63_ports {
THC63_LVDS_IN0,
THC63_LVDS_IN1,

View File

@ -3,22 +3,24 @@
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*/
#include <drm/drmP.h>
#include <linux/clk.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_graph.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <linux/clk.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/iopoll.h>
#include <linux/of_graph.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#define SN_DEVICE_REV_REG 0x08
#define SN_DPPLL_SRC_REG 0x0A

View File

@ -11,15 +11,15 @@
#include <linux/delay.h>
#include <linux/fwnode.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#define HOTPLUG_DEBOUNCE_MS 1100

View File

@ -31,13 +31,20 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <drm/drmP.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include "drm_legacy.h"
#include <asm/agp.h>
#include <drm/drm_agpsupport.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_print.h>
#include "drm_legacy.h"
/**
* Get AGP information.
*

View File

@ -26,13 +26,18 @@
*/
#include <drm/drmP.h>
#include <linux/sync_file.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_mode.h>
#include <drm/drm_print.h>
#include <drm/drm_writeback.h>
#include <linux/sync_file.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"

View File

@ -25,15 +25,18 @@
* Daniel Vetter <daniel.vetter@ffwll.ch>
*/
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_writeback.h>
#include <drm/drm_damage_helper.h>
#include <linux/dma-fence.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <drm/drm_writeback.h>
#include "drm_crtc_helper_internal.h"
#include "drm_crtc_internal.h"

View File

@ -24,12 +24,13 @@
* Daniel Vetter <daniel.vetter@ffwll.ch>
*/
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_plane.h>
#include <drm/drm_connector.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_plane.h>
#include <drm/drm_print.h>
#include <drm/drm_writeback.h>
#include <linux/slab.h>

View File

@ -28,10 +28,16 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <drm/drmP.h>
#include <linux/slab.h>
#include <drm/drm_auth.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_lease.h>
#include <drm/drm_print.h>
#include "drm_internal.h"
#include "drm_legacy.h"
#include <drm/drm_lease.h>
/**
* DOC: master and authentication

View File

@ -23,13 +23,16 @@
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_blend.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/sort.h>
#include <drm/drm_atomic.h>
#include <drm/drm_blend.h>
#include <drm/drm_device.h>
#include <drm/drm_print.h>
#include "drm_crtc_internal.h"
/**

View File

@ -28,15 +28,26 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/log2.h>
#include <linux/export.h>
#include <linux/log2.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/nospec.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <asm/shmparam.h>
#include <drm/drmP.h>
#include <drm/drm_agpsupport.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_pci.h>
#include <drm/drm_print.h>
#include "drm_legacy.h"
#include <linux/nospec.h>
static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
struct drm_local_map *map)

View File

@ -15,10 +15,10 @@
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem.h>
#include <drm/drm_mode.h>
#include <drm/drm_print.h>
#include <drm/drmP.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"
@ -27,7 +27,6 @@
* DOC: overview
*
* This library provides support for clients running in the kernel like fbdev and bootsplash.
* Currently it's only partially implemented, just enough to support fbdev.
*
* GEM drivers which provide a GEM based dumb buffer with a virtual address are supported.
*/
@ -92,14 +91,20 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
client->name = name;
client->funcs = funcs;
ret = drm_client_open(client);
ret = drm_client_modeset_create(client);
if (ret)
goto err_put_module;
ret = drm_client_open(client);
if (ret)
goto err_free;
drm_dev_get(dev);
return 0;
err_free:
drm_client_modeset_free(client);
err_put_module:
if (funcs)
module_put(funcs->owner);
@ -148,6 +153,7 @@ void drm_client_release(struct drm_client_dev *client)
DRM_DEV_DEBUG_KMS(dev->dev, "%s\n", client->name);
drm_client_modeset_free(client);
drm_client_close(client);
drm_dev_put(dev);
if (client->funcs)

View File

@ -0,0 +1,104 @@
// SPDX-License-Identifier: MIT
/*
* Copyright 2018 Noralf Trønnes
* Copyright (c) 2006-2009 Red Hat Inc.
* Copyright (c) 2006-2008 Intel Corporation
* Jesse Barnes <jesse.barnes@intel.com>
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
*/
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <drm/drm_client.h>
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
int drm_client_modeset_create(struct drm_client_dev *client)
{
struct drm_device *dev = client->dev;
unsigned int num_crtc = dev->mode_config.num_crtc;
unsigned int max_connector_count = 1;
struct drm_mode_set *modeset;
struct drm_crtc *crtc;
unsigned int i = 0;
/* Add terminating zero entry to enable index less iteration */
client->modesets = kcalloc(num_crtc + 1, sizeof(*client->modesets), GFP_KERNEL);
if (!client->modesets)
return -ENOMEM;
mutex_init(&client->modeset_mutex);
drm_for_each_crtc(crtc, dev)
client->modesets[i++].crtc = crtc;
/* Cloning is only supported in the single crtc case. */
if (num_crtc == 1)
max_connector_count = DRM_CLIENT_MAX_CLONED_CONNECTORS;
for (modeset = client->modesets; modeset->crtc; modeset++) {
modeset->connectors = kcalloc(max_connector_count,
sizeof(*modeset->connectors), GFP_KERNEL);
if (!modeset->connectors)
goto err_free;
}
return 0;
err_free:
drm_client_modeset_free(client);
return -ENOMEM;
}
void drm_client_modeset_release(struct drm_client_dev *client)
{
struct drm_mode_set *modeset;
unsigned int i;
drm_client_for_each_modeset(modeset, client) {
drm_mode_destroy(client->dev, modeset->mode);
modeset->mode = NULL;
modeset->fb = NULL;
for (i = 0; i < modeset->num_connectors; i++) {
drm_connector_put(modeset->connectors[i]);
modeset->connectors[i] = NULL;
}
modeset->num_connectors = 0;
}
}
/* TODO: Remove export when modeset code has been moved over */
EXPORT_SYMBOL(drm_client_modeset_release);
void drm_client_modeset_free(struct drm_client_dev *client)
{
struct drm_mode_set *modeset;
mutex_lock(&client->modeset_mutex);
drm_client_modeset_release(client);
drm_client_for_each_modeset(modeset, client)
kfree(modeset->connectors);
mutex_unlock(&client->modeset_mutex);
mutex_destroy(&client->modeset_mutex);
kfree(client->modesets);
}
struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc)
{
struct drm_mode_set *modeset;
drm_client_for_each_modeset(modeset, client)
if (modeset->crtc == crtc)
return modeset;
return NULL;
}
/* TODO: Remove export when modeset code has been moved over */
EXPORT_SYMBOL(drm_client_find_modeset);

View File

@ -20,9 +20,13 @@
* OF THIS SOFTWARE.
*/
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <linux/uaccess.h>
#include <drm/drm_color_mgmt.h>
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_print.h>
#include "drm_crtc_internal.h"

View File

@ -956,6 +956,46 @@ static const struct drm_prop_enum_list hdmi_colorspaces[] = {
* is no longer protected and userspace should take appropriate action
* (whatever that might be).
*
* HDR_OUTPUT_METADATA:
* Connector property to enable userspace to send HDR Metadata to
* driver. This metadata is based on the composition and blending
* policies decided by user, taking into account the hardware and
* sink capabilities. The driver gets this metadata and creates a
* Dynamic Range and Mastering Infoframe (DRM) in case of HDMI,
* SDP packet (Non-audio INFOFRAME SDP v1.3) for DP. This is then
* sent to sink. This notifies the sink of the upcoming frame's Color
* Encoding and Luminance parameters.
*
* Userspace first need to detect the HDR capabilities of sink by
* reading and parsing the EDID. Details of HDR metadata for HDMI
* are added in CTA 861.G spec. For DP , its defined in VESA DP
* Standard v1.4. It needs to then get the metadata information
* of the video/game/app content which are encoded in HDR (basically
* using HDR transfer functions). With this information it needs to
* decide on a blending policy and compose the relevant
* layers/overlays into a common format. Once this blending is done,
* userspace will be aware of the metadata of the composed frame to
* be send to sink. It then uses this property to communicate this
* metadata to driver which then make a Infoframe packet and sends
* to sink based on the type of encoder connected.
*
* Userspace will be responsible to do Tone mapping operation in case:
* - Some layers are HDR and others are SDR
* - HDR layers luminance is not same as sink
* It will even need to do colorspace conversion and get all layers
* to one common colorspace for blending. It can use either GL, Media
* or display engine to get this done based on the capabilties of the
* associated hardware.
*
* Driver expects metadata to be put in &struct hdr_output_metadata
* structure from userspace. This is received as blob and stored in
* &drm_connector_state.hdr_output_metadata. It parses EDID and saves the
* sink metadata in &struct hdr_sink_metadata, as
* &drm_connector.hdr_sink_metadata. Driver uses
* drm_hdmi_infoframe_set_hdr_metadata() helper to set the HDR metadata,
* hdmi_drm_infoframe_pack() to pack the infoframe as per spec, in case of
* HDMI encoder.
*
* max bpc:
* This range property is used by userspace to limit the bit depth. When
* used the driver would limit the bpc in accordance with the valid range

View File

@ -28,7 +28,13 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <drm/drmP.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_print.h>
#include "drm_legacy.h"
struct drm_ctx_list {

View File

@ -29,21 +29,23 @@
* Jesse Barnes <jesse.barnes@intel.com>
*/
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_crtc.h>
#include <drm/drm_encoder.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
/**
* DOC: overview

View File

@ -31,14 +31,30 @@
* and are not exported to drivers.
*/
enum drm_mode_status;
enum drm_connector_force;
#include <linux/types.h>
struct drm_display_mode;
struct work_struct;
struct drm_connector;
enum drm_color_encoding;
enum drm_color_range;
enum drm_connector_force;
enum drm_mode_status;
struct drm_atomic_state;
struct drm_bridge;
struct drm_connector;
struct drm_crtc;
struct drm_device;
struct drm_display_mode;
struct drm_file;
struct drm_framebuffer;
struct drm_mode_create_dumb;
struct drm_mode_fb_cmd2;
struct drm_mode_fb_cmd;
struct drm_mode_object;
struct drm_plane;
struct drm_property;
struct edid;
struct kref;
struct work_struct;
/* drm_crtc.c */
int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,

View File

@ -286,7 +286,7 @@ drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter,
iter->plane_src.y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
if (!iter->clips || !drm_rect_equals(&state->src, &old_state->src)) {
iter->clips = 0;
iter->clips = NULL;
iter->num_clips = 0;
iter->full_update = true;
}

View File

@ -24,20 +24,23 @@
*/
#include <linux/debugfs.h>
#include <linux/export.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/uaccess.h>
#include <drm/drm_client.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_edid.h>
#include <drm/drm_atomic.h>
#include <drm/drm_auth.h>
#include <drm/drm_client.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
#include <drm/drm_file.h>
#include <drm/drm_gem.h>
#include <drm/drmP.h>
#include "drm_internal.h"
#include "drm_crtc_internal.h"
#include "drm_internal.h"
#if defined(CONFIG_DEBUG_FS)

View File

@ -29,7 +29,14 @@
#include <linux/circ_buf.h>
#include <linux/ctype.h>
#include <linux/debugfs.h>
#include <drm/drmP.h>
#include <linux/poll.h>
#include <linux/uaccess.h>
#include <drm/drm_crtc.h>
#include <drm/drm_debugfs_crc.h>
#include <drm/drm_drv.h>
#include <drm/drm_print.h>
#include "drm_internal.h"
/**

View File

@ -34,7 +34,11 @@
*/
#include <linux/export.h>
#include <drm/drmP.h>
#include <drm/drm_drv.h>
#include <drm/drm_pci.h>
#include <drm/drm_print.h>
#include "drm_legacy.h"
/**

View File

@ -1996,7 +1996,11 @@ static void process_single_up_tx_qlock(struct drm_dp_mst_topology_mgr *mgr,
if (ret != 1)
DRM_DEBUG_KMS("failed to send msg in q %d\n", ret);
txmsg->dst->tx_slots[txmsg->seqno] = NULL;
if (txmsg->seqno != -1) {
WARN_ON((unsigned int)txmsg->seqno >
ARRAY_SIZE(txmsg->dst->tx_slots));
txmsg->dst->tx_slots[txmsg->seqno] = NULL;
}
}
static void drm_dp_queue_down_tx(struct drm_dp_mst_topology_mgr *mgr,

View File

@ -35,16 +35,19 @@
#include <linux/srcu.h>
#include <drm/drm_client.h>
#include <drm/drm_color_mgmt.h>
#include <drm/drm_drv.h>
#include <drm/drmP.h>
#include <drm/drm_file.h>
#include <drm/drm_mode_object.h>
#include <drm/drm_print.h>
#include "drm_crtc_internal.h"
#include "drm_legacy.h"
#include "drm_internal.h"
#include "drm_legacy.h"
/*
* drm_debug: Enable debug output.
* Bitmask of DRM_UT_x. See include/drm/drmP.h for details.
* Bitmask of DRM_UT_x. See include/drm/drm_print.h for details.
*/
unsigned int drm_debug = 0;
EXPORT_SYMBOL(drm_debug);

View File

@ -23,8 +23,10 @@
* OF THIS SOFTWARE.
*/
#include <drm/drmP.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem.h>
#include <drm/drm_mode.h>
#include "drm_crtc_internal.h"

View File

@ -281,6 +281,8 @@ struct edid *drm_load_edid_firmware(struct drm_connector *connector)
* the last one found one as a fallback.
*/
fwstr = kstrdup(edid_firmware, GFP_KERNEL);
if (!fwstr)
return ERR_PTR(-ENOMEM);
edidstr = fwstr;
while ((edidname = strsep(&edidstr, ","))) {

View File

@ -21,7 +21,9 @@
*/
#include <linux/export.h>
#include <drm/drmP.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_encoder.h>
#include "drm_crtc_internal.h"

View File

@ -32,18 +32,23 @@
#include <linux/console.h>
#include <linux/dma-buf.h>
#include <linux/kernel.h>
#include <linux/sysrq.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
#include <linux/slab.h>
#include <linux/sysrq.h>
#include <linux/vmalloc.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include "drm_crtc_internal.h"
#include "drm_crtc_helper_internal.h"
#include "drm_crtc_internal.h"
#include "drm_internal.h"
static bool drm_fbdev_emulation = true;
@ -317,13 +322,11 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
{
struct drm_fb_helper *helper = info->par;
const struct drm_crtc_helper_funcs *funcs;
int i;
struct drm_mode_set *mode_set;
list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
for (i = 0; i < helper->crtc_count; i++) {
struct drm_mode_set *mode_set =
&helper->crtc_info[i].mode_set;
mutex_lock(&helper->client.modeset_mutex);
drm_client_for_each_modeset(mode_set, &helper->client) {
if (!mode_set->crtc->enabled)
continue;
@ -340,6 +343,7 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
mode_set->y,
ENTER_ATOMIC_MODE_SET);
}
mutex_unlock(&helper->client.modeset_mutex);
}
return 0;
@ -353,14 +357,14 @@ EXPORT_SYMBOL(drm_fb_helper_debug_enter);
int drm_fb_helper_debug_leave(struct fb_info *info)
{
struct drm_fb_helper *helper = info->par;
struct drm_client_dev *client = &helper->client;
struct drm_crtc *crtc;
const struct drm_crtc_helper_funcs *funcs;
struct drm_mode_set *mode_set;
struct drm_framebuffer *fb;
int i;
for (i = 0; i < helper->crtc_count; i++) {
struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
mutex_lock(&client->modeset_mutex);
drm_client_for_each_modeset(mode_set, client) {
crtc = mode_set->crtc;
if (drm_drv_uses_atomic_modeset(crtc->dev))
continue;
@ -383,6 +387,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
crtc->y, LEAVE_ATOMIC_MODE_SET);
}
mutex_unlock(&client->modeset_mutex);
return 0;
}
@ -433,12 +438,14 @@ static bool drm_fb_helper_panel_rotation(struct drm_mode_set *modeset,
static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
{
struct drm_client_dev *client = &fb_helper->client;
struct drm_device *dev = fb_helper->dev;
struct drm_plane_state *plane_state;
struct drm_plane *plane;
struct drm_atomic_state *state;
int i, ret;
struct drm_modeset_acquire_ctx ctx;
struct drm_mode_set *mode_set;
int ret;
drm_modeset_acquire_init(&ctx, 0);
@ -468,8 +475,7 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
goto out_state;
}
for (i = 0; i < fb_helper->crtc_count; i++) {
struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
drm_client_for_each_modeset(mode_set, client) {
struct drm_plane *primary = mode_set->crtc->primary;
unsigned int rotation;
@ -517,9 +523,11 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
{
struct drm_client_dev *client = &fb_helper->client;
struct drm_device *dev = fb_helper->dev;
struct drm_mode_set *mode_set;
struct drm_plane *plane;
int i, ret = 0;
int ret = 0;
drm_modeset_lock_all(fb_helper->dev);
drm_for_each_plane(plane, dev) {
@ -532,8 +540,7 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
DRM_MODE_ROTATE_0);
}
for (i = 0; i < fb_helper->crtc_count; i++) {
struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
drm_client_for_each_modeset(mode_set, client) {
struct drm_crtc *crtc = mode_set->crtc;
if (crtc->funcs->cursor_set2) {
@ -559,11 +566,16 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
static int restore_fbdev_mode_force(struct drm_fb_helper *fb_helper)
{
struct drm_device *dev = fb_helper->dev;
int ret;
mutex_lock(&fb_helper->client.modeset_mutex);
if (drm_drv_uses_atomic_modeset(dev))
return restore_fbdev_mode_atomic(fb_helper, true);
ret = restore_fbdev_mode_atomic(fb_helper, true);
else
return restore_fbdev_mode_legacy(fb_helper);
ret = restore_fbdev_mode_legacy(fb_helper);
mutex_unlock(&fb_helper->client.modeset_mutex);
return ret;
}
static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
@ -682,15 +694,14 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
{
struct drm_client_dev *client = &fb_helper->client;
struct drm_device *dev = fb_helper->dev;
struct drm_connector *connector;
struct drm_mode_set *modeset;
int i, j;
int j;
drm_modeset_lock_all(dev);
for (i = 0; i < fb_helper->crtc_count; i++) {
modeset = &fb_helper->crtc_info[i].mode_set;
drm_client_for_each_modeset(modeset, client) {
if (!modeset->crtc->enabled)
continue;
@ -707,6 +718,7 @@ static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
{
struct drm_fb_helper *fb_helper = info->par;
struct drm_client_dev *client = &fb_helper->client;
struct drm_device *dev = fb_helper->dev;
/*
@ -716,10 +728,12 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
if (!drm_master_internal_acquire(dev))
goto unlock;
mutex_lock(&client->modeset_mutex);
if (drm_drv_uses_atomic_modeset(dev))
restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON);
else
dpms_legacy(fb_helper, dpms_mode);
mutex_unlock(&client->modeset_mutex);
drm_master_internal_release(dev);
unlock:
@ -762,43 +776,6 @@ int drm_fb_helper_blank(int blank, struct fb_info *info)
}
EXPORT_SYMBOL(drm_fb_helper_blank);
static void drm_fb_helper_modeset_release(struct drm_fb_helper *helper,
struct drm_mode_set *modeset)
{
int i;
for (i = 0; i < modeset->num_connectors; i++) {
drm_connector_put(modeset->connectors[i]);
modeset->connectors[i] = NULL;
}
modeset->num_connectors = 0;
drm_mode_destroy(helper->dev, modeset->mode);
modeset->mode = NULL;
/* FIXME should hold a ref? */
modeset->fb = NULL;
}
static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
{
int i;
for (i = 0; i < helper->connector_count; i++) {
drm_connector_put(helper->connector_info[i]->connector);
kfree(helper->connector_info[i]);
}
kfree(helper->connector_info);
for (i = 0; i < helper->crtc_count; i++) {
struct drm_mode_set *modeset = &helper->crtc_info[i].mode_set;
drm_fb_helper_modeset_release(helper, modeset);
kfree(modeset->connectors);
}
kfree(helper->crtc_info);
}
static void drm_fb_helper_resume_worker(struct work_struct *work)
{
struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
@ -877,7 +854,7 @@ EXPORT_SYMBOL(drm_fb_helper_prepare);
* drm_fb_helper_init - initialize a &struct drm_fb_helper
* @dev: drm device
* @fb_helper: driver-allocated fbdev helper structure to initialize
* @max_conn_count: max connector count
* @max_conn_count: max connector count (not used)
*
* This allocates the structures for the fbdev helper with the given limits.
* Note that this won't yet touch the hardware (through the driver interfaces)
@ -893,53 +870,36 @@ int drm_fb_helper_init(struct drm_device *dev,
struct drm_fb_helper *fb_helper,
int max_conn_count)
{
struct drm_crtc *crtc;
struct drm_mode_config *config = &dev->mode_config;
int i;
int ret;
if (!drm_fbdev_emulation) {
dev->fb_helper = fb_helper;
return 0;
}
if (!max_conn_count)
return -EINVAL;
fb_helper->crtc_info = kcalloc(config->num_crtc, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
if (!fb_helper->crtc_info)
return -ENOMEM;
fb_helper->crtc_count = config->num_crtc;
fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
if (!fb_helper->connector_info) {
kfree(fb_helper->crtc_info);
return -ENOMEM;
/*
* If this is not the generic fbdev client, initialize a drm_client
* without callbacks so we can use the modesets.
*/
if (!fb_helper->client.funcs) {
ret = drm_client_init(dev, &fb_helper->client, "drm_fb_helper", NULL);
if (ret)
return ret;
}
fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
if (!fb_helper->connector_info)
goto out_free;
fb_helper->connector_info_alloc_count = dev->mode_config.num_connector;
fb_helper->connector_count = 0;
for (i = 0; i < fb_helper->crtc_count; i++) {
fb_helper->crtc_info[i].mode_set.connectors =
kcalloc(max_conn_count,
sizeof(struct drm_connector *),
GFP_KERNEL);
if (!fb_helper->crtc_info[i].mode_set.connectors)
goto out_free;
fb_helper->crtc_info[i].mode_set.num_connectors = 0;
}
i = 0;
drm_for_each_crtc(crtc, dev) {
fb_helper->crtc_info[i].mode_set.crtc = crtc;
i++;
}
dev->fb_helper = fb_helper;
return 0;
out_free:
drm_fb_helper_crtc_free(fb_helper);
drm_client_release(&fb_helper->client);
return -ENOMEM;
}
EXPORT_SYMBOL(drm_fb_helper_init);
@ -1015,6 +975,7 @@ EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
{
struct fb_info *info;
int i;
if (!fb_helper)
return;
@ -1044,8 +1005,15 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
mutex_unlock(&kernel_fb_helper_lock);
mutex_destroy(&fb_helper->lock);
drm_fb_helper_crtc_free(fb_helper);
if (!fb_helper->client.funcs)
drm_client_release(&fb_helper->client);
for (i = 0; i < fb_helper->connector_count; i++) {
drm_connector_put(fb_helper->connector_info[i]->connector);
kfree(fb_helper->connector_info[i]);
}
kfree(fb_helper->connector_info);
}
EXPORT_SYMBOL(drm_fb_helper_fini);
@ -1390,13 +1358,14 @@ static int setcmap_pseudo_palette(struct fb_cmap *cmap, struct fb_info *info)
static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info)
{
struct drm_fb_helper *fb_helper = info->par;
struct drm_mode_set *modeset;
struct drm_crtc *crtc;
u16 *r, *g, *b;
int i, ret = 0;
int ret = 0;
drm_modeset_lock_all(fb_helper->dev);
for (i = 0; i < fb_helper->crtc_count; i++) {
crtc = fb_helper->crtc_info[i].mode_set.crtc;
drm_client_for_each_modeset(modeset, &fb_helper->client) {
crtc = modeset->crtc;
if (!crtc->funcs->gamma_set || !crtc->gamma_size)
return -EINVAL;
@ -1472,10 +1441,11 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
struct drm_modeset_acquire_ctx ctx;
struct drm_crtc_state *crtc_state;
struct drm_atomic_state *state;
struct drm_mode_set *modeset;
struct drm_crtc *crtc;
u16 *r, *g, *b;
int i, ret = 0;
bool replaced;
int ret = 0;
drm_modeset_acquire_init(&ctx, 0);
@ -1487,8 +1457,8 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
state->acquire_ctx = &ctx;
retry:
for (i = 0; i < fb_helper->crtc_count; i++) {
crtc = fb_helper->crtc_info[i].mode_set.crtc;
drm_client_for_each_modeset(modeset, &fb_helper->client) {
crtc = modeset->crtc;
if (!gamma_lut)
gamma_lut = setcmap_new_gamma_lut(crtc, cmap);
@ -1516,8 +1486,8 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
if (ret)
goto out_state;
for (i = 0; i < fb_helper->crtc_count; i++) {
crtc = fb_helper->crtc_info[i].mode_set.crtc;
drm_client_for_each_modeset(modeset, &fb_helper->client) {
crtc = modeset->crtc;
r = crtc->gamma_store;
g = r + crtc->gamma_size;
@ -1567,12 +1537,14 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
goto unlock;
}
mutex_lock(&fb_helper->client.modeset_mutex);
if (info->fix.visual == FB_VISUAL_TRUECOLOR)
ret = setcmap_pseudo_palette(cmap, info);
else if (drm_drv_uses_atomic_modeset(fb_helper->dev))
ret = setcmap_atomic(cmap, info);
else
ret = setcmap_legacy(cmap, info);
mutex_unlock(&fb_helper->client.modeset_mutex);
drm_master_internal_release(dev);
unlock:
@ -1596,7 +1568,6 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
{
struct drm_fb_helper *fb_helper = info->par;
struct drm_device *dev = fb_helper->dev;
struct drm_mode_set *mode_set;
struct drm_crtc *crtc;
int ret = 0;
@ -1624,8 +1595,7 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
* make. If we're not smart enough here, one should
* just consider switch the userspace to KMS.
*/
mode_set = &fb_helper->crtc_info[0].mode_set;
crtc = mode_set->crtc;
crtc = fb_helper->client.modesets[0].crtc;
/*
* Only wait for a vblank event if the CRTC is
@ -1822,16 +1792,14 @@ EXPORT_SYMBOL(drm_fb_helper_set_par);
static void pan_set(struct drm_fb_helper *fb_helper, int x, int y)
{
int i;
for (i = 0; i < fb_helper->crtc_count; i++) {
struct drm_mode_set *mode_set;
mode_set = &fb_helper->crtc_info[i].mode_set;
struct drm_mode_set *mode_set;
mutex_lock(&fb_helper->client.modeset_mutex);
drm_client_for_each_modeset(mode_set, &fb_helper->client) {
mode_set->x = x;
mode_set->y = y;
}
mutex_unlock(&fb_helper->client.modeset_mutex);
}
static int pan_display_atomic(struct fb_var_screeninfo *var,
@ -1842,7 +1810,7 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
pan_set(fb_helper, var->xoffset, var->yoffset);
ret = restore_fbdev_mode_atomic(fb_helper, true);
ret = restore_fbdev_mode_force(fb_helper);
if (!ret) {
info->var.xoffset = var->xoffset;
info->var.yoffset = var->yoffset;
@ -1856,14 +1824,13 @@ static int pan_display_legacy(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct drm_fb_helper *fb_helper = info->par;
struct drm_client_dev *client = &fb_helper->client;
struct drm_mode_set *modeset;
int ret = 0;
int i;
drm_modeset_lock_all(fb_helper->dev);
for (i = 0; i < fb_helper->crtc_count; i++) {
modeset = &fb_helper->crtc_info[i].mode_set;
mutex_lock(&client->modeset_mutex);
drm_client_for_each_modeset(modeset, client) {
modeset->x = var->xoffset;
modeset->y = var->yoffset;
@ -1875,6 +1842,7 @@ static int pan_display_legacy(struct fb_var_screeninfo *var,
}
}
}
mutex_unlock(&client->modeset_mutex);
drm_modeset_unlock_all(fb_helper->dev);
return ret;
@ -1921,10 +1889,12 @@ EXPORT_SYMBOL(drm_fb_helper_pan_display);
static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
int preferred_bpp)
{
struct drm_client_dev *client = &fb_helper->client;
int ret = 0;
int crtc_count = 0;
int i;
struct drm_fb_helper_surface_size sizes;
struct drm_mode_set *mode_set;
int best_depth = 0;
memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
@ -1975,13 +1945,13 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
* 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;
mutex_lock(&client->modeset_mutex);
drm_client_for_each_modeset(mode_set, client) {
struct drm_crtc *crtc = mode_set->crtc;
struct drm_plane *plane = crtc->primary;
int j;
DRM_DEBUG("test CRTC %d primary plane\n", i);
DRM_DEBUG("test CRTC %u primary plane\n", drm_crtc_index(crtc));
for (j = 0; j < plane->format_count; j++) {
const struct drm_format_info *fmt;
@ -2021,9 +1991,8 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
/* first up get a count of crtcs now in use and new min/maxes width/heights */
crtc_count = 0;
for (i = 0; i < fb_helper->crtc_count; i++) {
drm_client_for_each_modeset(mode_set, client) {
struct drm_display_mode *desired_mode;
struct drm_mode_set *mode_set;
int x, y, j;
/* in case of tile group, are we the last tile vert or horiz?
* If no tile group you are always the last one both vertically
@ -2031,7 +2000,6 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
*/
bool lastv = true, lasth = true;
mode_set = &fb_helper->crtc_info[i].mode_set;
desired_mode = mode_set->mode;
if (!desired_mode)
@ -2061,6 +2029,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
if (lastv)
sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
}
mutex_unlock(&client->modeset_mutex);
if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
DRM_INFO("Cannot find any crtc or sizes\n");
@ -2292,7 +2261,7 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
struct drm_display_mode *dmt_mode, *mode;
/* only contemplate cloning in the single crtc case */
if (fb_helper->crtc_count > 1)
if (fb_helper->dev->mode_config.num_crtc > 1)
return false;
count = 0;
@ -2481,15 +2450,17 @@ static bool connector_has_possible_crtc(struct drm_connector *connector,
}
static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
struct drm_fb_helper_crtc **best_crtcs,
struct drm_crtc **best_crtcs,
struct drm_display_mode **modes,
int n, int width, int height)
{
int c, o;
struct drm_client_dev *client = &fb_helper->client;
struct drm_connector *connector;
int my_score, best_score, score;
struct drm_fb_helper_crtc **crtcs, *crtc;
struct drm_crtc **crtcs, *crtc;
struct drm_mode_set *modeset;
struct drm_fb_helper_connector *fb_helper_conn;
int o;
if (n == fb_helper->connector_count)
return 0;
@ -2502,8 +2473,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
if (modes[n] == NULL)
return best_score;
crtcs = kcalloc(fb_helper->connector_count,
sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
if (!crtcs)
return best_score;
@ -2519,11 +2489,10 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
* select a crtc for this connector and then attempt to configure
* remaining connectors
*/
for (c = 0; c < fb_helper->crtc_count; c++) {
crtc = &fb_helper->crtc_info[c];
drm_client_for_each_modeset(modeset, client) {
crtc = modeset->crtc;
if (!connector_has_possible_crtc(connector,
crtc->mode_set.crtc))
if (!connector_has_possible_crtc(connector, crtc))
continue;
for (o = 0; o < n; o++)
@ -2532,7 +2501,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
if (o < n) {
/* ignore cloning unless only a single crtc */
if (fb_helper->crtc_count > 1)
if (fb_helper->dev->mode_config.num_crtc > 1)
continue;
if (!drm_mode_equal(modes[o], modes[n]))
@ -2540,14 +2509,13 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
}
crtcs[n] = crtc;
memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *));
memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));
score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
width, height);
if (score > best_score) {
best_score = score;
memcpy(best_crtcs, crtcs,
fb_helper->connector_count *
sizeof(struct drm_fb_helper_crtc *));
fb_helper->connector_count * sizeof(*crtcs));
}
}
@ -2555,21 +2523,9 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
return best_score;
}
static struct drm_fb_helper_crtc *
drm_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
{
int i;
for (i = 0; i < fb_helper->crtc_count; i++)
if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
return &fb_helper->crtc_info[i];
return NULL;
}
/* Try to read the BIOS display configuration and use it for the initial config */
static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
struct drm_fb_helper_crtc **crtcs,
struct drm_crtc **crtcs,
struct drm_display_mode **modes,
struct drm_fb_offset *offsets,
bool *enabled, int width, int height)
@ -2605,7 +2561,7 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
struct drm_fb_helper_connector *fb_conn;
struct drm_connector *connector;
struct drm_encoder *encoder;
struct drm_fb_helper_crtc *new_crtc;
struct drm_crtc *new_crtc;
fb_conn = fb_helper->connector_info[i];
connector = fb_conn->connector;
@ -2647,7 +2603,7 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
num_connectors_enabled++;
new_crtc = drm_fb_helper_crtc(fb_helper, connector->state->crtc);
new_crtc = connector->state->crtc;
/*
* Make sure we're not trying to drive multiple connectors
@ -2747,10 +2703,11 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
u32 width, u32 height)
{
struct drm_client_dev *client = &fb_helper->client;
struct drm_device *dev = fb_helper->dev;
struct drm_fb_helper_crtc **crtcs;
struct drm_display_mode **modes;
struct drm_fb_offset *offsets;
struct drm_crtc **crtcs;
bool *enabled;
int i;
@ -2758,8 +2715,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
/* prevent concurrent modification of connector_count by hotplug */
lockdep_assert_held(&fb_helper->lock);
crtcs = kcalloc(fb_helper->connector_count,
sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
modes = kcalloc(fb_helper->connector_count,
sizeof(struct drm_display_mode *), GFP_KERNEL);
offsets = kcalloc(fb_helper->connector_count,
@ -2771,6 +2727,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
goto out;
}
mutex_lock(&client->modeset_mutex);
mutex_lock(&fb_helper->dev->mode_config.mutex);
if (drm_fb_helper_probe_connector_modes(fb_helper, width, height) == 0)
DRM_DEBUG_KMS("No connectors reported connected with modes\n");
@ -2795,24 +2753,24 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
}
mutex_unlock(&fb_helper->dev->mode_config.mutex);
/* need to set the modesets up here for use later */
/* fill out the connector<->crtc mappings into the modesets */
for (i = 0; i < fb_helper->crtc_count; i++)
drm_fb_helper_modeset_release(fb_helper,
&fb_helper->crtc_info[i].mode_set);
drm_client_modeset_release(client);
drm_fb_helper_for_each_connector(fb_helper, i) {
struct drm_display_mode *mode = modes[i];
struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
struct drm_crtc *crtc = crtcs[i];
struct drm_fb_offset *offset = &offsets[i];
if (mode && fb_crtc) {
struct drm_mode_set *modeset = &fb_crtc->mode_set;
if (mode && crtc) {
struct drm_mode_set *modeset = drm_client_find_modeset(client, crtc);
struct drm_connector *connector =
fb_helper->connector_info[i]->connector;
DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
mode->name, crtc->base.id, offset->x, offset->y);
if (WARN_ON_ONCE(modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS ||
(dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1)))
break;
modeset->mode = drm_mode_duplicate(dev, mode);
drm_connector_get(connector);
@ -2821,6 +2779,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
modeset->y = offset->y;
}
}
mutex_unlock(&client->modeset_mutex);
out:
kfree(crtcs);
kfree(modes);
@ -2837,13 +2797,14 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
*/
static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
{
struct drm_client_dev *client = &fb_helper->client;
struct fb_info *info = fb_helper->fbdev;
unsigned int rotation, sw_rotations = 0;
struct drm_mode_set *modeset;
int i;
for (i = 0; i < fb_helper->crtc_count; i++) {
struct drm_mode_set *modeset = &fb_helper->crtc_info[i].mode_set;
mutex_lock(&client->modeset_mutex);
drm_client_for_each_modeset(modeset, client) {
if (!modeset->num_connectors)
continue;
@ -2855,6 +2816,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
else
sw_rotations |= rotation;
}
mutex_unlock(&client->modeset_mutex);
mutex_lock(&fb_helper->dev->mode_config.mutex);
drm_fb_helper_for_each_connector(fb_helper, i) {
@ -3070,8 +3032,7 @@ EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
* @funcs: fbdev helper functions
* @preferred_bpp: Preferred bits per pixel for the device.
* @dev->mode_config.preferred_depth is used if this is zero.
* @max_conn_count: Maximum number of connectors.
* @dev->mode_config.num_connector is used if this is zero.
* @max_conn_count: Maximum number of connectors (not used)
*
* This function sets up fbdev emulation and registers fbdev for access by
* userspace. If all connectors are disconnected, setup is deferred to the next
@ -3099,16 +3060,9 @@ int drm_fb_helper_fbdev_setup(struct drm_device *dev,
if (!preferred_bpp)
preferred_bpp = 32;
if (!max_conn_count)
max_conn_count = dev->mode_config.num_connector;
if (!max_conn_count) {
DRM_DEV_ERROR(dev->dev, "fbdev: No connectors\n");
return -EINVAL;
}
drm_fb_helper_prepare(dev, fb_helper, funcs);
ret = drm_fb_helper_init(dev, fb_helper, max_conn_count);
ret = drm_fb_helper_init(dev, fb_helper, 0);
if (ret < 0) {
DRM_DEV_ERROR(dev->dev, "fbdev: Failed to initialize (ret=%d)\n", ret);
return ret;
@ -3421,7 +3375,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
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);
ret = drm_fb_helper_init(dev, fb_helper, 0);
if (ret)
goto err;

View File

@ -31,17 +31,20 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <linux/dma-fence.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <drm/drm_client.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drmP.h>
#include <drm/drm_print.h>
#include "drm_legacy.h"
#include "drm_internal.h"
#include "drm_crtc_internal.h"
#include "drm_internal.h"
#include "drm_legacy.h"
/* from BKL pushdown */
DEFINE_MUTEX(drm_global_mutex);

View File

@ -21,9 +21,11 @@
* SOFTWARE.
*/
#include <drm/drmP.h>
#include <drm/drm_util.h>
#include <linux/slab.h>
#include <drm/drm_flip_work.h>
#include <drm/drm_print.h>
#include <drm/drm_util.h>
/**
* drm_flip_work_allocate_task - allocate a flip-work task

View File

@ -27,7 +27,7 @@
#include <linux/export.h>
#include <linux/kernel.h>
#include <drm/drmP.h>
#include <drm/drm_device.h>
#include <drm/drm_fourcc.h>
static char printable_char(int c)

View File

@ -21,16 +21,21 @@
*/
#include <linux/export.h>
#include <drm/drmP.h>
#include <drm/drm_auth.h>
#include <drm/drm_framebuffer.h>
#include <linux/uaccess.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_auth.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_print.h>
#include <drm/drm_util.h>
#include "drm_internal.h"
#include "drm_crtc_internal.h"
#include "drm_internal.h"
/**
* DOC: overview

View File

@ -38,10 +38,14 @@
#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_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_gem.h>
#include <drm/drm_print.h>
#include <drm/drm_vma_manager.h>
#include "drm_internal.h"
/** @file drm_gem.c

View File

@ -17,15 +17,16 @@
* GNU General Public License for more details.
*/
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/export.h>
#include <linux/dma-buf.h>
#include <linux/dma-mapping.h>
#include <linux/export.h>
#include <linux/mm.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <drm/drmP.h>
#include <drm/drm.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_vma_manager.h>

View File

@ -14,7 +14,6 @@
#include <linux/reservation.h>
#include <linux/slab.h>
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_damage_helper.h>
@ -285,6 +284,9 @@ EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty);
* There is no need for &drm_plane_helper_funcs.cleanup_fb hook for simple
* gem based framebuffer drivers which have their buffers always pinned in
* memory.
*
* See drm_atomic_set_fence_for_plane() for a discussion of implicit and
* explicit fencing in atomic modeset updates.
*/
int drm_gem_fb_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *state)
@ -315,6 +317,9 @@ EXPORT_SYMBOL_GPL(drm_gem_fb_prepare_fb);
* &dma_buf attached, extracts the exclusive fence and attaches it to plane
* state for the atomic helper to wait on. Drivers can use this as their
* &drm_simple_display_pipe_funcs.prepare_fb callback.
*
* See drm_atomic_set_fence_for_plane() for a discussion of implicit and
* explicit fencing in atomic modeset updates.
*/
int drm_gem_fb_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *plane_state)

View File

@ -32,11 +32,15 @@
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#include <drm/drmP.h>
#include <drm/drm_hashtab.h>
#include <linux/hash.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/hash.h>
#include <linux/mm.h>
#include <linux/rculist.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <drm/drm_hashtab.h>
#include <drm/drm_print.h>
int drm_ht_create(struct drm_open_hash *ht, unsigned int order)
{

View File

@ -28,8 +28,16 @@
#define DRM_IF_VERSION(maj, min) (maj << 16 | min)
struct drm_prime_file_private;
struct dentry;
struct dma_buf;
struct drm_connector;
struct drm_crtc;
struct drm_framebuffer;
struct drm_gem_object;
struct drm_master;
struct drm_minor;
struct drm_prime_file_private;
struct drm_printer;
/* drm_file.c */
extern struct mutex drm_global_mutex;

View File

@ -31,10 +31,13 @@
#include <linux/ratelimit.h>
#include <linux/export.h>
#include <drm/drmP.h>
#include "drm_legacy.h"
#include "drm_internal.h"
#include <drm/drm_agpsupport.h>
#include <drm/drm_file.h>
#include <drm/drm_print.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"
#include "drm_legacy.h"
#define DRM_IOCTL_VERSION32 DRM_IOWR(0x00, drm_version32_t)
#define DRM_IOCTL_GET_UNIQUE32 DRM_IOWR(0x01, drm_unique32_t)

View File

@ -28,16 +28,22 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <drm/drm_ioctl.h>
#include <drm/drmP.h>
#include <drm/drm_auth.h>
#include "drm_legacy.h"
#include "drm_internal.h"
#include "drm_crtc_internal.h"
#include <linux/pci.h>
#include <linux/export.h>
#include <linux/nospec.h>
#include <linux/pci.h>
#include <linux/uaccess.h>
#include <drm/drm_agpsupport.h>
#include <drm/drm_auth.h>
#include <drm/drm_crtc.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_print.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"
#include "drm_legacy.h"
/**
* DOC: getunique and setversion story

View File

@ -51,13 +51,18 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <drm/drm_irq.h>
#include <drm/drmP.h>
#include <linux/interrupt.h> /* For task queue support */
#include <linux/vgaarb.h>
#include <linux/export.h>
#include <linux/interrupt.h> /* For task queue support */
#include <linux/pci.h>
#include <linux/vgaarb.h>
#include <drm/drm.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_irq.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include "drm_internal.h"

View File

@ -26,7 +26,8 @@
*/
#include <linux/module.h>
#include <drm/drmP.h>
#include <drm/drm_print.h>
#include "drm_crtc_helper_internal.h"

View File

@ -11,14 +11,19 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/file.h>
#include <linux/uaccess.h>
#include <drm/drmP.h>
#include "drm_internal.h"
#include "drm_legacy.h"
#include "drm_crtc_internal.h"
#include <drm/drm_lease.h>
#include <drm/drm_auth.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_lease.h>
#include <drm/drm_print.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"
#include "drm_legacy.h"
#define drm_for_each_lessee(lessee, lessor) \
list_for_each_entry((lessee), &(lessor)->lessees, lessee_list)

View File

@ -29,11 +29,15 @@
* drivers use them, and removing them are API breaks.
*/
#include <linux/list.h>
#include <drm/drm.h>
#include <drm/drm_device.h>
#include <drm/drm_legacy.h>
struct agp_memory;
struct drm_device;
struct drm_file;
struct drm_buf_desc;
/*
* Generic DRM Contexts

View File

@ -33,7 +33,12 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <drm/drmP.h>
#include <drm/drm_agpsupport.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_irq.h>
#include <drm/drm_print.h>
#include "drm_internal.h"
#include "drm_legacy.h"

View File

@ -36,9 +36,13 @@
#include <linux/export.h>
#include <linux/sched/signal.h>
#include <drm/drmP.h>
#include "drm_legacy.h"
#include <drm/drm.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_print.h>
#include "drm_internal.h"
#include "drm_legacy.h"
static int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context);

View File

@ -33,10 +33,15 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <linux/highmem.h>
#include <linux/export.h>
#include <linux/highmem.h>
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <xen/xen.h>
#include <drm/drmP.h>
#include <drm/drm_agpsupport.h>
#include <drm/drm_device.h>
#include "drm_legacy.h"
#if IS_ENABLED(CONFIG_AGP)

View File

@ -42,12 +42,13 @@
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#include <drm/drmP.h>
#include <drm/drm_mm.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
#include <linux/export.h>
#include <linux/interval_tree_generic.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/stacktrace.h>
#include <drm/drm_mm.h>
/**
* DOC: Overview

View File

@ -20,9 +20,13 @@
* OF THIS SOFTWARE.
*/
#include <linux/uaccess.h>
#include <drm/drm_drv.h>
#include <drm/drm_encoder.h>
#include <drm/drm_file.h>
#include <drm/drm_mode_config.h>
#include <drm/drmP.h>
#include <drm/drm_print.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"

View File

@ -21,9 +21,14 @@
*/
#include <linux/export.h>
#include <drm/drmP.h>
#include <drm/drm_mode_object.h>
#include <linux/uaccess.h>
#include <drm/drm_atomic.h>
#include <drm/drm_drv.h>
#include <drm/drm_device.h>
#include <drm/drm_file.h>
#include <drm/drm_mode_object.h>
#include <drm/drm_print.h>
#include "drm_crtc_internal.h"

View File

@ -33,11 +33,14 @@
#include <linux/list.h>
#include <linux/list_sort.h>
#include <linux/export.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <video/of_videomode.h>
#include <video/videomode.h>
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_modes.h>
#include <drm/drm_print.h>
#include "drm_crtc_internal.h"

View File

@ -21,9 +21,9 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_modeset_lock.h>
/**

View File

@ -3,12 +3,13 @@
#include <linux/export.h>
#include <linux/list.h>
#include <linux/of_graph.h>
#include <drm/drmP.h>
#include <drm/drm_bridge.h>
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_encoder.h>
#include <drm/drm_panel.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
/**
* DOC: overview

View File

@ -22,12 +22,17 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/export.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <drm/drm.h>
#include <drm/drm_agpsupport.h>
#include <drm/drm_drv.h>
#include <drm/drm_pci.h>
#include <drm/drmP.h>
#include <drm/drm_print.h>
#include "drm_internal.h"
#include "drm_legacy.h"

View File

@ -24,14 +24,15 @@
*/
#include <linux/list.h>
#include <drm/drmP.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_rect.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_encoder.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_rect.h>
#define SUBPIXEL_MASK 0xffff

View File

@ -29,9 +29,12 @@
#include <linux/export.h>
#include <linux/dma-buf.h>
#include <linux/rbtree.h>
#include <drm/drm_prime.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem.h>
#include <drm/drmP.h>
#include <drm/drm_prime.h>
#include "drm_internal.h"

View File

@ -26,8 +26,13 @@
#define DEBUG /* for pr_debug() */
#include <stdarg.h>
#include <linux/io.h>
#include <linux/seq_file.h>
#include <drm/drmP.h>
#include <linux/slab.h>
#include <drm/drm.h>
#include <drm/drm_drv.h>
#include <drm/drm_print.h>
void __drm_puts_coredump(struct drm_printer *p, const char *str)

View File

@ -32,14 +32,15 @@
#include <linux/export.h>
#include <linux/moduleparam.h>
#include <drm/drmP.h>
#include <drm/drm_client.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_sysfs.h>
#include "drm_crtc_helper_internal.h"
@ -574,6 +575,9 @@ static void output_poll_execute(struct work_struct *work)
enum drm_connector_status old_status;
bool repoll = false, changed;
if (!dev->mode_config.poll_enabled)
return;
/* Pick up any changes detected by the probe functions. */
changed = dev->mode_config.delayed_event;
dev->mode_config.delayed_event = false;
@ -728,7 +732,11 @@ EXPORT_SYMBOL(drm_kms_helper_poll_init);
*/
void drm_kms_helper_poll_fini(struct drm_device *dev)
{
drm_kms_helper_poll_disable(dev);
if (!dev->mode_config.poll_enabled)
return;
dev->mode_config.poll_enabled = false;
cancel_delayed_work_sync(&dev->mode_config.output_poll_work);
}
EXPORT_SYMBOL(drm_kms_helper_poll_fini);

View File

@ -21,7 +21,12 @@
*/
#include <linux/export.h>
#include <drm/drmP.h>
#include <linux/uaccess.h>
#include <drm/drm_crtc.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_property.h>
#include "drm_crtc_internal.h"

View File

@ -24,7 +24,9 @@
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <drm/drmP.h>
#include <drm/drm_mode.h>
#include <drm/drm_print.h>
#include <drm/drm_rect.h>
/**

View File

@ -31,9 +31,14 @@
* DEALINGS IN THE SOFTWARE.
*/
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <drm/drmP.h>
#include <linux/vmalloc.h>
#include <drm/drm.h>
#include <drm/drm_drv.h>
#include <drm/drm_print.h>
#include "drm_legacy.h"
#define DEBUG_SCATTER 0

View File

@ -24,8 +24,8 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <drm/drm_print.h>
#include <drm/drm_scdc_helper.h>
#include <drm/drmP.h>
/**
* DOC: scdc helpers

View File

@ -7,13 +7,14 @@
* (at your option) any later version.
*/
#include <drm/drmP.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include <linux/slab.h>
/**
* DOC: overview

View File

@ -46,15 +46,20 @@
* The file takes a reference on the kref.
*/
#include <drm/drmP.h>
#include <linux/anon_inodes.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/anon_inodes.h>
#include <linux/sync_file.h>
#include <linux/sched/signal.h>
#include <linux/sync_file.h>
#include <linux/uaccess.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_gem.h>
#include <drm/drm_print.h>
#include <drm/drm_syncobj.h>
#include "drm_internal.h"
#include <drm/drm_syncobj.h>
struct syncobj_wait_entry {
struct list_head node;

View File

@ -13,13 +13,20 @@
*/
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <linux/gfp.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/gfp.h>
#include <linux/kdev_t.h>
#include <linux/slab.h>
#include <drm/drm_connector.h>
#include <drm/drm_device.h>
#include <drm/drm_file.h>
#include <drm/drm_modes.h>
#include <drm/drm_print.h>
#include <drm/drm_property.h>
#include <drm/drm_sysfs.h>
#include <drm/drmP.h>
#include "drm_internal.h"
#define to_drm_minor(d) dev_get_drvdata(d)

View File

@ -6,6 +6,8 @@
#include <linux/types.h>
#include <linux/tracepoint.h>
struct drm_file;
#undef TRACE_SYSTEM
#define TRACE_SYSTEM drm
#define TRACE_INCLUDE_FILE drm_trace

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