summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-10-01 15:00:20 +0100
committerMark Brown <broonie@kernel.org>2026-10-01 15:00:20 +0100
commit66fdeba7225471245f4b89b5ebd9954d7350e1be (patch)
tree100f0e75ada27a179d5728c5ac9ba81ab14de52e /drivers/gpu
parentd7ad64ac81f59eb769ee20eacbd8c3f514e44eac (diff)
parent7c4bda20eb0f150315d19f1b51058820e75d3f3d (diff)
downloadlinux-next-66fdeba7225471245f4b89b5ebd9954d7350e1be.tar.gz
linux-next-66fdeba7225471245f4b89b5ebd9954d7350e1be.zip
Merge branch 'for-linux-next' of https://gitlab.freedesktop.org/drm/misc/kernel.git
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/Kconfig7
-rw-r--r--drivers/gpu/drm/Makefile5
-rw-r--r--drivers/gpu/drm/adp/adp-mipi.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_display.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c1
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c1
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_crtc.c1
-rw-r--r--drivers/gpu/drm/armada/armada_fbdev.c2
-rw-r--r--drivers/gpu/drm/bridge/Kconfig18
-rw-r--r--drivers/gpu/drm/bridge/analogix/Kconfig1
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_core.c40
-rw-r--r--drivers/gpu/drm/bridge/aux-bridge.c1
-rw-r--r--drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c1
-rw-r--r--drivers/gpu/drm/bridge/fsl-ldb.c19
-rw-r--r--drivers/gpu/drm/bridge/imx/imx93-pdfc.c1
-rw-r--r--drivers/gpu/drm/bridge/panel.c563
-rw-r--r--drivers/gpu/drm/bridge/samsung-dsim.c24
-rw-r--r--drivers/gpu/drm/bridge/ssd2825.c23
-rw-r--r--drivers/gpu/drm/bridge/tc358767.c64
-rw-r--r--drivers/gpu/drm/bridge/tc358768.c25
-rw-r--r--drivers/gpu/drm/bridge/ti-tdp158.c1
-rw-r--r--drivers/gpu/drm/bridge/waveshare-dsi.c17
-rw-r--r--drivers/gpu/drm/clients/Makefile3
-rw-r--r--drivers/gpu/drm/clients/drm_fbdev_client.c2
-rw-r--r--drivers/gpu/drm/clients/drm_fbdev_helper.c (renamed from drivers/gpu/drm/drm_fb_helper.c)34
-rw-r--r--drivers/gpu/drm/display/drm_bridge_connector.c1
-rw-r--r--drivers/gpu/drm/display/drm_dp_mst_topology.c6
-rw-r--r--drivers/gpu/drm/drm_bridge.c17
-rw-r--r--drivers/gpu/drm/drm_connector.c2
-rw-r--r--drivers/gpu/drm/drm_crtc_helper_internal.h9
-rw-r--r--drivers/gpu/drm/drm_fbdev_dma.c2
-rw-r--r--drivers/gpu/drm/drm_fbdev_shmem.c2
-rw-r--r--drivers/gpu/drm/drm_fbdev_ttm.c2
-rw-r--r--drivers/gpu/drm/drm_kms_helper_common.c39
-rw-r--r--drivers/gpu/drm/drm_of.c63
-rw-r--r--drivers/gpu/drm/drm_panel.c664
-rw-r--r--drivers/gpu/drm/drm_panel_backlight_quirks.c2
-rw-r--r--drivers/gpu/drm/drm_panel_orientation_quirks.c2
-rw-r--r--drivers/gpu/drm/drm_syncobj.c35
-rw-r--r--drivers/gpu/drm/drm_timeout.c95
-rw-r--r--drivers/gpu/drm/exynos/exynos_dp.c36
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c2
-rw-r--r--drivers/gpu/drm/gma500/fbdev.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbdev.c2
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_wait.c17
-rw-r--r--drivers/gpu/drm/imagination/pvr_fw.c130
-rw-r--r--drivers/gpu/drm/imagination/pvr_fw.h18
-rw-r--r--drivers/gpu/drm/imx/dc/dc-kms.c1
-rw-r--r--drivers/gpu/drm/imx/dcss/Kconfig1
-rw-r--r--drivers/gpu/drm/imx/lcdc/imx-lcdc.c249
-rw-r--r--drivers/gpu/drm/ingenic/Kconfig1
-rw-r--r--drivers/gpu/drm/lima/lima_gem.c2
-rw-r--r--drivers/gpu/drm/logicvc/Kconfig1
-rw-r--r--drivers/gpu/drm/mcde/Kconfig2
-rw-r--r--drivers/gpu/drm/mcde/mcde_display.c1
-rw-r--r--drivers/gpu/drm/mcde/mcde_dsi.c45
-rw-r--r--drivers/gpu/drm/msm/dp/dp_display.c1
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.c3
-rw-r--r--drivers/gpu/drm/msm/msm_debugfs.c2
-rw-r--r--drivers/gpu/drm/msm/msm_fbdev.c2
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_drv.c43
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_drv.h2
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_kms.c12
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/disp.c1
-rw-r--r--drivers/gpu/drm/omapdrm/dss/omapdss.h1
-rw-r--r--drivers/gpu/drm/omapdrm/dss/output.c42
-rw-r--r--drivers/gpu/drm/omapdrm/omap_debugfs.c2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fbdev.c2
-rw-r--r--drivers/gpu/drm/panel/Kconfig3
-rw-r--r--drivers/gpu/drm/panel/panel-ebbg-ft8719.c23
-rw-r--r--drivers/gpu/drm/panel/panel-edp.c1
-rw-r--r--drivers/gpu/drm/panel/panel-ilitek-ili9882t.c234
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c57
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_drv.c2
-rw-r--r--drivers/gpu/drm/panthor/panthor_drv.c1
-rw-r--r--drivers/gpu/drm/pl111/Kconfig1
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_fbdev.c2
-rw-r--r--drivers/gpu/drm/renesas/rz-du/Kconfig13
-rw-r--r--drivers/gpu/drm/renesas/rz-du/Makefile1
-rw-r--r--drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c24
-rw-r--r--drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h3
-rw-r--r--drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c24
-rw-r--r--drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c162
-rw-r--r--drivers/gpu/drm/renesas/rz-du/rzg3l_lvds.c275
-rw-r--r--drivers/gpu/drm/renesas/rz-du/rzg3l_lvds_regs.h25
-rw-r--r--drivers/gpu/drm/rockchip/Kconfig2
-rw-r--r--drivers/gpu/drm/rockchip/analogix_dp-rockchip.c11
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_gem.c2
-rw-r--r--drivers/gpu/drm/scheduler/sched_entity.c51
-rw-r--r--drivers/gpu/drm/scheduler/sched_main.c1
-rw-r--r--drivers/gpu/drm/sitronix/st7571.c1
-rw-r--r--drivers/gpu/drm/solomon/ssd130x.c30
-rw-r--r--drivers/gpu/drm/stm/Kconfig1
-rw-r--r--drivers/gpu/drm/tegra/fbdev.c2
-rw-r--r--drivers/gpu/drm/tegra/rgb.c1
-rw-r--r--drivers/gpu/drm/tegra/uapi.c2
-rw-r--r--drivers/gpu/drm/tidss/Kconfig1
-rw-r--r--drivers/gpu/drm/tve200/Kconfig2
-rw-r--r--drivers/gpu/drm/tve200/tve200_drm.h1
-rw-r--r--drivers/gpu/drm/tve200/tve200_drv.c31
-rw-r--r--drivers/gpu/drm/v3d/v3d_bo.c3
-rw-r--r--drivers/gpu/drm/v3d/v3d_drv.h10
-rw-r--r--drivers/gpu/drm/vboxvideo/vbox_mode.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_gem.c3
-rw-r--r--drivers/gpu/drm/xe/xe_wait_user_fence.c2
109 files changed, 2129 insertions, 1328 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 65d46dfa7266..61111d50b1c6 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -46,7 +46,6 @@ config DRM_KMS_HELPER
tristate
depends on DRM
select DRM_PANIC_HELPER if DRM_PANIC
- select FB_CORE if DRM_FBDEV_EMULATION
help
CRTC helpers for KMS drivers.
@@ -256,7 +255,7 @@ config DRM_TTM_HELPER
tristate
depends on DRM
select DRM_TTM
- select DRM_KMS_HELPER if DRM_FBDEV_EMULATION
+ select DRM_CLIENT_LIB if DRM_FBDEV_EMULATION
select FB_CORE if DRM_FBDEV_EMULATION
select FB_SYSMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION
help
@@ -265,7 +264,7 @@ config DRM_TTM_HELPER
config DRM_GEM_DMA_HELPER
tristate
depends on DRM
- select DRM_KMS_HELPER if DRM_FBDEV_EMULATION
+ select DRM_CLIENT_LIB if DRM_FBDEV_EMULATION
select FB_CORE if DRM_FBDEV_EMULATION
select FB_DMAMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION
help
@@ -274,7 +273,7 @@ config DRM_GEM_DMA_HELPER
config DRM_GEM_SHMEM_HELPER
tristate
depends on DRM && MMU
- select DRM_KMS_HELPER if DRM_FBDEV_EMULATION
+ select DRM_CLIENT_LIB if DRM_FBDEV_EMULATION
select FB_CORE if DRM_FBDEV_EMULATION
select FB_SYSMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION
help
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index f0c340aa2ec6..2c6bc093a923 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -68,6 +68,7 @@ drm-y := \
drm_rect.o \
drm_syncobj.o \
drm_sysfs.o \
+ drm_timeout.o \
drm_trace_points.o \
drm_vblank.o \
drm_vblank_work.o \
@@ -79,7 +80,6 @@ drm-$(CONFIG_DRM_CLIENT) += \
drm_client_modeset.o \
drm_client_sysrq.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o
-drm-$(CONFIG_DRM_PANEL) += drm_panel.o
drm-$(CONFIG_OF) += drm_of.o
drm-$(CONFIG_PCI) += drm_pci.o
drm-$(CONFIG_DEBUG_FS) += \
@@ -95,6 +95,7 @@ drm-$(CONFIG_DRM_DRAW) += drm_draw.o
drm-$(CONFIG_DRM_RAS) += drm_ras.o drm_ras_nl.o drm_ras_genl_family.o
obj-$(CONFIG_DRM) += drm.o
+obj-$(CONFIG_DRM_PANEL) += drm_panel.o
obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
obj-$(CONFIG_DRM_PANEL_BACKLIGHT_QUIRKS) += drm_panel_backlight_quirks.o
@@ -155,10 +156,8 @@ drm_kms_helper-y := \
drm_self_refresh_helper.o \
drm_simple_kms_helper.o \
drm_vblank_helper.o
-drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
drm_kms_helper-$(CONFIG_DRM_PANIC_HELPER) += drm_panic_helper.o
drm_kms_helper-$(CONFIG_DRM_PANIC_SCREEN_QR_CODE) += drm_panic_helper_qr.o
-drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
#
diff --git a/drivers/gpu/drm/adp/adp-mipi.c b/drivers/gpu/drm/adp/adp-mipi.c
index 232bb9539423..956533870781 100644
--- a/drivers/gpu/drm/adp/adp-mipi.c
+++ b/drivers/gpu/drm/adp/adp-mipi.c
@@ -8,6 +8,7 @@
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
#define DSI_GEN_HDR 0x6c
#define DSI_GEN_PLD_DATA 0x70
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
index 59ea338b554c..126bfd9bb89e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -38,11 +38,11 @@
#include <linux/pci.h>
#include <linux/pm_runtime.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_modeset_helper.h>
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index 56eaf05899a8..7fa321c41f63 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -25,7 +25,6 @@
* Alex Deucher
* Jerome Glisse
*/
-#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/overflow.h>
#include <linux/pagemap.h>
@@ -40,6 +39,7 @@
#include <drm/drm_gem_ttm_helper.h>
#include <drm/ttm/ttm_tt.h>
#include <drm/drm_syncobj.h>
+#include <drm/drm_timeout.h>
#include "amdgpu.h"
#include "amdgpu_display.h"
@@ -652,23 +652,11 @@ int amdgpu_gem_mmap_ioctl(struct drm_device *dev, void *data,
*/
unsigned long amdgpu_gem_timeout(uint64_t timeout_ns)
{
- unsigned long timeout_jiffies;
- ktime_t timeout;
-
- /* clamp timeout if it's to large */
- if (((int64_t)timeout_ns) < 0)
+ /* Map anything that doesn't fit in a s64 to an infinite wait */
+ if (timeout_ns > S64_MAX)
return MAX_SCHEDULE_TIMEOUT;
- timeout = ktime_sub(ns_to_ktime(timeout_ns), ktime_get());
- if (ktime_to_ns(timeout) < 0)
- return 0;
-
- timeout_jiffies = nsecs_to_jiffies(ktime_to_ns(timeout));
- /* clamp timeout to avoid unsigned-> signed overflow */
- if (timeout_jiffies > MAX_SCHEDULE_TIMEOUT)
- return MAX_SCHEDULE_TIMEOUT - 1;
-
- return timeout_jiffies;
+ return drm_timeout_abs_to_jiffies(timeout_ns);
}
int amdgpu_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index f2f179421c4d..51a7a4091376 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -28,8 +28,8 @@
#include "amdgpu.h"
#include <drm/amdgpu_drm.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
#include "amdgpu_uvd.h"
#include "amdgpu_vce.h"
#include "atom.h"
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 2b0686bcc7fd..cd5cbb851075 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -98,7 +98,6 @@
#include <drm/drm_edid.h>
#include <drm/drm_eld.h>
#include <drm/drm_mode.h>
-#include <drm/drm_utils.h>
#include <drm/drm_vblank.h>
#include <drm/drm_colorop.h>
#include <drm/drm_gem_atomic_helper.h>
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c
index 45e1732a5b04..8dc57903de9e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c
@@ -41,7 +41,7 @@
#include <linux/backlight.h>
#include <linux/power_supply.h>
#include <drm/drm_edid.h>
-#include <drm/drm_utils.h>
+#include <drm/drm_panel_quirks.h>
#include <acpi/video.h>
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 2a63a1c9b79d..25f168a8ea31 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -62,7 +62,6 @@
#include <drm/drm_fixed.h>
#include <drm/drm_mode.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_utils.h>
#include <drm/display/drm_dp_mst_helper.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/drm_privacy_screen_consumer.h>
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
index 3d81b413efae..0fd069fc3386 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
@@ -15,6 +15,7 @@
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <drm/drm_bridge.h>
+#include <drm/drm_panel.h>
#include "komeda_dev.h"
#include "komeda_kms.h"
diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c
index 8bbae94804f8..f35afec2125f 100644
--- a/drivers/gpu/drm/armada/armada_fbdev.c
+++ b/drivers/gpu/drm/armada/armada_fbdev.c
@@ -9,9 +9,9 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <drm/clients/drm_fbdev_helper.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>
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 837db36cdf48..c7da6b02d7b6 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -87,7 +87,6 @@ config DRM_FSL_LDB
depends on OF
depends on ARCH_MXC || COMPILE_TEST
select DRM_KMS_HELPER
- select DRM_PANEL_BRIDGE
help
Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
@@ -151,6 +150,7 @@ config DRM_LONTIUM_LT8912B
config DRM_LONTIUM_LT9211
tristate "Lontium LT9211 DSI/LVDS/DPI bridge"
depends on OF
+ select DRM_PANEL
select DRM_PANEL_BRIDGE
select DRM_KMS_HELPER
select DRM_MIPI_DSI
@@ -259,7 +259,7 @@ config DRM_NXP_PTN3460
tristate "NXP PTN3460 DP/LVDS bridge"
depends on OF
select DRM_KMS_HELPER
- select DRM_PANEL
+ select DRM_PANEL_BRIDGE
help
NXP PTN3460 eDP-LVDS bridge chip driver.
@@ -276,7 +276,7 @@ config DRM_OF_DISPLAY_MODE_BRIDGE
config DRM_PARADE_PS8622
tristate "Parade eDP/LVDS bridge"
depends on OF
- select DRM_PANEL
+ select DRM_PANEL_BRIDGE
select DRM_KMS_HELPER
select BACKLIGHT_CLASS_DEVICE
help
@@ -302,7 +302,6 @@ config DRM_SAMSUNG_DSIM
depends on OF && HAS_IOMEM
select DRM_KMS_HELPER
select DRM_MIPI_DSI
- select DRM_PANEL_BRIDGE
select GENERIC_PHY
select GENERIC_PHY_MIPI_DPHY
help
@@ -350,7 +349,6 @@ config DRM_SOLOMON_SSD2825
depends on SPI_MASTER && OF
select DRM_MIPI_DSI
select DRM_KMS_HELPER
- select DRM_PANEL
help
Say Y here if you want support for the Solomon SSD2825 RGB/DSI
SPI bridge driver.
@@ -388,7 +386,7 @@ config DRM_TOSHIBA_TC358764
depends on OF
select DRM_MIPI_DSI
select DRM_KMS_HELPER
- select DRM_PANEL
+ select DRM_PANEL_BRIDGE
help
Toshiba TC358764 DSI/LVDS bridge driver.
@@ -400,7 +398,6 @@ config DRM_TOSHIBA_TC358767
select DRM_KMS_HELPER
select REGMAP_I2C
select DRM_MIPI_DSI
- select DRM_PANEL
help
Toshiba TC358767 eDP bridge chip driver.
@@ -409,7 +406,6 @@ config DRM_TOSHIBA_TC358768
depends on OF
select DRM_KMS_HELPER
select REGMAP_I2C
- select DRM_PANEL
select DRM_MIPI_DSI
select VIDEOMODE_HELPERS
help
@@ -422,16 +418,17 @@ config DRM_TOSHIBA_TC358775
select DRM_DISPLAY_HELPER
select DRM_KMS_HELPER
select REGMAP_I2C
- select DRM_PANEL
+ select DRM_PANEL_BRIDGE
select DRM_MIPI_DSI
help
Toshiba TC358775 DSI/LVDS bridge chip driver.
config DRM_TI_DLPC3433
tristate "TI DLPC3433 Display controller"
- depends on DRM && DRM_PANEL
+ depends on DRM
depends on OF
select DRM_MIPI_DSI
+ select DRM_PANEL_BRIDGE
help
TI DLPC3433 is a MIPI DSI based display controller bridge
for processing high resolution DMD based projectors.
@@ -494,6 +491,7 @@ config DRM_WAVESHARE_BRIDGE
tristate "Waveshare DSI bridge"
depends on OF
depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_PANEL
select DRM_PANEL_BRIDGE
select DRM_KMS_HELPER
select DRM_MIPI_DSI
diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig
index 57bb2daa5aaf..5672d83cb4a1 100644
--- a/drivers/gpu/drm/bridge/analogix/Kconfig
+++ b/drivers/gpu/drm/bridge/analogix/Kconfig
@@ -6,6 +6,7 @@ config DRM_ANALOGIX_ANX6345
select DRM_DISPLAY_DP_HELPER
select DRM_DISPLAY_HELPER
select DRM_KMS_HELPER
+ select DRM_PANEL
select REGMAP_I2C
help
ANX6345 is an ultra-low power Full-HD DisplayPort/eDP
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 18e76d1e78e1..6df6963740d2 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -29,7 +29,6 @@
#include <drm/drm_device.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>
@@ -1567,15 +1566,6 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
if (ret)
goto err_unregister_aux;
- if (dp->plat_data->panel) {
- dp->plat_data->next_bridge = devm_drm_panel_bridge_add(dp->dev,
- dp->plat_data->panel);
- if (IS_ERR(dp->plat_data->next_bridge)) {
- ret = PTR_ERR(dp->plat_data->next_bridge);
- goto err_unregister_aux;
- }
- }
-
ret = drm_bridge_attach(dp->encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret) {
DRM_ERROR("failed to create bridge (%d)\n", ret);
@@ -1647,6 +1637,11 @@ struct drm_dp_aux *analogix_dp_get_aux(struct analogix_dp_device *dp)
}
EXPORT_SYMBOL_GPL(analogix_dp_get_aux);
+static void analogix_dp_put_bridge(void *data)
+{
+ drm_bridge_put(data);
+}
+
static int analogix_dp_aux_done_probing(struct drm_dp_aux *aux)
{
struct analogix_dp_device *dp = to_dp(aux);
@@ -1655,14 +1650,25 @@ static int analogix_dp_aux_done_probing(struct drm_dp_aux *aux)
int ret;
/*
- * If drm_of_find_panel_or_bridge() returns -ENODEV, there may be no valid panel
- * or bridge nodes. The driver should go on for the driver-free bridge or the DP
- * mode applications.
+ * If of_drm_get_bridge_by_endpoint() returns -ENODEV, there may be no
+ * valid panel or bridge nodes. The driver should go on for the
+ * driver-free bridge or the DP mode applications.
*/
- ret = drm_of_find_panel_or_bridge(dp->dev->of_node, port, 0,
- &plat_data->panel, &plat_data->next_bridge);
- if (ret && ret != -ENODEV)
- return ret;
+ plat_data->next_bridge = of_drm_get_bridge_by_endpoint(dp->dev->of_node,
+ port, 0);
+ if (IS_ERR(plat_data->next_bridge)) {
+ if (PTR_ERR(plat_data->next_bridge) == -ENODEV)
+ plat_data->next_bridge = NULL;
+ else
+ return PTR_ERR(plat_data->next_bridge);
+ }
+
+ if (plat_data->next_bridge) {
+ ret = devm_add_action_or_reset(dp->dev, analogix_dp_put_bridge,
+ plat_data->next_bridge);
+ if (ret)
+ return ret;
+ }
return component_add(dp->dev, plat_data->ops);
}
diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/aux-bridge.c
index 169939d23310..90f76bb529cc 100644
--- a/drivers/gpu/drm/bridge/aux-bridge.c
+++ b/drivers/gpu/drm/bridge/aux-bridge.c
@@ -12,6 +12,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/bridge/aux-bridge.h>
+#include <drm/drm_panel.h>
static DEFINE_IDA(drm_aux_bridge_ida);
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index c3e466ded84a..1e28ea579b06 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -7,6 +7,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
#include <video/mipi_display.h>
#include <video/videomode.h>
diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
index 26cc72948f31..7ec84c81cd78 100644
--- a/drivers/gpu/drm/bridge/fsl-ldb.c
+++ b/drivers/gpu/drm/bridge/fsl-ldb.c
@@ -15,7 +15,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#define LDB_CTRL_CH0_ENABLE BIT(0)
#define LDB_CTRL_CH0_DI_SELECT BIT(1)
@@ -86,7 +85,6 @@ static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
struct fsl_ldb {
struct device *dev;
struct drm_bridge bridge;
- struct drm_bridge *panel_bridge;
struct clk *clk;
struct regmap *regmap;
const struct fsl_ldb_devdata *devdata;
@@ -119,7 +117,7 @@ static int fsl_ldb_attach(struct drm_bridge *bridge,
{
struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
- return drm_bridge_attach(encoder, fsl_ldb->panel_bridge,
+ return drm_bridge_attach(encoder, fsl_ldb->bridge.next_bridge,
bridge, flags);
}
@@ -298,7 +296,6 @@ static int fsl_ldb_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *panel_node;
struct device_node *remote1, *remote2;
- struct drm_panel *panel;
struct fsl_ldb *fsl_ldb;
int dual_link;
@@ -339,19 +336,13 @@ static int fsl_ldb_probe(struct platform_device *pdev)
fsl_ldb_is_dual(fsl_ldb) ? "dual-link mode" :
fsl_ldb->ch0_enabled ? "channel 0" : "channel 1");
- panel = of_drm_find_panel(panel_node);
- of_node_put(panel_node);
- if (IS_ERR(panel))
- return PTR_ERR(panel);
-
if (of_property_present(dev->of_node, "nxp,enable-termination-resistor"))
fsl_ldb->use_termination_resistor = true;
- fsl_ldb->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
- drm_panel_put(panel);
- if (IS_ERR(fsl_ldb->panel_bridge))
- return PTR_ERR(fsl_ldb->panel_bridge);
-
+ fsl_ldb->bridge.next_bridge = of_drm_find_and_get_bridge(panel_node);
+ of_node_put(panel_node);
+ if (!fsl_ldb->bridge.next_bridge)
+ return -ENODEV;
if (fsl_ldb_is_dual(fsl_ldb)) {
struct device_node *port1, *port2;
diff --git a/drivers/gpu/drm/bridge/imx/imx93-pdfc.c b/drivers/gpu/drm/bridge/imx/imx93-pdfc.c
index 2d6ca95ed554..2e5019ed951a 100644
--- a/drivers/gpu/drm/bridge/imx/imx93-pdfc.c
+++ b/drivers/gpu/drm/bridge/imx/imx93-pdfc.c
@@ -16,6 +16,7 @@
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_bridge.h>
+#include <drm/drm_panel.h>
#define IMX93_DISPLAY_MUX_REG 0x60
#define PARALLEL_DISP_FORMAT GENMASK(10, 8)
diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
deleted file mode 100644
index 02388a3de626..000000000000
--- a/drivers/gpu/drm/bridge/panel.c
+++ /dev/null
@@ -1,563 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Copyright (C) 2017 Broadcom
- */
-
-#include <linux/debugfs.h>
-#include <linux/export.h>
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_bridge.h>
-#include <drm/drm_connector.h>
-#include <drm/drm_encoder.h>
-#include <drm/drm_managed.h>
-#include <drm/drm_modeset_helper_vtables.h>
-#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
-#include <drm/drm_print.h>
-#include <drm/drm_probe_helper.h>
-
-struct panel_bridge {
- struct drm_bridge bridge;
- struct drm_connector connector;
- struct drm_panel *panel;
- u32 connector_type;
-};
-
-static inline struct panel_bridge *
-drm_bridge_to_panel_bridge(struct drm_bridge *bridge)
-{
- return container_of(bridge, struct panel_bridge, bridge);
-}
-
-static inline struct panel_bridge *
-drm_connector_to_panel_bridge(struct drm_connector *connector)
-{
- return container_of(connector, struct panel_bridge, connector);
-}
-
-static int panel_bridge_connector_get_modes(struct drm_connector *connector)
-{
- struct panel_bridge *panel_bridge =
- drm_connector_to_panel_bridge(connector);
-
- return drm_panel_get_modes(panel_bridge->panel, connector);
-}
-
-static const struct drm_connector_helper_funcs
-panel_bridge_connector_helper_funcs = {
- .get_modes = panel_bridge_connector_get_modes,
-};
-
-static const struct drm_connector_funcs panel_bridge_connector_funcs = {
- .reset = drm_atomic_helper_connector_reset,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = drm_connector_cleanup,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-static int panel_bridge_attach(struct drm_bridge *bridge,
- struct drm_encoder *encoder,
- enum drm_bridge_attach_flags flags)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
- struct drm_connector *connector = &panel_bridge->connector;
- int ret;
-
- if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
- return 0;
-
- drm_connector_helper_add(connector,
- &panel_bridge_connector_helper_funcs);
-
- ret = drm_connector_init(bridge->dev, connector,
- &panel_bridge_connector_funcs,
- panel_bridge->connector_type);
- if (ret) {
- DRM_ERROR("Failed to initialize connector\n");
- return ret;
- }
-
- drm_panel_bridge_set_orientation(connector, bridge);
-
- drm_connector_attach_encoder(&panel_bridge->connector,
- encoder);
-
- if (bridge->dev->registered) {
- if (connector->funcs->reset)
- connector->funcs->reset(connector);
- drm_connector_register(connector);
- }
-
- return 0;
-}
-
-static void panel_bridge_detach(struct drm_bridge *bridge)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
- struct drm_connector *connector = &panel_bridge->connector;
-
- /*
- * Cleanup the connector if we know it was initialized.
- *
- * FIXME: This wouldn't be needed if the panel_bridge structure was
- * allocated with drmm_kzalloc(). This might be tricky since the
- * drm_device pointer can only be retrieved when the bridge is attached.
- */
- if (connector->dev)
- drm_connector_cleanup(connector);
-}
-
-static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
- struct drm_atomic_commit *atomic_state)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
- struct drm_encoder *encoder = bridge->encoder;
- struct drm_crtc *crtc;
- struct drm_crtc_state *old_crtc_state;
-
- crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
- if (!crtc)
- return;
-
- old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
- if (old_crtc_state && old_crtc_state->self_refresh_active)
- return;
-
- drm_panel_prepare(panel_bridge->panel);
-}
-
-static void panel_bridge_atomic_enable(struct drm_bridge *bridge,
- struct drm_atomic_commit *atomic_state)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
- struct drm_encoder *encoder = bridge->encoder;
- struct drm_crtc *crtc;
- struct drm_crtc_state *old_crtc_state;
-
- crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
- if (!crtc)
- return;
-
- old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
- if (old_crtc_state && old_crtc_state->self_refresh_active)
- return;
-
- drm_panel_enable(panel_bridge->panel);
-}
-
-static void panel_bridge_atomic_disable(struct drm_bridge *bridge,
- struct drm_atomic_commit *atomic_state)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
- struct drm_encoder *encoder = bridge->encoder;
- struct drm_crtc *crtc;
- struct drm_crtc_state *new_crtc_state;
-
- crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
- if (!crtc)
- return;
-
- new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
- if (new_crtc_state && new_crtc_state->self_refresh_active)
- return;
-
- drm_panel_disable(panel_bridge->panel);
-}
-
-static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
- struct drm_atomic_commit *atomic_state)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
- struct drm_encoder *encoder = bridge->encoder;
- struct drm_crtc *crtc;
- struct drm_crtc_state *new_crtc_state;
-
- crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
- if (!crtc)
- return;
-
- new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
- if (new_crtc_state && new_crtc_state->self_refresh_active)
- return;
-
- drm_panel_unprepare(panel_bridge->panel);
-}
-
-static int panel_bridge_get_modes(struct drm_bridge *bridge,
- struct drm_connector *connector)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
-
- return drm_panel_get_modes(panel_bridge->panel, connector);
-}
-
-static void panel_bridge_debugfs_init(struct drm_bridge *bridge,
- struct dentry *root)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
- struct drm_panel *panel = panel_bridge->panel;
-
- root = debugfs_create_dir("panel", root);
- if (panel->funcs->debugfs_init)
- panel->funcs->debugfs_init(panel, root);
-}
-
-static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
- .attach = panel_bridge_attach,
- .detach = panel_bridge_detach,
- .atomic_pre_enable = panel_bridge_atomic_pre_enable,
- .atomic_enable = panel_bridge_atomic_enable,
- .atomic_disable = panel_bridge_atomic_disable,
- .atomic_post_disable = panel_bridge_atomic_post_disable,
- .get_modes = panel_bridge_get_modes,
- .atomic_create_state = drm_atomic_helper_bridge_create_state,
- .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
- .atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
- .debugfs_init = panel_bridge_debugfs_init,
-};
-
-/**
- * drm_bridge_is_panel - Checks if a drm_bridge is a panel_bridge.
- *
- * @bridge: The drm_bridge to be checked.
- *
- * Returns true if the bridge is a panel bridge, or false otherwise.
- */
-bool drm_bridge_is_panel(const struct drm_bridge *bridge)
-{
- return bridge->funcs == &panel_bridge_bridge_funcs;
-}
-EXPORT_SYMBOL(drm_bridge_is_panel);
-
-/**
- * drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that
- * just calls the appropriate functions from &drm_panel.
- *
- * @panel: The drm_panel being wrapped. Must be non-NULL.
- *
- * For drivers converting from directly using drm_panel: The expected
- * usage pattern is that during either encoder module probe or DSI
- * host attach, a drm_panel will be looked up through
- * drm_of_find_panel_or_bridge(). drm_panel_bridge_add() is used to
- * wrap that panel in the new bridge, and the result can then be
- * passed to drm_bridge_attach(). The drm_panel_prepare() and related
- * functions can be dropped from the encoder driver (they're now
- * called by the KMS helpers before calling into the encoder), along
- * with connector creation. When done with the bridge (after
- * drm_mode_config_cleanup() if the bridge has already been attached), then
- * drm_panel_bridge_remove() to free it.
- *
- * The connector type is set to @panel->connector_type, which must be set to a
- * known type. Calling this function with a panel whose connector type is
- * DRM_MODE_CONNECTOR_Unknown will return ERR_PTR(-EINVAL).
- *
- * See devm_drm_panel_bridge_add() for an automatically managed version of this
- * function.
- */
-struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel)
-{
- if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
- return ERR_PTR(-EINVAL);
-
- return drm_panel_bridge_add_typed(panel, panel->connector_type);
-}
-EXPORT_SYMBOL(drm_panel_bridge_add);
-
-/**
- * drm_panel_bridge_add_typed - Creates a &drm_bridge and &drm_connector with
- * an explicit connector type.
- * @panel: The drm_panel being wrapped. Must be non-NULL.
- * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
- *
- * This is just like drm_panel_bridge_add(), but forces the connector type to
- * @connector_type instead of infering it from the panel.
- *
- * This function is deprecated and should not be used in new drivers. Use
- * drm_panel_bridge_add() instead, and fix panel drivers as necessary if they
- * don't report a connector type.
- */
-struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
- u32 connector_type)
-{
- struct panel_bridge *panel_bridge;
-
- if (!panel)
- return ERR_PTR(-EINVAL);
-
- panel_bridge = devm_drm_bridge_alloc(panel->dev, struct panel_bridge, bridge,
- &panel_bridge_bridge_funcs);
- if (IS_ERR(panel_bridge))
- return (void *)panel_bridge;
-
- panel_bridge->connector_type = connector_type;
- panel_bridge->panel = drm_panel_get(panel);
-
- panel_bridge->bridge.of_node = panel->dev->of_node;
- panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES;
- panel_bridge->bridge.type = connector_type;
- panel_bridge->bridge.pre_enable_prev_first = panel->prepare_prev_first;
-
- drm_bridge_add(&panel_bridge->bridge);
-
- return &panel_bridge->bridge;
-}
-EXPORT_SYMBOL(drm_panel_bridge_add_typed);
-
-/**
- * drm_panel_bridge_remove - Unregisters and frees a drm_bridge
- * created by drm_panel_bridge_add().
- *
- * @bridge: The drm_bridge being freed.
- */
-void drm_panel_bridge_remove(struct drm_bridge *bridge)
-{
- struct panel_bridge *panel_bridge;
- struct drm_panel *panel;
-
- if (!bridge)
- return;
-
- if (!drm_bridge_is_panel(bridge)) {
- drm_warn(bridge->dev, "%s: called on non-panel bridge!\n", __func__);
- return;
- }
-
- panel_bridge = drm_bridge_to_panel_bridge(bridge);
- panel = panel_bridge->panel;
-
- drm_bridge_remove(bridge);
- /* TODO remove this after reworking panel_bridge lifetime */
- devm_drm_put_bridge(panel->dev, bridge);
- drm_panel_put(panel);
-}
-EXPORT_SYMBOL(drm_panel_bridge_remove);
-
-/**
- * drm_panel_bridge_set_orientation - Set the connector's panel orientation
- * from the bridge that can be transformed to panel bridge.
- *
- * @connector: The connector to be set panel orientation.
- * @bridge: The drm_bridge to be transformed to panel bridge.
- *
- * Returns 0 on success, negative errno on failure.
- */
-int drm_panel_bridge_set_orientation(struct drm_connector *connector,
- struct drm_bridge *bridge)
-{
- struct panel_bridge *panel_bridge;
-
- panel_bridge = drm_bridge_to_panel_bridge(bridge);
-
- return drm_connector_set_orientation_from_panel(connector,
- panel_bridge->panel);
-}
-EXPORT_SYMBOL(drm_panel_bridge_set_orientation);
-
-static void devm_drm_panel_bridge_release(struct device *dev, void *res)
-{
- struct drm_bridge *bridge = *(struct drm_bridge **)res;
- struct panel_bridge *panel_bridge;
- struct drm_panel *panel;
-
- if (!bridge)
- return;
-
- panel_bridge = drm_bridge_to_panel_bridge(bridge);
- panel = panel_bridge->panel;
- drm_bridge_remove(bridge);
- drm_panel_put(panel);
-}
-
-/**
- * devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector
- * that just calls the appropriate functions from &drm_panel.
- * @dev: device to tie the bridge lifetime to
- * @panel: The drm_panel being wrapped. Must be non-NULL.
- *
- * This is the managed version of drm_panel_bridge_add() which automatically
- * calls drm_panel_bridge_remove() when @dev is unbound.
- */
-struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
- struct drm_panel *panel)
-{
- if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
- return ERR_PTR(-EINVAL);
-
- return devm_drm_panel_bridge_add_typed(dev, panel,
- panel->connector_type);
-}
-EXPORT_SYMBOL(devm_drm_panel_bridge_add);
-
-/**
- * devm_drm_panel_bridge_add_typed - Creates a managed &drm_bridge and
- * &drm_connector with an explicit connector type.
- * @dev: device to tie the bridge lifetime to
- * @panel: The drm_panel being wrapped. Must be non-NULL.
- * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
- *
- * This is just like devm_drm_panel_bridge_add(), but forces the connector type
- * to @connector_type instead of infering it from the panel.
- *
- * This function is deprecated and should not be used in new drivers. Use
- * devm_drm_panel_bridge_add() instead, and fix panel drivers as necessary if
- * they don't report a connector type.
- */
-struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
- struct drm_panel *panel,
- u32 connector_type)
-{
- struct drm_bridge **ptr, *bridge;
-
- ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
- GFP_KERNEL);
- if (!ptr)
- return ERR_PTR(-ENOMEM);
-
- bridge = drm_panel_bridge_add_typed(panel, connector_type);
- if (IS_ERR(bridge)) {
- devres_free(ptr);
- return bridge;
- }
-
- *ptr = bridge;
- devres_add(dev, ptr);
-
- return bridge;
-}
-EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
-
-static void drmm_drm_panel_bridge_release(struct drm_device *drm, void *ptr)
-{
- struct drm_bridge *bridge = ptr;
-
- drm_panel_bridge_remove(bridge);
-}
-
-/**
- * drmm_panel_bridge_add - Creates a DRM-managed &drm_bridge and
- * &drm_connector that just calls the
- * appropriate functions from &drm_panel.
- *
- * @drm: DRM device to tie the bridge lifetime to
- * @panel: The drm_panel being wrapped. Must be non-NULL.
- *
- * This is the DRM-managed version of drm_panel_bridge_add() which
- * automatically calls drm_panel_bridge_remove() when @dev is cleaned
- * up.
- */
-struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,
- struct drm_panel *panel)
-{
- struct drm_bridge *bridge;
- int ret;
-
- bridge = drm_panel_bridge_add_typed(panel, panel->connector_type);
- if (IS_ERR(bridge))
- return bridge;
-
- ret = drmm_add_action_or_reset(drm, drmm_drm_panel_bridge_release,
- bridge);
- if (ret)
- return ERR_PTR(ret);
-
- return bridge;
-}
-EXPORT_SYMBOL(drmm_panel_bridge_add);
-
-/**
- * drm_panel_bridge_connector - return the connector for the panel bridge
- * @bridge: The drm_bridge.
- *
- * drm_panel_bridge creates the connector.
- * This function gives external access to the connector.
- *
- * Returns: Pointer to drm_connector
- */
-struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge)
-{
- struct panel_bridge *panel_bridge;
-
- panel_bridge = drm_bridge_to_panel_bridge(bridge);
-
- return &panel_bridge->connector;
-}
-EXPORT_SYMBOL(drm_panel_bridge_connector);
-
-#ifdef CONFIG_OF
-/**
- * devm_drm_of_get_bridge - Return next bridge in the chain
- * @dev: device to tie the bridge lifetime to
- * @np: device tree node containing encoder output ports
- * @port: port in the device tree node
- * @endpoint: endpoint in the device tree node
- *
- * Given a DT node's port and endpoint number, finds the connected node
- * and returns the associated bridge if any, or creates and returns a
- * drm panel bridge instance if a panel is connected.
- *
- * Returns a pointer to the bridge if successful, or an error pointer
- * otherwise.
- */
-struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
- struct device_node *np,
- u32 port, u32 endpoint)
-{
- struct drm_bridge *bridge;
- struct drm_panel *panel;
- int ret;
-
- ret = drm_of_find_panel_or_bridge(np, port, endpoint,
- &panel, &bridge);
- if (ret)
- return ERR_PTR(ret);
-
- if (panel) {
- bridge = devm_drm_panel_bridge_add(dev, panel);
- drm_panel_put(panel);
- }
-
- return bridge;
-}
-EXPORT_SYMBOL(devm_drm_of_get_bridge);
-
-/**
- * drmm_of_get_bridge - Return next bridge in the chain
- * @drm: device to tie the bridge lifetime to
- * @np: device tree node containing encoder output ports
- * @port: port in the device tree node
- * @endpoint: endpoint in the device tree node
- *
- * Given a DT node's port and endpoint number, finds the connected node
- * and returns the associated bridge if any, or creates and returns a
- * drm panel bridge instance if a panel is connected.
- *
- * Returns a drmm managed pointer to the bridge if successful, or an error
- * pointer otherwise.
- */
-struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
- struct device_node *np,
- u32 port, u32 endpoint)
-{
- struct drm_bridge *bridge;
- struct drm_panel *panel;
- int ret;
-
- ret = drm_of_find_panel_or_bridge(np, port, endpoint,
- &panel, &bridge);
- if (ret)
- return ERR_PTR(ret);
-
- if (panel) {
- bridge = drmm_panel_bridge_add(drm, panel);
- drm_panel_put(panel);
- }
-
- return bridge;
-}
-EXPORT_SYMBOL(drmm_of_get_bridge);
-
-#endif
diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c
index a60fb7430956..480e568dd2c9 100644
--- a/drivers/gpu/drm/bridge/samsung-dsim.c
+++ b/drivers/gpu/drm/bridge/samsung-dsim.c
@@ -25,7 +25,6 @@
#include <video/mipi_display.h>
#include <drm/bridge/samsung-dsim.h>
-#include <drm/drm_panel.h>
#include <drm/drm_print.h>
/* returns true iff both arguments logically differs */
@@ -1898,7 +1897,6 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
struct device *dev = dsi->dev;
struct device_node *np = dev->of_node;
struct device_node *remote;
- struct drm_panel *panel;
int ret = 0;
/*
@@ -1913,7 +1911,7 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
of_node_name_eq(remote, "ports"))
continue;
- goto of_find_panel_or_bridge;
+ goto of_find_bridge;
}
/*
@@ -1927,25 +1925,13 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
remote = of_graph_get_remote_node(np, 1, 0);
-of_find_panel_or_bridge:
+of_find_bridge:
if (!remote)
return -ENODEV;
- panel = of_drm_find_panel(remote);
- if (!IS_ERR(panel)) {
- next_bridge = devm_drm_panel_bridge_add(dev, panel);
- drm_panel_put(panel);
- if (IS_ERR(next_bridge)) {
- ret = PTR_ERR(next_bridge);
- next_bridge = NULL; // Inhibit the cleanup action on an ERR_PTR
- } else {
- drm_bridge_get(next_bridge);
- }
- } else {
- next_bridge = of_drm_find_and_get_bridge(remote);
- if (!next_bridge)
- ret = -EINVAL;
- }
+ next_bridge = of_drm_find_and_get_bridge(remote);
+ if (!next_bridge)
+ ret = -EINVAL;
of_node_put(remote);
diff --git a/drivers/gpu/drm/bridge/ssd2825.c b/drivers/gpu/drm/bridge/ssd2825.c
index b0142d6d40dc..71877699dfab 100644
--- a/drivers/gpu/drm/bridge/ssd2825.c
+++ b/drivers/gpu/drm/bridge/ssd2825.c
@@ -17,7 +17,6 @@
#include <drm/drm_drv.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <video/mipi_display.h>
#define SSD2825_DEVICE_ID_REG 0xb0
@@ -114,7 +113,6 @@ static const struct regulator_bulk_data ssd2825_supplies[] = {
struct ssd2825_dsi_output {
struct mipi_dsi_device *dev;
- struct drm_panel *panel;
struct drm_bridge *bridge;
};
@@ -277,7 +275,6 @@ static int ssd2825_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_d
{
struct ssd2825_priv *priv = dsi_host_to_ssd2825(host);
struct drm_bridge *bridge;
- struct drm_panel *panel;
struct device_node *ep;
int ret;
@@ -295,20 +292,14 @@ static int ssd2825_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_d
return -EOPNOTSUPP;
}
- ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, &panel, &bridge);
- if (ret)
- return ret;
+ bridge = of_drm_get_bridge_by_endpoint(host->dev->of_node, 1, 0);
+ if (IS_ERR(bridge))
+ return PTR_ERR(bridge);
- if (panel) {
- bridge = drm_panel_bridge_add_typed(panel, DRM_MODE_CONNECTOR_DSI);
- drm_panel_put(panel);
- if (IS_ERR(bridge))
- return PTR_ERR(bridge);
- }
+ bridge->type = DRM_MODE_CONNECTOR_DSI;
priv->output.dev = dev;
priv->output.bridge = bridge;
- priv->output.panel = panel;
priv->dsi_lanes = dev->lanes;
@@ -333,8 +324,7 @@ static int ssd2825_dsi_host_detach(struct mipi_dsi_host *host, struct mipi_dsi_d
struct ssd2825_priv *priv = dsi_host_to_ssd2825(host);
drm_bridge_remove(&priv->bridge);
- if (priv->output.panel)
- drm_panel_bridge_remove(priv->output.bridge);
+ drm_bridge_put(priv->output.bridge);
return 0;
}
@@ -579,9 +569,6 @@ static void ssd2825_bridge_atomic_pre_enable(struct drm_bridge *bridge,
/* Initial DSI configuration register set */
ssd2825_write_reg(priv, SSD2825_CONFIGURATION_REG, config);
ssd2825_write_reg(priv, SSD2825_VC_CTRL_REG, 0);
-
- if (priv->output.panel)
- drm_panel_enable(priv->output.panel);
}
static void ssd2825_bridge_atomic_enable(struct drm_bridge *bridge,
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index ac83af7902cd..51f4baa62a53 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -35,7 +35,6 @@
#include <drm/drm_edid.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>
@@ -370,7 +369,6 @@ struct tc_data {
struct drm_dp_aux aux;
struct drm_bridge bridge;
- struct drm_bridge *panel_bridge;
struct drm_connector connector;
struct mipi_dsi_device *dsi;
@@ -1742,8 +1740,8 @@ static int tc_connector_get_modes(struct drm_connector *connector)
return 0;
}
- if (tc->panel_bridge) {
- num_modes = drm_bridge_get_modes(tc->panel_bridge, connector);
+ if (tc->bridge.next_bridge) {
+ num_modes = drm_bridge_get_modes(tc->bridge.next_bridge, connector);
if (num_modes > 0)
return num_modes;
}
@@ -1788,7 +1786,7 @@ tc_connector_detect(struct drm_connector *connector, bool force)
if (tc->hpd_pin >= 0)
return tc_bridge_detect(&tc->bridge, connector);
- if (tc->panel_bridge)
+ if (tc->bridge.next_bridge)
return connector_status_connected;
else
return connector_status_unknown;
@@ -1809,10 +1807,10 @@ static int tc_dpi_bridge_attach(struct drm_bridge *bridge,
{
struct tc_data *tc = bridge_to_tc(bridge);
- if (!tc->panel_bridge)
+ if (!tc->bridge.next_bridge)
return 0;
- return drm_bridge_attach(tc->bridge.encoder, tc->panel_bridge,
+ return drm_bridge_attach(tc->bridge.encoder, tc->bridge.next_bridge,
&tc->bridge, flags);
}
@@ -1825,9 +1823,9 @@ static int tc_edp_bridge_attach(struct drm_bridge *bridge,
struct drm_device *drm = bridge->dev;
int ret;
- if (tc->panel_bridge) {
+ if (tc->bridge.next_bridge) {
/* If a connector is required then this driver shall create it */
- ret = drm_bridge_attach(tc->bridge.encoder, tc->panel_bridge,
+ ret = drm_bridge_attach(tc->bridge.encoder, tc->bridge.next_bridge,
&tc->bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret)
return ret;
@@ -2318,53 +2316,31 @@ static int tc_probe_dpi_bridge_endpoint(struct tc_data *tc)
{
struct device *dev = tc->dev;
struct drm_bridge *bridge;
- struct drm_panel *panel;
- int ret;
/* port@1 is the DPI input/output port */
- ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, &bridge);
- if (ret && ret != -ENODEV)
- return dev_err_probe(dev, ret,
- "Could not find DPI panel or bridge\n");
-
- if (panel) {
- bridge = devm_drm_panel_bridge_add(dev, panel);
- drm_panel_put(panel);
- if (IS_ERR(bridge))
- return PTR_ERR(bridge);
- }
-
- if (bridge) {
- tc->panel_bridge = bridge;
- tc->bridge.type = DRM_MODE_CONNECTOR_DPI;
+ bridge = of_drm_get_bridge_by_endpoint(dev->of_node, 1, 0);
+ if (IS_ERR(bridge))
+ return dev_err_probe(dev, PTR_ERR(bridge),
+ "Could not find DPI bridge\n");
- return 0;
- }
+ tc->bridge.next_bridge = bridge;
+ tc->bridge.type = DRM_MODE_CONNECTOR_DPI;
- return ret;
+ return 0;
}
static int tc_probe_edp_bridge_endpoint(struct tc_data *tc)
{
struct device *dev = tc->dev;
- struct drm_panel *panel;
- int ret;
+ struct drm_bridge *bridge;
/* port@2 is the output port */
- ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, NULL);
- if (ret && ret != -ENODEV)
- return dev_err_probe(dev, ret,
- "Could not find DSI panel or bridge\n");
-
- if (panel) {
- struct drm_bridge *panel_bridge;
-
- panel_bridge = devm_drm_panel_bridge_add(dev, panel);
- drm_panel_put(panel);
- if (IS_ERR(panel_bridge))
- return PTR_ERR(panel_bridge);
+ bridge = of_drm_get_bridge_by_endpoint(dev->of_node, 2, 0);
+ if (IS_ERR(bridge) && PTR_ERR(bridge) != -ENODEV)
+ return dev_err_probe(dev, PTR_ERR(bridge), "Could not find DSI bridge\n");
- tc->panel_bridge = panel_bridge;
+ if (!IS_ERR(bridge)) {
+ tc->bridge.next_bridge = bridge;
tc->bridge.type = DRM_MODE_CONNECTOR_eDP;
} else {
tc->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c
index 19b43efcf93f..18f73ad2589e 100644
--- a/drivers/gpu/drm/bridge/tc358768.c
+++ b/drivers/gpu/drm/bridge/tc358768.c
@@ -22,7 +22,6 @@
#include <drm/drm_drv.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <video/mipi_display.h>
#include <video/videomode.h>
@@ -137,7 +136,6 @@ static const char * const tc358768_supplies[] = {
struct tc358768_dsi_output {
struct mipi_dsi_device *dev;
- struct drm_panel *panel;
struct drm_bridge *bridge;
};
@@ -443,7 +441,6 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host,
{
struct tc358768_priv *priv = dsi_host_to_tc358768(host);
struct drm_bridge *bridge;
- struct drm_panel *panel;
struct device_node *ep;
int ret;
@@ -471,24 +468,15 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host,
return -ENOTSUPP;
}
- ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, &panel,
- &bridge);
- if (ret)
- return ret;
+ bridge = of_drm_get_bridge_by_endpoint(host->dev->of_node, 1, 0);
+ if (IS_ERR(bridge))
+ return PTR_ERR(bridge);
- if (panel) {
- bridge = drm_panel_bridge_add_typed(panel,
- DRM_MODE_CONNECTOR_DSI);
- drm_panel_put(panel);
- if (IS_ERR(bridge))
- return PTR_ERR(bridge);
-
- bridge->pre_enable_prev_first = true;
- }
+ bridge->type = DRM_MODE_CONNECTOR_DSI;
+ bridge->pre_enable_prev_first = true;
priv->output.dev = dev;
priv->output.bridge = bridge;
- priv->output.panel = panel;
priv->dsi_lanes = dev->lanes;
priv->dsi_bpp = mipi_dsi_pixel_format_to_bpp(dev->format);
@@ -518,8 +506,7 @@ static int tc358768_dsi_host_detach(struct mipi_dsi_host *host,
struct tc358768_priv *priv = dsi_host_to_tc358768(host);
drm_bridge_remove(&priv->bridge);
- if (priv->output.panel)
- drm_panel_bridge_remove(priv->output.bridge);
+ drm_bridge_put(priv->output.bridge);
return 0;
}
diff --git a/drivers/gpu/drm/bridge/ti-tdp158.c b/drivers/gpu/drm/bridge/ti-tdp158.c
index 01fc643bd78f..8e3e99cbe41a 100644
--- a/drivers/gpu/drm/bridge/ti-tdp158.c
+++ b/drivers/gpu/drm/bridge/ti-tdp158.c
@@ -8,6 +8,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
+#include <drm/drm_panel.h>
struct tdp158 {
struct drm_bridge bridge;
diff --git a/drivers/gpu/drm/bridge/waveshare-dsi.c b/drivers/gpu/drm/bridge/waveshare-dsi.c
index 420f3b870a74..2c40bfef2b45 100644
--- a/drivers/gpu/drm/bridge/waveshare-dsi.c
+++ b/drivers/gpu/drm/bridge/waveshare-dsi.c
@@ -16,11 +16,9 @@
#include <drm/drm_bridge.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
struct ws_bridge {
struct drm_bridge bridge;
- struct drm_bridge *next_bridge;
struct backlight_device *backlight;
struct device *dev;
struct regmap *reg_map;
@@ -89,7 +87,7 @@ static int ws_bridge_bridge_attach(struct drm_bridge *bridge,
{
struct ws_bridge *ws = bridge_to_ws_bridge(bridge);
- return drm_bridge_attach(encoder, ws->next_bridge,
+ return drm_bridge_attach(encoder, ws->bridge.next_bridge,
&ws->bridge, flags);
}
@@ -150,7 +148,6 @@ static struct backlight_device *ws_bridge_create_backlight(struct ws_bridge *ws)
static int ws_bridge_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
- struct drm_panel *panel;
struct ws_bridge *ws;
int ret;
@@ -164,14 +161,10 @@ static int ws_bridge_probe(struct i2c_client *i2c)
if (IS_ERR(ws->reg_map))
return dev_err_probe(dev, PTR_ERR(ws->reg_map), "Failed to allocate regmap\n");
- ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, &panel, NULL);
- if (ret)
- return dev_err_probe(dev, ret, "Failed to find remote panel\n");
-
- ws->next_bridge = devm_drm_panel_bridge_add(dev, panel);
- drm_panel_put(panel);
- if (IS_ERR(ws->next_bridge))
- return PTR_ERR(ws->next_bridge);
+ ws->bridge.next_bridge = of_drm_get_bridge_by_endpoint(dev->of_node, 1, -1);
+ if (IS_ERR(ws->bridge.next_bridge))
+ return dev_err_probe(dev, PTR_ERR(ws->bridge.next_bridge),
+ "Failed to find remote bridge\n");
ws->backlight = ws_bridge_create_backlight(ws);
if (IS_ERR(ws->backlight)) {
diff --git a/drivers/gpu/drm/clients/Makefile b/drivers/gpu/drm/clients/Makefile
index c16addbc327f..1304ff358509 100644
--- a/drivers/gpu/drm/clients/Makefile
+++ b/drivers/gpu/drm/clients/Makefile
@@ -4,5 +4,6 @@ subdir-ccflags-y += -I$(src)/..
drm_client_lib-y := drm_client_setup.o
drm_client_lib-$(CONFIG_DRM_CLIENT_LOG) += drm_log.o
-drm_client_lib-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fbdev_client.o
+drm_client_lib-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fbdev_client.o \
+ drm_fbdev_helper.o
obj-$(CONFIG_DRM_CLIENT_LIB) += drm_client_lib.o
diff --git a/drivers/gpu/drm/clients/drm_fbdev_client.c b/drivers/gpu/drm/clients/drm_fbdev_client.c
index 7574bd36f45e..eec463d19943 100644
--- a/drivers/gpu/drm/clients/drm_fbdev_client.c
+++ b/drivers/gpu/drm/clients/drm_fbdev_client.c
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_client.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>
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/clients/drm_fbdev_helper.c
index d4664ed468b2..fff3cf6a0aed 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/clients/drm_fbdev_helper.c
@@ -32,9 +32,9 @@
#include <linux/console.h>
#include <linux/export.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_framebuffer_helper.h>
@@ -43,39 +43,9 @@
#include <drm/drm_vblank.h>
#include "drm_internal.h"
+#include "drm_crtc_helper_internal.h"
#include "drm_crtc_internal.h"
-static bool drm_fbdev_emulation = true;
-module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
-MODULE_PARM_DESC(fbdev_emulation,
- "Enable legacy fbdev emulation [default=true]");
-
-static int drm_fbdev_overalloc = CONFIG_DRM_FBDEV_OVERALLOC;
-module_param(drm_fbdev_overalloc, int, 0444);
-MODULE_PARM_DESC(drm_fbdev_overalloc,
- "Overallocation of the fbdev buffer (%) [default="
- __MODULE_STRING(CONFIG_DRM_FBDEV_OVERALLOC) "]");
-
-/*
- * In order to keep user-space compatibility, we want in certain use-cases
- * to keep leaking the fbdev physical address to the user-space program
- * handling the fbdev buffer.
- *
- * This is a bad habit, essentially kept to support closed-source OpenGL
- * drivers that should really be moved into open-source upstream projects
- * instead of using legacy physical addresses in user space to communicate
- * with other out-of-tree kernel modules.
- *
- * This module_param *should* be removed as soon as possible and be
- * considered as a broken and legacy behaviour from a modern fbdev device.
- */
-static bool drm_leak_fbdev_smem;
-#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
-module_param_unsafe(drm_leak_fbdev_smem, bool, 0600);
-MODULE_PARM_DESC(drm_leak_fbdev_smem,
- "Allow unsafe leaking fbdev physical smem address [default=false]");
-#endif
-
/**
* DOC: fbdev helpers
*
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 707d7143e475..81f3e26f6fdf 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -18,6 +18,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_managed.h>
#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/display/drm_hdcp_helper.h>
diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c
index 7ce9e212770a..b7fce0bf8acc 100644
--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c
@@ -2161,6 +2161,9 @@ ssize_t drm_dp_mst_dpcd_read(struct drm_dp_aux *aux,
struct drm_dp_mst_port *port = container_of(aux, struct drm_dp_mst_port,
aux);
+ if (!port->ddps)
+ return -EIO;
+
return drm_dp_send_dpcd_read(port->mgr, port,
offset, size, buffer);
}
@@ -2184,6 +2187,9 @@ ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux,
struct drm_dp_mst_port *port = container_of(aux, struct drm_dp_mst_port,
aux);
+ if (!port->ddps)
+ return -EIO;
+
return drm_dp_send_dpcd_write(port->mgr, port,
offset, size, buffer);
}
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 2f4208b34234..1b4ee746acb9 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -1745,23 +1745,6 @@ struct drm_bridge *of_drm_get_bridge_by_endpoint(const struct device_node *np,
EXPORT_SYMBOL_GPL(of_drm_get_bridge_by_endpoint);
#endif
-/**
- * devm_drm_put_bridge - Release a bridge reference obtained via devm
- * @dev: device that got the bridge via devm
- * @bridge: pointer to a struct drm_bridge obtained via devm
- *
- * Same as drm_bridge_put() for bridge pointers obtained via devm functions
- * such as devm_drm_bridge_alloc().
- *
- * This function is a temporary workaround and MUST NOT be used. Manual
- * handling of bridge lifetime is inherently unsafe.
- */
-void devm_drm_put_bridge(struct device *dev, struct drm_bridge *bridge)
-{
- devm_release_action(dev, drm_bridge_put_void, bridge);
-}
-EXPORT_SYMBOL(devm_drm_put_bridge);
-
static void drm_bridge_debugfs_show_bridge(struct drm_printer *p,
struct drm_bridge *bridge,
unsigned int idx,
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index d94c86bfed86..893716a9e489 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -28,10 +28,10 @@
#include <drm/drm_file.h>
#include <drm/drm_managed.h>
#include <drm/drm_panel.h>
+#include <drm/drm_panel_quirks.h>
#include <drm/drm_print.h>
#include <drm/drm_privacy_screen_consumer.h>
#include <drm/drm_sysfs.h>
-#include <drm/drm_utils.h>
#include <linux/export.h>
#include <linux/platform_device.h>
diff --git a/drivers/gpu/drm/drm_crtc_helper_internal.h b/drivers/gpu/drm/drm_crtc_helper_internal.h
index bae73936acf9..adcc9a2e24ee 100644
--- a/drivers/gpu/drm/drm_crtc_helper_internal.h
+++ b/drivers/gpu/drm/drm_crtc_helper_internal.h
@@ -29,6 +29,8 @@
#ifndef __DRM_CRTC_HELPER_INTERNAL_H__
#define __DRM_CRTC_HELPER_INTERNAL_H__
+#include <linux/types.h>
+
enum drm_mode_status;
struct drm_connector;
struct drm_crtc;
@@ -36,6 +38,13 @@ struct drm_display_mode;
struct drm_encoder;
struct drm_modeset_acquire_ctx;
+/* drm_kms_helper_common.c */
+#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
+extern bool drm_fbdev_emulation;
+extern int drm_fbdev_overalloc;
+extern bool drm_leak_fbdev_smem;
+#endif
+
/* drm_probe_helper.c */
enum drm_mode_status drm_crtc_mode_valid(struct drm_crtc *crtc,
const struct drm_display_mode *mode);
diff --git a/drivers/gpu/drm/drm_fbdev_dma.c b/drivers/gpu/drm/drm_fbdev_dma.c
index 9412d9fdd74b..452f84400350 100644
--- a/drivers/gpu/drm/drm_fbdev_dma.c
+++ b/drivers/gpu/drm/drm_fbdev_dma.c
@@ -4,10 +4,10 @@
#include <linux/fb.h>
#include <linux/vmalloc.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fbdev_dma.h>
#include <drm/drm_fb_dma_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_print.h>
diff --git a/drivers/gpu/drm/drm_fbdev_shmem.c b/drivers/gpu/drm/drm_fbdev_shmem.c
index 458c899b5d4f..8eb05fe9bc98 100644
--- a/drivers/gpu/drm/drm_fbdev_shmem.c
+++ b/drivers/gpu/drm/drm_fbdev_shmem.c
@@ -3,9 +3,9 @@
#include <linux/export.h>
#include <linux/fb.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fbdev_shmem.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_shmem_helper.h>
diff --git a/drivers/gpu/drm/drm_fbdev_ttm.c b/drivers/gpu/drm/drm_fbdev_ttm.c
index 160bc35d8738..8eb59c2ac5ea 100644
--- a/drivers/gpu/drm/drm_fbdev_ttm.c
+++ b/drivers/gpu/drm/drm_fbdev_ttm.c
@@ -4,9 +4,9 @@
#include <linux/moduleparam.h>
#include <linux/vmalloc.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem.h>
#include <drm/drm_print.h>
diff --git a/drivers/gpu/drm/drm_kms_helper_common.c b/drivers/gpu/drm/drm_kms_helper_common.c
index b5d5b469b444..1e55ecac4698 100644
--- a/drivers/gpu/drm/drm_kms_helper_common.c
+++ b/drivers/gpu/drm/drm_kms_helper_common.c
@@ -25,10 +25,49 @@
*
*/
+#include <linux/export.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include "drm_crtc_helper_internal.h"
#include "drm_panic_internal.h"
+#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
+bool drm_fbdev_emulation = true;
+EXPORT_SYMBOL(drm_fbdev_emulation);
+module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
+MODULE_PARM_DESC(fbdev_emulation, "Enable legacy fbdev emulation [default=true]");
+
+int drm_fbdev_overalloc = CONFIG_DRM_FBDEV_OVERALLOC;
+EXPORT_SYMBOL(drm_fbdev_overalloc);
+module_param(drm_fbdev_overalloc, int, 0444);
+MODULE_PARM_DESC(drm_fbdev_overalloc,
+ "Overallocation of the fbdev buffer (%) [default="
+ __MODULE_STRING(CONFIG_DRM_FBDEV_OVERALLOC) "]");
+
+/*
+ * In order to keep user-space compatibility, we want in certain use-cases
+ * to keep leaking the fbdev physical address to the user-space program
+ * handling the fbdev buffer.
+ *
+ * This is a bad habit, essentially kept to support closed-source OpenGL
+ * drivers that should really be moved into open-source upstream projects
+ * instead of using legacy physical addresses in user space to communicate
+ * with other out-of-tree kernel modules.
+ *
+ * This module_param *should* be removed as soon as possible and be
+ * considered as a broken and legacy behaviour from a modern fbdev device.
+ */
+bool drm_leak_fbdev_smem;
+EXPORT_SYMBOL(drm_leak_fbdev_smem);
+#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
+module_param_unsafe(drm_leak_fbdev_smem, bool, 0600);
+MODULE_PARM_DESC(drm_leak_fbdev_smem,
+ "Allow unsafe leaking fbdev physical smem address [default=false]");
+#endif
+
+#endif
+
static int __init drm_kms_helper_init(void)
{
return drm_panic_helper_init();
diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
index 2b53124ded68..411f258d9f91 100644
--- a/drivers/gpu/drm/drm_of.c
+++ b/drivers/gpu/drm/drm_of.c
@@ -264,69 +264,6 @@ int drm_of_get_panel_orientation(const struct device_node *np,
}
EXPORT_SYMBOL_GPL(drm_of_get_panel_orientation);
-/**
- * drm_of_find_panel_or_bridge - return connected panel or bridge device
- * @np: device tree node containing encoder output ports
- * @port: port in the device tree node
- * @endpoint: endpoint in the device tree node
- * @panel: pointer to hold returned drm_panel, must not be NULL. On success
- * the caller must call drm_panel_put() when done with the panel
- * @bridge: pointer to hold returned drm_bridge
- *
- * Given a DT node's port and endpoint number, find the connected node and
- * return either the associated struct drm_panel or drm_bridge device.
- *
- * This function is deprecated and should not be used in new drivers. Use
- * of_drm_get_bridge_by_endpoint() instead when not looking for a panel, or
- * devm_drm_of_get_bridge() otherwise.
- *
- * Returns zero if successful, or one of the standard error codes if it fails.
- */
-int drm_of_find_panel_or_bridge(const struct device_node *np,
- int port, int endpoint,
- struct drm_panel **panel,
- struct drm_bridge **bridge)
-{
- if (WARN_ON(!panel))
- return -EINVAL;
-
- *panel = NULL;
- if (bridge)
- *bridge = NULL;
-
- /*
- * of_graph_get_remote_node() produces a noisy error message if port
- * node isn't found and the absence of the port is a legit case here,
- * so at first we silently check whether a graph is present in the
- * device-tree node.
- */
- if (!of_graph_is_present(np))
- return -ENODEV;
-
- struct device_node *remote __free(device_node) =
- of_graph_get_remote_node(np, port, endpoint);
- if (!remote)
- return -ENODEV;
-
- *panel = of_drm_find_panel(remote);
- if (!IS_ERR(*panel))
- return 0;
-
- *panel = NULL;
-
- if (bridge) {
- /* No panel found yet, check for a bridge next. */
- *bridge = of_drm_find_bridge(remote);
- if (*bridge)
- return 0;
-
- *bridge = NULL;
- }
-
- return -EPROBE_DEFER;
-}
-EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge);
-
enum drm_of_lvds_pixels {
DRM_OF_LVDS_EVEN = BIT(0),
DRM_OF_LVDS_ODD = BIT(1),
diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index f8f6082e637f..c00529bfb706 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -1,36 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2013, NVIDIA Corporation. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sub license,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
+ * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Copyright (C) 2017 Broadcom
*/
#include <linux/backlight.h>
+#include <linux/debugfs.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
static DEFINE_MUTEX(panel_lock);
static LIST_HEAD(panel_list);
@@ -46,6 +38,526 @@ static LIST_HEAD(panel_list);
* take look at drm_panel_bridge_add() and devm_drm_panel_bridge_add().
*/
+static inline struct drm_panel *
+drm_bridge_to_panel(const struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct drm_panel, bridge);
+}
+
+static inline struct drm_panel *
+drm_connector_to_panel(const struct drm_connector *connector)
+{
+ return container_of(connector, struct drm_panel, connector);
+}
+
+struct panel_bridge {
+ struct drm_bridge bridge;
+ struct drm_connector connector;
+ struct drm_panel *panel;
+ u32 connector_type;
+};
+
+static int panel_bridge_connector_get_modes(struct drm_connector *connector)
+{
+ struct drm_panel *panel = drm_connector_to_panel(connector);
+
+ return drm_panel_get_modes(panel, connector);
+}
+
+static const struct drm_connector_helper_funcs
+panel_bridge_connector_helper_funcs = {
+ .get_modes = panel_bridge_connector_get_modes,
+};
+
+static const struct drm_connector_funcs panel_bridge_connector_funcs = {
+ .reset = drm_atomic_helper_connector_reset,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = drm_connector_cleanup,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int panel_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
+ enum drm_bridge_attach_flags flags)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+ struct drm_connector *connector = &panel->connector;
+ int ret;
+
+ if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
+ return 0;
+
+ drm_connector_helper_add(connector,
+ &panel_bridge_connector_helper_funcs);
+
+ ret = drm_connector_init(bridge->dev, connector,
+ &panel_bridge_connector_funcs,
+ panel->connector_type);
+ if (ret) {
+ DRM_ERROR("Failed to initialize connector\n");
+ return ret;
+ }
+
+ drm_panel_bridge_set_orientation(connector, bridge);
+
+ drm_connector_attach_encoder(connector, encoder);
+
+ if (bridge->dev->registered) {
+ if (connector->funcs->reset)
+ connector->funcs->reset(connector);
+ drm_connector_register(connector);
+ }
+
+ return 0;
+}
+
+static void panel_bridge_detach(struct drm_bridge *bridge)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+ struct drm_connector *connector = &panel->connector;
+
+ /* Cleanup the connector if we know it was initialized */
+ if (connector->dev)
+ drm_connector_cleanup(connector);
+}
+
+static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *atomic_state)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+ struct drm_encoder *encoder = bridge->encoder;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *old_crtc_state;
+
+ crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+ if (!crtc)
+ return;
+
+ old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+ if (old_crtc_state && old_crtc_state->self_refresh_active)
+ return;
+
+ drm_panel_prepare(panel);
+}
+
+static void panel_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *atomic_state)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+ struct drm_encoder *encoder = bridge->encoder;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *old_crtc_state;
+
+ crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+ if (!crtc)
+ return;
+
+ old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+ if (old_crtc_state && old_crtc_state->self_refresh_active)
+ return;
+
+ drm_panel_enable(panel);
+}
+
+static void panel_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *atomic_state)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+ struct drm_encoder *encoder = bridge->encoder;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *new_crtc_state;
+
+ crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+ if (!crtc)
+ return;
+
+ new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+ if (new_crtc_state && new_crtc_state->self_refresh_active)
+ return;
+
+ drm_panel_disable(panel);
+}
+
+static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *atomic_state)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+ struct drm_encoder *encoder = bridge->encoder;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *new_crtc_state;
+
+ crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+ if (!crtc)
+ return;
+
+ new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+ if (new_crtc_state && new_crtc_state->self_refresh_active)
+ return;
+
+ drm_panel_unprepare(panel);
+}
+
+static int panel_bridge_get_modes(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+
+ return drm_panel_get_modes(panel, connector);
+}
+
+static void panel_bridge_debugfs_init(struct drm_bridge *bridge,
+ struct dentry *root)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+
+ root = debugfs_create_dir("panel", root);
+ if (panel->funcs->debugfs_init)
+ panel->funcs->debugfs_init(panel, root);
+}
+
+static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
+ .attach = panel_bridge_attach,
+ .detach = panel_bridge_detach,
+ .atomic_pre_enable = panel_bridge_atomic_pre_enable,
+ .atomic_enable = panel_bridge_atomic_enable,
+ .atomic_disable = panel_bridge_atomic_disable,
+ .atomic_post_disable = panel_bridge_atomic_post_disable,
+ .get_modes = panel_bridge_get_modes,
+ .atomic_create_state = drm_atomic_helper_bridge_create_state,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
+ .debugfs_init = panel_bridge_debugfs_init,
+};
+
+/**
+ * drm_bridge_is_panel - Checks if a drm_bridge is a panel_bridge.
+ *
+ * @bridge: The drm_bridge to be checked.
+ *
+ * Returns true if the bridge is a panel bridge, or false otherwise.
+ */
+bool drm_bridge_is_panel(const struct drm_bridge *bridge)
+{
+ return bridge->funcs == &panel_bridge_bridge_funcs;
+}
+EXPORT_SYMBOL(drm_bridge_is_panel);
+
+/**
+ * drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that
+ * just calls the appropriate functions from &drm_panel.
+ *
+ * @panel: The drm_panel being wrapped. Must be non-NULL.
+ *
+ * This function is deprecated. A drm_bridge is embedded into every panel.
+ * Don't use it in new drivers and update your driver to stop using it.
+ *
+ * For drivers converting from directly using drm_panel: The expected
+ * usage pattern is that during either encoder module probe or DSI
+ * host attach, a drm_panel will be looked up through
+ * drm_of_find_panel_or_bridge(). drm_panel_bridge_add() is used to
+ * wrap that panel in the new bridge, and the result can then be
+ * passed to drm_bridge_attach(). The drm_panel_prepare() and related
+ * functions can be dropped from the encoder driver (they're now
+ * called by the KMS helpers before calling into the encoder), along
+ * with connector creation. When done with the bridge (after
+ * drm_mode_config_cleanup() if the bridge has already been attached), then
+ * drm_panel_bridge_remove() to free it.
+ *
+ * The connector type is set to @panel->connector_type, which must be set to a
+ * known type. Calling this function with a panel whose connector type is
+ * DRM_MODE_CONNECTOR_Unknown will return ERR_PTR(-EINVAL).
+ *
+ * See devm_drm_panel_bridge_add() for an automatically managed version of this
+ * function.
+ */
+struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel)
+{
+ if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
+ return ERR_PTR(-EINVAL);
+
+ return drm_panel_bridge_add_typed(panel, panel->connector_type);
+}
+EXPORT_SYMBOL(drm_panel_bridge_add);
+
+/**
+ * drm_panel_bridge_add_typed - Pretend to create a &drm_bridge and &drm_connector with
+ * an explicit connector type.
+ * @panel: The drm_panel being wrapped. Must be non-NULL.
+ * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
+ *
+ * This is just like drm_panel_bridge_add(), but forces the connector type to
+ * @connector_type instead of infering it from the panel.
+ *
+ * This function is deprecated. A drm_bridge is embedded into every panel.
+ * Don't use it in new drivers and update your driver to stop using it.
+ */
+struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
+ u32 connector_type)
+{
+ if (!panel)
+ return ERR_PTR(-EINVAL);
+
+ return drm_bridge_get(&panel->bridge);
+}
+EXPORT_SYMBOL(drm_panel_bridge_add_typed);
+
+/**
+ * drm_panel_bridge_remove - Unregisters and frees a drm_bridge
+ * created by drm_panel_bridge_add().
+ *
+ * @bridge: The drm_bridge being freed.
+ *
+ * This function is deprecated. A drm_bridge is embedded into every panel
+ * and removed when the panel is removed. Don't use it in new drivers and
+ * update your driver to stop using it.
+ */
+void drm_panel_bridge_remove(struct drm_bridge *bridge)
+{
+ if (!bridge)
+ return;
+
+ if (!drm_bridge_is_panel(bridge)) {
+ drm_warn(bridge->dev, "%s: called on non-panel bridge!\n", __func__);
+ return;
+ }
+
+ drm_bridge_put(bridge);
+}
+EXPORT_SYMBOL(drm_panel_bridge_remove);
+
+/**
+ * drm_panel_bridge_set_orientation - Set the connector's panel orientation
+ * from the bridge that can be transformed to panel bridge.
+ *
+ * @connector: The connector to be set panel orientation.
+ * @bridge: The drm_bridge whose orientation should be set.
+ *
+ * Returns 0 on success, negative errno on failure.
+ */
+int drm_panel_bridge_set_orientation(struct drm_connector *connector,
+ struct drm_bridge *bridge)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+
+ return drm_connector_set_orientation_from_panel(connector, panel);
+}
+EXPORT_SYMBOL(drm_panel_bridge_set_orientation);
+
+static void devm_drm_panel_bridge_release(struct device *dev, void *res)
+{
+ struct drm_bridge *bridge = *(struct drm_bridge **)res;
+
+ if (!bridge)
+ return;
+
+ drm_bridge_put(bridge);
+}
+
+/**
+ * devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector
+ * that just calls the appropriate functions from &drm_panel.
+ * @dev: device to tie the bridge lifetime to
+ * @panel: The drm_panel being wrapped. Must be non-NULL.
+ *
+ * This function is deprecated. A drm_bridge is embedded into every panel.
+ * Don't use it in new drivers and update your driver to stop using it.
+ *
+ * This is the managed version of drm_panel_bridge_add() which automatically
+ * calls drm_panel_bridge_remove() when @dev is unbound.
+ */
+struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
+ struct drm_panel *panel)
+{
+ if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
+ return ERR_PTR(-EINVAL);
+
+ return devm_drm_panel_bridge_add_typed(dev, panel,
+ panel->connector_type);
+}
+EXPORT_SYMBOL(devm_drm_panel_bridge_add);
+
+/**
+ * devm_drm_panel_bridge_add_typed - Creates a managed &drm_bridge and
+ * &drm_connector with an explicit connector type.
+ * @dev: device to tie the bridge lifetime to
+ * @panel: The drm_panel being wrapped. Must be non-NULL.
+ * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
+ *
+ * This is just like devm_drm_panel_bridge_add(), but forces the connector type
+ * to @connector_type instead of infering it from the panel.
+ *
+ * This function is deprecated. A drm_bridge is embedded into every panel.
+ * Don't use it in new drivers and update your driver to stop using it.
+ */
+struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
+ struct drm_panel *panel,
+ u32 connector_type)
+{
+ struct drm_bridge **ptr, *bridge;
+
+ ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
+ GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ bridge = drm_panel_bridge_add_typed(panel, connector_type);
+ if (IS_ERR(bridge)) {
+ devres_free(ptr);
+ return bridge;
+ }
+
+ *ptr = bridge;
+ devres_add(dev, ptr);
+
+ return &panel->bridge;
+}
+EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
+
+static void drmm_drm_panel_bridge_release(struct drm_device *drm, void *ptr)
+{
+ struct drm_bridge *bridge = ptr;
+
+ drm_panel_bridge_remove(bridge);
+}
+
+/**
+ * drmm_panel_bridge_add - Creates a DRM-managed &drm_bridge and
+ * &drm_connector that just calls the
+ * appropriate functions from &drm_panel.
+ *
+ * @drm: DRM device to tie the bridge lifetime to
+ * @panel: The drm_panel being wrapped. Must be non-NULL.
+ *
+ * This function is deprecated. A drm_bridge is embedded into every panel.
+ * Don't use it in new drivers and update your driver to stop using it.
+ *
+ * This is the DRM-managed version of drm_panel_bridge_add() which
+ * automatically calls drm_panel_bridge_remove() when @dev is cleaned
+ * up.
+ */
+struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,
+ struct drm_panel *panel)
+{
+ struct drm_bridge *bridge;
+ int ret;
+
+ bridge = drm_panel_bridge_add_typed(panel, panel->connector_type);
+ if (IS_ERR(bridge))
+ return bridge;
+
+ ret = drmm_add_action_or_reset(drm, drmm_drm_panel_bridge_release,
+ bridge);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return bridge;
+}
+EXPORT_SYMBOL(drmm_panel_bridge_add);
+
+/**
+ * drm_panel_bridge_connector - return the connector for the panel (for
+ * legacy drivers not using DRM_BRIDGE_ATTACH_NO_CONNECTOR)
+ * @bridge: The drm_bridge.
+ *
+ * This function gives external access to the connector.
+ *
+ * Returns: Pointer to drm_connector
+ */
+struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge)
+{
+ struct drm_panel *panel;
+
+ panel = drm_bridge_to_panel(bridge);
+
+ return &panel->connector;
+}
+EXPORT_SYMBOL(drm_panel_bridge_connector);
+
+#ifdef CONFIG_OF
+/**
+ * devm_drm_of_get_bridge - Return next bridge in the chain
+ * @dev: device to tie the bridge lifetime to
+ * @np: device tree node containing encoder output ports
+ * @port: port in the device tree node
+ * @endpoint: endpoint in the device tree node
+ *
+ * This function is deprecated. A drm_bridge is embedded into every panel.
+ * Don't use it in new drivers and convert your driver to
+ * of_drm_get_bridge_by_endpoint().
+ *
+ * Given a DT node's port and endpoint number, finds the connected node
+ * and returns the associated bridge if any, or creates and returns a
+ * drm panel bridge instance if a panel is connected.
+ *
+ * Returns a pointer to the bridge if successful, or an error pointer
+ * otherwise.
+ */
+struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
+ struct device_node *np,
+ u32 port, u32 endpoint)
+{
+ struct drm_bridge *bridge;
+ struct drm_panel *panel;
+ int ret;
+
+ ret = drm_of_find_panel_or_bridge(np, port, endpoint,
+ &panel, &bridge);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (panel) {
+ bridge = devm_drm_panel_bridge_add(dev, panel);
+ drm_panel_put(panel);
+ }
+
+ return bridge;
+}
+EXPORT_SYMBOL(devm_drm_of_get_bridge);
+
+/**
+ * drmm_of_get_bridge - Return next bridge in the chain
+ * @drm: device to tie the bridge lifetime to
+ * @np: device tree node containing encoder output ports
+ * @port: port in the device tree node
+ * @endpoint: endpoint in the device tree node
+ *
+ * This function is deprecated. A drm_bridge is embedded into every panel.
+ * Don't use it in new drivers and convert your driver to
+ * of_drm_get_bridge_by_endpoint().
+ *
+ * Given a DT node's port and endpoint number, finds the connected node
+ * and returns the associated bridge if any, or creates and returns a
+ * drm panel bridge instance if a panel is connected.
+ *
+ * Returns a drmm managed pointer to the bridge if successful, or an error
+ * pointer otherwise.
+ */
+struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
+ struct device_node *np,
+ u32 port, u32 endpoint)
+{
+ struct drm_bridge *bridge;
+ struct drm_panel *panel;
+ int ret;
+
+ ret = drm_of_find_panel_or_bridge(np, port, endpoint,
+ &panel, &bridge);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (panel) {
+ bridge = drmm_panel_bridge_add(drm, panel);
+ drm_panel_put(panel);
+ }
+
+ return bridge;
+}
+EXPORT_SYMBOL(drmm_of_get_bridge);
+
+#endif
+
/**
* drm_panel_init - initialize a panel
* @panel: DRM panel
@@ -86,6 +598,13 @@ void drm_panel_add(struct drm_panel *panel)
mutex_lock(&panel_lock);
list_add_tail(&panel->list, &panel_list);
mutex_unlock(&panel_lock);
+
+ panel->bridge.of_node = panel->dev->of_node;
+ panel->bridge.ops = DRM_BRIDGE_OP_MODES;
+ panel->bridge.type = panel->connector_type;
+ panel->bridge.pre_enable_prev_first = panel->prepare_prev_first;
+
+ drm_bridge_add(&panel->bridge);
}
EXPORT_SYMBOL(drm_panel_add);
@@ -97,6 +616,7 @@ EXPORT_SYMBOL(drm_panel_add);
*/
void drm_panel_remove(struct drm_panel *panel)
{
+ drm_bridge_remove(&panel->bridge);
mutex_lock(&panel_lock);
list_del_init(&panel->list);
mutex_unlock(&panel_lock);
@@ -370,13 +890,6 @@ int drm_panel_get_modes(struct drm_panel *panel,
}
EXPORT_SYMBOL(drm_panel_get_modes);
-static void __drm_panel_free(struct kref *kref)
-{
- struct drm_panel *panel = container_of(kref, struct drm_panel, refcount);
-
- kfree(panel->container);
-}
-
/**
* drm_panel_get - Acquire a panel reference
* @panel: DRM panel
@@ -387,10 +900,8 @@ static void __drm_panel_free(struct kref *kref)
*/
struct drm_panel *drm_panel_get(struct drm_panel *panel)
{
- if (!panel)
- return panel;
-
- kref_get(&panel->refcount);
+ if (panel)
+ drm_bridge_get(&panel->bridge);
return panel;
}
@@ -406,7 +917,7 @@ EXPORT_SYMBOL(drm_panel_get);
void drm_panel_put(struct drm_panel *panel)
{
if (panel)
- kref_put(&panel->refcount, __drm_panel_free);
+ drm_bridge_put(&panel->bridge);
}
EXPORT_SYMBOL(drm_panel_put);
@@ -429,8 +940,22 @@ void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset,
const struct drm_panel_funcs *funcs,
int connector_type)
{
- void *container;
+ /*
+ * Struct embedding and offsets:
+ *
+ * |--------------- user container struct ------------|
+ * : |---------- struct drm_panel ------------|
+ * : : |----- struct drm_bridge ------|
+ * A B C
+ *
+ * B - A = offset (passed as argument)
+ * C - B = panel_bridge_offset
+ * C - A = alloc_bridge_offset
+ */
+ const size_t panel_bridge_offset = offsetof(struct drm_panel, bridge);
+ const size_t alloc_bridge_offset = offset + panel_bridge_offset;
struct drm_panel *panel;
+ void *container;
int err;
if (!funcs) {
@@ -438,14 +963,16 @@ void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset,
return ERR_PTR(-EINVAL);
}
- container = kzalloc(size, GFP_KERNEL);
- if (!container)
- return ERR_PTR(-ENOMEM);
+ container = __devm_drm_bridge_alloc(dev, size, alloc_bridge_offset,
+ &panel_bridge_bridge_funcs);
+ if (IS_ERR(container))
+ return container;
panel = container + offset;
- panel->container = container;
panel->funcs = funcs;
- kref_init(&panel->refcount);
+ panel->bridge.of_node = dev->of_node;
+
+ drm_panel_get(panel);
err = devm_add_action_or_reset(dev, drm_panel_put_void, panel);
if (err)
@@ -498,6 +1025,69 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np)
return ERR_PTR(-EPROBE_DEFER);
}
EXPORT_SYMBOL(of_drm_find_panel);
+
+/**
+ * drm_of_find_panel_or_bridge - return connected panel or bridge device
+ * @np: device tree node containing encoder output ports
+ * @port: port in the device tree node
+ * @endpoint: endpoint in the device tree node
+ * @panel: pointer to hold returned drm_panel, must not be NULL. On success
+ * the caller must call drm_panel_put() when done with the panel
+ * @bridge: pointer to hold returned drm_bridge
+ *
+ * Given a DT node's port and endpoint number, find the connected node and
+ * return either the associated struct drm_panel or drm_bridge device.
+ *
+ * This function is deprecated and should not be used in new drivers. Use
+ * of_drm_get_bridge_by_endpoint() instead when not looking for a panel, or
+ * devm_drm_of_get_bridge() otherwise.
+ *
+ * Returns zero if successful, or one of the standard error codes if it fails.
+ */
+int drm_of_find_panel_or_bridge(const struct device_node *np,
+ int port, int endpoint,
+ struct drm_panel **panel,
+ struct drm_bridge **bridge)
+{
+ if (WARN_ON(!panel))
+ return -EINVAL;
+
+ *panel = NULL;
+ if (bridge)
+ *bridge = NULL;
+
+ /*
+ * of_graph_get_remote_node() produces a noisy error message if port
+ * node isn't found and the absence of the port is a legit case here,
+ * so at first we silently check whether a graph is present in the
+ * device-tree node.
+ */
+ if (!of_graph_is_present(np))
+ return -ENODEV;
+
+ struct device_node *remote __free(device_node) =
+ of_graph_get_remote_node(np, port, endpoint);
+ if (!remote)
+ return -ENODEV;
+
+ *panel = of_drm_find_panel(remote);
+ if (!IS_ERR(*panel))
+ return 0;
+
+ *panel = NULL;
+
+ if (bridge) {
+ /* No panel found yet, check for a bridge next. */
+ *bridge = of_drm_find_bridge(remote);
+ if (*bridge)
+ return 0;
+
+ *bridge = NULL;
+ }
+
+ return -EPROBE_DEFER;
+}
+EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge);
#endif
/*
diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c
index e417c7533053..dcb91e12bac6 100644
--- a/drivers/gpu/drm/drm_panel_backlight_quirks.c
+++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c
@@ -5,7 +5,7 @@
#include <linux/export.h>
#include <linux/module.h>
#include <drm/drm_edid.h>
-#include <drm/drm_utils.h>
+#include <drm/drm_panel_quirks.h>
struct drm_panel_match {
enum dmi_field field;
diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c
index 3a218fb592ce..813a204cd201 100644
--- a/drivers/gpu/drm/drm_panel_orientation_quirks.c
+++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c
@@ -12,7 +12,7 @@
#include <linux/export.h>
#include <linux/module.h>
#include <drm/drm_connector.h>
-#include <drm/drm_utils.h>
+#include <drm/drm_panel_quirks.h>
#ifdef CONFIG_DMI
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index c23a5de27eff..f1d4da168545 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -208,7 +208,7 @@
#include <drm/drm_gem.h>
#include <drm/drm_print.h>
#include <drm/drm_syncobj.h>
-#include <drm/drm_utils.h>
+#include <drm/drm_timeout.h>
#include "drm_internal.h"
@@ -1193,39 +1193,6 @@ err_free_points:
return timeout;
}
-/**
- * drm_timeout_abs_to_jiffies - calculate jiffies timeout from absolute value
- *
- * @timeout_nsec: timeout nsec component in ns, 0 for poll
- *
- * Calculate the timeout in jiffies from an absolute time in sec/nsec.
- */
-signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec)
-{
- ktime_t abs_timeout, now;
- u64 timeout_ns, timeout_jiffies64;
-
- /* make 0 timeout means poll - absolute 0 doesn't seem valid */
- if (timeout_nsec == 0)
- return 0;
-
- abs_timeout = ns_to_ktime(timeout_nsec);
- now = ktime_get();
-
- if (!ktime_after(abs_timeout, now))
- return 0;
-
- timeout_ns = ktime_to_ns(ktime_sub(abs_timeout, now));
-
- timeout_jiffies64 = nsecs_to_jiffies64(timeout_ns);
- /* clamp timeout to avoid infinite timeout */
- if (timeout_jiffies64 >= MAX_SCHEDULE_TIMEOUT - 1)
- return MAX_SCHEDULE_TIMEOUT - 1;
-
- return timeout_jiffies64 + 1;
-}
-EXPORT_SYMBOL(drm_timeout_abs_to_jiffies);
-
static int drm_syncobj_array_wait(struct drm_device *dev,
struct drm_file *file_private,
struct drm_syncobj_wait *wait,
diff --git a/drivers/gpu/drm/drm_timeout.c b/drivers/gpu/drm/drm_timeout.c
new file mode 100644
index 000000000000..1a823607c633
--- /dev/null
+++ b/drivers/gpu/drm/drm_timeout.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Timeout conversion helpers for wait ioctls.
+ *
+ * Copyright 2017 Red Hat
+ * Copyright 2016 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/export.h>
+#include <linux/jiffies.h>
+#include <linux/ktime.h>
+#include <linux/math64.h>
+#include <linux/sched.h>
+
+#include <drm/drm_timeout.h>
+
+/**
+ * drm_timeout_abs_to_jiffies - calculate jiffies timeout from absolute value
+ * @timeout_nsec: timeout nsec component in ns, 0 for poll
+ *
+ * Calculate the timeout in jiffies from an absolute time in ns. The result is
+ * clamped to MAX_SCHEDULE_TIMEOUT - 1 to avoid infinite timeouts.
+ *
+ * Returns:
+ * The number of jiffies until the given timeout, or the upper limit.
+ */
+signed long drm_timeout_abs_to_jiffies(s64 timeout_nsec)
+{
+ ktime_t abs_timeout, now;
+ u64 timeout_ns, timeout_jiffies64;
+
+ /* make 0 timeout means poll - absolute 0 doesn't seem valid */
+ if (timeout_nsec == 0)
+ return 0;
+
+ abs_timeout = ns_to_ktime(timeout_nsec);
+ now = ktime_get();
+
+ if (!ktime_after(abs_timeout, now))
+ return 0;
+
+ timeout_ns = ktime_to_ns(ktime_sub(abs_timeout, now));
+
+ timeout_jiffies64 = nsecs_to_jiffies64(timeout_ns);
+ /* clamp timeout to avoid infinite timeout */
+ if (timeout_jiffies64 >= MAX_SCHEDULE_TIMEOUT - 1)
+ return MAX_SCHEDULE_TIMEOUT - 1;
+
+ return timeout_jiffies64 + 1;
+}
+EXPORT_SYMBOL(drm_timeout_abs_to_jiffies);
+
+/**
+ * drm_timeout_rel_to_jiffies - calculate jiffies timeout from relative value
+ * @timeout_nsec: relative timeout in ns, 0 for poll
+ *
+ * Calculate the timeout in jiffies from a relative timeout in ns, for drivers
+ * whose UAPI expresses a wait as a duration rather than as a deadline.
+ *
+ * The result is clamped to MAX_JIFFY_OFFSET. That keeps it positive once it is
+ * converted to the signed long taken by dma_fence_wait_timeout() and friends,
+ * which matters on 32-bit, and keeps it distinct from MAX_SCHEDULE_TIMEOUT so
+ * that a finite wait is never understood as an infinite one.
+ *
+ * It's strongly discouraged to use relative timeouts in uAPIs, as they do not
+ * survive a restarted ioctl. A signal-interrupted ioctl is re-entered with the
+ * same arguments, so the duration starts counting from zero again. New uAPIs
+ * should take an absolute deadline and use drm_timeout_abs_to_jiffies().
+ *
+ * Returns:
+ * 0 if @timeout_nsec is 0. Otherwise the equivalent number of jiffies and
+ * clamped to MAX_JIFFY_OFFSET.
+ */
+unsigned long drm_timeout_rel_to_jiffies(u64 timeout_nsec)
+{
+ u64 secs;
+ u32 rem;
+
+ /* Make 0 timeout means poll, as for the absolute variant. */
+ if (timeout_nsec == 0)
+ return 0;
+
+ /*
+ * As nsecs_to_jiffies64() does not guard against overflow, split
+ * the timeout into whole seconds and nanoseconds. This way
+ * nsecs_to_jiffies64() is always handed a value below a second.
+ */
+ secs = div_u64_rem(timeout_nsec, NSEC_PER_SEC, &rem);
+ if (secs >= MAX_JIFFY_OFFSET / HZ)
+ return MAX_JIFFY_OFFSET;
+
+ return min_t(u64, MAX_JIFFY_OFFSET,
+ secs_to_jiffies(secs) + nsecs_to_jiffies64(rem) + 1);
+}
+EXPORT_SYMBOL(drm_timeout_rel_to_jiffies);
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index e1c9e2946b8a..82c238829921 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -26,7 +26,6 @@
#include <drm/drm_crtc.h>
#include <drm/drm_encoder.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/exynos_drm.h>
@@ -147,7 +146,6 @@ static const struct component_ops exynos_dp_ops = {
static int exynos_dp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *np;
struct exynos_dp_device *dp;
dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
@@ -163,18 +161,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
*/
platform_set_drvdata(pdev, dp);
- /* This is for the backward compatibility. */
- np = of_parse_phandle(dev->of_node, "panel", 0);
- if (np) {
- dp->plat_data.panel = of_drm_find_panel(np);
-
- of_node_put(np);
- if (IS_ERR(dp->plat_data.panel))
- return PTR_ERR(dp->plat_data.panel);
-
- goto out;
- }
-
if (of_get_display_timings(dev->of_node)) {
dp->plat_data.next_bridge = devm_drm_of_display_mode_bridge(dp->dev,
dp->dev->of_node,
@@ -189,19 +175,11 @@ static int exynos_dp_probe(struct platform_device *pdev)
dp->plat_data.power_off = exynos_dp_poweroff;
dp->plat_data.ops = &exynos_dp_ops;
-out:
dp->adp = analogix_dp_probe(dev, &dp->plat_data);
- if (IS_ERR(dp->adp)) {
- /*
- * The driver core does not invoke remove() for failed probes,
- * so release the probe-time panel reference here.
- */
- if (dp->plat_data.panel)
- drm_panel_put(dp->plat_data.panel);
+ if (IS_ERR(dp->adp))
return PTR_ERR(dp->adp);
- }
- if (dp->plat_data.panel || dp->plat_data.next_bridge)
+ if (dp->plat_data.next_bridge)
return component_add(&pdev->dev, &exynos_dp_ops);
else
return analogix_dp_finish_probe(dp->adp);
@@ -209,16 +187,6 @@ out:
static void exynos_dp_remove(struct platform_device *pdev)
{
- struct exynos_dp_device *dp = platform_get_drvdata(pdev);
-
- /*
- * Release the probe-time reference from of_drm_find_panel(). If bind
- * ran, the panel_bridge holds a second reference that devm cleanup
- * will release when the bridge is destroyed after remove() returns.
- */
- if (dp->plat_data.panel)
- drm_panel_put(dp->plat_data.panel);
-
component_del(&pdev->dev, &exynos_dp_ops);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 8641c9e84d4c..f412269d6323 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -10,9 +10,9 @@
#include <linux/fb.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_prime.h>
diff --git a/drivers/gpu/drm/gma500/fbdev.c b/drivers/gpu/drm/gma500/fbdev.c
index d1e93588234f..428912574f20 100644
--- a/drivers/gpu/drm/gma500/fbdev.c
+++ b/drivers/gpu/drm/gma500/fbdev.c
@@ -7,9 +7,9 @@
#include <linux/fb.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_framebuffer.h>
#include "gem.h"
diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c
index db0e36dd8722..219ee17de3f6 100644
--- a/drivers/gpu/drm/i915/display/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/display/intel_fbdev.c
@@ -38,10 +38,10 @@
#include <linux/vga_switcheroo.h>
#include <drm/clients/drm_client_setup.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/intel/display_parent_interface.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_framebuffer_helper.h>
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_wait.c b/drivers/gpu/drm/i915/gem/i915_gem_wait.c
index 2893df65c359..872d4045813a 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_wait.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_wait.c
@@ -7,6 +7,8 @@
#include <linux/dma-fence-chain.h>
#include <linux/jiffies.h>
+#include <drm/drm_timeout.h>
+
#include "gt/intel_engine.h"
#include "gt/intel_rps.h"
@@ -184,25 +186,12 @@ i915_gem_object_wait(struct drm_i915_gem_object *obj,
return !timeout ? -ETIME : 0;
}
-static inline unsigned long nsecs_to_jiffies_timeout(const u64 n)
-{
- /* nsecs_to_jiffies64() does not guard against overflow */
- if ((NSEC_PER_SEC % HZ) != 0 &&
- div_u64(n, NSEC_PER_SEC) >= MAX_JIFFY_OFFSET / HZ)
- return MAX_JIFFY_OFFSET;
-
- return min_t(u64, MAX_JIFFY_OFFSET, nsecs_to_jiffies64(n) + 1);
-}
-
static unsigned long to_wait_timeout(s64 timeout_ns)
{
if (timeout_ns < 0)
return MAX_SCHEDULE_TIMEOUT;
- if (timeout_ns == 0)
- return 0;
-
- return nsecs_to_jiffies_timeout(timeout_ns);
+ return drm_timeout_rel_to_jiffies(timeout_ns);
}
/**
diff --git a/drivers/gpu/drm/imagination/pvr_fw.c b/drivers/gpu/drm/imagination/pvr_fw.c
index c6c77b152342..c7988278df3f 100644
--- a/drivers/gpu/drm/imagination/pvr_fw.c
+++ b/drivers/gpu/drm/imagination/pvr_fw.c
@@ -278,37 +278,6 @@ pvr_fw_find_mmu_segment(struct pvr_device *pvr_dev, u32 addr, u32 size, void *fw
return -EINVAL;
}
-static int
-pvr_fw_create_fwif_connection_ctl(struct pvr_device *pvr_dev)
-{
- struct drm_device *drm_dev = from_pvr_device(pvr_dev);
- struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev;
-
- fw_dev->fwif_connection_ctl =
- pvr_fw_object_create_and_map_offset(pvr_dev,
- fw_dev->fw_heap_info.config_offset +
- PVR_ROGUE_FWIF_CONNECTION_CTL_OFFSET,
- sizeof(*fw_dev->fwif_connection_ctl),
- PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
- NULL, NULL,
- &fw_dev->mem.fwif_connection_ctl_obj);
- if (IS_ERR(fw_dev->fwif_connection_ctl)) {
- drm_err(drm_dev,
- "Unable to allocate FWIF connection control memory\n");
- return PTR_ERR(fw_dev->fwif_connection_ctl);
- }
-
- return 0;
-}
-
-static void
-pvr_fw_fini_fwif_connection_ctl(struct pvr_device *pvr_dev)
-{
- struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev;
-
- pvr_fw_object_unmap_and_destroy(fw_dev->mem.fwif_connection_ctl_obj);
-}
-
static void
fw_osinit_init(void *cpu_ptr, void *priv)
{
@@ -459,21 +428,34 @@ pvr_fw_create_structures(struct pvr_device *pvr_dev)
struct pvr_fw_mem *fw_mem = &fw_dev->mem;
int err;
+ err = pvr_fw_object_create_offset(pvr_dev,
+ fw_dev->fw_heap_info.config_offset +
+ PVR_ROGUE_FWIF_CONNECTION_CTL_OFFSET,
+ sizeof(struct rogue_fwif_connection_ctl),
+ PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
+ NULL, NULL,
+ &fw_mem->fwif_connection_ctl_obj);
+ if (err) {
+ drm_err(drm_dev,
+ "Unable to allocate FWIF connection control memory\n");
+ return err;
+ }
+
fw_dev->power_sync = pvr_fw_object_create_and_map(pvr_dev, sizeof(*fw_dev->power_sync),
PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
NULL, NULL, &fw_mem->power_sync_obj);
if (IS_ERR(fw_dev->power_sync)) {
drm_err(drm_dev, "Unable to allocate FW power_sync structure\n");
- return PTR_ERR(fw_dev->power_sync);
+ err = PTR_ERR(fw_dev->power_sync);
+ goto err_release_connection_ctl;
}
- fw_dev->hwrinfobuf = pvr_fw_object_create_and_map(pvr_dev, sizeof(*fw_dev->hwrinfobuf),
- PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
- NULL, NULL, &fw_mem->hwrinfobuf_obj);
- if (IS_ERR(fw_dev->hwrinfobuf)) {
+ err = pvr_fw_object_create(pvr_dev, sizeof(struct rogue_fwif_hwrinfobuf),
+ PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
+ NULL, NULL, &fw_mem->hwrinfobuf_obj);
+ if (err) {
drm_err(drm_dev,
"Unable to allocate FW hwrinfobuf structure\n");
- err = PTR_ERR(fw_dev->hwrinfobuf);
goto err_release_power_sync;
}
@@ -536,16 +518,14 @@ pvr_fw_create_structures(struct pvr_device *pvr_dev)
goto err_fw_trace_fini;
}
- fw_dev->fwif_osinit =
- pvr_fw_object_create_and_map_offset(pvr_dev,
- fw_dev->fw_heap_info.config_offset +
- PVR_ROGUE_FWIF_OSINIT_OFFSET,
- sizeof(*fw_dev->fwif_osinit),
- PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
- fw_osinit_init, pvr_dev, &fw_mem->osinit_obj);
- if (IS_ERR(fw_dev->fwif_osinit)) {
+ err = pvr_fw_object_create_offset(pvr_dev,
+ fw_dev->fw_heap_info.config_offset +
+ PVR_ROGUE_FWIF_OSINIT_OFFSET,
+ sizeof(struct rogue_fwif_osinit),
+ PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
+ fw_osinit_init, pvr_dev, &fw_mem->osinit_obj);
+ if (err) {
drm_err(drm_dev, "Unable to allocate FW OSINIT structure\n");
- err = PTR_ERR(fw_dev->fwif_osinit);
goto err_release_osdata;
}
@@ -565,7 +545,7 @@ pvr_fw_create_structures(struct pvr_device *pvr_dev)
return 0;
err_release_osinit:
- pvr_fw_object_unmap_and_destroy(fw_mem->osinit_obj);
+ pvr_fw_object_destroy(fw_mem->osinit_obj);
err_release_osdata:
pvr_fw_object_unmap_and_destroy(fw_mem->osdata_obj);
@@ -589,11 +569,14 @@ err_release_mmucache_sync_obj:
pvr_fw_object_destroy(fw_mem->mmucache_sync_obj);
err_release_hwrinfobuf:
- pvr_fw_object_unmap_and_destroy(fw_mem->hwrinfobuf_obj);
+ pvr_fw_object_destroy(fw_mem->hwrinfobuf_obj);
err_release_power_sync:
pvr_fw_object_unmap_and_destroy(fw_mem->power_sync_obj);
+err_release_connection_ctl:
+ pvr_fw_object_destroy(fw_mem->fwif_connection_ctl_obj);
+
return err;
}
@@ -611,10 +594,11 @@ pvr_fw_destroy_structures(struct pvr_device *pvr_dev)
pvr_fw_object_unmap_and_destroy(fw_mem->sysinit_obj);
pvr_fw_object_destroy(fw_mem->mmucache_sync_obj);
- pvr_fw_object_unmap_and_destroy(fw_mem->hwrinfobuf_obj);
+ pvr_fw_object_destroy(fw_mem->hwrinfobuf_obj);
pvr_fw_object_unmap_and_destroy(fw_mem->power_sync_obj);
pvr_fw_object_unmap_and_destroy(fw_mem->osdata_obj);
- pvr_fw_object_unmap_and_destroy(fw_mem->osinit_obj);
+ pvr_fw_object_destroy(fw_mem->osinit_obj);
+ pvr_fw_object_destroy(fw_mem->fwif_connection_ctl_obj);
}
/**
@@ -755,10 +739,6 @@ pvr_fw_process(struct pvr_device *pvr_dev)
pvr_fw_object_vunmap(fw_mem->code_obj);
fw_code_ptr = NULL;
- err = pvr_fw_create_fwif_connection_ctl(pvr_dev);
- if (err)
- goto err_free_kdata;
-
return 0;
err_free_kdata:
@@ -842,8 +822,6 @@ pvr_fw_cleanup(struct pvr_device *pvr_dev)
{
struct pvr_fw_mem *fw_mem = &pvr_dev->fw_dev.mem;
- pvr_fw_fini_fwif_connection_ctl(pvr_dev);
-
kfree(fw_mem->core_data);
kfree(fw_mem->core_code);
kfree(fw_mem->data);
@@ -1403,6 +1381,46 @@ pvr_fw_object_create_and_map_offset(struct pvr_device *pvr_dev,
}
/**
+ * pvr_fw_object_create_offset() - Create a FW object and map to firmware
+ * at the provided offset.
+ * @pvr_dev: PowerVR device pointer.
+ * @fw_addr: Base address of desired FW mapping, offset from start of FW heap.
+ * If a specific FW address is not required, pass %U32_MAX.
+ * @size: Size of object, in bytes.
+ * @flags: Options which affect both this operation and future mapping
+ * operations performed on the returned object. Must be a combination of
+ * DRM_PVR_BO_* and/or PVR_BO_* flags.
+ * @init: Initialisation callback.
+ * @init_priv: Private pointer to pass to initialisation callback.
+ * @fw_obj_out: Pointer to location to store created object pointer.
+ *
+ * %DRM_PVR_BO_DEVICE_PM_FW_PROTECT is implied for all FW objects. Consequently,
+ * this function will fail if @flags has %DRM_PVR_BO_CPU_ALLOW_USERSPACE_ACCESS
+ * set.
+ *
+ * Returns:
+ * * 0 on success, or
+ * * Any error returned by pvr_fw_object_create_and_map().
+ */
+int
+pvr_fw_object_create_offset(struct pvr_device *pvr_dev, u32 fw_addr,
+ size_t size, u64 flags,
+ void (*init)(void *cpu_ptr, void *priv),
+ void *init_priv, struct pvr_fw_object **fw_obj_out)
+{
+ void *cpu_ptr;
+
+ cpu_ptr = pvr_fw_object_create_and_map_offset(pvr_dev, fw_addr, size, flags,
+ init, init_priv, fw_obj_out);
+ if (IS_ERR(cpu_ptr))
+ return PTR_ERR(cpu_ptr);
+
+ pvr_fw_object_vunmap(*fw_obj_out);
+
+ return 0;
+}
+
+/**
* pvr_fw_object_destroy() - Destroy a pvr_fw_object
* @fw_obj: Pointer to object to destroy.
*/
diff --git a/drivers/gpu/drm/imagination/pvr_fw.h b/drivers/gpu/drm/imagination/pvr_fw.h
index 4b25291135b6..626a1fdb6a4d 100644
--- a/drivers/gpu/drm/imagination/pvr_fw.h
+++ b/drivers/gpu/drm/imagination/pvr_fw.h
@@ -349,30 +349,18 @@ struct pvr_fw_device {
/** @fw_mm_base: Base address of address space managed by @fw_mm. */
u64 fw_mm_base;
- /**
- * @fwif_connection_ctl: Pointer to CPU mapping of FWIF connection
- * control structure.
- */
- struct rogue_fwif_connection_ctl *fwif_connection_ctl;
-
/** @fwif_sysinit: Pointer to CPU mapping of FW SYSINIT structure. */
struct rogue_fwif_sysinit *fwif_sysinit;
/** @fwif_sysdata: Pointer to CPU mapping of FW SYSDATA structure. */
struct rogue_fwif_sysdata *fwif_sysdata;
- /** @fwif_osinit: Pointer to CPU mapping of FW OSINIT structure. */
- struct rogue_fwif_osinit *fwif_osinit;
-
/** @fwif_osdata: Pointer to CPU mapping of FW OSDATA structure. */
struct rogue_fwif_osdata *fwif_osdata;
/** @power_sync: Pointer to CPU mapping of power sync state. */
u32 *power_sync;
- /** @hwrinfobuf: Pointer to CPU mapping of FW HWR info buffer. */
- struct rogue_fwif_hwrinfobuf *hwrinfobuf;
-
/** @fw_trace: Device firmware trace buffer state. */
struct pvr_fw_trace fw_trace;
@@ -430,6 +418,12 @@ void *pvr_fw_object_create_and_map(struct pvr_device *pvr_dev, size_t size, u64
void (*init)(void *cpu_ptr, void *priv),
void *init_priv, struct pvr_fw_object **pvr_obj_out);
+int
+pvr_fw_object_create_offset(struct pvr_device *pvr_dev, u32 fw_addr,
+ size_t size, u64 flags,
+ void (*init)(void *cpu_ptr, void *priv),
+ void *init_priv, struct pvr_fw_object **pvr_obj_out);
+
void *
pvr_fw_object_create_and_map_offset(struct pvr_device *pvr_dev, u32 dev_offset, size_t size,
u64 flags, void (*init)(void *cpu_ptr, void *priv),
diff --git a/drivers/gpu/drm/imx/dc/dc-kms.c b/drivers/gpu/drm/imx/dc/dc-kms.c
index a9adcfc68b84..0e2ce6a42548 100644
--- a/drivers/gpu/drm/imx/dc/dc-kms.c
+++ b/drivers/gpu/drm/imx/dc/dc-kms.c
@@ -15,6 +15,7 @@
#include <drm/drm_encoder.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_mode_config.h>
+#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
diff --git a/drivers/gpu/drm/imx/dcss/Kconfig b/drivers/gpu/drm/imx/dcss/Kconfig
index e014ed3ae66c..d278bebfc33c 100644
--- a/drivers/gpu/drm/imx/dcss/Kconfig
+++ b/drivers/gpu/drm/imx/dcss/Kconfig
@@ -6,6 +6,7 @@ config DRM_IMX_DCSS
select DRM_DISPLAY_HELPER
select DRM_BRIDGE_CONNECTOR
select DRM_GEM_DMA_HELPER
+ select DRM_PANEL
select VIDEOMODE_HELPERS
depends on DRM && ((ARCH_MXC && ARM64) || COMPILE_TEST)
help
diff --git a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c
index c67fe80b8115..8f0a0d4cf61a 100644
--- a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c
+++ b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c
@@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: 2020 Marian Cichy <M.Cichy@pengutronix.de>
#include <drm/clients/drm_client_setup.h>
+#include <drm/drm_atomic.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_damage_helper.h>
@@ -14,10 +15,11 @@
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_of.h>
+#include <drm/drm_plane_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include <drm/drm_vblank.h>
+#include <drm/drm_vblank_helper.h>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
@@ -101,7 +103,9 @@
struct imx_lcdc {
struct drm_device drm;
- struct drm_simple_display_pipe pipe;
+ struct drm_plane plane;
+ struct drm_crtc crtc;
+ struct drm_encoder encoder;
struct drm_connector *connector;
void __iomem *base;
@@ -134,14 +138,15 @@ static unsigned int imx_lcdc_get_format(unsigned int drm_format)
}
}
-static void imx_lcdc_update_hw_registers(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *old_state,
+static void imx_lcdc_update_hw_registers(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state,
+ struct drm_crtc_state *new_crtc_state,
+ struct drm_plane_state *new_state,
bool mode_set)
{
- struct drm_crtc *crtc = &pipe->crtc;
- struct drm_plane_state *new_state = pipe->plane.state;
+ struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(crtc->dev);
+ const struct drm_display_mode *mode = &new_crtc_state->mode;
struct drm_framebuffer *fb = new_state->fb;
- struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev);
u32 lpcr, lvcr, lhcr;
u32 framesize;
dma_addr_t addr;
@@ -154,24 +159,24 @@ static void imx_lcdc_update_hw_registers(struct drm_simple_display_pipe *pipe,
return;
/* Disable PER clock to make register write possible */
- if (old_state && old_state->crtc && old_state->crtc->enabled)
+ if (old_crtc_state && old_crtc_state->enable)
clk_disable_unprepare(lcdc->clk_per);
/* Framesize */
- framesize = FIELD_PREP(IMX21LCDC_LSR_XMAX, crtc->mode.hdisplay >> 4) |
- FIELD_PREP(IMX21LCDC_LSR_YMAX, crtc->mode.vdisplay);
+ framesize = FIELD_PREP(IMX21LCDC_LSR_XMAX, mode->hdisplay >> 4) |
+ FIELD_PREP(IMX21LCDC_LSR_YMAX, mode->vdisplay);
writel(framesize, lcdc->base + IMX21LCDC_LSR);
/* HSYNC */
- lhcr = FIELD_PREP(IMX21LCDC_LHCR_HFPORCH, crtc->mode.hsync_start - crtc->mode.hdisplay - 1) |
- FIELD_PREP(IMX21LCDC_LHCR_HWIDTH, crtc->mode.hsync_end - crtc->mode.hsync_start - 1) |
- FIELD_PREP(IMX21LCDC_LHCR_HBPORCH, crtc->mode.htotal - crtc->mode.hsync_end - 3);
+ lhcr = FIELD_PREP(IMX21LCDC_LHCR_HFPORCH, mode->hsync_start - mode->hdisplay - 1) |
+ FIELD_PREP(IMX21LCDC_LHCR_HWIDTH, mode->hsync_end - mode->hsync_start - 1) |
+ FIELD_PREP(IMX21LCDC_LHCR_HBPORCH, mode->htotal - mode->hsync_end - 3);
writel(lhcr, lcdc->base + IMX21LCDC_LHCR);
/* VSYNC */
- lvcr = FIELD_PREP(IMX21LCDC_LVCR_VFPORCH, crtc->mode.vsync_start - crtc->mode.vdisplay) |
- FIELD_PREP(IMX21LCDC_LVCR_VWIDTH, crtc->mode.vsync_end - crtc->mode.vsync_start) |
- FIELD_PREP(IMX21LCDC_LVCR_VBPORCH, crtc->mode.vtotal - crtc->mode.vsync_end);
+ lvcr = FIELD_PREP(IMX21LCDC_LVCR_VFPORCH, mode->vsync_start - mode->vdisplay) |
+ FIELD_PREP(IMX21LCDC_LVCR_VWIDTH, mode->vsync_end - mode->vsync_start) |
+ FIELD_PREP(IMX21LCDC_LVCR_VBPORCH, mode->vtotal - mode->vsync_end);
writel(lvcr, lcdc->base + IMX21LCDC_LVCR);
lpcr = readl(lcdc->base + IMX21LCDC_LPCR);
@@ -183,19 +188,20 @@ static void imx_lcdc_update_hw_registers(struct drm_simple_display_pipe *pipe,
writel(new_state->fb->pitches[0] / 4, lcdc->base + IMX21LCDC_LVPWR);
/* Enable PER clock */
- if (new_state->crtc->enabled)
+ if (new_crtc_state->enable)
clk_prepare_enable(lcdc->clk_per);
}
-static void imx_lcdc_pipe_enable(struct drm_simple_display_pipe *pipe,
- struct drm_crtc_state *crtc_state,
- struct drm_plane_state *plane_state)
+static void imx_lcdc_crtc_helper_atomic_enable(struct drm_crtc *crtc,
+ struct drm_atomic_commit *commit)
{
int ret;
int clk_div;
int bpp;
- struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev);
- struct drm_display_mode *mode = &pipe->crtc.mode;
+ struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(crtc->dev);
+ struct drm_crtc_state *cstate = drm_atomic_get_new_crtc_state(commit, crtc);
+ struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(commit, &lcdc->plane);
+ struct drm_display_mode *mode = &cstate->mode;
struct drm_display_info *disp_info = &lcdc->connector->display_info;
const int hsync_pol = (mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : 1;
const int vsync_pol = (mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : 1;
@@ -206,7 +212,7 @@ static void imx_lcdc_pipe_enable(struct drm_simple_display_pipe *pipe,
clk_div = DIV_ROUND_CLOSEST_ULL(clk_get_rate(lcdc->clk_per),
mode->clock * 1000);
- bpp = imx_lcdc_get_format(plane_state->fb->format->format);
+ bpp = imx_lcdc_get_format(pstate->fb->format->format);
writel(FIELD_PREP(IMX21LCDC_LPCR_PCD, clk_div - 1) |
FIELD_PREP(IMX21LCDC_LPCR_LPPOL, hsync_pol) |
@@ -230,40 +236,46 @@ static void imx_lcdc_pipe_enable(struct drm_simple_display_pipe *pipe,
ret = clk_prepare_enable(lcdc->clk_ipg);
if (ret) {
- dev_err(pipe->crtc.dev->dev, "Cannot enable ipg clock: %pe\n", ERR_PTR(ret));
+ dev_err(crtc->dev->dev, "Cannot enable ipg clock: %pe\n", ERR_PTR(ret));
return;
}
ret = clk_prepare_enable(lcdc->clk_ahb);
if (ret) {
- dev_err(pipe->crtc.dev->dev, "Cannot enable ahb clock: %pe\n", ERR_PTR(ret));
+ dev_err(crtc->dev->dev, "Cannot enable ahb clock: %pe\n", ERR_PTR(ret));
clk_disable_unprepare(lcdc->clk_ipg);
return;
}
- imx_lcdc_update_hw_registers(pipe, NULL, true);
+ imx_lcdc_update_hw_registers(crtc, NULL, cstate, pstate, true);
/* Enable VBLANK Interrupt */
writel(INTR_EOF, lcdc->base + IMX21LCDC_LIER);
+
+ drm_crtc_vblank_on(crtc);
}
-static void imx_lcdc_pipe_disable(struct drm_simple_display_pipe *pipe)
+static void imx_lcdc_crtc_helper_atomic_disable(struct drm_crtc *crtc,
+ struct drm_atomic_commit *commit)
{
- struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev);
- struct drm_crtc *crtc = &lcdc->pipe.crtc;
+ struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(commit, crtc);
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(commit, crtc);
+ struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(crtc->dev);
struct drm_pending_vblank_event *event;
+ drm_crtc_vblank_off(crtc);
+
clk_disable_unprepare(lcdc->clk_ahb);
clk_disable_unprepare(lcdc->clk_ipg);
- if (pipe->crtc.enabled)
+ if (old_crtc_state->enable)
clk_disable_unprepare(lcdc->clk_per);
spin_lock_irq(&lcdc->drm.event_lock);
- event = crtc->state->event;
+ event = new_crtc_state->event;
if (event) {
- crtc->state->event = NULL;
+ new_crtc_state->event = NULL;
drm_crtc_send_vblank_event(crtc, event);
}
spin_unlock_irq(&lcdc->drm.event_lock);
@@ -272,65 +284,132 @@ static void imx_lcdc_pipe_disable(struct drm_simple_display_pipe *pipe)
writel(0, lcdc->base + IMX21LCDC_LIER);
}
-static int imx_lcdc_pipe_check(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *plane_state,
- struct drm_crtc_state *crtc_state)
+static int imx_lcdc_crtc_helper_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_commit *commit)
{
+ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(commit, crtc);
+ struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(commit, crtc);
const struct drm_display_mode *mode = &crtc_state->mode;
- const struct drm_display_mode *old_mode = &pipe->crtc.state->mode;
+ const struct drm_display_mode *old_mode = &old_crtc_state->mode;
+ int ret;
+
+ if (crtc_state->enable) {
+ ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state);
+ if (ret)
+ return ret;
+ }
- if (mode->hdisplay < LCDC_MIN_XRES || mode->hdisplay > LCDC_MAX_XRES ||
- mode->vdisplay < LCDC_MIN_YRES || mode->vdisplay > LCDC_MAX_YRES ||
- mode->hdisplay % 0x10) { /* must be multiple of 16 */
- drm_err(pipe->crtc.dev, "unsupported display mode (%u x %u)\n",
+ if (crtc_state->enable &&
+ (mode->hdisplay < LCDC_MIN_XRES || mode->hdisplay > LCDC_MAX_XRES ||
+ mode->vdisplay < LCDC_MIN_YRES || mode->vdisplay > LCDC_MAX_YRES ||
+ mode->hdisplay % 0x10)) { /* must be multiple of 16 */
+ drm_err(crtc->dev, "unsupported display mode (%u x %u)\n",
mode->hdisplay, mode->vdisplay);
return -EINVAL;
}
- crtc_state->mode_changed =
- old_mode->hdisplay != mode->hdisplay ||
- old_mode->vdisplay != mode->vdisplay;
+ if (old_mode->hdisplay != mode->hdisplay ||
+ old_mode->vdisplay != mode->vdisplay)
+ crtc_state->mode_changed = true;
- return 0;
+ return drm_atomic_add_affected_planes(commit, crtc);
}
-static void imx_lcdc_pipe_update(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *old_state)
+static void imx_lcdc_plane_helper_atomic_update(struct drm_plane *plane,
+ struct drm_atomic_commit *commit)
{
- struct drm_crtc *crtc = &pipe->crtc;
- struct drm_pending_vblank_event *event = crtc->state->event;
- struct drm_plane_state *new_state = pipe->plane.state;
+ struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(commit, plane);
+ struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(commit, plane);
+ struct drm_crtc *crtc = new_state->crtc;
+ struct drm_crtc_state *old_crtc_state = NULL;
+ struct drm_crtc_state *new_crtc_state;
struct drm_framebuffer *fb = new_state->fb;
struct drm_framebuffer *old_fb = old_state->fb;
struct drm_crtc *old_crtc = old_state->crtc;
bool mode_changed = false;
+ if (!fb || !crtc)
+ return;
+
+ if (old_crtc)
+ old_crtc_state = drm_atomic_get_old_crtc_state(commit, old_crtc);
+
+ new_crtc_state = drm_atomic_get_new_crtc_state(commit, crtc);
+ if (!new_crtc_state)
+ return;
+
if (old_fb && old_fb->format != fb->format)
mode_changed = true;
else if (old_crtc != crtc)
mode_changed = true;
- imx_lcdc_update_hw_registers(pipe, old_state, mode_changed);
+ if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
+ imx_lcdc_update_hw_registers(crtc, old_crtc_state, new_crtc_state,
+ new_state, mode_changed);
+}
- if (event) {
- crtc->state->event = NULL;
+static int imx_lcdc_plane_helper_atomic_check(struct drm_plane *plane,
+ struct drm_atomic_commit *commit)
+{
+ struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(commit, plane);
+ struct drm_crtc_state *crtc_state = NULL;
- spin_lock_irq(&crtc->dev->event_lock);
+ if (plane_state->crtc) {
+ crtc_state = drm_atomic_get_crtc_state(commit, plane_state->crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+ }
- if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0)
- drm_crtc_arm_vblank_event(crtc, event);
- else
- drm_crtc_send_vblank_event(crtc, event);
+ return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
+ DRM_PLANE_NO_SCALING,
+ DRM_PLANE_NO_SCALING,
+ false, false);
+}
- spin_unlock_irq(&crtc->dev->event_lock);
- }
+static const struct drm_plane_helper_funcs imx_lcdc_plane_helper_funcs = {
+ .prepare_fb = drm_gem_plane_helper_prepare_fb,
+ .atomic_check = imx_lcdc_plane_helper_atomic_check,
+ .atomic_update = imx_lcdc_plane_helper_atomic_update,
+};
+
+static const struct drm_plane_funcs imx_lcdc_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = drm_plane_cleanup,
+ .atomic_create_state = drm_atomic_helper_plane_create_state,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static const struct drm_crtc_helper_funcs imx_lcdc_crtc_helper_funcs = {
+ .atomic_check = imx_lcdc_crtc_helper_atomic_check,
+ .atomic_enable = imx_lcdc_crtc_helper_atomic_enable,
+ .atomic_disable = imx_lcdc_crtc_helper_atomic_disable,
+ .atomic_flush = drm_crtc_vblank_atomic_flush,
+};
+
+static int imx_lcdc_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+ return 0;
}
-static const struct drm_simple_display_pipe_funcs imx_lcdc_pipe_funcs = {
- .enable = imx_lcdc_pipe_enable,
- .disable = imx_lcdc_pipe_disable,
- .check = imx_lcdc_pipe_check,
- .update = imx_lcdc_pipe_update,
+static void imx_lcdc_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+}
+
+static const struct drm_crtc_funcs imx_lcdc_crtc_funcs = {
+ .atomic_create_state = drm_atomic_helper_crtc_create_state,
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .enable_vblank = imx_lcdc_crtc_enable_vblank,
+ .disable_vblank = imx_lcdc_crtc_disable_vblank,
+};
+
+static const struct drm_encoder_funcs imx_lcdc_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
};
static const struct drm_mode_config_funcs imx_lcdc_mode_config_funcs = {
@@ -368,7 +447,7 @@ MODULE_DEVICE_TABLE(of, imx_lcdc_of_dev_id);
static irqreturn_t imx_lcdc_irq_handler(int irq, void *arg)
{
struct imx_lcdc *lcdc = arg;
- struct drm_crtc *crtc = &lcdc->pipe.crtc;
+ struct drm_crtc *crtc = &lcdc->crtc;
unsigned int status;
status = readl(lcdc->base + IMX21LCDC_LISR);
@@ -386,6 +465,9 @@ static int imx_lcdc_probe(struct platform_device *pdev)
struct imx_lcdc *lcdc;
struct drm_device *drm;
struct drm_bridge *bridge;
+ struct drm_plane *plane;
+ struct drm_crtc *crtc;
+ struct drm_encoder *encoder;
int irq;
int ret;
struct device *dev = &pdev->dev;
@@ -427,23 +509,40 @@ static int imx_lcdc_probe(struct platform_device *pdev)
if (ret)
return dev_err_probe(dev, ret, "Cannot initialize mode configuration structure\n");
- /* CRTC, Plane, Encoder */
- ret = drm_simple_display_pipe_init(drm, &lcdc->pipe,
- &imx_lcdc_pipe_funcs,
- imx_lcdc_formats,
- ARRAY_SIZE(imx_lcdc_formats), NULL, NULL);
+ plane = &lcdc->plane;
+ ret = drm_universal_plane_init(drm, plane, 0,
+ &imx_lcdc_plane_funcs,
+ imx_lcdc_formats,
+ ARRAY_SIZE(imx_lcdc_formats),
+ NULL,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret < 0)
+ return dev_err_probe(drm->dev, ret, "Cannot initialize primary plane\n");
+ drm_plane_helper_add(plane, &imx_lcdc_plane_helper_funcs);
+
+ crtc = &lcdc->crtc;
+ ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL,
+ &imx_lcdc_crtc_funcs, NULL);
+ if (ret < 0)
+ return dev_err_probe(drm->dev, ret, "Cannot initialize CRTC\n");
+ drm_crtc_helper_add(crtc, &imx_lcdc_crtc_helper_funcs);
+
+ encoder = &lcdc->encoder;
+ ret = drm_encoder_init(drm, encoder, &imx_lcdc_encoder_funcs,
+ DRM_MODE_ENCODER_NONE, NULL);
if (ret < 0)
- return dev_err_probe(drm->dev, ret, "Cannot setup simple display pipe\n");
+ return dev_err_probe(drm->dev, ret, "Cannot initialize encoder\n");
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
if (ret < 0)
return dev_err_probe(drm->dev, ret, "Failed to initialize vblank\n");
- ret = drm_bridge_attach(&lcdc->pipe.encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+ ret = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret)
return dev_err_probe(drm->dev, ret, "Cannot attach bridge\n");
- lcdc->connector = drm_bridge_connector_init(drm, &lcdc->pipe.encoder);
+ lcdc->connector = drm_bridge_connector_init(drm, encoder);
if (IS_ERR(lcdc->connector))
return dev_err_probe(drm->dev, PTR_ERR(lcdc->connector), "Cannot init bridge connector\n");
@@ -482,7 +581,9 @@ static int imx_lcdc_probe(struct platform_device *pdev)
drm->mode_config.funcs = &imx_lcdc_mode_config_funcs;
drm->mode_config.helper_private = &imx_lcdc_mode_config_helpers;
- drm_mode_config_reset(drm);
+ ret = drm_mode_config_create_initial_state(drm);
+ if (ret)
+ return dev_err_probe(dev, ret, "Cannot create initial state\n");
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
diff --git a/drivers/gpu/drm/ingenic/Kconfig b/drivers/gpu/drm/ingenic/Kconfig
index 04ecfb0c5dd6..987ed42f6f7a 100644
--- a/drivers/gpu/drm/ingenic/Kconfig
+++ b/drivers/gpu/drm/ingenic/Kconfig
@@ -7,6 +7,7 @@ config DRM_INGENIC
depends on COMMON_CLK
select DRM_BRIDGE
select DRM_CLIENT_SELECTION
+ select DRM_PANEL
select DRM_PANEL_BRIDGE
select DRM_KMS_HELPER
select DRM_DISPLAY_HELPER
diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c
index 0c73860bb501..97e1dc541c2e 100644
--- a/drivers/gpu/drm/lima/lima_gem.c
+++ b/drivers/gpu/drm/lima/lima_gem.c
@@ -10,7 +10,7 @@
#include <drm/drm_file.h>
#include <drm/drm_syncobj.h>
-#include <drm/drm_utils.h>
+#include <drm/drm_timeout.h>
#include <drm/lima_drm.h>
diff --git a/drivers/gpu/drm/logicvc/Kconfig b/drivers/gpu/drm/logicvc/Kconfig
index 11aae1626199..95cdc5cb8cd5 100644
--- a/drivers/gpu/drm/logicvc/Kconfig
+++ b/drivers/gpu/drm/logicvc/Kconfig
@@ -5,6 +5,7 @@ config DRM_LOGICVC
select DRM_CLIENT_SELECTION
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
+ select DRM_PANEL
select REGMAP
select REGMAP_MMIO
help
diff --git a/drivers/gpu/drm/mcde/Kconfig b/drivers/gpu/drm/mcde/Kconfig
index 3516c8d2a5d9..81e7d3796c06 100644
--- a/drivers/gpu/drm/mcde/Kconfig
+++ b/drivers/gpu/drm/mcde/Kconfig
@@ -9,7 +9,7 @@ config DRM_MCDE
select DRM_CLIENT_SELECTION
select DRM_MIPI_DSI
select DRM_BRIDGE
- select DRM_PANEL_BRIDGE
+ select DRM_PANEL
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
help
diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c
index af1b8c466a02..281f5b3274bd 100644
--- a/drivers/gpu/drm/mcde/mcde_display.c
+++ b/drivers/gpu/drm/mcde/mcde_display.c
@@ -18,6 +18,7 @@
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_bridge.h>
#include <drm/drm_vblank.h>
diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c
index ce078aa3910f..daac8d67913d 100644
--- a/drivers/gpu/drm/mcde/mcde_dsi.c
+++ b/drivers/gpu/drm/mcde/mcde_dsi.c
@@ -11,17 +11,15 @@
#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>
-#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_encoder.h>
#include <drm/drm_mipi_dsi.h>
-#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
-#include <drm/drm_probe_helper.h>
#include "mcde_drm.h"
#include "mcde_dsi_regs.h"
@@ -39,7 +37,6 @@ struct mcde_dsi {
struct device *dev;
struct mcde *mcde;
struct drm_bridge bridge;
- struct drm_panel *panel;
struct mipi_dsi_host dsi_host;
struct mipi_dsi_device *mdsi;
const struct drm_display_mode *mode;
@@ -1076,7 +1073,6 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
struct drm_device *drm = data;
struct mcde *mcde = to_mcde(drm);
struct mcde_dsi *d = dev_get_drvdata(dev);
- struct drm_panel *panel = NULL;
struct drm_bridge *bridge __free(drm_bridge_put) = NULL;
if (!of_get_available_child_count(dev->of_node)) {
@@ -1104,40 +1100,21 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
/* Look for a panel as a child to this node */
for_each_available_child_of_node_scoped(dev->of_node, child) {
- panel = of_drm_find_panel(child);
- if (IS_ERR(panel)) {
- dev_err(dev, "failed to find panel try bridge (%ld)\n",
- PTR_ERR(panel));
- panel = NULL;
-
- bridge = of_drm_find_and_get_bridge(child);
- if (!bridge) {
- dev_err(dev, "failed to find bridge\n");
- return -EINVAL;
- }
+ bridge = of_drm_find_and_get_bridge(child);
+ if (!bridge) {
+ dev_err(dev, "failed to find bridge\n");
+ return -EINVAL;
}
- if (panel || bridge)
- break;
+ break;
}
- if (panel) {
- bridge = drm_panel_bridge_add_typed(panel,
- DRM_MODE_CONNECTOR_DSI);
- drm_panel_put(panel);
- if (IS_ERR(bridge)) {
- dev_err(dev, "error adding panel bridge\n");
- return PTR_ERR(bridge);
- }
- drm_bridge_get(bridge);
- dev_info(dev, "connected to panel\n");
- d->panel = panel;
- } else if (bridge) {
+ if (!bridge) {
+ dev_err(dev, "no bridge\n");
+ return -ENODEV;
+ } else if (!drm_bridge_is_panel(bridge)) {
/* TODO: AV8100 HDMI encoder goes here for example */
dev_info(dev, "connected to non-panel bridge (unsupported)\n");
return -ENODEV;
- } else {
- dev_err(dev, "no panel or bridge\n");
- return -ENODEV;
}
d->bridge.next_bridge = drm_bridge_get(bridge);
@@ -1159,8 +1136,6 @@ static void mcde_dsi_unbind(struct device *dev, struct device *master,
{
struct mcde_dsi *d = dev_get_drvdata(dev);
- if (d->panel)
- drm_panel_bridge_remove(d->bridge.next_bridge);
regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET,
PRCM_DSI_SW_RESET_DSI0_SW_RESETN, 0);
}
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 4dcbd9b99d06..6abe30bdff12 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -15,6 +15,7 @@
#include <drm/display/drm_dp_aux_bus.h>
#include <drm/display/drm_hdmi_audio_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_panel.h>
#include "msm_drv.h"
#include "msm_kms.h"
diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
index 3c9f01ed6271..c726fc628a08 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.c
+++ b/drivers/gpu/drm/msm/dsi/dsi.c
@@ -5,6 +5,8 @@
#include "dsi.h"
+#include <drm/drm_panel.h>
+
bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
{
unsigned long host_flags = msm_dsi_host_get_mode_flags(msm_dsi->host);
@@ -267,4 +269,3 @@ void msm_dsi_snapshot(struct msm_disp_state *disp_state, struct msm_dsi *msm_dsi
msm_dsi_host_snapshot(disp_state, msm_dsi->host);
msm_dsi_phy_snapshot(disp_state, msm_dsi->phy);
}
-
diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c
index f12701e286ec..d05307bfa123 100644
--- a/drivers/gpu/drm/msm/msm_debugfs.c
+++ b/drivers/gpu/drm/msm/msm_debugfs.c
@@ -9,8 +9,8 @@
#include <linux/debugfs.h>
#include <linux/fault-inject.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_debugfs.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_file.h>
#include <drm/drm_framebuffer.h>
diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c
index dd6d6c507d77..f37cc3f97a21 100644
--- a/drivers/gpu/drm/msm/msm_fbdev.c
+++ b/drivers/gpu/drm/msm/msm_fbdev.c
@@ -6,9 +6,9 @@
#include <linux/fb.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_file.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
index 8b4a500347fb..641691fc92c8 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c
+++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
@@ -12,7 +12,10 @@
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
+#include <linux/media-bus-format.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/pm_runtime.h>
@@ -207,11 +210,41 @@ static void mxsfb_irq_uninstall(struct drm_device *dev)
free_irq(mxsfb->irq, dev);
}
+static int mxsfb_of_bus_fmt(const struct device_node *ep, u32 *bus_format)
+{
+ u32 bus_width;
+ int ret;
+
+ ret = of_property_read_u32(ep, "bus-width", &bus_width);
+ if (ret == -EINVAL)
+ return 0;
+ if (ret)
+ return ret;
+
+ switch (bus_width) {
+ case 16:
+ *bus_format = MEDIA_BUS_FMT_RGB565_1X16;
+ break;
+ case 18:
+ *bus_format = MEDIA_BUS_FMT_RGB666_1X18;
+ break;
+ case 24:
+ *bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int mxsfb_load(struct drm_device *drm,
const struct mxsfb_devdata *devdata)
{
struct platform_device *pdev = to_platform_device(drm->dev);
+ struct device_node *np = pdev->dev.of_node;
struct mxsfb_drm_private *mxsfb;
+ struct device_node *ep;
int ret;
mxsfb = devm_kzalloc(&pdev->dev, sizeof(*mxsfb), GFP_KERNEL);
@@ -238,6 +271,16 @@ static int mxsfb_load(struct drm_device *drm,
if (IS_ERR(mxsfb->clk_disp_axi))
mxsfb->clk_disp_axi = NULL;
+ ep = of_graph_get_next_endpoint(np, NULL);
+ if (ep) {
+ ret = mxsfb_of_bus_fmt(ep, &mxsfb->bus_format);
+ of_node_put(ep);
+ if (ret) {
+ dev_err(drm->dev, "Invalid bus-width endpoint property\n");
+ return ret;
+ }
+ }
+
ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32));
if (ret)
return ret;
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
index d160d921b25f..bdc47ce5be79 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h
+++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
@@ -46,6 +46,8 @@ struct mxsfb_drm_private {
struct drm_connector *connector;
struct drm_bridge *bridge;
+ u32 bus_format;
+
bool crc_active;
};
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_kms.c b/drivers/gpu/drm/mxsfb/mxsfb_kms.c
index 6e82f8f76793..bbc2a2df9f16 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_kms.c
+++ b/drivers/gpu/drm/mxsfb/mxsfb_kms.c
@@ -386,6 +386,18 @@ static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc,
if (!bus_format)
bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+ /*
+ * Prefer the bus format derived from the OF graph endpoint "bus-width"
+ * property when available. Otherwise, use the bus format reported by
+ * the downstream bridge or panel.
+ *
+ * This supports mismatched display and interface bus widths, such as
+ * a 24-bit panel connected through an 18-bit interface or an 18-bit
+ * panel connected through a 24-bit interface.
+ */
+ if (mxsfb->bus_format)
+ bus_format = mxsfb->bus_format;
+
mxsfb_crtc_mode_set_nofb(mxsfb, bridge_state, bus_format);
/* Write cur_buf as well to avoid an initial corrupt frame */
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index add19d479ebe..e91130f93db6 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -40,7 +40,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_eld.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fixed.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
index 4c22c09c93d5..e3e685c931f1 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
@@ -204,7 +204,6 @@ struct omap_dss_device {
struct dss_device *dss;
struct drm_bridge *bridge;
struct drm_bridge *next_bridge;
- struct drm_panel *panel;
struct list_head list;
diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c
index 6e9bc605ee22..36d37deac802 100644
--- a/drivers/gpu/drm/omapdrm/dss/output.c
+++ b/drivers/gpu/drm/omapdrm/dss/output.c
@@ -12,7 +12,6 @@
#include <linux/of_graph.h>
#include <drm/drm_bridge.h>
-#include <drm/drm_panel.h>
#include "dss.h"
#include "omapdss.h"
@@ -20,40 +19,16 @@
int omapdss_device_init_output(struct omap_dss_device *out,
struct drm_bridge *local_bridge)
{
- struct device_node *remote_node;
+ struct drm_bridge *bridge;
int ret;
- remote_node = of_graph_get_remote_node(out->dev->of_node,
- out->of_port, 0);
- if (!remote_node) {
+ bridge = of_drm_get_bridge_by_endpoint(out->dev->of_node, out->of_port, 0);
+ if (IS_ERR(bridge)) {
dev_dbg(out->dev, "failed to find video sink\n");
return 0;
}
- out->panel = of_drm_find_panel(remote_node);
- if (IS_ERR(out->panel))
- out->panel = NULL;
-
- if (!out->panel)
- out->bridge = of_drm_find_and_get_bridge(remote_node);
-
- of_node_put(remote_node);
-
- if (out->panel) {
- struct drm_bridge *bridge;
-
- bridge = drm_panel_bridge_add(out->panel);
- drm_panel_put(out->panel);
- if (IS_ERR(bridge)) {
- dev_err(out->dev,
- "unable to create panel bridge (%ld)\n",
- PTR_ERR(bridge));
- ret = PTR_ERR(bridge);
- goto error;
- }
-
- out->bridge = drm_bridge_get(bridge);
- }
+ out->bridge = bridge;
if (local_bridge) {
if (!out->bridge) {
@@ -65,11 +40,6 @@ int omapdss_device_init_output(struct omap_dss_device *out,
out->bridge = drm_bridge_get(local_bridge);
}
- if (!out->bridge) {
- ret = -EPROBE_DEFER;
- goto error;
- }
-
return 0;
error:
@@ -79,10 +49,6 @@ error:
void omapdss_device_cleanup_output(struct omap_dss_device *out)
{
- if (out->bridge && out->panel)
- drm_panel_bridge_remove(out->next_bridge ?
- out->next_bridge : out->bridge);
-
drm_bridge_put(out->next_bridge);
drm_bridge_put(out->bridge);
}
diff --git a/drivers/gpu/drm/omapdrm/omap_debugfs.c b/drivers/gpu/drm/omapdrm/omap_debugfs.c
index 9edc1b3f9f95..1c40c489ed72 100644
--- a/drivers/gpu/drm/omapdrm/omap_debugfs.c
+++ b/drivers/gpu/drm/omapdrm/omap_debugfs.c
@@ -6,10 +6,10 @@
#include <linux/seq_file.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_file.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_print.h>
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index 4881777642d2..e1dcc3cb7c55 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
@@ -7,9 +7,9 @@
#include <linux/fb.h>
#include <drm/clients/drm_client_setup.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_file.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 747f47347521..53a1fc2913fe 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -1,7 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
config DRM_PANEL
- bool
+ tristate
depends on DRM
+ select DRM_KMS_HELPER
help
Panel registration and lookup framework.
diff --git a/drivers/gpu/drm/panel/panel-ebbg-ft8719.c b/drivers/gpu/drm/panel/panel-ebbg-ft8719.c
index fb9f9f42be4f..1652de70900f 100644
--- a/drivers/gpu/drm/panel/panel-ebbg-ft8719.c
+++ b/drivers/gpu/drm/panel/panel-ebbg-ft8719.c
@@ -54,8 +54,9 @@ static void ebbg_ft8719_reset(struct ebbg_ft8719 *ctx)
usleep_range(15000, 16000);
}
-static int ebbg_ft8719_on(struct ebbg_ft8719 *ctx)
+static int ebbg_ft8719_enable(struct drm_panel *panel)
{
+ struct ebbg_ft8719 *ctx = to_ebbg_ft8719(panel);
struct mipi_dsi_device *dsi = ctx->dsi;
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
@@ -72,19 +73,20 @@ static int ebbg_ft8719_on(struct ebbg_ft8719 *ctx)
return dsi_ctx.accum_err;
}
-static int ebbg_ft8719_off(struct ebbg_ft8719 *ctx)
+static int ebbg_ft8719_disable(struct drm_panel *panel)
{
+ struct ebbg_ft8719 *ctx = to_ebbg_ft8719(panel);
struct mipi_dsi_device *dsi = ctx->dsi;
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
- dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+ ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
mipi_dsi_usleep_range(&dsi_ctx, 10000, 11000);
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 90);
- return dsi_ctx.accum_err;
+ return 0;
}
static int ebbg_ft8719_prepare(struct drm_panel *panel)
@@ -98,12 +100,6 @@ static int ebbg_ft8719_prepare(struct drm_panel *panel)
ebbg_ft8719_reset(ctx);
- ret = ebbg_ft8719_on(ctx);
- if (ret < 0) {
- gpiod_set_value_cansleep(ctx->reset_gpio, 1);
- return ret;
- }
-
return 0;
}
@@ -111,7 +107,6 @@ static int ebbg_ft8719_unprepare(struct drm_panel *panel)
{
struct ebbg_ft8719 *ctx = to_ebbg_ft8719(panel);
- ebbg_ft8719_off(ctx);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
@@ -153,6 +148,8 @@ static int ebbg_ft8719_get_modes(struct drm_panel *panel,
static const struct drm_panel_funcs ebbg_ft8719_panel_funcs = {
.prepare = ebbg_ft8719_prepare,
+ .enable = ebbg_ft8719_enable,
+ .disable = ebbg_ft8719_disable,
.unprepare = ebbg_ft8719_unprepare,
.get_modes = ebbg_ft8719_get_modes,
};
@@ -198,6 +195,8 @@ static int ebbg_ft8719_probe(struct mipi_dsi_device *dsi)
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_CLOCK_NON_CONTINUOUS;
+ ctx->panel.prepare_prev_first = true;
+
ret = drm_panel_of_backlight(&ctx->panel);
if (ret)
return dev_err_probe(dev, ret, "Failed to get backlight\n");
@@ -244,4 +243,4 @@ module_mipi_dsi_driver(ebbg_ft8719_driver);
MODULE_AUTHOR("Joel Selvaraj <jo@jsfamily.in>");
MODULE_DESCRIPTION("DRM driver for EBBG FT8719 video dsi panel");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c
index 29f250e6e64d..5d7d696b7725 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -2084,6 +2084,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('B', 'O', 'E', 0x3879, &delay_200_500_e80, "NT116WHM-N21"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x388b, &delay_200_500_e80, "NV116FH1-M31"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x388c, &delay_200_500_e80, "NV116FH1-M30"),
+ EDP_PANEL_ENTRY('B', 'O', 'E', 0x38ae, &delay_200_500_e50, "NV140WU2-M70"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x38ea, &delay_200_500_e50, "NV140FHM-T0A"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1130, &delay_200_500_e50, "N116BGE-EB2"),
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c b/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c
index d4b383138488..bea5ca70c775 100644
--- a/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c
@@ -133,6 +133,207 @@ static const struct drm_dsc_config tianma_il79900a_dsc = {
.flatness_min_qp = 3,
};
+static int rpi_10inch_init(struct ili9882t *ili)
+{
+ struct mipi_dsi_multi_context ctx = { .dsi = ili->dsi };
+
+ mipi_dsi_usleep_range(&ctx, 5000, 5100);
+
+ il79900a_switch_page(&ctx, 0x01);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x00, 0x42);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x01, 0x11);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x02, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x03, 0x00);
+
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x04, 0x01);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x05, 0x11);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x06, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x07, 0x00);
+
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x08, 0x80);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x09, 0x01);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x0a, 0x71);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x0c, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x0e, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x0d, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x0f, 0x00);
+
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x30, 0x07);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x31, 0x07);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x32, 0x07);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x33, 0x07);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x34, 0x07);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x35, 0x01);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x36, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x37, 0x28);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x38, 0x29);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x39, 0x11);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x3A, 0x13);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x3B, 0x15);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x3C, 0x17);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x3D, 0x09);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x3E, 0x0D);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x3F, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x40, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x41, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x42, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x43, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x44, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x45, 0x02);
+
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x48, 0x07);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x49, 0x07);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x4A, 0x07);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x4B, 0x07);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x4C, 0x07);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x4D, 0x01);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x4E, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x4F, 0x28);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x50, 0x29);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x51, 0x10);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x52, 0x12);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x53, 0x14);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x54, 0x16);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x55, 0x08);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x56, 0x0C);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x57, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x58, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x59, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x5A, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x5B, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x5C, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x5D, 0x02);
+
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x2C, 0xB0);
+
+ il79900a_switch_page(&ctx, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x07, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x06, 0xD2);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x53, 0x1F);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x5E, 0x40);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x84, 0x00);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x29, 0x3A);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x2A, 0x3B);
+
+ il79900a_switch_page(&ctx, 0x03);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x20, 0x01);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x21, 0x3C);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x22, 0xFA);
+
+ il79900a_switch_page(&ctx, 0x12);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x87, 0x2C);
+
+ il79900a_switch_page(&ctx, 0x05);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x61, 0x8F);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x6D, 0xBB);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x5A, 0x7C);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x67, 0x7C);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x54, 0x92);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x55, 0x92);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x40, 0xD2);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x46, 0x70);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x30, 0x47);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x7A, 0x89);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0xA4, 0x0B);
+
+ il79900a_switch_page(&ctx, 0x06);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0xC0, 0x80);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0xC1, 0x7);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0xCA, 0x58);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0xCB, 0x2);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0xCE, 0x58);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0xCF, 0x2);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x10, 0x0);
+
+ il79900a_switch_page(&ctx, 0x0b);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x76, 0x55);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x78, 0x68);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x77, 0x0D);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x79, 0x60);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x7A, 0x10);
+
+ il79900a_switch_page(&ctx, 0x08);
+ mipi_dsi_dcs_write_seq_multi(&ctx,
+ 0xE0, 0x00, 0x1E, 0x3F,
+ 0x68, 0x7D, 0x72, 0x86,
+ 0x89, 0x92, 0x8E, 0xA5,
+ 0xA8, 0xAA, 0xBD, 0xB8,
+ 0xBE, 0xC5, 0xD6, 0xCD,
+ 0xC3, 0xDA, 0xEB, 0xED);
+ mipi_dsi_dcs_write_seq_multi(&ctx,
+ 0xE1, 0x00, 0x1E, 0x3F,
+ 0x68, 0x7D, 0x72, 0x86,
+ 0x89, 0x92, 0x8E, 0xA5,
+ 0xA8, 0xAA, 0xBD, 0xB8,
+ 0xBE, 0xC5, 0xD6, 0xCD,
+ 0xC3, 0xDA, 0xEB, 0xED);
+
+ il79900a_switch_page(&ctx, 0x14);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x85, 0xCC);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x87, 0x91);
+
+ il79900a_switch_page(&ctx, 0x10);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x11, 0x3);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x12, 0x34);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x10, 0x1);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x13, 0x4);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x14, 0xBB);
+
+ il79900a_switch_page(&ctx, 0x0b);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x94, 0x88);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x95, 0x23);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x96, 0x0B);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x97, 0x0B);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x98, 0xC6);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x99, 0xC6);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0xA6, 0x47);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0xA7, 0x77);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0xA8, 0x5);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0xA9, 0x5);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0xAA, 0xBA);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0xAB, 0xBA);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0xBD, 0x92);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0xBE, 0xE0);
+
+ il79900a_switch_page(&ctx, 0x0e);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x0, 0x80);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x14, 0x3);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x12, 0x0);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x13, 0x4);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x11, 0x1);
+
+ il79900a_switch_page(&ctx, 0x02);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x80, 0x11);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x82, 0x11);
+ il79900a_switch_page(&ctx, 0x12);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x82, 0x2C);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x85, 0x2C);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x87, 0x2C);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x88, 0xEC);
+ il79900a_switch_page(&ctx, 0x10);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x4, 0x1);
+ il79900a_switch_page(&ctx, 0x11);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x0C, 0x80);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x3C, 0x80);
+
+ il79900a_switch_page(&ctx, 0x06);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x0E, 0x0);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x0E, 0x3F);
+ mipi_dsi_dcs_write_seq_multi(&ctx, 0x10, 0x0);
+
+ il79900a_switch_page(&ctx, 0x00);
+ mipi_dsi_dcs_set_tear_on_multi(&ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+ mipi_dsi_dcs_exit_sleep_mode_multi(&ctx);
+
+ mipi_dsi_msleep(&ctx, 120);
+
+ mipi_dsi_dcs_set_display_on_multi(&ctx);
+
+ mipi_dsi_msleep(&ctx, 20);
+
+ return ctx.accum_err;
+};
+
static int starry_ili9882t_init(struct ili9882t *ili)
{
struct mipi_dsi_multi_context ctx = { .dsi = ili->dsi };
@@ -670,6 +871,19 @@ static int ili9882t_enable(struct drm_panel *panel)
return 0;
}
+static const struct drm_display_mode rpi_10inch_default_mode = {
+ .clock = 166666,
+ .hdisplay = 1200,
+ .hsync_start = 1200 + 28,
+ .hsync_end = 1200 + 28 + 10,
+ .htotal = 1200 + 28 + 10 + 30,
+ .vdisplay = 1920,
+ .vsync_start = 1920 + 238,
+ .vsync_end = 1920 + 238 + 4,
+ .vtotal = 1920 + 238 + 4 + 28,
+ .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
static const struct drm_display_mode starry_ili9882t_default_mode = {
.clock = 165280,
.hdisplay = 1200,
@@ -696,6 +910,20 @@ static const struct drm_display_mode tianma_il79900a_default_mode = {
.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
};
+static const struct panel_desc rpi_10inch_desc = {
+ .modes = &rpi_10inch_default_mode,
+ .bpc = 8,
+ .size = {
+ .width_mm = 135,
+ .height_mm = 216,
+ },
+ .lanes = 4,
+ .format = MIPI_DSI_FMT_RGB888,
+ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+ MIPI_DSI_MODE_LPM,
+ .init = rpi_10inch_init,
+};
+
static const struct panel_desc starry_ili9882t_desc = {
.modes = &starry_ili9882t_default_mode,
.bpc = 8,
@@ -787,7 +1015,7 @@ static int ili9882t_add(struct ili9882t *ili)
if (IS_ERR(ili->pp1800))
return PTR_ERR(ili->pp1800);
- ili->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+ ili->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
if (IS_ERR(ili->enable_gpio)) {
dev_err(dev, "cannot get enable-gpios %ld\n",
PTR_ERR(ili->enable_gpio));
@@ -808,6 +1036,7 @@ static int ili9882t_add(struct ili9882t *ili)
ili->base.funcs = &ili9882t_funcs;
ili->base.dev = &ili->dsi->dev;
+ ili->base.prepare_prev_first = true;
return devm_drm_panel_add(dev, &ili->base);
}
@@ -846,6 +1075,9 @@ static int ili9882t_probe(struct mipi_dsi_device *dsi)
}
static const struct of_device_id ili9882t_of_match[] = {
+ { .compatible = "raspberrypi,dsi-10inch",
+ .data = &rpi_10inch_desc
+ },
{ .compatible = "starry,ili9882t",
.data = &starry_ili9882t_desc
},
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index c95964ba25a9..d7dbd7442919 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -1593,6 +1593,31 @@ static const struct panel_desc boe_bp101wx1_100 = {
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
+static const struct display_timing boe_dv215fhm_r01_timing = {
+ .pixelclock = { 148500000, 148500000, 148500000 },
+ .hactive = { 1920, 1920, 1920 },
+ .hfront_porch = { 88, 88, 88 },
+ .hback_porch = { 148, 148, 148 },
+ .hsync_len = { 44, 44, 44 },
+ .vactive = { 1080, 1080, 1080 },
+ .vfront_porch = { 4, 4, 4 },
+ .vback_porch = { 36, 36, 36 },
+ .vsync_len = { 5, 5, 5 },
+ .flags = DISPLAY_FLAGS_DE_HIGH,
+};
+
+static const struct panel_desc boe_dv215fhm_r01 = {
+ .timings = &boe_dv215fhm_r01_timing,
+ .num_timings = 1,
+ .bpc = 8,
+ .size = {
+ .width = 476,
+ .height = 268,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+ .connector_type = DRM_MODE_CONNECTOR_LVDS,
+};
+
static const struct display_timing boe_ev121wxm_n10_1850_timing = {
.pixelclock = { 69922000, 71000000, 72293000 },
.hactive = { 1280, 1280, 1280 },
@@ -5114,6 +5139,32 @@ static const struct panel_desc tpk_f10a_0102 = {
},
};
+static const struct drm_display_mode truly_tft320240_229_e_mode = {
+ .clock = 6410,
+ .hdisplay = 320,
+ .hsync_start = 320 + 8,
+ .hsync_end = 320 + 8 + 39,
+ .htotal = 320 + 8 + 39 + 4,
+ .vdisplay = 240,
+ .vsync_start = 240 + 8,
+ .vsync_end = 240 + 8 + 8,
+ .vtotal = 240 + 8 + 8 + 4,
+ .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc truly_tft320240_229_e = {
+ .modes = &truly_tft320240_229_e_mode,
+ .num_modes = 1,
+ .bpc = 8,
+ .size = {
+ .width = 70,
+ .height = 53,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+ .bus_flags = DRM_BUS_FLAG_DE_HIGH,
+ .connector_type = DRM_MODE_CONNECTOR_DPI,
+};
+
static const struct display_timing urt_umsh_8596md_timing = {
.pixelclock = { 33260000, 33260000, 33260000 },
.hactive = { 800, 800, 800 },
@@ -5760,6 +5811,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "boe,bp101wx1-100",
.data = &boe_bp101wx1_100,
}, {
+ .compatible = "boe,dv215fhm-r01",
+ .data = &boe_dv215fhm_r01,
+ }, {
.compatible = "boe,ev121wxm-n10-1850",
.data = &boe_ev121wxm_n10_1850,
}, {
@@ -6168,6 +6222,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "tpk,f10a-0102",
.data = &tpk_f10a_0102,
}, {
+ .compatible = "truly,tft320240-229-e",
+ .data = &truly_tft320240_229_e,
+ }, {
.compatible = "urt,umsh-8596md-t",
.data = &urt_umsh_8596md_parallel,
}, {
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 96a66d673ba6..70c05210ea84 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -18,7 +18,7 @@
#include <drm/drm_ioctl.h>
#include <drm/drm_print.h>
#include <drm/drm_syncobj.h>
-#include <drm/drm_utils.h>
+#include <drm/drm_timeout.h>
#include "panfrost_device.h"
#include "panfrost_drv.h"
diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c
index 8cdba0c1a14b..1ca8aedd83f4 100644
--- a/drivers/gpu/drm/panthor/panthor_drv.c
+++ b/drivers/gpu/drm/panthor/panthor_drv.c
@@ -25,7 +25,6 @@
#include <drm/drm_ioctl.h>
#include <drm/drm_print.h>
#include <drm/drm_syncobj.h>
-#include <drm/drm_utils.h>
#include <drm/gpu_scheduler.h>
#include <drm/panthor_drm.h>
diff --git a/drivers/gpu/drm/pl111/Kconfig b/drivers/gpu/drm/pl111/Kconfig
index 82e918820950..20201ec20aa7 100644
--- a/drivers/gpu/drm/pl111/Kconfig
+++ b/drivers/gpu/drm/pl111/Kconfig
@@ -9,6 +9,7 @@ config DRM_PL111
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
select DRM_BRIDGE
+ select DRM_PANEL
select DRM_PANEL_BRIDGE
help
Choose this option for DRM support for the PL111 CLCD controller.
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 65dc1efb26ad..9e4dc4531c90 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -33,11 +33,11 @@
#include <linux/vga_switcheroo.h>
#include <linux/vgaarb.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_cache.h>
#include <drm/drm_client_event.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_device.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_file.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_probe_helper.h>
diff --git a/drivers/gpu/drm/radeon/radeon_fbdev.c b/drivers/gpu/drm/radeon/radeon_fbdev.c
index 3e243f5e2f44..e40c23d9dff2 100644
--- a/drivers/gpu/drm/radeon/radeon_fbdev.c
+++ b/drivers/gpu/drm/radeon/radeon_fbdev.c
@@ -29,9 +29,9 @@
#include <linux/pm_runtime.h>
#include <linux/vga_switcheroo.h>
+#include <drm/clients/drm_fbdev_helper.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_framebuffer.h>
#include <drm/drm_gem_framebuffer_helper.h>
diff --git a/drivers/gpu/drm/renesas/rz-du/Kconfig b/drivers/gpu/drm/renesas/rz-du/Kconfig
index 7f2ef7137ae5..0dbe86bd65d0 100644
--- a/drivers/gpu/drm/renesas/rz-du/Kconfig
+++ b/drivers/gpu/drm/renesas/rz-du/Kconfig
@@ -26,3 +26,16 @@ config DRM_RZG2L_MIPI_DSI
def_tristate DRM_RZG2L_DU
depends on DRM_RZG2L_USE_MIPI_DSI
select DRM_MIPI_DSI
+
+config DRM_RZG3L_USE_LVDS
+ bool "RZ/G3L DU LVDS Encoder Support"
+ depends on DRM_BRIDGE && OF
+ depends on DRM_RZG2L_DU || COMPILE_TEST
+ default DRM_RZG2L_DU
+ help
+ Enable support for the RZ/G3L Display Unit embedded LVDS encoder.
+
+config DRM_RZG3L_LVDS
+ def_tristate DRM_RZG2L_DU
+ depends on DRM_RZG3L_USE_LVDS
+ select DRM_KMS_HELPER
diff --git a/drivers/gpu/drm/renesas/rz-du/Makefile b/drivers/gpu/drm/renesas/rz-du/Makefile
index 2987900ea6b6..46decb7ac4f1 100644
--- a/drivers/gpu/drm/renesas/rz-du/Makefile
+++ b/drivers/gpu/drm/renesas/rz-du/Makefile
@@ -8,3 +8,4 @@ rzg2l-du-drm-$(CONFIG_VIDEO_RENESAS_VSP1) += rzg2l_du_vsp.o
obj-$(CONFIG_DRM_RZG2L_DU) += rzg2l-du-drm.o
obj-$(CONFIG_DRM_RZG2L_MIPI_DSI) += rzg2l_mipi_dsi.o
+obj-$(CONFIG_DRM_RZG3L_LVDS) += rzg3l_lvds.o
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
index 3d13f61d3c97..6c2dc86abc7d 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
@@ -55,6 +55,26 @@ static const struct rzg2l_du_device_info rzg2l_du_r9a07g044_info = {
.mode_clock_max = 83500,
};
+static const struct rzg2l_du_device_info rzg2l_du_r9a08g046_info = {
+ .channels_mask = BIT(0),
+ .routes = {
+ [RZG2L_DU_OUTPUT_DSI0] = {
+ .possible_outputs = BIT(0),
+ .port = 0,
+ },
+ [RZG2L_DU_OUTPUT_DPAD0] = {
+ .possible_outputs = BIT(0),
+ .port = 1,
+ },
+ [RZG2L_DU_OUTPUT_LVDS0] = {
+ .possible_outputs = BIT(0),
+ .port = 2,
+ },
+ },
+ .mode_clock_min = 5440,
+ .mode_clock_max = 87000,
+};
+
static const struct rzg2l_du_device_info rzg2l_du_r9a09g057_info = {
.channels_mask = BIT(0),
.routes = {
@@ -81,6 +101,7 @@ static const struct rzg2l_du_device_info rzg2l_du_r9a09g077_info = {
static const struct of_device_id rzg2l_du_of_table[] = {
{ .compatible = "renesas,r9a07g043u-du", .data = &rzg2l_du_r9a07g043u_info },
{ .compatible = "renesas,r9a07g044-du", .data = &rzg2l_du_r9a07g044_info },
+ { .compatible = "renesas,r9a08g046-du", .data = &rzg2l_du_r9a08g046_info },
{ .compatible = "renesas,r9a09g057-du", .data = &rzg2l_du_r9a09g057_info },
{ .compatible = "renesas,r9a09g077-du", .data = &rzg2l_du_r9a09g077_info },
{ /* sentinel */ }
@@ -92,7 +113,8 @@ const char *rzg2l_du_output_name(enum rzg2l_du_output output)
{
static const char * const names[] = {
[RZG2L_DU_OUTPUT_DSI0] = "DSI0",
- [RZG2L_DU_OUTPUT_DPAD0] = "DPAD0"
+ [RZG2L_DU_OUTPUT_DPAD0] = "DPAD0",
+ [RZG2L_DU_OUTPUT_LVDS0] = "LVDS0"
};
if (output >= ARRAY_SIZE(names))
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
index baf076d69cda..e9626ef37cde 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
@@ -25,6 +25,7 @@ struct drm_property;
enum rzg2l_du_output {
RZG2L_DU_OUTPUT_DSI0,
RZG2L_DU_OUTPUT_DPAD0,
+ RZG2L_DU_OUTPUT_LVDS0,
RZG2L_DU_OUTPUT_MAX,
};
@@ -33,7 +34,7 @@ enum rzg2l_du_output {
* @possible_outputs: bitmask of possible outputs
* @port: device tree port number corresponding to this output route
*
- * The DU has 2 possible outputs (DPAD0, DSI0). Output routing data
+ * The DU has 3 possible outputs (DPAD0, DSI0, LVDS0). Output routing data
* specify the valid SoC outputs, which CRTC can drive the output, and the type
* of in-SoC encoder for the output.
*/
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c
index 3d0999e4fcfd..a1b48973aa8e 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_encoder.c
@@ -7,6 +7,7 @@
* Based on rcar_du_encoder.c
*/
+#include <linux/clk.h>
#include <linux/export.h>
#include <linux/of.h>
@@ -15,6 +16,7 @@
#include <drm/drm_bridge_connector.h>
#include <drm/drm_panel.h>
+#include "rzg2l_du_crtc.h"
#include "rzg2l_du_drv.h"
#include "rzg2l_du_encoder.h"
@@ -64,8 +66,30 @@ rzg2l_du_encoder_mode_valid(struct drm_encoder *encoder,
return MODE_OK;
}
+static void rzg2l_du_encoder_atomic_mode_set(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct rzg2l_du_encoder *renc = to_rzg2l_encoder(encoder);
+ struct rzg2l_du_crtc *rcrtc = to_rzg2l_crtc(crtc_state->crtc);
+ struct clk *clk_parent;
+
+ clk_parent = clk_get_parent(rcrtc->rzg2l_clocks.dclk);
+
+ /*
+ * Request appropriate duty cycle
+ * - LVDS path has DUTY H/L=4/3, 4/7 duty cycle.
+ * - DSI/RGB path has symmetric 50% duty cycle.
+ */
+ if (renc->output == RZG2L_DU_OUTPUT_LVDS0)
+ clk_set_duty_cycle(clk_parent, 4, 7);
+ else
+ clk_set_duty_cycle(clk_parent, 1, 2);
+}
+
static const struct drm_encoder_helper_funcs rzg2l_du_encoder_helper_funcs = {
.mode_valid = rzg2l_du_encoder_mode_valid,
+ .atomic_mode_set = rzg2l_du_encoder_atomic_mode_set,
};
int rzg2l_du_encoder_init(struct rzg2l_du_device *rcdu,
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
index 0590ade96b91..5b257f5adf06 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -18,6 +18,7 @@
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/pwrseq/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/units.h>
@@ -38,6 +39,7 @@ MODULE_IMPORT_NS("RZV2H_CPG");
#define RZG2L_DCS_BUF_SIZE 128 /* Maximum DCS buffer size in external memory. */
#define RZ_MIPI_DSI_FEATURE_16BPP BIT(0)
+#define RZ_MIPI_DSI_FEATURE_PWRRDY BIT(1)
struct rzg2l_mipi_dsi;
@@ -54,10 +56,14 @@ struct rzg2l_mipi_dsi_hw_info {
const u8 *table;
const u8 table_size;
} cpg_plldsi;
+ const struct rzg2l_mipi_dsi_timings *dsi_global_timings;
+ unsigned int num_dsi_global_timings;
u32 phy_reg_offset;
u32 link_reg_offset;
+ u32 dphyctrl0_init_val;
unsigned long min_dclk;
unsigned long max_dclk;
+ u16 activation_dly;
u8 features;
};
@@ -83,6 +89,8 @@ struct rzg2l_mipi_dsi {
struct clk *vclk;
struct clk *lpclk;
+ struct pwrseq_desc *pwrseq;
+
enum mipi_dsi_pixel_format format;
unsigned int num_data_lanes;
unsigned int lanes;
@@ -218,6 +226,107 @@ static const struct rzg2l_mipi_dsi_timings rzg2l_mipi_dsi_global_timings[] = {
},
};
+static const struct rzg2l_mipi_dsi_timings rzg3l_mipi_dsi_global_timings[] = {
+ {
+ .hsfreq_max = 100000000,
+ .t_init = 79801,
+ .tclk_prepare = 10,
+ .ths_prepare = 18,
+ .tclk_zero = 35,
+ .tclk_pre = 13,
+ .tclk_post = 94,
+ .tclk_trail = 10,
+ .ths_zero = 16,
+ .ths_trail = 22,
+ .ths_exit = 15,
+ .tlpx = 9,
+ },
+ {
+ .hsfreq_max = 150000000,
+ .t_init = 79801,
+ .tclk_prepare = 10,
+ .ths_prepare = 16,
+ .tclk_zero = 35,
+ .tclk_pre = 13,
+ .tclk_post = 94,
+ .tclk_trail = 10,
+ .ths_zero = 16,
+ .ths_trail = 15,
+ .ths_exit = 15,
+ .tlpx = 9,
+ },
+ {
+ .hsfreq_max = 250000000,
+ .t_init = 79801,
+ .tclk_prepare = 10,
+ .ths_prepare = 13,
+ .tclk_zero = 35,
+ .tclk_pre = 13,
+ .tclk_post = 58,
+ .tclk_trail = 8,
+ .ths_zero = 16,
+ .ths_trail = 10,
+ .ths_exit = 15,
+ .tlpx = 9,
+ },
+ {
+ .hsfreq_max = 400000000,
+ .t_init = 79801,
+ .tclk_prepare = 10,
+ .ths_prepare = 12,
+ .tclk_zero = 35,
+ .tclk_pre = 4,
+ .tclk_post = 58,
+ .tclk_trail = 7,
+ .ths_zero = 16,
+ .ths_trail = 9,
+ .ths_exit = 15,
+ .tlpx = 9,
+ },
+ {
+ .hsfreq_max = 600000000,
+ .t_init = 79801,
+ .tclk_prepare = 10,
+ .ths_prepare = 11,
+ .tclk_zero = 35,
+ .tclk_pre = 4,
+ .tclk_post = 35,
+ .tclk_trail = 5,
+ .ths_zero = 16,
+ .ths_trail = 6,
+ .ths_exit = 15,
+ .tlpx = 9,
+ },
+ {
+ .hsfreq_max = 1000000000,
+ .t_init = 79801,
+ .tclk_prepare = 10,
+ .ths_prepare = 11,
+ .tclk_zero = 35,
+ .tclk_pre = 4,
+ .tclk_post = 35,
+ .tclk_trail = 5,
+ .ths_zero = 16,
+ .ths_trail = 6,
+ .ths_exit = 15,
+ .tlpx = 9,
+ },
+ {
+ .hsfreq_max = 1500000000,
+ .t_init = 79801,
+ .tclk_prepare = 10,
+ .ths_prepare = 11,
+ .tclk_zero = 35,
+ .tclk_pre = 4,
+ .tclk_post = 35,
+ .tclk_trail = 4,
+ .ths_zero = 16,
+ .ths_trail = 5,
+ .ths_exit = 15,
+ .tlpx = 9,
+ },
+};
+
/**
* struct rzv2h_mipi_dsi_timings - Timing parameter table structure
*
@@ -486,16 +595,14 @@ static int rzg2l_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi,
u32 dphytim3;
/* All DSI global operation timings are set with recommended setting */
- for (i = 0; i < ARRAY_SIZE(rzg2l_mipi_dsi_global_timings); ++i) {
- dphy_timings = &rzg2l_mipi_dsi_global_timings[i];
+ for (i = 0; i < dsi->info->num_dsi_global_timings; ++i) {
+ dphy_timings = &dsi->info->dsi_global_timings[i];
if (hsfreq <= dphy_timings->hsfreq_max)
break;
}
/* Initializing DPHY before accessing LINK */
- dphyctrl0 = DSIDPHYCTRL0_CAL_EN_HSRX_OFS | DSIDPHYCTRL0_CMN_MASTER_EN |
- DSIDPHYCTRL0_RE_VDD_DETVCCQLV18 | DSIDPHYCTRL0_EN_BGR;
-
+ dphyctrl0 = dsi->info->dphyctrl0_init_val;
rzg2l_mipi_dsi_phy_write(dsi, DSIDPHYCTRL0, dphyctrl0);
usleep_range(20, 30);
@@ -807,7 +914,7 @@ static int rzg2l_mipi_dsi_startup(struct rzg2l_mipi_dsi *dsi,
if (ret < 0)
goto err_phy;
- fsleep(1000);
+ fsleep(dsi->info->activation_dly);
}
return 0;
@@ -1394,6 +1501,25 @@ static const struct dev_pm_ops rzg2l_mipi_pm_ops = {
* Probe & Remove
*/
+static int rzg2l_mipi_dsi_pwrrdy_init(struct rzg2l_mipi_dsi *dsi)
+{
+ if (!(dsi->info->features & RZ_MIPI_DSI_FEATURE_PWRRDY))
+ return 0;
+
+ dsi->pwrseq = devm_pwrseq_get(dsi->dev, "dsi-pwrrdy");
+ if (IS_ERR(dsi->pwrseq)) {
+ /*
+ * This platform requires a sequencer. If we can't get it, we
+ * must return the error (including -EPROBE_DEFER to wait for
+ * the provider to appear)
+ */
+ return dev_err_probe(dsi->dev, PTR_ERR(dsi->pwrseq),
+ "Failed to get required power sequencer\n");
+ }
+
+ return pwrseq_enable(dsi->pwrseq);
+}
+
static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
{
unsigned int num_data_lanes;
@@ -1452,6 +1578,10 @@ static int rzg2l_mipi_dsi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dsi);
+ ret = rzg2l_mipi_dsi_pwrrdy_init(dsi);
+ if (ret)
+ return ret;
+
pm_runtime_enable(dsi->dev);
ret = pm_runtime_resume_and_get(dsi->dev);
@@ -1530,12 +1660,32 @@ static const struct rzg2l_mipi_dsi_hw_info rzg2l_mipi_dsi_info = {
.dphy_init = rzg2l_mipi_dsi_dphy_init,
.dphy_exit = rzg2l_mipi_dsi_dphy_exit,
.dphy_conf_clks = rzg2l_dphy_conf_clks,
+ .dsi_global_timings = rzg2l_mipi_dsi_global_timings,
+ .num_dsi_global_timings = ARRAY_SIZE(rzg2l_mipi_dsi_global_timings),
.link_reg_offset = 0x10000,
+ .dphyctrl0_init_val = DSIDPHYCTRL0_CAL_EN_HSRX_OFS | DSIDPHYCTRL0_CMN_MASTER_EN |
+ DSIDPHYCTRL0_RE_VDD_DETVCCQLV18 | DSIDPHYCTRL0_EN_BGR,
.min_dclk = 5803,
.max_dclk = 148500,
+ .activation_dly = 1000,
+};
+
+static const struct rzg2l_mipi_dsi_hw_info rzg3l_mipi_dsi_info = {
+ .dphy_init = rzg2l_mipi_dsi_dphy_init,
+ .dphy_exit = rzg2l_mipi_dsi_dphy_exit,
+ .dphy_conf_clks = rzg2l_dphy_conf_clks,
+ .dsi_global_timings = rzg3l_mipi_dsi_global_timings,
+ .num_dsi_global_timings = ARRAY_SIZE(rzg3l_mipi_dsi_global_timings),
+ .link_reg_offset = 0x10000,
+ .dphyctrl0_init_val = DSIDPHYCTRL0_CMN_MASTER_EN | DSIDPHYCTRL0_EN_BGR,
+ .min_dclk = 5440,
+ .max_dclk = 187500,
+ .activation_dly = 100,
+ .features = RZ_MIPI_DSI_FEATURE_16BPP | RZ_MIPI_DSI_FEATURE_PWRRDY,
};
static const struct of_device_id rzg2l_mipi_dsi_of_table[] = {
+ { .compatible = "renesas,r9a08g046-mipi-dsi", .data = &rzg3l_mipi_dsi_info, },
{ .compatible = "renesas,r9a09g057-mipi-dsi", .data = &rzv2h_mipi_dsi_info, },
{ .compatible = "renesas,rzg2l-mipi-dsi", .data = &rzg2l_mipi_dsi_info, },
{ /* sentinel */ }
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg3l_lvds.c b/drivers/gpu/drm/renesas/rz-du/rzg3l_lvds.c
new file mode 100644
index 000000000000..99ad6445d359
--- /dev/null
+++ b/drivers/gpu/drm/renesas/rz-du/rzg3l_lvds.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G3L LVDS Encoder Driver
+ *
+ * Copyright (C) 2026 Renesas Electronics Corporation
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+
+#include "rzg3l_lvds_regs.h"
+
+enum rzg3l_lvds_mode {
+ RZG3L_LVDS_MODE_JEIDA = 0,
+ RZG3L_LVDS_MODE_JEIDA_MIRROR = 1,
+ RZG3L_LVDS_MODE_MODE2 = 2,
+ RZG3L_LVDS_MODE_MODE2_MIRROR = 3,
+ RZG3L_LVDS_MODE_VESA = 4,
+ RZG3L_LVDS_MODE_VESA_MIRROR = 5,
+ RZG3L_LVDS_MODE_MODE6 = 6,
+ RZG3L_LVDS_MODE_MODE6_MIRROR = 7,
+};
+
+struct rzg3l_lvds {
+ struct device *dev;
+ struct reset_control_bulk_data resets[2];
+ struct reset_control_bulk_data dsi_resets[2];
+ struct regmap *regmap;
+ struct drm_bridge bridge;
+};
+
+#define bridge_to_rzg3l_lvds(b) \
+ container_of(b, struct rzg3l_lvds, bridge)
+
+static const struct regmap_config rzg3l_lvds_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = LVDS_0_CTL_OFFSET,
+};
+
+/* -----------------------------------------------------------------------------
+ * Bridge
+ */
+
+static void rzg3l_lvds_atomic_enable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *state)
+{
+ struct rzg3l_lvds *lvds = bridge_to_rzg3l_lvds(bridge);
+ const struct drm_bridge_state *bridge_state;
+ u32 fmt;
+
+ if (WARN_ON(pm_runtime_get_sync(lvds->dev) < 0))
+ return;
+
+ /* Get the LVDS format from the bridge state. */
+ bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
+ if (WARN_ON(!bridge_state))
+ return;
+
+ switch (bridge_state->output_bus_cfg.format) {
+ case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
+ fmt = RZG3L_LVDS_MODE_JEIDA;
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
+ fmt = RZG3L_LVDS_MODE_VESA;
+ break;
+ default:
+ fmt = RZG3L_LVDS_MODE_VESA;
+ dev_warn(lvds->dev, "Unsupported bus fmt 0x%04x\n",
+ bridge_state->output_bus_cfg.format);
+ break;
+ }
+
+ regmap_update_bits(lvds->regmap, LVDS_0_PHY_OFFSET,
+ LVDS_0_PHY_CH_EN_BGR, LVDS_0_PHY_CH_EN_BGR);
+ fsleep(20);
+
+ regmap_update_bits(lvds->regmap, LVDS_0_PHY_OFFSET,
+ LVDS_0_PHY_CH_EN_LDO, LVDS_0_PHY_CH_EN_LDO);
+ fsleep(10);
+
+ regmap_write(lvds->regmap, LVDS_CMN, LVDS_CMN_RST_PHY0_SEL);
+ regmap_update_bits(lvds->regmap, LVDS_0_CTL_OFFSET,
+ LVDS_0_CTL_FMT_SEL0_MSK,
+ FIELD_PREP(LVDS_0_CTL_FMT_SEL0_MSK, fmt));
+ regmap_update_bits(lvds->regmap, LVDS_0_PHY_OFFSET,
+ LVDS_0_PHY_CH_IO_EN0_MSK, LVDS_0_PHY_CH_IO_EN0);
+ regmap_write(lvds->regmap, LVDS_CMN,
+ LVDS_CMN_RST_PHY0_SEL | LVDS_CMN_PHY_RESET);
+ fsleep(100);
+}
+
+static void rzg3l_lvds_atomic_disable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *state)
+{
+ struct rzg3l_lvds *lvds = bridge_to_rzg3l_lvds(bridge);
+
+ {
+ PM_RUNTIME_ACQUIRE_IF_ENABLED(lvds->dev, pm);
+ if (!PM_RUNTIME_ACQUIRE_ERR(&pm)) {
+ regmap_update_bits(lvds->regmap, LVDS_CMN,
+ LVDS_CMN_PHY_RESET, 0);
+ regmap_update_bits(lvds->regmap, LVDS_0_PHY_OFFSET,
+ LVDS_0_PHY_CH_IO_EN0_MSK, 0);
+ regmap_update_bits(lvds->regmap, LVDS_0_PHY_OFFSET,
+ LVDS_0_PHY_CH_EN_LDO, 0);
+ regmap_update_bits(lvds->regmap, LVDS_0_PHY_OFFSET,
+ LVDS_0_PHY_CH_EN_BGR, 0);
+ }
+ }
+
+ pm_runtime_put_sync(lvds->dev);
+}
+
+static int rzg3l_lvds_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
+ enum drm_bridge_attach_flags flags)
+{
+ struct rzg3l_lvds *lvds = bridge_to_rzg3l_lvds(bridge);
+
+ return drm_bridge_attach(encoder, lvds->bridge.next_bridge, bridge, flags);
+}
+
+static enum drm_mode_status
+rzg3l_lvds_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ if (mode->clock > 87000)
+ return MODE_CLOCK_HIGH;
+
+ if (mode->clock < 25000)
+ return MODE_CLOCK_LOW;
+
+ return MODE_OK;
+}
+
+static const struct drm_bridge_funcs rzg3l_lvds_bridge_ops = {
+ .attach = rzg3l_lvds_attach,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_create_state = drm_atomic_helper_bridge_create_state,
+ .atomic_enable = rzg3l_lvds_atomic_enable,
+ .atomic_disable = rzg3l_lvds_atomic_disable,
+ .mode_valid = rzg3l_lvds_bridge_mode_valid,
+};
+
+/* -----------------------------------------------------------------------------
+ * Power Management
+ */
+
+static int rzg3l_lvds_pm_runtime_suspend(struct device *dev)
+{
+ struct rzg3l_lvds *lvds = dev_get_drvdata(dev);
+
+ return reset_control_bulk_assert(ARRAY_SIZE(lvds->resets), lvds->resets);
+}
+
+static int rzg3l_lvds_pm_runtime_resume(struct device *dev)
+{
+ struct rzg3l_lvds *lvds = dev_get_drvdata(dev);
+
+ return reset_control_bulk_deassert(ARRAY_SIZE(lvds->resets), lvds->resets);
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(rzg3l_lvds_pm_ops,
+ rzg3l_lvds_pm_runtime_suspend,
+ rzg3l_lvds_pm_runtime_resume, NULL);
+
+/* -----------------------------------------------------------------------------
+ * Probe & Remove
+ */
+
+static int rzg3l_lvds_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rzg3l_lvds *lvds;
+ void __iomem *base;
+ int ret;
+
+ lvds = devm_drm_bridge_alloc(dev, struct rzg3l_lvds, bridge,
+ &rzg3l_lvds_bridge_ops);
+ if (IS_ERR(lvds))
+ return PTR_ERR(lvds);
+
+ lvds->dev = dev;
+ lvds->bridge.of_node = pdev->dev.of_node;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ lvds->regmap = devm_regmap_init_mmio(dev, base, &rzg3l_lvds_regmap_config);
+ if (IS_ERR(lvds->regmap))
+ return dev_err_probe(dev, PTR_ERR(lvds->regmap),
+ "Failed to init regmap\n");
+
+ lvds->resets[0].id = "prst";
+ lvds->resets[1].id = "lvdrst";
+ ret = devm_reset_control_bulk_get_exclusive(dev, ARRAY_SIZE(lvds->resets),
+ lvds->resets);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get prst/core resets\n");
+
+ platform_set_drvdata(pdev, lvds);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable Runtime PM\n");
+
+ lvds->bridge.next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
+ if (IS_ERR(lvds->bridge.next_bridge))
+ return dev_err_probe(dev, PTR_ERR(lvds->bridge.next_bridge),
+ "Failed to get next bridge\n");
+
+ /*
+ * This module cannot be used at the same time as MIPI-DSI, so assert
+ * the MIPI_DSI_CMN_RSTB and MIPI_DSI_ARESET_N resets before using this
+ * module.
+ */
+ lvds->dsi_resets[0].id = "rst";
+ lvds->dsi_resets[1].id = "arst";
+ ret = devm_reset_control_bulk_get_exclusive(dev, ARRAY_SIZE(lvds->dsi_resets),
+ lvds->dsi_resets);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get rst/arst resets\n");
+
+ ret = reset_control_bulk_assert(ARRAY_SIZE(lvds->dsi_resets), lvds->dsi_resets);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_drm_bridge_add(dev, &lvds->bridge);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register drm bridge\n");
+
+ return ret;
+}
+
+static const struct of_device_id rzg3l_lvds_of_table[] = {
+ { .compatible = "renesas,r9a08g046-lvds" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, rzg3l_lvds_of_table);
+
+static struct platform_driver rzg3l_lvds_platform_driver = {
+ .probe = rzg3l_lvds_probe,
+ .driver = {
+ .name = "rzg3l-lvds",
+ .pm = pm_ptr(&rzg3l_lvds_pm_ops),
+ .of_match_table = rzg3l_lvds_of_table,
+ },
+};
+
+module_platform_driver(rzg3l_lvds_platform_driver);
+
+MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
+MODULE_AUTHOR("Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/G3L LVDS Encoder Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg3l_lvds_regs.h b/drivers/gpu/drm/renesas/rz-du/rzg3l_lvds_regs.h
new file mode 100644
index 000000000000..5b276cca9a5d
--- /dev/null
+++ b/drivers/gpu/drm/renesas/rz-du/rzg3l_lvds_regs.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * RZ/G3L LVDS Interface Registers Definitions
+ *
+ * Copyright (C) 2026 Renesas Electronics Corporation
+ *
+ */
+
+#ifndef __RZG3L_LVDS_REGS_H__
+#define __RZG3L_LVDS_REGS_H__
+
+#define LVDS_CMN 0x00
+#define LVDS_CMN_RST_PHY0_SEL BIT(24)
+#define LVDS_CMN_PHY_RESET BIT(0)
+
+#define LVDS_0_PHY_OFFSET 0x10
+#define LVDS_0_PHY_CH_IO_EN0_MSK 0x1f
+#define LVDS_0_PHY_CH_IO_EN0 (LVDS_0_PHY_CH_IO_EN0_MSK << 0)
+#define LVDS_0_PHY_CH_EN_BGR BIT(8)
+#define LVDS_0_PHY_CH_EN_LDO BIT(9)
+
+#define LVDS_0_CTL_OFFSET 0x14
+#define LVDS_0_CTL_FMT_SEL0_MSK GENMASK(23, 20)
+
+#endif /* __RZG3L_LVDS_REGS_H__ */
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 4e58685f58ff..754d9b977ff1 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -125,6 +125,7 @@ config ROCKCHIP_LVDS
depends on PINCTRL && OF
select DRM_DISPLAY_HELPER
select DRM_BRIDGE_CONNECTOR
+ select DRM_PANEL
help
Choose this option to enable support for Rockchip LVDS controllers.
Rockchip rk3288 SoC has LVDS TX Controller can be used, and it
@@ -137,6 +138,7 @@ config ROCKCHIP_RGB
depends on PINCTRL
select DRM_DISPLAY_HELPER
select DRM_BRIDGE_CONNECTOR
+ select DRM_PANEL
help
Choose this option to enable support for Rockchip RGB output.
Some Rockchip CRTCs, like rv1108, can directly output parallel
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index efd5a98e80bd..ccdd4b9ecdb8 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -28,7 +28,6 @@
#include <drm/drm_bridge_connector.h>
#include <drm/bridge/analogix_dp.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -487,16 +486,6 @@ static int rockchip_dp_probe(struct platform_device *pdev)
static void rockchip_dp_remove(struct platform_device *pdev)
{
- struct rockchip_dp_device *dp = platform_get_drvdata(pdev);
-
- /*
- * Release the probe-time reference from of_drm_find_panel(). If bind
- * ran, the panel_bridge holds a second reference that devm cleanup
- * will release when the bridge is destroyed after remove() returns.
- */
- if (dp->plat_data.panel)
- drm_panel_put(dp->plat_data.panel);
-
component_del(&pdev->dev, &rockchip_dp_component_ops);
}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
index 9a1dc9f12072..b55113a7a00b 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -8,9 +8,9 @@
#include <linux/iommu.h>
#include <linux/vmalloc.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm.h>
#include <drm/drm_dumb_buffers.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_prime.h>
diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c
index e4069fcb0272..7be0387bac3c 100644
--- a/drivers/gpu/drm/scheduler/sched_entity.c
+++ b/drivers/gpu/drm/scheduler/sched_entity.c
@@ -136,7 +136,6 @@ int drm_sched_entity_init(struct drm_sched_entity *entity,
DRM_SCHED_PRIORITY_KERNEL : priority;
entity->num_sched_list = num_sched_list;
entity->sched_list = num_sched_list > 1 ? sched_list : NULL;
- RCU_INIT_POINTER(entity->last_scheduled, NULL);
RB_CLEAR_NODE(&entity->rb_tree_node);
if (!sched_list[0]->sched_rq) {
@@ -233,10 +232,10 @@ int drm_sched_entity_error(struct drm_sched_entity *entity)
struct dma_fence *fence;
int r;
- rcu_read_lock();
- fence = rcu_dereference(entity->last_scheduled);
+ spin_lock(&entity->lock);
+ fence = entity->last_scheduled;
r = fence ? fence->error : 0;
- rcu_read_unlock();
+ spin_unlock(&entity->lock);
return r;
}
@@ -319,9 +318,9 @@ void drm_sched_entity_kill(struct drm_sched_entity *entity)
/* Make sure this entity is not used by the scheduler at the moment */
wait_for_completion(&entity->entity_idle);
- /* The entity is guaranteed to not be used by the scheduler */
- prev = rcu_dereference_check(entity->last_scheduled, true);
- dma_fence_get(prev);
+ spin_lock(&entity->lock);
+ prev = dma_fence_get(entity->last_scheduled);
+ spin_unlock(&entity->lock);
while ((job = drm_sched_entity_queue_pop(entity))) {
struct drm_sched_fence *s_fence = job->s_fence;
@@ -413,8 +412,7 @@ void drm_sched_entity_fini(struct drm_sched_entity *entity)
entity->dependency = NULL;
}
- dma_fence_put(rcu_dereference_check(entity->last_scheduled, true));
- RCU_INIT_POINTER(entity->last_scheduled, NULL);
+ dma_fence_put(entity->last_scheduled);
drm_sched_entity_stats_put(entity->stats);
}
EXPORT_SYMBOL(drm_sched_entity_fini);
@@ -536,6 +534,10 @@ drm_sched_job_dependency(struct drm_sched_job *job,
struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity)
{
+ /* Helper to avoid dropping the reference while the entity lock is held,
+ * just to have some more robustness.
+ */
+ struct dma_fence *prev_last_scheduled;
struct drm_sched_job *sched_job;
sched_job = drm_sched_entity_queue_peek(entity);
@@ -552,22 +554,15 @@ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity)
if (entity->guilty && atomic_read(entity->guilty))
dma_fence_set_error(&sched_job->s_fence->finished, -ECANCELED);
- dma_fence_put(rcu_dereference_check(entity->last_scheduled, true));
- rcu_assign_pointer(entity->last_scheduled,
- dma_fence_get(&sched_job->s_fence->finished));
-
- /*
- * If the queue is empty we allow drm_sched_entity_select_rq() to
- * locklessly access ->last_scheduled. This only works if we set the
- * pointer before we dequeue and if we a write barrier here.
- */
- smp_wmb();
-
spin_lock(&entity->lock);
+ prev_last_scheduled = entity->last_scheduled;
+ entity->last_scheduled = dma_fence_get(&sched_job->s_fence->finished);
spsc_queue_pop(&entity->job_queue);
drm_sched_rq_pop_entity(entity);
spin_unlock(&entity->lock);
+ dma_fence_put(prev_last_scheduled);
+
/* Jobs and entities might have different lifecycles. Since we're
* removing the job from the entities queue, set the jobs entity pointer
* to NULL to prevent any future access of the entity through this job.
@@ -591,21 +586,15 @@ void drm_sched_entity_select_rq(struct drm_sched_entity *entity)
if (spsc_queue_count(&entity->job_queue))
return;
- /*
- * Only when the queue is empty are we guaranteed that
- * drm_sched_run_job_work() cannot change entity->last_scheduled. To
- * enforce ordering we need a read barrier here. See
- * drm_sched_entity_pop_job() for the other side.
- */
- smp_rmb();
-
- fence = rcu_dereference_check(entity->last_scheduled, true);
+ spin_lock(&entity->lock);
+ fence = entity->last_scheduled;
/* stay on the same engine if the previous job hasn't finished */
- if (fence && !dma_fence_is_signaled(fence))
+ if (fence && !dma_fence_is_signaled(fence)) {
+ spin_unlock(&entity->lock);
return;
+ }
- spin_lock(&entity->lock);
sched = drm_sched_pick_best(entity->sched_list, entity->num_sched_list);
rq = sched ? sched->sched_rq[entity->rq_priority] : NULL;
if (rq != entity->rq) {
diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c
index aba5545033ac..b9580ce1ddec 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -77,7 +77,6 @@
#include <drm/drm_gem.h>
#include <drm/drm_syncobj.h>
#include <drm/gpu_scheduler.h>
-#include <drm/spsc_queue.h>
#include "sched_internal.h"
diff --git a/drivers/gpu/drm/sitronix/st7571.c b/drivers/gpu/drm/sitronix/st7571.c
index fc3ba5e8600f..5e60c4685671 100644
--- a/drivers/gpu/drm/sitronix/st7571.c
+++ b/drivers/gpu/drm/sitronix/st7571.c
@@ -20,7 +20,6 @@
#include <drm/drm_damage_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_encoder.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fbdev_shmem.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c
index 324467ae9309..8cbf18754487 100644
--- a/drivers/gpu/drm/solomon/ssd130x.c
+++ b/drivers/gpu/drm/solomon/ssd130x.c
@@ -415,6 +415,20 @@ static int ssd130x_set_page_range(struct ssd130x_device *ssd130x,
return 0;
}
+static int ssd132x_set_col_range(struct ssd130x_device *ssd130x,
+ u8 col_start, u8 cols)
+{
+ return ssd130x_write_cmd(ssd130x, 3, SSD132X_SET_COL_RANGE,
+ col_start, col_start + cols - 1);
+}
+
+static int ssd132x_set_row_range(struct ssd130x_device *ssd130x,
+ u8 row_start, u8 rows)
+{
+ return ssd130x_write_cmd(ssd130x, 3, SSD132X_SET_ROW_RANGE,
+ row_start, row_start + rows - 1);
+}
+
/* Set page and column start address for page addressing mode */
static int ssd130x_set_page_pos(struct ssd130x_device *ssd130x,
u8 page_start, u8 col_start)
@@ -896,13 +910,12 @@ static int ssd132x_update_rect(struct ssd130x_device *ssd130x,
* the second byte are SEG2 (D1[3:0]) and SEG3 (D1[7:4]) and so on.
*/
- /* Set column start and end */
- ret = ssd130x_write_cmd(ssd130x, 3, SSD132X_SET_COL_RANGE, col, col + columns - 1);
+ /* Set address range for horizontal addressing mode */
+ ret = ssd132x_set_col_range(ssd130x, col, columns);
if (ret < 0)
return ret;
- /* Set row start and end */
- ret = ssd130x_write_cmd(ssd130x, 3, SSD132X_SET_ROW_RANGE, row, row + rows - 1);
+ ret = ssd132x_set_row_range(ssd130x, row, rows);
if (ret < 0)
return ret;
@@ -1052,9 +1065,18 @@ static void ssd132x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array)
{
unsigned int columns = DIV_ROUND_UP(ssd130x->width, SSD132X_SEGMENT_WIDTH);
unsigned int height = ssd130x->height;
+ int ret;
memset(data_array, 0, columns * height);
+ ret = ssd132x_set_col_range(ssd130x, 0, columns);
+ if (ret < 0)
+ return;
+
+ ret = ssd132x_set_row_range(ssd130x, 0, height);
+ if (ret < 0)
+ return;
+
/* Write out update in one go since horizontal addressing mode is used */
ssd130x_write_data(ssd130x, data_array, columns * height);
}
diff --git a/drivers/gpu/drm/stm/Kconfig b/drivers/gpu/drm/stm/Kconfig
index 635be0ac00af..1e3205aa2c7e 100644
--- a/drivers/gpu/drm/stm/Kconfig
+++ b/drivers/gpu/drm/stm/Kconfig
@@ -6,6 +6,7 @@ config DRM_STM
select DRM_CLIENT_SELECTION
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
+ select DRM_PANEL
select DRM_PANEL_BRIDGE
select VIDEOMODE_HELPERS
select FB_PROVIDE_GET_FB_UNMAPPED_AREA if FB
diff --git a/drivers/gpu/drm/tegra/fbdev.c b/drivers/gpu/drm/tegra/fbdev.c
index 003e80cf7b9a..64c2e64f219b 100644
--- a/drivers/gpu/drm/tegra/fbdev.c
+++ b/drivers/gpu/drm/tegra/fbdev.c
@@ -11,9 +11,9 @@
#include <linux/fb.h>
#include <linux/vmalloc.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_framebuffer_helper.h>
diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c
index bc1c93c7554c..b6d09a8d8e5e 100644
--- a/drivers/gpu/drm/tegra/rgb.c
+++ b/drivers/gpu/drm/tegra/rgb.c
@@ -10,6 +10,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_encoder.h>
+#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include "drm.h"
diff --git a/drivers/gpu/drm/tegra/uapi.c b/drivers/gpu/drm/tegra/uapi.c
index c0ac6b45f2d7..bee310b07eb0 100644
--- a/drivers/gpu/drm/tegra/uapi.c
+++ b/drivers/gpu/drm/tegra/uapi.c
@@ -7,7 +7,7 @@
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
-#include <drm/drm_utils.h>
+#include <drm/drm_timeout.h>
#include "drm.h"
#include "uapi.h"
diff --git a/drivers/gpu/drm/tidss/Kconfig b/drivers/gpu/drm/tidss/Kconfig
index 31ad582b7602..52a64fa1ad5d 100644
--- a/drivers/gpu/drm/tidss/Kconfig
+++ b/drivers/gpu/drm/tidss/Kconfig
@@ -7,6 +7,7 @@ config DRM_TIDSS
select DRM_DISPLAY_HELPER
select DRM_BRIDGE_CONNECTOR
select DRM_GEM_DMA_HELPER
+ select DRM_PANEL
help
The TI Keystone family SoCs introduced a new generation of
Display SubSystem. There is currently three Keystone family
diff --git a/drivers/gpu/drm/tve200/Kconfig b/drivers/gpu/drm/tve200/Kconfig
index a9d6fe535d88..afe243df4ebb 100644
--- a/drivers/gpu/drm/tve200/Kconfig
+++ b/drivers/gpu/drm/tve200/Kconfig
@@ -7,7 +7,7 @@ config DRM_TVE200
depends on OF
select DRM_BRIDGE
select DRM_CLIENT_SELECTION
- select DRM_PANEL_BRIDGE
+ select DRM_PANEL
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
help
diff --git a/drivers/gpu/drm/tve200/tve200_drm.h b/drivers/gpu/drm/tve200/tve200_drm.h
index 631a9f5d9aa6..708f8020667a 100644
--- a/drivers/gpu/drm/tve200/tve200_drm.h
+++ b/drivers/gpu/drm/tve200/tve200_drm.h
@@ -103,7 +103,6 @@ struct tve200_drm_dev_private {
struct drm_device *drm;
struct drm_connector *connector;
- struct drm_panel *panel;
struct drm_bridge *bridge;
struct drm_plane plane;
struct drm_crtc crtc;
diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c
index 63ca4a53fc4c..2bcb9dc86ffd 100644
--- a/drivers/gpu/drm/tve200/tve200_drv.c
+++ b/drivers/gpu/drm/tve200/tve200_drv.c
@@ -65,7 +65,6 @@ static int tve200_modeset_init(struct drm_device *dev)
{
struct drm_mode_config *mode_config;
struct tve200_drm_dev_private *priv = dev->dev_private;
- struct drm_panel *panel;
struct drm_bridge *bridge;
int ret;
@@ -77,19 +76,10 @@ static int tve200_modeset_init(struct drm_device *dev)
mode_config->min_height = 240;
mode_config->max_height = 576;
- ret = drm_of_find_panel_or_bridge(dev->dev->of_node,
- 0, 0, &panel, &bridge);
- if (ret && ret != -ENODEV)
- return ret;
- if (panel) {
- bridge = drm_panel_bridge_add_typed(panel,
- DRM_MODE_CONNECTOR_Unknown);
- drm_panel_put(panel);
- if (IS_ERR(bridge)) {
- ret = PTR_ERR(bridge);
- goto out_bridge;
- }
- } else {
+ bridge = of_drm_get_bridge_by_endpoint(dev->dev->of_node, 0, 0);
+ if (IS_ERR(bridge) && PTR_ERR(bridge) != -ENODEV)
+ return PTR_ERR(bridge);
+ if (IS_ERR(bridge) || !drm_bridge_is_panel(bridge)) {
/*
* TODO: when we are using a different bridge than a panel
* (such as a dumb VGA connector) we need to devise a different
@@ -100,13 +90,14 @@ static int tve200_modeset_init(struct drm_device *dev)
goto out_bridge;
}
+ bridge->type = DRM_MODE_CONNECTOR_Unknown;
+
ret = tve200_display_init(dev);
if (ret) {
dev_err(dev->dev, "failed to init display\n");
goto out_bridge;
}
- priv->panel = panel;
priv->bridge = bridge;
ret = drm_bridge_attach(&priv->encoder, bridge, NULL, 0);
@@ -121,9 +112,6 @@ static int tve200_modeset_init(struct drm_device *dev)
goto out_bridge;
}
- dev_info(dev->dev, "attached to panel %s\n",
- dev_name(panel->dev));
-
ret = drm_vblank_init(dev, 1);
if (ret) {
dev_err(dev->dev, "failed to init vblank\n");
@@ -136,8 +124,6 @@ static int tve200_modeset_init(struct drm_device *dev)
goto finish;
out_bridge:
- if (panel)
- drm_panel_bridge_remove(bridge);
drm_mode_config_cleanup(dev);
finish:
return ret;
@@ -233,8 +219,6 @@ static int tve200_probe(struct platform_device *pdev)
return 0;
mode_config_cleanup:
- if (priv->panel)
- drm_panel_bridge_remove(priv->bridge);
drm_mode_config_cleanup(drm);
clk_disable:
clk_disable_unprepare(priv->pclk);
@@ -248,10 +232,9 @@ static void tve200_remove(struct platform_device *pdev)
struct drm_device *drm = platform_get_drvdata(pdev);
struct tve200_drm_dev_private *priv = drm->dev_private;
+ drm_bridge_put(priv->bridge);
drm_dev_unregister(drm);
drm_atomic_helper_shutdown(drm);
- if (priv->panel)
- drm_panel_bridge_remove(priv->bridge);
drm_mode_config_cleanup(drm);
clk_disable_unprepare(priv->pclk);
drm_dev_put(drm);
diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c
index a847d2f0ccf5..db95a2fac5d0 100644
--- a/drivers/gpu/drm/v3d/v3d_bo.c
+++ b/drivers/gpu/drm/v3d/v3d_bo.c
@@ -19,6 +19,7 @@
#include <linux/vmalloc.h>
#include <drm/drm_print.h>
+#include <drm/drm_timeout.h>
#include "v3d_drv.h"
#include "uapi/drm/v3d_drm.h"
@@ -281,7 +282,7 @@ v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
ktime_t start = ktime_get();
u64 delta_ns;
unsigned long timeout_jiffies =
- nsecs_to_jiffies_timeout(args->timeout_ns);
+ drm_timeout_rel_to_jiffies(args->timeout_ns);
if (args->pad != 0)
return -EINVAL;
diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
index d40610a34db9..7c7bdf6e51a5 100644
--- a/drivers/gpu/drm/v3d/v3d_drv.h
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
@@ -588,16 +588,6 @@ struct v3d_submit_ext {
(Wmax))
#define wait_for(COND, MS) _wait_for((COND), (MS) * 1000, 10, 1000)
-static inline unsigned long nsecs_to_jiffies_timeout(const u64 n)
-{
- /* nsecs_to_jiffies64() does not guard against overflow */
- if ((NSEC_PER_SEC % HZ) != 0 &&
- div_u64(n, NSEC_PER_SEC) >= MAX_JIFFY_OFFSET / HZ)
- return MAX_JIFFY_OFFSET;
-
- return min_t(u64, MAX_JIFFY_OFFSET, nsecs_to_jiffies64(n) + 1);
-}
-
/* v3d_bo.c */
struct drm_gem_object *v3d_create_object(struct drm_device *dev, size_t size);
void v3d_free_object(struct drm_gem_object *gem_obj);
diff --git a/drivers/gpu/drm/vboxvideo/vbox_mode.c b/drivers/gpu/drm/vboxvideo/vbox_mode.c
index bb3f7f0ad7c4..7c34299fa531 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_mode.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_mode.c
@@ -13,11 +13,11 @@
#include <linux/iosys-map.h>
#include <linux/export.h>
+#include <drm/clients/drm_fbdev_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
#include <drm/drm_edid.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index 3212b9167620..0ea921bab906 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -32,6 +32,7 @@
#include <drm/drm_exec.h>
#include <drm/drm_print.h>
#include <drm/drm_syncobj.h>
+#include <drm/drm_timeout.h>
#include "vc4_drv.h"
#include "vc4_regs.h"
@@ -982,7 +983,7 @@ vc4_wait_bo_ioctl(struct drm_device *dev, void *data,
int ret;
struct drm_vc4_wait_bo *args = data;
unsigned long timeout_jiffies =
- usecs_to_jiffies(div_u64(args->timeout_ns, 1000));
+ drm_timeout_rel_to_jiffies(args->timeout_ns);
ktime_t start = ktime_get();
u64 delta_ns;
diff --git a/drivers/gpu/drm/xe/xe_wait_user_fence.c b/drivers/gpu/drm/xe/xe_wait_user_fence.c
index 51eb940ceb4e..e241f3ec3547 100644
--- a/drivers/gpu/drm/xe/xe_wait_user_fence.c
+++ b/drivers/gpu/drm/xe/xe_wait_user_fence.c
@@ -7,7 +7,7 @@
#include <drm/drm_device.h>
#include <drm/drm_file.h>
-#include <drm/drm_utils.h>
+#include <drm/drm_timeout.h>
#include <uapi/drm/xe_drm.h>
#include "xe_device.h"