summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2024-06-21 11:06:48 +1000
committerDave Airlie <airlied@redhat.com>2024-06-21 11:06:56 +1000
commitab3d8479626d281f43db0d41b8e36f6a9bd9980a (patch)
tree779a421a2659ddec0d34992804138e3e101857ad /drivers
parent91c93e475ca4b4bd5f1e8d525c9a9810283db056 (diff)
parentb9578c49456340ca4d3c7ddbaca054ffc2b51bc1 (diff)
Merge tag 'drm-misc-next-2024-06-20' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next
drm-misc-next for 6.11: UAPI Changes: - New monochrome TV mode variant Cross-subsystem Changes: - dma heaps: Change slightly the allocation hook prototype Core Changes: Driver Changes: - ivpu: various improvements over firmware handling, clocks, power management, scheduling and logging. - mgag200: Add BMC output, enable polling - panfrost: Enable MT8188 support - tidss: drm_panic support - zynqmp_dp: IRQ cleanups, debugfs DP compliance testing API - bridge: - sii902x: state validation improvements - panel: - edp: Drop legacy panel compatibles - simple-bridge: Switch to devm_drm_bridge_add Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maxime Ripard <mripard@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240620-heretic-honored-macaque-b40f8a@houat
Diffstat (limited to 'drivers')
-rw-r--r--drivers/accel/ivpu/ivpu_debugfs.c39
-rw-r--r--drivers/accel/ivpu/ivpu_drv.c41
-rw-r--r--drivers/accel/ivpu/ivpu_drv.h6
-rw-r--r--drivers/accel/ivpu/ivpu_fw.c31
-rw-r--r--drivers/accel/ivpu/ivpu_fw.h2
-rw-r--r--drivers/accel/ivpu/ivpu_hw.c30
-rw-r--r--drivers/accel/ivpu/ivpu_hw.h4
-rw-r--r--drivers/accel/ivpu/ivpu_hw_btrs.c44
-rw-r--r--drivers/accel/ivpu/ivpu_hw_btrs.h6
-rw-r--r--drivers/accel/ivpu/ivpu_hw_btrs_lnl_reg.h10
-rw-r--r--drivers/accel/ivpu/ivpu_ipc.c3
-rw-r--r--drivers/accel/ivpu/ivpu_ipc.h4
-rw-r--r--drivers/accel/ivpu/ivpu_job.c29
-rw-r--r--drivers/accel/ivpu/ivpu_job.h4
-rw-r--r--drivers/accel/ivpu/ivpu_jsm_msg.c52
-rw-r--r--drivers/accel/ivpu/ivpu_jsm_msg.h2
-rw-r--r--drivers/accel/ivpu/ivpu_mmu.c10
-rw-r--r--drivers/accel/ivpu/ivpu_mmu_context.c86
-rw-r--r--drivers/accel/ivpu/ivpu_mmu_context.h2
-rw-r--r--drivers/accel/ivpu/ivpu_pm.c106
-rw-r--r--drivers/accel/ivpu/ivpu_pm.h10
-rw-r--r--drivers/accel/ivpu/vpu_boot_api.h16
-rw-r--r--drivers/dma-buf/heaps/cma_heap.c4
-rw-r--r--drivers/dma-buf/heaps/system_heap.c4
-rw-r--r--drivers/gpu/drm/Kconfig2
-rw-r--r--drivers/gpu/drm/bridge/sii902x.c46
-rw-r--r--drivers/gpu/drm/bridge/simple-bridge.c13
-rw-r--r--drivers/gpu/drm/ci/build.sh1
-rw-r--r--drivers/gpu/drm/ci/gitlab-ci.yml1
-rwxr-xr-xdrivers/gpu/drm/ci/igt_runner.sh6
-rw-r--r--drivers/gpu/drm/ci/image-tags.yml2
-rw-r--r--drivers/gpu/drm/ci/test.yml24
-rw-r--r--drivers/gpu/drm/ci/x86_64.config1
-rw-r--r--drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt1
-rw-r--r--drivers/gpu/drm/ci/xfails/msm-apq8096-fails.txt1
-rw-r--r--drivers/gpu/drm/ci/xfails/vkms-none-fails.txt57
-rw-r--r--drivers/gpu/drm/ci/xfails/vkms-none-flakes.txt69
-rw-r--r--drivers/gpu/drm/ci/xfails/vkms-none-skips.txt119
-rw-r--r--drivers/gpu/drm/drm_connector.c7
-rw-r--r--drivers/gpu/drm/drm_modes.c5
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c5
-rw-r--r--drivers/gpu/drm/mgag200/Makefile3
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_bmc.c107
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.h34
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200.c47
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200eh.c47
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200eh3.c47
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200er.c47
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200ev.c47
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200ew3.c47
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200se.c47
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200wb.c47
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_vga.c72
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_chan.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dmem.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_exec.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c30
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_sched.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_uvmm.c2
-rw-r--r--drivers/gpu/drm/panel/panel-edp.c192
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_drv.c10
-rw-r--r--drivers/gpu/drm/tidss/tidss_plane.c14
-rw-r--r--drivers/gpu/drm/xlnx/zynqmp_dp.c37
-rw-r--r--drivers/gpu/drm/xlnx/zynqmp_dpsub.c1
-rw-r--r--drivers/gpu/drm/xlnx/zynqmp_kms.c22
68 files changed, 1105 insertions, 716 deletions
diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c
index 10d6408c9831..6f86f8df30db 100644
--- a/drivers/accel/ivpu/ivpu_debugfs.c
+++ b/drivers/accel/ivpu/ivpu_debugfs.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2020-2023 Intel Corporation
+ * Copyright (C) 2020-2024 Intel Corporation
*/
#include <linux/debugfs.h>
@@ -381,6 +381,39 @@ static const struct file_operations ivpu_resume_engine_fops = {
.write = ivpu_resume_engine_fn,
};
+static int dct_active_get(void *data, u64 *active_percent)
+{
+ struct ivpu_device *vdev = data;
+
+ *active_percent = vdev->pm->dct_active_percent;
+
+ return 0;
+}
+
+static int dct_active_set(void *data, u64 active_percent)
+{
+ struct ivpu_device *vdev = data;
+ int ret;
+
+ if (active_percent > 100)
+ return -EINVAL;
+
+ ret = ivpu_rpm_get(vdev);
+ if (ret)
+ return ret;
+
+ if (active_percent)
+ ret = ivpu_pm_dct_enable(vdev, active_percent);
+ else
+ ret = ivpu_pm_dct_disable(vdev);
+
+ ivpu_rpm_put(vdev);
+
+ return ret;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(ivpu_dct_fops, dct_active_get, dct_active_set, "%llu\n");
+
void ivpu_debugfs_init(struct ivpu_device *vdev)
{
struct dentry *debugfs_root = vdev->drm.debugfs_root;
@@ -409,7 +442,9 @@ void ivpu_debugfs_init(struct ivpu_device *vdev)
debugfs_create_file("resume_engine", 0200, debugfs_root, vdev,
&ivpu_resume_engine_fops);
- if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_40XX)
+ if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_40XX) {
debugfs_create_file("fw_profiling_freq_drive", 0200,
debugfs_root, vdev, &fw_profiling_freq_fops);
+ debugfs_create_file("dct", 0644, debugfs_root, vdev, &ivpu_dct_fops);
+ }
}
diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c
index f3e0d55f4adb..c91400ecf926 100644
--- a/drivers/accel/ivpu/ivpu_drv.c
+++ b/drivers/accel/ivpu/ivpu_drv.c
@@ -58,11 +58,11 @@ module_param_named(sched_mode, ivpu_sched_mode, int, 0444);
MODULE_PARM_DESC(sched_mode, "Scheduler mode: 0 - Default scheduler, 1 - Force HW scheduler");
bool ivpu_disable_mmu_cont_pages;
-module_param_named(disable_mmu_cont_pages, ivpu_disable_mmu_cont_pages, bool, 0644);
+module_param_named(disable_mmu_cont_pages, ivpu_disable_mmu_cont_pages, bool, 0444);
MODULE_PARM_DESC(disable_mmu_cont_pages, "Disable MMU contiguous pages optimization");
bool ivpu_force_snoop;
-module_param_named(force_snoop, ivpu_force_snoop, bool, 0644);
+module_param_named(force_snoop, ivpu_force_snoop, bool, 0444);
MODULE_PARM_DESC(force_snoop, "Force snooping for NPU host memory access");
struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv)
@@ -391,8 +391,13 @@ int ivpu_boot(struct ivpu_device *vdev)
ivpu_hw_irq_enable(vdev);
ivpu_ipc_enable(vdev);
- if (ivpu_fw_is_cold_boot(vdev))
+ if (ivpu_fw_is_cold_boot(vdev)) {
+ ret = ivpu_pm_dct_init(vdev);
+ if (ret)
+ return ret;
+
return ivpu_hw_sched_init(vdev);
+ }
return 0;
}
@@ -446,6 +451,26 @@ static const struct drm_driver driver = {
.minor = DRM_IVPU_DRIVER_MINOR,
};
+static void ivpu_context_abort_invalid(struct ivpu_device *vdev)
+{
+ struct ivpu_file_priv *file_priv;
+ unsigned long ctx_id;
+
+ mutex_lock(&vdev->context_list_lock);
+
+ xa_for_each(&vdev->context_xa, ctx_id, file_priv) {
+ if (!file_priv->has_mmu_faults || file_priv->aborted)
+ continue;
+
+ mutex_lock(&file_priv->lock);
+ ivpu_context_abort_locked(file_priv);
+ file_priv->aborted = true;
+ mutex_unlock(&file_priv->lock);
+ }
+
+ mutex_unlock(&vdev->context_list_lock);
+}
+
static irqreturn_t ivpu_irq_thread_handler(int irq, void *arg)
{
struct ivpu_device *vdev = arg;
@@ -459,6 +484,12 @@ static irqreturn_t ivpu_irq_thread_handler(int irq, void *arg)
case IVPU_HW_IRQ_SRC_IPC:
ivpu_ipc_irq_thread_handler(vdev);
break;
+ case IVPU_HW_IRQ_SRC_MMU_EVTQ:
+ ivpu_context_abort_invalid(vdev);
+ break;
+ case IVPU_HW_IRQ_SRC_DCT:
+ ivpu_pm_dct_irq_thread_handler(vdev);
+ break;
default:
ivpu_err_ratelimited(vdev, "Unknown IRQ source: %u\n", irq_src);
break;
@@ -664,14 +695,14 @@ static void ivpu_bo_unbind_all_user_contexts(struct ivpu_device *vdev)
static void ivpu_dev_fini(struct ivpu_device *vdev)
{
+ ivpu_jobs_abort_all(vdev);
+ ivpu_pm_cancel_recovery(vdev);
ivpu_pm_disable(vdev);
ivpu_prepare_for_reset(vdev);
ivpu_shutdown(vdev);
ivpu_ms_cleanup_all(vdev);
- ivpu_jobs_abort_all(vdev);
ivpu_job_done_consumer_fini(vdev);
- ivpu_pm_cancel_recovery(vdev);
ivpu_bo_unbind_all_user_contexts(vdev);
ivpu_ipc_fini(vdev);
diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h
index 39df96a7623b..63f13b697eed 100644
--- a/drivers/accel/ivpu/ivpu_drv.h
+++ b/drivers/accel/ivpu/ivpu_drv.h
@@ -32,6 +32,8 @@
#define IVPU_HW_IP_50XX 50
#define IVPU_HW_IP_60XX 60
+#define IVPU_HW_IP_REV_LNL_B0 4
+
#define IVPU_HW_BTRS_MTL 1
#define IVPU_HW_BTRS_LNL 2
@@ -102,6 +104,7 @@ struct ivpu_wa_table {
bool interrupt_clear_with_0;
bool disable_clock_relinquish;
bool disable_d0i3_msg;
+ bool wp0_during_power_up;
};
struct ivpu_hw_info;
@@ -147,7 +150,6 @@ struct ivpu_device {
int boot;
int jsm;
int tdr;
- int reschedule_suspend;
int autosuspend;
int d0i3_entry_msg;
} timeout;
@@ -168,6 +170,7 @@ struct ivpu_file_priv {
struct ivpu_bo *ms_info_bo;
bool has_mmu_faults;
bool bound;
+ bool aborted;
};
extern int ivpu_dbg_mask;
@@ -184,6 +187,7 @@ extern bool ivpu_force_snoop;
#define IVPU_TEST_MODE_D0I3_MSG_ENABLE BIT(5)
#define IVPU_TEST_MODE_PREEMPTION_DISABLE BIT(6)
#define IVPU_TEST_MODE_HWS_EXTRA_EVENTS BIT(7)
+#define IVPU_TEST_MODE_DISABLE_TIMEOUTS BIT(8)
extern int ivpu_test_mode;
struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv);
diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c
index 1fc4befe7461..de3d66116375 100644
--- a/drivers/accel/ivpu/ivpu_fw.c
+++ b/drivers/accel/ivpu/ivpu_fw.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2020-2023 Intel Corporation
+ * Copyright (C) 2020-2024 Intel Corporation
*/
#include <linux/firmware.h>
@@ -123,6 +123,14 @@ ivpu_fw_check_api_ver_lt(struct ivpu_device *vdev, const struct vpu_firmware_hea
return false;
}
+static bool is_within_range(u64 addr, size_t size, u64 range_start, size_t range_size)
+{
+ if (addr < range_start || addr + size > range_start + range_size)
+ return false;
+
+ return true;
+}
+
static int ivpu_fw_parse(struct ivpu_device *vdev)
{
struct ivpu_fw_info *fw = vdev->fw;
@@ -205,10 +213,24 @@ static int ivpu_fw_parse(struct ivpu_device *vdev)
fw->primary_preempt_buf_size = fw_hdr->preemption_buffer_1_size;
fw->secondary_preempt_buf_size = fw_hdr->preemption_buffer_2_size;
+ if (fw_hdr->ro_section_start_address && !is_within_range(fw_hdr->ro_section_start_address,
+ fw_hdr->ro_section_size,
+ fw_hdr->image_load_address,
+ fw_hdr->image_size)) {
+ ivpu_err(vdev, "Invalid read-only section: start address 0x%llx, size %u\n",
+ fw_hdr->ro_section_start_address, fw_hdr->ro_section_size);
+ return -EINVAL;
+ }
+
+ fw->read_only_addr = fw_hdr->ro_section_start_address;
+ fw->read_only_size = fw_hdr->ro_section_size;
+
ivpu_dbg(vdev, FW_BOOT, "Size: file %lu image %u runtime %u shavenn %u\n",
fw->file->size, fw->image_size, fw->runtime_size, fw->shave_nn_size);
ivpu_dbg(vdev, FW_BOOT, "Address: runtime 0x%llx, load 0x%llx, entry point 0x%llx\n",
fw->runtime_addr, image_load_addr, fw->entry_point);
+ ivpu_dbg(vdev, FW_BOOT, "Read-only section: address 0x%llx, size %u\n",
+ fw->read_only_addr, fw->read_only_size);
return 0;
}
@@ -270,6 +292,13 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev)
return -ENOMEM;
}
+ ret = ivpu_mmu_context_set_pages_ro(vdev, &vdev->gctx, fw->read_only_addr,
+ fw->read_only_size);
+ if (ret) {
+ ivpu_err(vdev, "Failed to set firmware image read-only\n");
+ goto err_free_fw_mem;
+ }
+
fw->mem_log_crit = ivpu_bo_create_global(vdev, IVPU_FW_CRITICAL_BUFFER_SIZE,
DRM_IVPU_BO_CACHED | DRM_IVPU_BO_MAPPABLE);
if (!fw->mem_log_crit) {
diff --git a/drivers/accel/ivpu/ivpu_fw.h b/drivers/accel/ivpu/ivpu_fw.h
index 66fc7da3ab0f..40d9d17be3f5 100644
--- a/drivers/accel/ivpu/ivpu_fw.h
+++ b/drivers/accel/ivpu/ivpu_fw.h
@@ -30,6 +30,8 @@ struct ivpu_fw_info {
u32 dvfs_mode;
u32 primary_preempt_buf_size;
u32 secondary_preempt_buf_size;
+ u64 read_only_addr;
+ u32 read_only_size;
};
int ivpu_fw_init(struct ivpu_device *vdev);
diff --git a/drivers/accel/ivpu/ivpu_hw.c b/drivers/accel/ivpu/ivpu_hw.c
index 9f5e3875baf1..27f0fe4d54e0 100644
--- a/drivers/accel/ivpu/ivpu_hw.c
+++ b/drivers/accel/ivpu/ivpu_hw.c
@@ -61,37 +61,48 @@ static void wa_init(struct ivpu_device *vdev)
if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
vdev->wa.interrupt_clear_with_0 = ivpu_hw_btrs_irqs_clear_with_0_mtl(vdev);
- if (ivpu_device_id(vdev) == PCI_DEVICE_ID_LNL)
+ if (ivpu_device_id(vdev) == PCI_DEVICE_ID_LNL &&
+ ivpu_revision(vdev) < IVPU_HW_IP_REV_LNL_B0)
vdev->wa.disable_clock_relinquish = true;
+ if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
+ vdev->wa.wp0_during_power_up = true;
+
IVPU_PRINT_WA(punit_disabled);
IVPU_PRINT_WA(clear_runtime_mem);
IVPU_PRINT_WA(interrupt_clear_with_0);
IVPU_PRINT_WA(disable_clock_relinquish);
+ IVPU_PRINT_WA(wp0_during_power_up);
}
static void timeouts_init(struct ivpu_device *vdev)
{
- if (ivpu_is_fpga(vdev)) {
+ if (ivpu_test_mode & IVPU_TEST_MODE_DISABLE_TIMEOUTS) {
+ vdev->timeout.boot = -1;
+ vdev->timeout.jsm = -1;
+ vdev->timeout.tdr = -1;
+ vdev->timeout.autosuspend = -1;
+ vdev->timeout.d0i3_entry_msg = -1;
+ } else if (ivpu_is_fpga(vdev)) {
vdev->timeout.boot = 100000;
vdev->timeout.jsm = 50000;
vdev->timeout.tdr = 2000000;
- vdev->timeout.reschedule_suspend = 1000;
vdev->timeout.autosuspend = -1;
vdev->timeout.d0i3_entry_msg = 500;
} else if (ivpu_is_simics(vdev)) {
vdev->timeout.boot = 50;
vdev->timeout.jsm = 500;
vdev->timeout.tdr = 10000;
- vdev->timeout.reschedule_suspend = 10;
vdev->timeout.autosuspend = -1;
vdev->timeout.d0i3_entry_msg = 100;
} else {
vdev->timeout.boot = 1000;
vdev->timeout.jsm = 500;
vdev->timeout.tdr = 2000;
- vdev->timeout.reschedule_suspend = 10;
- vdev->timeout.autosuspend = 10;
+ if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
+ vdev->timeout.autosuspend = 10;
+ else
+ vdev->timeout.autosuspend = 100;
vdev->timeout.d0i3_entry_msg = 5;
}
}
@@ -125,6 +136,13 @@ int ivpu_hw_power_up(struct ivpu_device *vdev)
{
int ret;
+ if (IVPU_WA(wp0_during_power_up)) {
+ /* WP requests may fail when powering down, so issue WP 0 here */
+ ret = wp_disable(vdev);
+ if (ret)
+ ivpu_warn(vdev, "Failed to disable workpoint: %d\n", ret);
+ }
+
ret = ivpu_hw_btrs_d0i3_disable(vdev);
if (ret)
ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret);
diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h
index 8ddf9f93189d..1c0c98e3afb8 100644
--- a/drivers/accel/ivpu/ivpu_hw.h
+++ b/drivers/accel/ivpu/ivpu_hw.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2020 - 2024 Intel Corporation
+ * Copyright (C) 2020-2024 Intel Corporation
*/
#ifndef __IVPU_HW_H__
@@ -15,6 +15,8 @@
#define IVPU_HW_IRQ_FIFO_LENGTH 1024
#define IVPU_HW_IRQ_SRC_IPC 1
+#define IVPU_HW_IRQ_SRC_MMU_EVTQ 2
+#define IVPU_HW_IRQ_SRC_DCT 3
struct ivpu_addr_range {
resource_size_t start;
diff --git a/drivers/accel/ivpu/ivpu_hw_btrs.c b/drivers/accel/ivpu/ivpu_hw_btrs.c
index 13734d1abc7d..745e5248803d 100644
--- a/drivers/accel/ivpu/ivpu_hw_btrs.c
+++ b/drivers/accel/ivpu/ivpu_hw_btrs.c
@@ -504,6 +504,8 @@ static int ip_reset_lnl(struct ivpu_device *vdev)
int ret;
u32 val;
+ ivpu_hw_btrs_clock_relinquish_disable_lnl(vdev);
+
ret = REGB_POLL_FLD(VPU_HW_BTRS_LNL_IP_RESET, TRIGGER, 0, TIMEOUT_US);
if (ret) {
ivpu_err(vdev, "Wait for *_TRIGGER timed out\n");
@@ -641,8 +643,11 @@ bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq)
if (!status)
return false;
- if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, SURV_ERR, status))
+ if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, SURV_ERR, status)) {
ivpu_dbg(vdev, IRQ, "Survivability IRQ\n");
+ if (!kfifo_put(&vdev->hw->irq.fifo, IVPU_HW_IRQ_SRC_DCT))
+ ivpu_err_ratelimited(vdev, "IRQ FIFO full\n");
+ }
if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, FREQ_CHANGE, status))
ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq: %08x", REGB_RD32(VPU_HW_BTRS_LNL_PLL_FREQ));
@@ -692,21 +697,40 @@ bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq)
return true;
}
-static void dct_drive_40xx(struct ivpu_device *vdev, u32 dct_val)
+int ivpu_hw_btrs_dct_get_request(struct ivpu_device *vdev, bool *enable)
{
- u32 val = REGB_RD32(VPU_HW_BTRS_LNL_PCODE_MAILBOX);
+ u32 val = REGB_RD32(VPU_HW_BTRS_LNL_PCODE_MAILBOX_SHADOW);
+ u32 cmd = REG_GET_FLD(VPU_HW_BTRS_LNL_PCODE_MAILBOX_SHADOW, CMD, val);
+ u32 param1 = REG_GET_FLD(VPU_HW_BTRS_LNL_PCODE_MAILBOX_SHADOW, PARAM1, val);
- val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_PCODE_MAILBOX, CMD, DCT_REQ, val);
- val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_PCODE_MAILBOX, PARAM1,
- dct_val ? DCT_ENABLE : DCT_DISABLE, val);
- val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_PCODE_MAILBOX, PARAM2, dct_val, val);
+ if (cmd != DCT_REQ) {
+ ivpu_err_ratelimited(vdev, "Unsupported PCODE command: 0x%x\n", cmd);
+ return -EBADR;
+ }
- REGB_WR32(VPU_HW_BTRS_LNL_PCODE_MAILBOX, val);
+ switch (param1) {
+ case DCT_ENABLE:
+ *enable = true;
+ return 0;
+ case DCT_DISABLE:
+ *enable = false;
+ return 0;
+ default:
+ ivpu_err_ratelimited(vdev, "Invalid PARAM1 value: %u\n", param1);
+ return -EINVAL;
+ }
}
-void ivpu_hw_btrs_dct_drive(struct ivpu_device *vdev, u32 dct_val)
+void ivpu_hw_btrs_dct_set_status(struct ivpu_device *vdev, bool enable, u32 active_percent)
{
- return dct_drive_40xx(vdev, dct_val);
+ u32 val = 0;
+ u32 cmd = enable ? DCT_ENABLE : DCT_DISABLE;
+
+ val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS, CMD, DCT_REQ, val);
+ val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS, PARAM1, cmd, val);
+ val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS, PARAM2, active_percent, val);
+
+ REGB_WR32(VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS, val);
}
static u32 pll_ratio_to_freq_mtl(u32 ratio, u32 config)
diff --git a/drivers/accel/ivpu/ivpu_hw_btrs.h b/drivers/accel/ivpu/ivpu_hw_btrs.h
index b3e3ae2aa578..04f14f50fed6 100644
--- a/drivers/accel/ivpu/ivpu_hw_btrs.h
+++ b/drivers/accel/ivpu/ivpu_hw_btrs.h
@@ -15,6 +15,9 @@
#define PLL_PROFILING_FREQ_HIGH 400000000
#define PLL_RATIO_TO_FREQ(x) ((x) * PLL_REF_CLK_FREQ)
+#define DCT_DEFAULT_ACTIVE_PERCENT 15u
+#define DCT_PERIOD_US 35300u
+
int ivpu_hw_btrs_info_init(struct ivpu_device *vdev);
void ivpu_hw_btrs_freq_ratios_init(struct ivpu_device *vdev);
int ivpu_hw_btrs_irqs_clear_with_0_mtl(struct ivpu_device *vdev);
@@ -31,7 +34,8 @@ void ivpu_hw_btrs_ats_print_lnl(struct ivpu_device *vdev);
void ivpu_hw_btrs_clock_relinquish_disable_lnl(struct ivpu_device *vdev);
bool ivpu_hw_btrs_irq_handler_mtl(struct ivpu_device *vdev, int irq);
bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq);
-void ivpu_hw_btrs_dct_drive(struct ivpu_device *vdev, u32 dct_val);
+int ivpu_hw_btrs_dct_get_request(struct ivpu_device *vdev, bool *enable);
+void ivpu_hw_btrs_dct_set_status(struct ivpu_device *vdev, bool enable, u32 dct_percent);
u32 ivpu_hw_btrs_pll_freq_get(struct ivpu_device *vdev);
u32 ivpu_hw_btrs_ratio_to_freq(struct ivpu_device *vdev, u32 ratio);
u32 ivpu_hw_btrs_telemetry_offset_get(struct ivpu_device *vdev);
diff --git a/drivers/accel/ivpu/ivpu_hw_btrs_lnl_reg.h b/drivers/accel/ivpu/ivpu_hw_btrs_lnl_reg.h
index 93733bde02b0..fc51f3098f97 100644
--- a/drivers/accel/ivpu/ivpu_hw_btrs_lnl_reg.h
+++ b/drivers/accel/ivpu/ivpu_hw_btrs_lnl_reg.h
@@ -44,11 +44,11 @@
#define VPU_HW_BTRS_LNL_IMR_ERR_CFI1_HIGH 0x0000005cu
#define VPU_HW_BTRS_LNL_IMR_ERR_CFI1_CLEAR 0x00000060u
-#define VPU_HW_BTRS_LNL_PCODE_MAILBOX 0x00000070u
-#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_CMD_MASK GENMASK(7, 0)
-#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_PARAM1_MASK GENMASK(15, 8)
-#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_PARAM2_MASK GENMASK(23, 16)
-#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_PARAM3_MASK GENMASK(31, 24)
+#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS 0x00000070u
+#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS_CMD_MASK GENMASK(7, 0)
+#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS_PARAM1_MASK GENMASK(15, 8)
+#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS_PARAM2_MASK GENMASK(23, 16)
+#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS_PARAM3_MASK GENMASK(31, 24)
#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_SHADOW 0x00000074u
#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_SHADOW_CMD_MASK GENMASK(7, 0)
diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c
index 74ab964d229b..78b32a823241 100644
--- a/drivers/accel/ivpu/ivpu_ipc.c
+++ b/drivers/accel/ivpu/ivpu_ipc.c
@@ -210,8 +210,7 @@ void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *c
ivpu_ipc_tx_release(vdev, cons->tx_vpu_addr);
}
-static int
-ivpu_ipc_send(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct vpu_jsm_msg *req)
+int ivpu_ipc_send(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct vpu_jsm_msg *req)
{
struct ivpu_ipc_info *ipc = vdev->ipc;
int ret;
diff --git a/drivers/accel/ivpu/ivpu_ipc.h b/drivers/accel/ivpu/ivpu_ipc.h
index 75f532428d68..4fe38141045e 100644
--- a/drivers/accel/ivpu/ivpu_ipc.h
+++ b/drivers/accel/ivpu/ivpu_ipc.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2020-2023 Intel Corporation
+ * Copyright (C) 2020-2024 Intel Corporation
*/
#ifndef __IVPU_IPC_H__
@@ -96,6 +96,8 @@ void ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *c
u32 channel, ivpu_ipc_rx_callback_t callback);
void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons);
+int ivpu_ipc_send(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
+ struct vpu_jsm_msg *req);
int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
struct ivpu_ipc_hdr *ipc_buf, struct vpu_jsm_msg *jsm_msg,
unsigned long timeout_ms);
diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c
index e4e24813fe03..be2e2bf0f43f 100644
--- a/drivers/accel/ivpu/ivpu_job.c
+++ b/drivers/accel/ivpu/ivpu_job.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2020-2023 Intel Corporation
+ * Copyright (C) 2020-2024 Intel Corporation
*/
#include <drm/drm_file.h>
@@ -312,6 +312,33 @@ void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev)
mutex_unlock(&vdev->context_list_lock);
}
+static void ivpu_cmdq_fini_all(struct ivpu_file_priv *file_priv)
+{
+ u16 engine;
+ u8 priority;
+
+ for (engine = 0; engine < IVPU_NUM_ENGINES; engine++) {
+ for (priority = 0; priority < IVPU_NUM_PRIORITIES; priority++) {
+ int cmdq_idx = IVPU_CMDQ_INDEX(engine, priority);
+
+ if (file_priv->cmdq[cmdq_idx])
+ ivpu_cmdq_fini(file_priv, file_priv->cmdq[cmdq_idx]);
+ }
+ }
+}
+
+void ivpu_context_abort_locked(struct ivpu_file_priv *file_priv)
+{
+ struct ivpu_device *vdev = file_priv->vdev;
+
+ lockdep_assert_held(&file_priv->lock);
+
+ ivpu_cmdq_fini_all(file_priv);
+
+ if (vdev->hw->sched_mode == VPU_SCHEDULING_MODE_OS)
+ ivpu_jsm_context_release(vdev, file_priv->ctx.id);
+}
+
static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job)
{
struct ivpu_device *vdev = job->vdev;
diff --git a/drivers/accel/ivpu/ivpu_job.h b/drivers/accel/ivpu/ivpu_job.h
index e50002b5788c..6accb94028c7 100644
--- a/drivers/accel/ivpu/ivpu_job.h
+++ b/drivers/accel/ivpu/ivpu_job.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2020-2023 Intel Corporation
+ * Copyright (C) 2020-2024 Intel Corporation
*/
#ifndef __IVPU_JOB_H__
@@ -57,6 +57,8 @@ struct ivpu_job {
int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file);
+void ivpu_context_abort_locked(struct ivpu_file_priv *file_priv);
+
void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv);
void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev);
diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.c b/drivers/accel/ivpu/ivpu_jsm_msg.c
index e8dd73d947e4..46ef16c3c069 100644
--- a/drivers/accel/ivpu/ivpu_jsm_msg.c
+++ b/drivers/accel/ivpu/ivpu_jsm_msg.c
@@ -103,14 +103,10 @@ int ivpu_jsm_register_db(struct ivpu_device *vdev, u32 ctx_id, u32 db_id,
ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_REGISTER_DB_DONE, &resp,
VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
- if (ret) {
- ivpu_err_ratelimited(vdev, "Failed to register doorbell %d: %d\n", db_id, ret);
- return ret;
- }
-
- ivpu_dbg(vdev, JSM, "Doorbell %d registered to context %d\n", db_id, ctx_id);
+ if (ret)
+ ivpu_err_ratelimited(vdev, "Failed to register doorbell %u: %d\n", db_id, ret);
- return 0;
+ return ret;
}
int ivpu_jsm_unregister_db(struct ivpu_device *vdev, u32 db_id)
@@ -123,14 +119,10 @@ int ivpu_jsm_unregister_db(struct ivpu_device *vdev, u32 db_id)
ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_UNREGISTER_DB_DONE, &resp,
VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
- if (ret) {
- ivpu_warn_ratelimited(vdev, "Failed to unregister doorbell %d: %d\n", db_id, ret);
- return ret;
- }
-
- ivpu_dbg(vdev, JSM, "Doorbell %d unregistered\n", db_id);
+ if (ret)
+ ivpu_warn_ratelimited(vdev, "Failed to unregister doorbell %u: %d\n", db_id, ret);
- return 0;
+ return ret;
}
int ivpu_jsm_get_heartbeat(struct ivpu_device *vdev, u32 engine, u64 *heartbeat)
@@ -255,11 +247,16 @@ int ivpu_jsm_context_release(struct ivpu_device *vdev, u32 host_ssid)
{
struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_SSID_RELEASE };
struct vpu_jsm_msg resp;
+ int ret;
req.payload.ssid_release.host_ssid = host_ssid;
- return ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_SSID_RELEASE_DONE, &resp,
- VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
+ ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_SSID_RELEASE_DONE, &resp,
+ VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
+ if (ret)
+ ivpu_warn_ratelimited(vdev, "Failed to release context: %d\n", ret);
+
+ return ret;
}
int ivpu_jsm_pwr_d0i3_enter(struct ivpu_device *vdev)
@@ -538,3 +535,26 @@ int ivpu_jsm_metric_streamer_info(struct ivpu_device *vdev, u64 metric_group_mas
return ret;
}
+
+int ivpu_jsm_dct_enable(struct ivpu_device *vdev, u32 active_us, u32 inactive_us)
+{
+ struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_DCT_ENABLE };
+ struct vpu_jsm_msg resp;
+
+ req.payload.pwr_dct_control.dct_active_us = active_us;
+ req.payload.pwr_dct_control.dct_inactive_us = inactive_us;
+
+ return ivpu_ipc_send_receive_active(vdev, &req, VPU_JSM_MSG_DCT_ENABLE_DONE,
+ &resp, VPU_IPC_CHAN_ASYNC_CMD,
+ vdev->timeout.jsm);
+}
+
+int ivpu_jsm_dct_disable(struct ivpu_device *vdev)
+{
+ struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_DCT_DISABLE };
+ struct vpu_jsm_msg resp;
+
+ return ivpu_ipc_send_receive_active(vdev, &req, VPU_JSM_MSG_DCT_DISABLE_DONE,
+ &resp, VPU_IPC_CHAN_ASYNC_CMD,
+ vdev->timeout.jsm);
+}
diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.h b/drivers/accel/ivpu/ivpu_jsm_msg.h
index 060363409fb3..e4e42c0ff6e6 100644
--- a/drivers/accel/ivpu/ivpu_jsm_msg.h
+++ b/drivers/accel/ivpu/ivpu_jsm_msg.h
@@ -41,4 +41,6 @@ int ivpu_jsm_metric_streamer_update(struct ivpu_device *vdev, u64 metric_group_m
u64 buffer_addr, u64 buffer_size, u64 *bytes_written);
int ivpu_jsm_metric_streamer_info(struct ivpu_device *vdev, u64 metric_group_mask, u64 buffer_addr,
u64 buffer_size, u32 *sample_size, u64 *info_size);
+int ivpu_jsm_dct_enable(struct ivpu_device *vdev, u32 active_us, u32 inactive_us);
+int ivpu_jsm_dct_disable(struct ivpu_device *vdev);
#endif
diff --git a/drivers/accel/ivpu/ivpu_mmu.c b/drivers/accel/ivpu/ivpu_mmu.c
index 8682e6145520..c078e214b221 100644
--- a/drivers/accel/ivpu/ivpu_mmu.c
+++ b/drivers/accel/ivpu/ivpu_mmu.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2020-2023 Intel Corporation
+ * Copyright (C) 2020-2024 Intel Corporation
*/
#include <linux/circ_buf.h>
@@ -878,8 +878,9 @@ static void ivpu_mmu_dump_event(struct ivpu_device *vdev, u32 *event)
u64 in_addr = ((u64)event[5]) << 32 | event[4];
u32 sid = event[1];
- ivpu_err(vdev, "MMU EVTQ: 0x%x (%s) SSID: %d SID: %d, e[2] %08x, e[3] %08x, in addr: 0x%llx, fetch addr: 0x%llx\n",
- op, ivpu_mmu_event_to_str(op), ssid, sid, event[2], event[3], in_addr, fetch_addr);
+ ivpu_err_ratelimited(vdev, "MMU EVTQ: 0x%x (%s) SSID: %d SID: %d, e[2] %08x, e[3] %08x, in addr: 0x%llx, fetch addr: 0x%llx\n",
+ op, ivpu_mmu_event_to_str(op), ssid, sid,
+ event[2], event[3], in_addr, fetch_addr);
}
static u32 *ivpu_mmu_get_event(struct ivpu_device *vdev)
@@ -915,6 +916,9 @@ void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev)
ivpu_mmu_user_context_mark_invalid(vdev, ssid);
REGV_WR32(IVPU_MMU_REG_EVTQ_CONS_SEC, vdev->mmu->evtq.cons);
}
+
+ if (!kfifo_put(&vdev->hw->irq.fifo, IVPU_HW_IRQ_SRC_MMU_EVTQ))
+ ivpu_err_ratelimited(vdev, "IRQ FIFO full\n");
}
void ivpu_mmu_evtq_dump(struct ivpu_device *vdev)
diff --git a/drivers/accel/ivpu/ivpu_mmu_context.c b/drivers/accel/ivpu/ivpu_mmu_context.c
index 128aef8e5a19..bbe652a7019d 100644
--- a/drivers/accel/ivpu/ivpu_mmu_context.c
+++ b/drivers/accel/ivpu/ivpu_mmu_context.c
@@ -24,6 +24,7 @@
#define IVPU_MMU_ENTRY_FLAG_CONT BIT(52)
#define IVPU_MMU_ENTRY_FLAG_NG BIT(11)
#define IVPU_MMU_ENTRY_FLAG_AF BIT(10)
+#define IVPU_MMU_ENTRY_FLAG_RO BIT(7)
#define IVPU_MMU_ENTRY_FLAG_USER BIT(6)
#define IVPU_MMU_ENTRY_FLAG_LLC_COHERENT BIT(2)
#define IVPU_MMU_ENTRY_FLAG_TYPE_PAGE BIT(1)
@@ -319,6 +320,91 @@ ivpu_mmu_context_map_pages(struct ivpu_device *vdev, struct ivpu_mmu_context *ct
return 0;
}
+static void ivpu_mmu_context_set_page_ro(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
+ u64 vpu_addr)
+{
+ int pgd_idx = FIELD_GET(IVPU_MMU_PGD_INDEX_MASK, vpu_addr);
+ int pud_idx = FIELD_GET(IVPU_MMU_PUD_INDEX_MASK, vpu_addr);
+ int pmd_idx = FIELD_GET(IVPU_MMU_PMD_INDEX_MASK, vpu_addr);
+ int pte_idx = FIELD_GET(IVPU_MMU_PTE_INDEX_MASK, vpu_addr);
+
+ ctx->pgtable.pte_ptrs[pgd_idx][pud_idx][pmd_idx][pte_idx] |= IVPU_MMU_ENTRY_FLAG_RO;
+}
+
+static void ivpu_mmu_context_split_page(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
+ u64 vpu_addr)
+{
+ int pgd_idx = FIELD_GET(IVPU_MMU_PGD_INDEX_MASK, vpu_addr);
+ int pud_idx = FIELD_GET(IVPU_MMU_PUD_INDEX_MASK, vpu_addr);
+ int pmd_idx = FIELD_GET(IVPU_MMU_PMD_INDEX_MASK, vpu_addr);
+ int pte_idx = FIELD_GET(IVPU_MMU_PTE_INDEX_MASK, vpu_addr);
+
+ ctx->pgtable.pte_ptrs[pgd_idx][pud_idx][pmd_idx][pte_idx] &= ~IVPU_MMU_ENTRY_FLAG_CONT;
+}
+
+static void ivpu_mmu_context_split_64k_page(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
+ u64 vpu_addr)
+{
+ u64 start = ALIGN_DOWN(vpu_addr, IVPU_MMU_CONT_PAGES_SIZE);
+ u64 end = ALIGN(vpu_addr, IVPU_MMU_CONT_PAGES_SIZE);
+ u64 offset = 0;
+
+ ivpu_dbg(vdev, MMU_MAP, "Split 64K page ctx: %u vpu_addr: 0x%llx\n", ctx->id, vpu_addr);
+
+ while (start + offset < end) {
+ ivpu_mmu_context_split_page(vdev, ctx, start + offset);
+ offset += IVPU_MMU_PAGE_SIZE;
+ }
+}
+
+int
+ivpu_mmu_context_set_pages_ro(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u64 vpu_addr,
+ size_t size)
+{
+ u64 end = vpu_addr + size;
+ size_t size_left = size;
+ int ret;
+
+ if (size == 0)
+ return 0;
+
+ if (drm_WARN_ON(&vdev->drm, !IS_ALIGNED(vpu_addr | size, IVPU_MMU_PAGE_SIZE)))
+ return -EINVAL;
+
+ mutex_lock(&ctx->lock);
+
+ ivpu_dbg(vdev, MMU_MAP, "Set read-only pages ctx: %u vpu_addr: 0x%llx size: %lu\n",
+ ctx->id, vpu_addr, size);
+
+ if (!ivpu_disable_mmu_cont_pages) {
+ /* Split 64K contiguous page at the beginning if needed */
+ if (!IS_ALIGNED(vpu_addr, IVPU_MMU_CONT_PAGES_SIZE))
+ ivpu_mmu_context_split_64k_page(vdev, ctx, vpu_addr);
+
+ /* Split 64K contiguous page at the end if needed */
+ if (!IS_ALIGNED(vpu_addr + size, IVPU_MMU_CONT_PAGES_SIZE))
+ ivpu_mmu_context_split_64k_page(vdev, ctx, vpu_addr + size);
+ }
+
+ while (size_left) {
+ if (vpu_addr < end)
+ ivpu_mmu_context_set_page_ro(vdev, ctx, vpu_addr);
+
+ vpu_addr += IVPU_MMU_PAGE_SIZE;
+ size_left -= IVPU_MMU_PAGE_SIZE;
+ }
+
+ /* Ensure page table modifications are flushed from wc buffers to memory */
+ wmb();
+
+ mutex_unlock(&ctx->lock);
+ ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id);
+ if (ret)
+ ivpu_err(vdev, "Failed to invalidate TLB for ctx %u: %d\n", ctx->id, ret);
+
+ return 0;
+}
+
static void ivpu_mmu_context_unmap_pages(struct ivpu_mmu_context *ctx, u64 vpu_addr, size_t size)
{
while (size) {
diff --git a/drivers/accel/ivpu/ivpu_mmu_context.h b/drivers/accel/ivpu/ivpu_mmu_context.h
index 535db3a1fc74..7f9aaf3d10c2 100644
--- a/drivers/accel/ivpu/ivpu_mmu_context.h
+++ b/drivers/accel/ivpu/ivpu_mmu_context.h
@@ -46,5 +46,7 @@ int ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *
u64 vpu_addr, struct sg_table *sgt, bool llc_coherent);
void ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
u64 vpu_addr, struct sg_table *sgt);
+int ivpu_mmu_context_set_pages_ro(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
+ u64 vpu_addr, size_t size);
#endif /* __IVPU_MMU_CONTEXT_H__ */
diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c
index 02b4eac13f8b..59d3170f5e35 100644
--- a/drivers/accel/ivpu/ivpu_pm.c
+++ b/drivers/accel/ivpu/ivpu_pm.c
@@ -237,33 +237,30 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
struct ivpu_device *vdev = to_ivpu_device(drm);
- bool hw_is_idle = true;
- int ret;
+ int ret, ret_d0i3;
+ bool is_idle;
drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa));
drm_WARN_ON(&vdev->drm, work_pending(&vdev->pm->recovery_work));
ivpu_dbg(vdev, PM, "Runtime suspend..\n");
- if (!ivpu_hw_is_idle(vdev) && vdev->pm->suspend_reschedule_counter) {
- ivpu_dbg(vdev, PM, "Failed to enter idle, rescheduling suspend, retries left %d\n",
- vdev->pm->suspend_reschedule_counter);
- pm_schedule_suspend(dev, vdev->timeout.reschedule_suspend);
- vdev->pm->suspend_reschedule_counter--;
- return -EAGAIN;
- }
+ ivpu_mmu_disable(vdev);
- if (!vdev->pm->suspend_reschedule_counter)
- hw_is_idle = false;
- else if (ivpu_jsm_pwr_d0i3_enter(vdev))
- hw_is_idle = false;
+ is_idle = ivpu_hw_is_idle(vdev) || vdev->pm->dct_active_percent;
+ if (!is_idle)
+ ivpu_err(vdev, "NPU is not idle before autosuspend\n");
+
+ ret_d0i3 = ivpu_jsm_pwr_d0i3_enter(vdev);
+ if (ret_d0i3)
+ ivpu_err(vdev, "Failed to prepare for d0i3: %d\n", ret_d0i3);
ret = ivpu_suspend(vdev);
if (ret)
ivpu_err(vdev, "Failed to suspend NPU: %d\n", ret);
- if (!hw_is_idle) {
- ivpu_err(vdev, "NPU failed to enter idle, force suspended.\n");
+ if (!is_idle || ret_d0i3) {
+ ivpu_err(vdev, "Forcing cold boot due to previous errors\n");
atomic_inc(&vdev->pm->reset_counter);
ivpu_fw_log_dump(vdev);
ivpu_pm_prepare_cold_boot(vdev);
@@ -271,8 +268,6 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev)
ivpu_pm_prepare_warm_boot(vdev);
}
- vdev->pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT;
-
ivpu_dbg(vdev, PM, "Runtime suspend done.\n");
return 0;
@@ -300,17 +295,6 @@ int ivpu_rpm_get(struct ivpu_device *vdev)
int ret;
ret = pm_runtime_resume_and_get(vdev->drm.dev);
- if (!drm_WARN_ON(&vdev->drm, ret < 0))
- vdev->pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT;
-
- return ret;
-}
-
-int ivpu_rpm_get_if_active(struct ivpu_device *vdev)
-{
- int ret;
-
- ret = pm_runtime_get_if_in_use(vdev->drm.dev);
drm_WARN_ON(&vdev->drm, ret < 0);
return ret;
@@ -365,7 +349,6 @@ void ivpu_pm_init(struct ivpu_device *vdev)
int delay;
pm->vdev = vdev;
- pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT;
init_rwsem(&pm->reset_lock);
atomic_set(&pm->reset_pending, 0);
@@ -406,3 +389,68 @@ void ivpu_pm_disable(struct ivpu_device *vdev)
pm_runtime_get_noresume(vdev->drm.dev);
pm_runtime_forbid(vdev->drm.dev);
}
+
+int ivpu_pm_dct_init(struct ivpu_device *vdev)
+{
+ if (vdev->pm->dct_active_percent)
+ return ivpu_pm_dct_enable(vdev, vdev->pm->dct_active_percent);
+
+ return 0;
+}
+
+int ivpu_pm_dct_enable(struct ivpu_device *vdev, u8 active_percent)
+{
+ u32 active_us, inactive_us;
+ int ret;
+
+ if (active_percent == 0 || active_percent > 100)
+ return -EINVAL;
+
+ active_us = (DCT_PERIOD_US * active_percent) / 100;
+ inactive_us = DCT_PERIOD_US - active_us;
+
+ ret = ivpu_jsm_dct_enable(vdev, active_us, inactive_us);
+ if (ret) {
+ ivpu_err_ratelimited(vdev, "Filed to enable DCT: %d\n", ret);
+ return ret;
+ }
+
+ vdev->pm->dct_active_percent = active_percent;
+
+ ivpu_dbg(vdev, PM, "DCT set to %u%% (D0: %uus, D0i2: %uus)\n",
+ active_percent, active_us, inactive_us);
+ return 0;
+}
+
+int ivpu_pm_dct_disable(struct ivpu_device *vdev)
+{
+ int ret;
+
+ ret = ivpu_jsm_dct_disable(vdev);
+ if (ret) {
+ ivpu_err_ratelimited(vdev, "Filed to disable DCT: %d\n", ret);
+ return ret;
+ }
+
+ vdev->pm->dct_active_percent = 0;
+
+ ivpu_dbg(vdev, PM, "DCT disabled\n");
+ return 0;
+}
+
+void ivpu_pm_dct_irq_thread_handler(struct ivpu_device *vdev)
+{
+ bool enable;
+ int ret;
+
+ if (ivpu_hw_btrs_dct_get_request(vdev, &enable))
+ return;
+
+ if (vdev->pm->dct_active_percent)
+ ret = ivpu_pm_dct_enable(vdev, DCT_DEFAULT_ACTIVE_PERCENT);
+ else
+ ret = ivpu_pm_dct_disable(vdev);
+
+ if (!ret)
+ ivpu_hw_btrs_dct_set_status(vdev, enable, vdev->pm->dct_active_percent);
+}
diff --git a/drivers/accel/ivpu/ivpu_pm.h b/drivers/accel/ivpu/ivpu_pm.h
index ec60fbeefefc..b70efe6c36e4 100644
--- a/drivers/accel/ivpu/ivpu_pm.h
+++ b/drivers/accel/ivpu/ivpu_pm.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2020-2023 Intel Corporation
+ * Copyright (C) 2020-2024 Intel Corporation
*/
#ifndef __IVPU_PM_H__
@@ -19,7 +19,7 @@ struct ivpu_pm_info {
atomic_t reset_counter;
atomic_t reset_pending;
bool is_warmboot;
- u32 suspend_reschedule_counter;
+ u8 dct_active_percent;
};
void ivpu_pm_init(struct ivpu_device *vdev);
@@ -36,11 +36,15 @@ void ivpu_pm_reset_prepare_cb(struct pci_dev *pdev);
void ivpu_pm_reset_done_cb(struct pci_dev *pdev);
int __must_check ivpu_rpm_get(struct ivpu_device *vdev);
-int __must_check ivpu_rpm_get_if_active(struct ivpu_device *vdev);
void ivpu_rpm_put(struct ivpu_device *vdev);
void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason);
void ivpu_start_job_timeout_detection(struct ivpu_device *vdev);
void ivpu_stop_job_timeout_detection(struct ivpu_device *vdev);
+int ivpu_pm_dct_init(struct ivpu_device *vdev);
+int ivpu_pm_dct_enable(struct ivpu_device *vdev, u8 active_percent);
+int ivpu_pm_dct_disable(struct ivpu_device *vdev);
+void ivpu_pm_dct_irq_thread_handler(struct ivpu_device *vdev);
+
#endif /* __IVPU_PM_H__ */
diff --git a/drivers/accel/ivpu/vpu_boot_api.h b/drivers/accel/ivpu/vpu_boot_api.h
index 87cac7bc730a..82954b91b748 100644
--- a/drivers/accel/ivpu/vpu_boot_api.h
+++ b/drivers/accel/ivpu/vpu_boot_api.h
@@ -27,7 +27,7 @@
* Minor version changes when API backward compatibility is preserved.
* Resets to 0 if Major version is incremented.
*/
-#define VPU_BOOT_API_VER_MINOR 22
+#define VPU_BOOT_API_VER_MINOR 24
/*
* API header changed (field names, documentation, formatting) but API itself has not been changed
@@ -80,6 +80,11 @@ struct vpu_firmware_header {
u32 preemption_buffer_2_size;
/* Space reserved for future preemption-related fields. */
u32 preemption_reserved[6];
+ /* FW image read only section start address, 4KB aligned */
+ u64 ro_section_start_address;
+ /* FW image read only section size, 4KB aligned */
+ u32 ro_section_size;
+ u32 reserved;
};
/*
@@ -333,7 +338,14 @@ struct vpu_boot_params {
* The KMD is required to update this value on every VPU reset.
*/
u64 system_time_us;
- u32 pad4[18];
+ u32 pad4[2];
+ /*
+ * The delta between device monotonic time and the current value of the
+ * HW timestamp register, in ticks. Written by the firmware during boot.
+ * Can be used by the KMD to calculate device time.
+ */
+ u64 device_time_delta_ticks;
+ u32 pad7[14];
/* Warm boot information: 0x400 - 0x43F */
u32 warm_boot_sections_count;
u32 warm_boot_start_address_reference;
diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c
index 4a63567e93ba..c384004b918e 100644
--- a/drivers/dma-buf/heaps/cma_heap.c
+++ b/drivers/dma-buf/heaps/cma_heap.c
@@ -274,8 +274,8 @@ static const struct dma_buf_ops cma_heap_buf_ops = {
static struct dma_buf *cma_heap_allocate(struct dma_heap *heap,
unsigned long len,
- unsigned long fd_flags,
- unsigned long heap_flags)
+ u32 fd_flags,
+ u64 heap_flags)
{
struct cma_heap *cma_heap = dma_heap_get_drvdata(heap);
struct cma_heap_buffer *buffer;
diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c
index 9076d47ed2ef..d78cdb9d01e5 100644
--- a/drivers/dma-buf/heaps/system_heap.c
+++ b/drivers/dma-buf/heaps/system_heap.c
@@ -333,8 +333,8 @@ static struct page *alloc_largest_available(unsigned long size,
static struct dma_buf *system_heap_allocate(struct dma_heap *heap,
unsigned long len,
- unsigned long fd_flags,
- unsigned long heap_flags)
+ u32 fd_flags,
+ u64 heap_flags)
{
struct system_heap_buffer *buffer;
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index a9df94291622..f5c989aed7e9 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -107,7 +107,7 @@ config DRM_KMS_HELPER
config DRM_PANIC
bool "Display a user-friendly message when a kernel panic occurs"
- depends on DRM && !FRAMEBUFFER_CONSOLE
+ depends on DRM && !(FRAMEBUFFER_CONSOLE && VT_CONSOLE)
select DRM_KMS_HELPER
select FONT_SUPPORT
help
diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
index 2fbeda9025bf..7f91b0db161e 100644
--- a/drivers/gpu/drm/bridge/sii902x.c
+++ b/drivers/gpu/drm/bridge/sii902x.c
@@ -163,6 +163,14 @@
#define SII902X_AUDIO_PORT_INDEX 3
+/*
+ * The maximum resolution supported by the HDMI bridge is 1080p@60Hz
+ * and 1920x1200 requiring a pixel clock of 165MHz and the minimum
+ * resolution supported is 480p@60Hz requiring a pixel clock of 25MHz
+ */
+#define SII902X_MIN_PIXEL_CLOCK_KHZ 25000
+#define SII902X_MAX_PIXEL_CLOCK_KHZ 165000
+
struct sii902x {
struct i2c_client *i2c;
struct regmap *regmap;
@@ -310,20 +318,12 @@ static int sii902x_get_modes(struct drm_connector *connector)
return num;
}
-static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- /* TODO: check mode */
-
- return MODE_OK;
-}
-
static const struct drm_connector_helper_funcs sii902x_connector_helper_funcs = {
.get_modes = sii902x_get_modes,
- .mode_valid = sii902x_mode_valid,
};
-static void sii902x_bridge_disable(struct drm_bridge *bridge)
+static void sii902x_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct sii902x *sii902x = bridge_to_sii902x(bridge);
@@ -336,7 +336,8 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge)
mutex_unlock(&sii902x->mutex);
}
-static void sii902x_bridge_enable(struct drm_bridge *bridge)
+static void sii902x_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct sii902x *sii902x = bridge_to_sii902x(bridge);
@@ -495,6 +496,10 @@ static int sii902x_bridge_atomic_check(struct drm_bridge *bridge,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
+ if (crtc_state->mode.clock < SII902X_MIN_PIXEL_CLOCK_KHZ ||
+ crtc_state->mode.clock > SII902X_MAX_PIXEL_CLOCK_KHZ)
+ return -EINVAL;
+
/*
* There might be flags negotiation supported in future but
* set the bus flags in atomic_check statically for now.
@@ -504,11 +509,25 @@ static int sii902x_bridge_atomic_check(struct drm_bridge *bridge,
return 0;
}
+static enum drm_mode_status
+sii902x_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ if (mode->clock < SII902X_MIN_PIXEL_CLOCK_KHZ)
+ return MODE_CLOCK_LOW;
+
+ if (mode->clock > SII902X_MAX_PIXEL_CLOCK_KHZ)
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
static const struct drm_bridge_funcs sii902x_bridge_funcs = {
.attach = sii902x_bridge_attach,
.mode_set = sii902x_bridge_mode_set,
- .disable = sii902x_bridge_disable,
- .enable = sii902x_bridge_enable,
+ .atomic_disable = sii902x_bridge_atomic_disable,
+ .atomic_enable = sii902x_bridge_atomic_enable,
.detect = sii902x_bridge_detect,
.edid_read = sii902x_bridge_edid_read,
.atomic_reset = drm_atomic_helper_bridge_reset,
@@ -516,6 +535,7 @@ static const struct drm_bridge_funcs sii902x_bridge_funcs = {
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_get_input_bus_fmts = sii902x_bridge_atomic_get_input_bus_fmts,
.atomic_check = sii902x_bridge_atomic_check,
+ .mode_valid = sii902x_bridge_mode_valid,
};
static int sii902x_mute(struct sii902x *sii902x, bool mute)
diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c
index 2ca89f313cd1..ab0b0e36e97a 100644
--- a/drivers/gpu/drm/bridge/simple-bridge.c
+++ b/drivers/gpu/drm/bridge/simple-bridge.c
@@ -170,7 +170,6 @@ static int simple_bridge_probe(struct platform_device *pdev)
sbridge = devm_kzalloc(&pdev->dev, sizeof(*sbridge), GFP_KERNEL);
if (!sbridge)
return -ENOMEM;
- platform_set_drvdata(pdev, sbridge);
sbridge->info = of_device_get_match_data(&pdev->dev);
@@ -208,16 +207,7 @@ static int simple_bridge_probe(struct platform_device *pdev)
sbridge->bridge.of_node = pdev->dev.of_node;
sbridge->bridge.timings = sbridge->info->timings;
- drm_bridge_add(&sbridge->bridge);
-
- return 0;
-}
-
-static void simple_bridge_remove(struct platform_device *pdev)
-{
- struct simple_bridge *sbridge = platform_get_drvdata(pdev);
-
- drm_bridge_remove(&sbridge->bridge);
+ return devm_drm_bridge_add(&pdev->dev, &sbridge->bridge);
}
/*
@@ -294,7 +284,6 @@ MODULE_DEVICE_TABLE(of, simple_bridge_match);
static struct platform_driver simple_bridge_driver = {
.probe = simple_bridge_probe,
- .remove_new = simple_bridge_remove,
.driver = {
.name = "simple-bridge",
.of_match_table = simple_bridge_match,
diff --git a/drivers/gpu/drm/ci/build.sh b/drivers/gpu/drm/ci/build.sh
index 97e920b9d257..5a3bdcffae32 100644
--- a/drivers/gpu/drm/ci/build.sh
+++ b/drivers/gpu/drm/ci/build.sh
@@ -160,7 +160,6 @@ fi
mkdir -p artifacts/install/lib
mv install/* artifacts/install/.
-rm -rf artifacts/install/modules
ln -s common artifacts/install/ci-common
cp .config artifacts/${CI_JOB_NAME}_config
diff --git a/drivers/gpu/drm/ci/gitlab-ci.yml b/drivers/gpu/drm/ci/gitlab-ci.yml
index 1b29c3b6406b..80fb0f57ae46 100644
--- a/drivers/gpu/drm/ci/gitlab-ci.yml
+++ b/drivers/gpu/drm/ci/gitlab-ci.yml
@@ -123,6 +123,7 @@ stages:
- msm
- rockchip
- virtio-gpu
+ - software-driver
# YAML anchors for rule conditions
# --------------------------------
diff --git a/drivers/gpu/drm/ci/igt_runner.sh b/drivers/gpu/drm/ci/igt_runner.sh
index d49ad434b580..79f41d7da772 100755
--- a/drivers/gpu/drm/ci/igt_runner.sh
+++ b/drivers/gpu/drm/ci/igt_runner.sh
@@ -30,10 +30,10 @@ case "$DRIVER_NAME" in
export IGT_FORCE_DRIVER="panfrost"
fi
;;
- amdgpu)
+ amdgpu|vkms)
# Cannot use HWCI_KERNEL_MODULES as at that point we don't have the module in /lib
- mv /install/modules/lib/modules/* /lib/modules/.
- modprobe amdgpu
+ mv /install/modules/lib/modules/* /lib/modules/. || true
+ modprobe --first-time $DRIVER_NAME
;;
esac
diff --git a/drivers/gpu/drm/ci/image-tags.yml b/drivers/gpu/drm/ci/image-tags.yml
index 60323ebc7304..13eda37bdf05 100644
--- a/drivers/gpu/drm/ci/image-tags.yml
+++ b/drivers/gpu/drm/ci/image-tags.yml
@@ -4,7 +4,7 @@ variables:
DEBIAN_BASE_TAG: "${CONTAINER_TAG}"
DEBIAN_X86_64_BUILD_IMAGE_PATH: "debian/x86_64_build"
- DEBIAN_BUILD_TAG: "2023-10-08-config"
+ DEBIAN_BUILD_TAG: "2024-06-10-vkms"
KERNEL_ROOTFS_TAG: "2023-10-06-amd"
diff --git a/drivers/gpu/drm/ci/test.yml b/drivers/gpu/drm/ci/test.yml
index 322cce714657..ee908b66aad2 100644
--- a/drivers/gpu/drm/ci/test.yml
+++ b/drivers/gpu/drm/ci/test.yml
@@ -338,7 +338,7 @@ meson:g12b:
RUNNER_TAG: mesa-ci-x86-64-lava-meson-g12b-a311d-khadas-vim3
virtio_gpu:none:
- stage: virtio-gpu
+ stage: software-driver
variables:
CROSVM_GALLIUM_DRIVER: llvmpipe
DRIVER_NAME: virtio_gpu
@@ -358,3 +358,25 @@ virtio_gpu:none:
- debian/x86_64_test-gl
- testing:x86_64
- igt:x86_64
+
+vkms:none:
+ stage: software-driver
+ variables:
+ DRIVER_NAME: vkms
+ GPU_VERSION: none
+ extends:
+ - .test-gl
+ - .test-rules
+ tags:
+ - kvm
+ script:
+ - ln -sf $CI_PROJECT_DIR/install /install
+ - mv install/bzImage /lava-files/bzImage
+ - mkdir -p /lib/modules
+ - mkdir -p $CI_PROJECT_DIR/results
+ - ln -sf $CI_PROJECT_DIR/results /results
+ - ./install/crosvm-runner.sh ./install/igt_runner.sh
+ needs:
+ - debian/x86_64_test-gl
+ - testing:x86_64
+ - igt:x86_64
diff --git a/drivers/gpu/drm/ci/x86_64.config b/drivers/gpu/drm/ci/x86_64.config
index 1cbd49a5b23a..8eaba388b141 100644
--- a/drivers/gpu/drm/ci/x86_64.config
+++ b/drivers/gpu/drm/ci/x86_64.config
@@ -24,6 +24,7 @@ CONFIG_DRM=y
CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_PWM_CROS_EC=y
CONFIG_BACKLIGHT_PWM=y
+CONFIG_DRM_VKMS=m
# Strip out some stuff we don't need for graphics testing, to reduce
# the build.
diff --git a/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt b/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt
index 3dfbabdf905e..6e7fd1ccd1e3 100644
--- a/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt
+++ b/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt
@@ -4,7 +4,6 @@ device_reset@unbind-cold-reset-rebind,Fail
device_reset@unbind-reset-rebind,Fail
dumb_buffer@invalid-bpp,Fail
kms_3d,Fail
-kms_addfb_basic@addfb25-bad-modifier,Fail
kms_cursor_legacy@forked-move,Fail
kms_cursor_legacy@single-bo,Fail
kms_cursor_legacy@torture-bo,Fail
diff --git a/drivers/gpu/drm/ci/xfails/msm-apq8096-fails.txt b/drivers/gpu/drm/ci/xfails/msm-apq8096-fails.txt
index 23a5f6f9097f..46ca69ce2ffe 100644
--- a/drivers/gpu/drm/ci/xfails/msm-apq8096-fails.txt
+++ b/drivers/gpu/drm/ci/xfails/msm-apq8096-fails.txt
@@ -4,6 +4,5 @@ device_reset@unbind-cold-reset-rebind,Fail
device_reset@unbind-reset-rebind,Fail
dumb_buffer@invalid-bpp,Fail
kms_3d,Fail
-kms_addfb_basic@addfb25-bad-modifier,Fail
kms_lease@lease-uevent,Fail
tools_test@tools_test,Fail
diff --git a/drivers/gpu/drm/ci/xfails/vkms-none-fails.txt b/drivers/gpu/drm/ci/xfails/vkms-none-fails.txt
new file mode 100644
index 000000000000..691c383b21a0
--- /dev/null
+++ b/drivers/gpu/drm/ci/xfails/vkms-none-fails.txt
@@ -0,0 +1,57 @@
+core_hotunplug@hotrebind,Fail
+core_hotunplug@hotrebind-lateclose,Fail
+core_hotunplug@hotreplug,Fail
+core_hotunplug@hotreplug-lateclose,Fail
+core_hotunplug@hotunbind-rebind,Fail
+core_hotunplug@hotunplug-rescan,Fail
+core_hotunplug@unbind-rebind,Fail
+core_hotunplug@unplug-rescan,Fail
+device_reset@cold-reset-bound,Fail
+device_reset@reset-bound,Fail
+device_reset@unbind-cold-reset-rebind,Fail
+device_reset@unbind-reset-rebind,Fail
+dumb_buffer@invalid-bpp,Fail
+kms_content_protection@atomic,Crash
+kms_content_protection@atomic-dpms,Crash
+kms_content_protection@content-type-change,Crash
+kms_content_protection@lic-type-0,Crash
+kms_content_protection@lic-type-1,Crash
+kms_content_protection@srm,Crash
+kms_content_protection@type1,Crash
+kms_content_protection@uevent,Crash
+kms_cursor_crc@cursor-rapid-movement-128x128,Fail
+kms_cursor_crc@cursor-rapid-movement-128x42,Fail
+kms_cursor_crc@cursor-rapid-movement-256x256,Fail
+kms_cursor_crc@cursor-rapid-movement-256x85,Fail
+kms_cursor_crc@cursor-rapid-movement-32x10,Fail
+kms_cursor_crc@cursor-rapid-movement-32x32,Fail
+kms_cursor_crc@cursor-rapid-movement-512x170,Fail
+kms_cursor_crc@cursor-rapid-movement-512x512,Fail
+kms_cursor_crc@cursor-rapid-movement-64x21,Fail
+kms_cursor_crc@cursor-rapid-movement-64x64,Fail
+kms_cursor_legacy@basic-flip-before-cursor-atomic,Fail
+kms_cursor_legacy@basic-flip-before-cursor-legacy,Fail
+kms_cursor_legacy@cursor-vs-flip-atomic,Fail
+kms_cursor_legacy@cursor-vs-flip-legacy,Fail
+kms_cursor_legacy@cursor-vs-flip-toggle,Fail
+kms_cursor_legacy@cursor-vs-flip-varying-size,Fail
+kms_cursor_legacy@flip-vs-cursor-atomic,Fail
+kms_cursor_legacy@flip-vs-cursor-crc-atomic,Fail
+kms_cursor_legacy@flip-vs-cursor-crc-legacy,Fail
+kms_cursor_legacy@flip-vs-cursor-legacy,Fail
+kms_flip@flip-vs-modeset-vs-hang,Fail
+kms_flip@flip-vs-panning-vs-hang,Fail
+kms_flip@flip-vs-suspend,Timeout
+kms_flip@flip-vs-suspend-interruptible,Timeout
+kms_flip@plain-flip-fb-recreate,Fail
+kms_lease@lease-uevent,Fail
+kms_pipe_crc_basic@nonblocking-crc,Fail
+kms_pipe_crc_basic@nonblocking-crc-frame-sequence,Fail
+kms_writeback@writeback-check-output,Fail
+kms_writeback@writeback-check-output-XRGB2101010,Fail
+kms_writeback@writeback-fb-id,Fail
+kms_writeback@writeback-fb-id-XRGB2101010,Fail
+kms_writeback@writeback-invalid-parameters,Fail
+kms_writeback@writeback-pixel-formats,Fail
+perf@i915-ref-count,Fail
+tools_test@tools_test,Fail
diff --git a/drivers/gpu/drm/ci/xfails/vkms-none-flakes.txt b/drivers/gpu/drm/ci/xfails/vkms-none-flakes.txt
new file mode 100644
index 000000000000..eeaa1d5825af
--- /dev/null
+++ b/drivers/gpu/drm/ci/xfails/vkms-none-flakes.txt
@@ -0,0 +1,69 @@
+# Board Name: vkms
+# Bug Report: https://lore.kernel.org/dri-devel/61ed26af-062c-443c-9df2-d1ee319f3fb0@collabora.com/T/#u
+# Failure Rate: 50
+# IGT Version: 1.28-g0df7b9b97
+# Linux Version: 6.9.0-rc7
+kms_cursor_legacy@long-nonblocking-modeset-vs-cursor-atomic
+
+# Board Name: vkms
+# Bug Report: https://lore.kernel.org/dri-devel/61ed26af-062c-443c-9df2-d1ee319f3fb0@collabora.com/T/#u
+# Failure Rate: 50
+# IGT Version: 1.28-g0df7b9b97
+# Linux Version: 6.9.0-rc7
+kms_flip@basic-flip-vs-wf_vblank
+
+# Board Name: vkms
+# Bug Report: https://lore.kernel.org/dri-devel/61ed26af-062c-443c-9df2-d1ee319f3fb0@collabora.com/T/#u
+# Failure Rate: 50
+# IGT Version: 1.28-g0df7b9b97
+# Linux Version: 6.9.0-rc7
+kms_flip@flip-vs-expired-vblank-interruptible
+
+# Board Name: vkms
+# Bug Report: https://lore.kernel.org/dri-devel/61ed26af-062c-443c-9df2-d1ee319f3fb0@collabora.com/T/#u
+# Failure Rate: 50
+# IGT Version: 1.28-g0df7b9b97
+# Linux Version: 6.9.0-rc7
+kms_flip@flip-vs-wf_vblank-interruptible
+
+# Board Name: vkms
+# Bug Report: https://lore.kernel.org/dri-devel/61ed26af-062c-443c-9df2-d1ee319f3fb0@collabora.com/T/#u
+# Failure Rate: 50
+# IGT Version: 1.28-g0df7b9b97
+# Linux Version: 6.9.0-rc7
+kms_flip@plain-flip-fb-recreate-interruptible
+
+# Board Name: vkms
+# Bug Report: https://lore.kernel.org/dri-devel/61ed26af-062c-443c-9df2-d1ee319f3fb0@collabora.com/T/#u
+# Failure Rate: 50
+# IGT Version: 1.28-g0df7b9b97
+# Linux Version: 6.9.0-rc7
+kms_flip@plain-flip-ts-check
+
+# Board Name: vkms
+# Bug Report: https://lore.kernel.org/dri-devel/61ed26af-062c-443c-9df2-d1ee319f3fb0@collabora.com/T/#u
+# Failure Rate: 50
+# IGT Version: 1.28-g0df7b9b97
+# Linux Version: 6.9.0-rc7
+kms_flip@plain-flip-ts-check-interruptible
+
+# Board Name: vkms
+# Bug Report: https://lore.kernel.org/dri-devel/61ed26af-062c-443c-9df2-d1ee319f3fb0@collabora.com/T/#u
+# Failure Rate: 50
+# IGT Version: 1.28-g0df7b9b97
+# Linux Version: 6.9.0-rc7
+kms_flip@flip-vs-absolute-wf_vblank
+
+# Board Name: vkms
+# Bug Report: https://lore.kernel.org/dri-devel/61ed26af-062c-443c-9df2-d1ee319f3fb0@collabora.com/T/#u
+# Failure Rate: 50
+# IGT Version: 1.28-g0df7b9b97
+# Linux Version: 6.9.0-rc7
+kms_flip@flip-vs-absolute-wf_vblank-interruptible
+
+# Board Name: vkms
+# Bug Report: https://lore.kernel.org/dri-devel/61ed26af-062c-443c-9df2-d1ee319f3fb0@collabora.com/T/#u
+# Failure Rate: 50
+# IGT Version: 1.28-g0df7b9b97
+# Linux Version: 6.9.0-rc7
+kms_flip@flip-vs-blocking-wf-vblank
diff --git a/drivers/gpu/drm/ci/xfails/vkms-none-skips.txt b/drivers/gpu/drm/ci/xfails/vkms-none-skips.txt
new file mode 100644
index 000000000000..fd5d1271115f
--- /dev/null
+++ b/drivers/gpu/drm/ci/xfails/vkms-none-skips.txt
@@ -0,0 +1,119 @@
+# keeps printing vkms_vblank_simulate: vblank timer overrun and never ends
+kms_invalid_mode@int-max-clock
+
+# Kernel panic
+kms_cursor_crc@cursor-rapid-movement-32x10
+# Oops: 0000 [#1] PREEMPT SMP NOPTI
+# CPU: 0 PID: 2635 Comm: kworker/u8:13 Not tainted 6.9.0-rc7-g40935263a1fd #1
+# Hardware name: ChromiumOS crosvm, BIOS 0
+# Workqueue: vkms_composer vkms_composer_worker [vkms]
+# RIP: 0010:compose_active_planes+0x1c7/0x4e0 [vkms]
+# Code: c9 0f 84 6a 01 00 00 8b 42 30 2b 42 28 41 39 c5 0f 8c 6f 01 00 00 49 83 c7 01 49 39 df 74 3b 4b 8b 34 fc 48 8b 96 48 01 00 00 <8b> 42 78 89 c1 83 e1 0a a8 20 74 b1 45 89 f5 41 f7 d5 44 03 6a 34
+# RSP: 0018:ffffbb4700c17d58 EFLAGS: 00010246
+# RAX: 0000000000000400 RBX: 0000000000000002 RCX: 0000000000000002
+# RDX: 0000000000000000 RSI: ffffa2ad0788c000 RDI: 00000000fff479a8
+# RBP: 0000000000000004 R08: 0000000000000000 R09: 0000000000000000
+# R10: ffffa2ad0bb14000 R11: 0000000000000000 R12: ffffa2ad03e21700
+# R13: 0000000000000003 R14: 0000000000000004 R15: 0000000000000000
+# FS: 0000000000000000(0000) GS:ffffa2ad2bc00000(0000) knlGS:0000000000000000
+# CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+# CR2: 0000000000000078 CR3: 000000010bd30000 CR4: 0000000000350ef0
+# Call Trace:
+# <TASK>
+# ? __die+0x1e/0x60
+# ? page_fault_oops+0x17b/0x490
+# ? exc_page_fault+0x6d/0x230
+# ? asm_exc_page_fault+0x26/0x30
+# ? compose_active_planes+0x1c7/0x4e0 [vkms]
+# ? compose_active_planes+0x2a3/0x4e0 [vkms]
+# ? srso_return_thunk+0x5/0x5f
+# vkms_composer_worker+0x205/0x240 [vkms]
+# process_one_work+0x1f4/0x6b0
+# ? lock_is_held_type+0x9e/0x110
+# worker_thread+0x17e/0x350
+# ? __pfx_worker_thread+0x10/0x10
+# kthread+0xce/0x100
+# ? __pfx_kthread+0x10/0x10
+# ret_from_fork+0x2f/0x50
+# ? __pfx_kthread+0x10/0x10
+# ret_from_fork_asm+0x1a/0x30
+# </TASK>
+# Modules linked in: vkms
+# CR2: 0000000000000078
+# ---[ end trace 0000000000000000 ]---
+# RIP: 0010:compose_active_planes+0x1c7/0x4e0 [vkms]
+# Code: c9 0f 84 6a 01 00 00 8b 42 30 2b 42 28 41 39 c5 0f 8c 6f 01 00 00 49 83 c7 01 49 39 df 74 3b 4b 8b 34 fc 48 8b 96 48 01 00 00 <8b> 42 78 89 c1 83 e1 0a a8 20 74 b1 45 89 f5 41 f7 d5 44 03 6a 34
+# RSP: 0018:ffffbb4700c17d58 EFLAGS: 00010246
+# RAX: 0000000000000400 RBX: 0000000000000002 RCX: 0000000000000002
+# RDX: 0000000000000000 RSI: ffffa2ad0788c000 RDI: 00000000fff479a8
+# RBP: 0000000000000004 R08: 0000000000000000 R09: 0000000000000000
+# R10: ffffa2ad0bb14000 R11: 0000000000000000 R12: ffffa2ad03e21700
+# R13: 0000000000000003 R14: 0000000000000004 R15: 0000000000000000
+# FS: 0000000000000000(0000) GS:ffffa2ad2bc00000(0000) knlGS:0000000000000000
+# CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+
+kms_cursor_crc@cursor-rapid-movement-256x85
+# [drm:drm_crtc_add_crc_entry] *ERROR* Overflow of CRC buffer, userspace reads too slow.
+# Oops: 0000 [#1] PREEMPT SMP NOPTI
+# CPU: 1 PID: 10 Comm: kworker/u8:0 Not tainted 6.9.0-rc7-g646381cde463 #1
+# Hardware name: ChromiumOS crosvm, BIOS 0
+# Workqueue: vkms_composer vkms_composer_worker [vkms]
+# RIP: 0010:compose_active_planes+0x1c7/0x4e0 [vkms]
+# Code: c9 0f 84 6a 01 00 00 8b 42 30 2b 42 28 41 39 c5 0f 8c 6f 01 00 00 49 83 c7 01 49 39 df 74 3b 4b 8b 34 fc 48 8b 96 48 01 00 00 <8b> 42 78 89 c1 83 e1 0a a8 20 74 b1 45 89 f5 41 f7 d5 44 03 6a 34
+# RSP: 0018:ffffa7e980057d58 EFLAGS: 00010246
+# RAX: 0000000000000400 RBX: 0000000000000002 RCX: 0000000000000002
+# RDX: 0000000000000000 RSI: ffff977987aa5c00 RDI: 000000001b43a85f
+# RBP: 0000000000000001 R08: 0000000000000000 R09: 0000000000000000
+# R10: ffff977981bf0000 R11: 0000000000000000 R12: ffff977989622590
+# R13: 0000000000000000 R14: 0000000000000001 R15: 0000000000000000
+# FS: 0000000000000000(0000) GS:ffff9779abd00000(0000) knlGS:0000000000000000
+# CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+# CR2: 0000000000000078 CR3: 0000000109b38000 CR4: 0000000000350ef0
+# Call Trace:
+# <TASK>
+# ? __die+0x1e/0x60
+# ? page_fault_oops+0x17b/0x490
+# ? exc_page_fault+0x6d/0x230
+# ? asm_exc_page_fault+0x26/0x30
+# ? compose_active_planes+0x1c7/0x4e0 [vkms]
+# ? compose_active_planes+0x2a3/0x4e0 [vkms]
+# ? srso_return_thunk+0x5/0x5f
+# vkms_composer_worker+0x205/0x240 [vkms]
+# process_one_work+0x1f4/0x6b0
+# ? lock_is_held_type+0x9e/0x110
+# worker_thread+0x17e/0x350
+# ? __pfx_worker_thread+0x10/0x10
+# kthread+0xce/0x100
+# ? __pfx_kthread+0x10/0x10
+# ret_from_fork+0x2f/0x50
+# ? __pfx_kthread+0x10/0x10
+# ret_from_fork_asm+0x1a/0x30
+# </TASK>
+# Modules linked in: vkms
+# CR2: 0000000000000078
+# ---[ end trace 0000000000000000 ]---
+# RIP: 0010:compose_active_planes+0x1c7/0x4e0 [vkms]
+# Code: c9 0f 84 6a 01 00 00 8b 42 30 2b 42 28 41 39 c5 0f 8c 6f 01 00 00 49 83 c7 01 49 39 df 74 3b 4b 8b 34 fc 48 8b 96 48 01 00 00 <8b> 42 78 89 c1 83 e1 0a a8 20 74 b1 45 89 f5 41 f7 d5 44 03 6a 34
+# RSP: 0018:ffffa7e980057d58 EFLAGS: 00010246
+# RAX: 0000000000000400 RBX: 0000000000000002 RCX: 0000000000000002
+# RDX: 0000000000000000 RSI: ffff977987aa5c00 RDI: 000000001b43a85f
+# RBP: 0000000000000001 R08: 0000000000000000 R09: 0000000000000000
+# R10: ffff977981bf0000 R11: 0000000000000000 R12: ffff977989622590
+# R13: 0000000000000000 R14: 0000000000000001 R15: 0000000000000000
+# FS: 0000000000000000(0000) GS:ffff9779abd00000(0000) knlGS:0000000000000000
+# CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+# CR2: 0000000000000078 CR3: 0000000109b38000 CR4: 0000000000350ef0
+
+# Skip driver specific tests
+^amdgpu.*
+msm_.*
+nouveau_.*
+panfrost_.*
+^v3d.*
+^vc4.*
+^vmwgfx*
+
+# Skip intel specific tests
+gem_.*
+i915_.*
+xe_.*
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 3d73a981004c..ab6ab7ff7ea8 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1087,6 +1087,7 @@ static const struct drm_prop_enum_list drm_tv_mode_enum_list[] = {
{ DRM_MODE_TV_MODE_PAL_M, "PAL-M" },
{ DRM_MODE_TV_MODE_PAL_N, "PAL-N" },
{ DRM_MODE_TV_MODE_SECAM, "SECAM" },
+ { DRM_MODE_TV_MODE_MONOCHROME, "Mono" },
};
DRM_ENUM_NAME_FN(drm_get_tv_mode_name, drm_tv_mode_enum_list)
@@ -1858,6 +1859,12 @@ EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property);
* TV Mode is CCIR System B (aka 625-lines) together with
* the SECAM Color Encoding.
*
+ * Mono:
+ *
+ * Use timings appropriate to the DRM mode, including
+ * equalizing pulses for a 525-line or 625-line mode,
+ * with no pedestal or color encoding.
+ *
* Drivers can set up this property by calling
* drm_mode_create_tv_properties().
*/
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 2d8b0371619d..1a0890083aee 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -531,7 +531,8 @@ static int fill_analog_mode(struct drm_device *dev,
* @interlace: whether to compute an interlaced mode
*
* This function creates a struct drm_display_mode instance suited for
- * an analog TV output, for one of the usual analog TV mode.
+ * an analog TV output, for one of the usual analog TV modes. Where
+ * this is DRM_MODE_TV_MODE_MONOCHROME, a 625-line mode will be created.
*
* Note that @hdisplay is larger than the usual constraints for the PAL
* and NTSC timings, and we'll choose to ignore most timings constraints
@@ -569,6 +570,8 @@ struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev,
case DRM_MODE_TV_MODE_PAL_N:
fallthrough;
case DRM_MODE_TV_MODE_SECAM:
+ fallthrough;
+ case DRM_MODE_TV_MODE_MONOCHROME:
analog = DRM_MODE_ANALOG_PAL;
break;
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 249c8c2cb319..bb49d552e671 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -1259,8 +1259,9 @@ int drm_connector_helper_tv_get_modes(struct drm_connector *connector)
for (i = 0; i < tv_mode_property->num_values; i++)
supported_tv_modes |= BIT(tv_mode_property->values[i]);
- if ((supported_tv_modes & ntsc_modes) &&
- (supported_tv_modes & pal_modes)) {
+ if (((supported_tv_modes & ntsc_modes) &&
+ (supported_tv_modes & pal_modes)) ||
+ (supported_tv_modes & BIT(DRM_MODE_TV_MODE_MONOCHROME))) {
uint64_t default_mode;
if (drm_object_property_get_default_value(&connector->base,
diff --git a/drivers/gpu/drm/mgag200/Makefile b/drivers/gpu/drm/mgag200/Makefile
index 0b919352046e..d1b25f9f6586 100644
--- a/drivers/gpu/drm/mgag200/Makefile
+++ b/drivers/gpu/drm/mgag200/Makefile
@@ -11,6 +11,7 @@ mgag200-y := \
mgag200_g200ew3.o \
mgag200_g200se.o \
mgag200_g200wb.o \
- mgag200_mode.o
+ mgag200_mode.o \
+ mgag200_vga.o
obj-$(CONFIG_DRM_MGAG200) += mgag200.o
diff --git a/drivers/gpu/drm/mgag200/mgag200_bmc.c b/drivers/gpu/drm/mgag200/mgag200_bmc.c
index 2ba2e3c5086a..23ef85aa7e37 100644
--- a/drivers/gpu/drm/mgag200/mgag200_bmc.c
+++ b/drivers/gpu/drm/mgag200/mgag200_bmc.c
@@ -2,8 +2,18 @@
#include <linux/delay.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_probe_helper.h>
+
#include "mgag200_drv.h"
+static struct mgag200_bmc_connector *to_mgag200_bmc_connector(struct drm_connector *connector)
+{
+ return container_of(connector, struct mgag200_bmc_connector, base);
+}
+
void mgag200_bmc_disable_vidrst(struct mga_device *mdev)
{
u8 tmp;
@@ -97,3 +107,100 @@ void mgag200_bmc_enable_vidrst(struct mga_device *mdev)
tmp &= ~0x10;
WREG_DAC(MGA1064_GEN_IO_DATA, tmp);
}
+
+static const struct drm_encoder_funcs mgag200_bmc_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static int mgag200_bmc_connector_helper_detect_ctx(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx,
+ bool force)
+{
+ struct mgag200_bmc_connector *bmc_connector = to_mgag200_bmc_connector(connector);
+ struct drm_connector *physical_connector = bmc_connector->physical_connector;
+
+ /*
+ * Most user-space compositors cannot handle more than one connected
+ * connector per CRTC. Hence, we only mark the BMC as connected if the
+ * physical connector is disconnected. If the physical connector's status
+ * is connected or unknown, the BMC remains disconnected. This has no
+ * effect on the output of the BMC.
+ *
+ * FIXME: Remove this logic once user-space compositors can handle more
+ * than one connector per CRTC. The BMC should always be connected.
+ */
+
+ if (physical_connector && physical_connector->status == connector_status_disconnected)
+ return connector_status_connected;
+
+ return connector_status_disconnected;
+}
+
+static int mgag200_bmc_connector_helper_get_modes(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ const struct mgag200_device_info *minfo = mdev->info;
+
+ return drm_add_modes_noedid(connector, minfo->max_hdisplay, minfo->max_vdisplay);
+}
+
+static const struct drm_connector_helper_funcs mgag200_bmc_connector_helper_funcs = {
+ .get_modes = mgag200_bmc_connector_helper_get_modes,
+ .detect_ctx = mgag200_bmc_connector_helper_detect_ctx,
+};
+
+static const struct drm_connector_funcs mgag200_bmc_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 mgag200_bmc_connector_init(struct drm_device *dev,
+ struct mgag200_bmc_connector *bmc_connector,
+ struct drm_connector *physical_connector)
+{
+ struct drm_connector *connector = &bmc_connector->base;
+ int ret;
+
+ ret = drm_connector_init(dev, connector, &mgag200_bmc_connector_funcs,
+ DRM_MODE_CONNECTOR_VIRTUAL);
+ if (ret)
+ return ret;
+ drm_connector_helper_add(connector, &mgag200_bmc_connector_helper_funcs);
+
+ bmc_connector->physical_connector = physical_connector;
+
+ return 0;
+}
+
+int mgag200_bmc_output_init(struct mga_device *mdev, struct drm_connector *physical_connector)
+{
+ struct drm_device *dev = &mdev->base;
+ struct drm_crtc *crtc = &mdev->crtc;
+ struct drm_encoder *encoder;
+ struct mgag200_bmc_connector *bmc_connector;
+ struct drm_connector *connector;
+ int ret;
+
+ encoder = &mdev->output.bmc.encoder;
+ ret = drm_encoder_init(dev, encoder, &mgag200_bmc_encoder_funcs,
+ DRM_MODE_ENCODER_VIRTUAL, NULL);
+ if (ret)
+ return ret;
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+
+ bmc_connector = &mdev->output.bmc.bmc_connector;
+ ret = mgag200_bmc_connector_init(dev, bmc_connector, physical_connector);
+ if (ret)
+ return ret;
+ connector = &bmc_connector->base;
+
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
index 20e3710e056b..7f7dfbd0f013 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -186,6 +186,11 @@ static inline struct mgag200_crtc_state *to_mgag200_crtc_state(struct drm_crtc_s
return container_of(base, struct mgag200_crtc_state, base);
}
+struct mgag200_bmc_connector {
+ struct drm_connector base;
+ struct drm_connector *physical_connector;
+};
+
enum mga_type {
G200_PCI,
G200_AGP,
@@ -283,8 +288,16 @@ struct mga_device {
struct drm_plane primary_plane;
struct drm_crtc crtc;
- struct drm_encoder encoder;
- struct drm_connector connector;
+ struct {
+ struct {
+ struct drm_encoder encoder;
+ struct drm_connector connector;
+ } vga;
+ struct {
+ struct drm_encoder encoder;
+ struct mgag200_bmc_connector bmc_connector;
+ } bmc;
+ } output;
};
static inline struct mga_device *to_mga_device(struct drm_device *dev)
@@ -417,27 +430,18 @@ void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_st
.atomic_duplicate_state = mgag200_crtc_atomic_duplicate_state, \
.atomic_destroy_state = mgag200_crtc_atomic_destroy_state
-#define MGAG200_DAC_ENCODER_FUNCS \
- .destroy = drm_encoder_cleanup
-
-#define MGAG200_VGA_CONNECTOR_HELPER_FUNCS \
- .get_modes = drm_connector_helper_get_modes
-
-#define MGAG200_VGA_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
-
void mgag200_set_mode_regs(struct mga_device *mdev, const struct drm_display_mode *mode);
void mgag200_set_format_regs(struct mga_device *mdev, const struct drm_format_info *format);
void mgag200_enable_display(struct mga_device *mdev);
void mgag200_init_registers(struct mga_device *mdev);
int mgag200_mode_config_init(struct mga_device *mdev, resource_size_t vram_available);
+/* mgag200_vga.c */
+int mgag200_vga_output_init(struct mga_device *mdev);
+
/* mgag200_bmc.c */
void mgag200_bmc_disable_vidrst(struct mga_device *mdev);
void mgag200_bmc_enable_vidrst(struct mga_device *mdev);
+int mgag200_bmc_output_init(struct mga_device *mdev, struct drm_connector *physical_connector);
#endif /* __MGAG200_DRV_H__ */
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200.c b/drivers/gpu/drm/mgag200/mgag200_g200.c
index 39a29d8ffca6..f874e2949840 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200.c
@@ -9,7 +9,6 @@
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h>
-#include "mgag200_ddc.h"
#include "mgag200_drv.h"
static int mgag200_g200_init_pci_options(struct pci_dev *pdev)
@@ -184,26 +183,11 @@ static const struct drm_crtc_funcs mgag200_g200_crtc_funcs = {
MGAG200_CRTC_FUNCS,
};
-static const struct drm_encoder_funcs mgag200_g200_dac_encoder_funcs = {
- MGAG200_DAC_ENCODER_FUNCS,
-};
-
-static const struct drm_connector_helper_funcs mgag200_g200_vga_connector_helper_funcs = {
- MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
-};
-
-static const struct drm_connector_funcs mgag200_g200_vga_connector_funcs = {
- MGAG200_VGA_CONNECTOR_FUNCS,
-};
-
static int mgag200_g200_pipeline_init(struct mga_device *mdev)
{
struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc;
- struct drm_encoder *encoder = &mdev->encoder;
- struct drm_connector *connector = &mdev->connector;
- struct i2c_adapter *ddc;
int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0,
@@ -231,35 +215,9 @@ static int mgag200_g200_pipeline_init(struct mga_device *mdev)
drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
- encoder->possible_crtcs = drm_crtc_mask(crtc);
- ret = drm_encoder_init(dev, encoder, &mgag200_g200_dac_encoder_funcs,
- DRM_MODE_ENCODER_DAC, NULL);
- if (ret) {
- drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
- return ret;
- }
-
- ddc = mgag200_ddc_create(mdev);
- if (IS_ERR(ddc)) {
- ret = PTR_ERR(ddc);
- drm_err(dev, "failed to add DDC bus: %d\n", ret);
- return ret;
- }
-
- ret = drm_connector_init_with_ddc(dev, connector,
- &mgag200_g200_vga_connector_funcs,
- DRM_MODE_CONNECTOR_VGA, ddc);
- if (ret) {
- drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
- return ret;
- }
- drm_connector_helper_add(connector, &mgag200_g200_vga_connector_helper_funcs);
-
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret) {
- drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ ret = mgag200_vga_output_init(mdev);
+ if (ret)
return ret;
- }
return 0;
}
@@ -443,6 +401,7 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct
return ERR_PTR(ret);
drm_mode_config_reset(dev);
+ drm_kms_helper_poll_init(dev);
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c
index 619fee7ffdf5..52bf49ead5c5 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c
@@ -9,7 +9,6 @@
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h>
-#include "mgag200_ddc.h"
#include "mgag200_drv.h"
void mgag200_g200eh_init_registers(struct mga_device *mdev)
@@ -183,26 +182,11 @@ static const struct drm_crtc_funcs mgag200_g200eh_crtc_funcs = {
MGAG200_CRTC_FUNCS,
};
-static const struct drm_encoder_funcs mgag200_g200eh_dac_encoder_funcs = {
- MGAG200_DAC_ENCODER_FUNCS,
-};
-
-static const struct drm_connector_helper_funcs mgag200_g200eh_vga_connector_helper_funcs = {
- MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
-};
-
-static const struct drm_connector_funcs mgag200_g200eh_vga_connector_funcs = {
- MGAG200_VGA_CONNECTOR_FUNCS,
-};
-
static int mgag200_g200eh_pipeline_init(struct mga_device *mdev)
{
struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc;
- struct drm_encoder *encoder = &mdev->encoder;
- struct drm_connector *connector = &mdev->connector;
- struct i2c_adapter *ddc;
int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0,
@@ -230,35 +214,13 @@ static int mgag200_g200eh_pipeline_init(struct mga_device *mdev)
drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
- encoder->possible_crtcs = drm_crtc_mask(crtc);
- ret = drm_encoder_init(dev, encoder, &mgag200_g200eh_dac_encoder_funcs,
- DRM_MODE_ENCODER_DAC, NULL);
- if (ret) {
- drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
- return ret;
- }
-
- ddc = mgag200_ddc_create(mdev);
- if (IS_ERR(ddc)) {
- ret = PTR_ERR(ddc);
- drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ ret = mgag200_vga_output_init(mdev);
+ if (ret)
return ret;
- }
- ret = drm_connector_init_with_ddc(dev, connector,
- &mgag200_g200eh_vga_connector_funcs,
- DRM_MODE_CONNECTOR_VGA, ddc);
- if (ret) {
- drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
- return ret;
- }
- drm_connector_helper_add(connector, &mgag200_g200eh_vga_connector_helper_funcs);
-
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret) {
- drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+ if (ret)
return ret;
- }
return 0;
}
@@ -315,6 +277,7 @@ struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const stru
return ERR_PTR(ret);
drm_mode_config_reset(dev);
+ drm_kms_helper_poll_init(dev);
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
index a172b8a4500a..e7f89b2a59fd 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
@@ -8,7 +8,6 @@
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h>
-#include "mgag200_ddc.h"
#include "mgag200_drv.h"
/*
@@ -87,26 +86,11 @@ static const struct drm_crtc_funcs mgag200_g200eh3_crtc_funcs = {
MGAG200_CRTC_FUNCS,
};
-static const struct drm_encoder_funcs mgag200_g200eh3_dac_encoder_funcs = {
- MGAG200_DAC_ENCODER_FUNCS,
-};
-
-static const struct drm_connector_helper_funcs mgag200_g200eh3_vga_connector_helper_funcs = {
- MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
-};
-
-static const struct drm_connector_funcs mgag200_g200eh3_vga_connector_funcs = {
- MGAG200_VGA_CONNECTOR_FUNCS,
-};
-
static int mgag200_g200eh3_pipeline_init(struct mga_device *mdev)
{
struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc;
- struct drm_encoder *encoder = &mdev->encoder;
- struct drm_connector *connector = &mdev->connector;
- struct i2c_adapter *ddc;
int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0,
@@ -134,35 +118,13 @@ static int mgag200_g200eh3_pipeline_init(struct mga_device *mdev)
drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
- encoder->possible_crtcs = drm_crtc_mask(crtc);
- ret = drm_encoder_init(dev, encoder, &mgag200_g200eh3_dac_encoder_funcs,
- DRM_MODE_ENCODER_DAC, NULL);
- if (ret) {
- drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
- return ret;
- }
-
- ddc = mgag200_ddc_create(mdev);
- if (IS_ERR(ddc)) {
- ret = PTR_ERR(ddc);
- drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ ret = mgag200_vga_output_init(mdev);
+ if (ret)
return ret;
- }
- ret = drm_connector_init_with_ddc(dev, connector,
- &mgag200_g200eh3_vga_connector_funcs,
- DRM_MODE_CONNECTOR_VGA, ddc);
- if (ret) {
- drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
- return ret;
- }
- drm_connector_helper_add(connector, &mgag200_g200eh3_vga_connector_helper_funcs);
-
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret) {
- drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+ if (ret)
return ret;
- }
return 0;
}
@@ -220,6 +182,7 @@ struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev,
return ERR_PTR(ret);
drm_mode_config_reset(dev);
+ drm_kms_helper_poll_init(dev);
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c
index a11c91331e43..4e8a1756138d 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200er.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c
@@ -9,7 +9,6 @@
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h>
-#include "mgag200_ddc.h"
#include "mgag200_drv.h"
static void mgag200_g200er_init_registers(struct mga_device *mdev)
@@ -226,26 +225,11 @@ static const struct drm_crtc_funcs mgag200_g200er_crtc_funcs = {
MGAG200_CRTC_FUNCS,
};
-static const struct drm_encoder_funcs mgag200_g200er_dac_encoder_funcs = {
- MGAG200_DAC_ENCODER_FUNCS,
-};
-
-static const struct drm_connector_helper_funcs mgag200_g200er_vga_connector_helper_funcs = {
- MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
-};
-
-static const struct drm_connector_funcs mgag200_g200er_vga_connector_funcs = {
- MGAG200_VGA_CONNECTOR_FUNCS,
-};
-
static int mgag200_g200er_pipeline_init(struct mga_device *mdev)
{
struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc;
- struct drm_encoder *encoder = &mdev->encoder;
- struct drm_connector *connector = &mdev->connector;
- struct i2c_adapter *ddc;
int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0,
@@ -273,35 +257,13 @@ static int mgag200_g200er_pipeline_init(struct mga_device *mdev)
drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
- encoder->possible_crtcs = drm_crtc_mask(crtc);
- ret = drm_encoder_init(dev, encoder, &mgag200_g200er_dac_encoder_funcs,
- DRM_MODE_ENCODER_DAC, NULL);
- if (ret) {
- drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
- return ret;
- }
-
- ddc = mgag200_ddc_create(mdev);
- if (IS_ERR(ddc)) {
- ret = PTR_ERR(ddc);
- drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ ret = mgag200_vga_output_init(mdev);
+ if (ret)
return ret;
- }
- ret = drm_connector_init_with_ddc(dev, connector,
- &mgag200_g200er_vga_connector_funcs,
- DRM_MODE_CONNECTOR_VGA, ddc);
- if (ret) {
- drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
- return ret;
- }
- drm_connector_helper_add(connector, &mgag200_g200er_vga_connector_helper_funcs);
-
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret) {
- drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+ if (ret)
return ret;
- }
return 0;
}
@@ -354,6 +316,7 @@ struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const stru
return ERR_PTR(ret);
drm_mode_config_reset(dev);
+ drm_kms_helper_poll_init(dev);
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c
index dfb641b83842..d884f3cb0ec7 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c
@@ -9,7 +9,6 @@
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h>
-#include "mgag200_ddc.h"
#include "mgag200_drv.h"
static void mgag200_g200ev_init_registers(struct mga_device *mdev)
@@ -227,26 +226,11 @@ static const struct drm_crtc_funcs mgag200_g200ev_crtc_funcs = {
MGAG200_CRTC_FUNCS,
};
-static const struct drm_encoder_funcs mgag200_g200ev_dac_encoder_funcs = {
- MGAG200_DAC_ENCODER_FUNCS,
-};
-
-static const struct drm_connector_helper_funcs mgag200_g200ev_vga_connector_helper_funcs = {
- MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
-};
-
-static const struct drm_connector_funcs mgag200_g200ev_vga_connector_funcs = {
- MGAG200_VGA_CONNECTOR_FUNCS,
-};
-
static int mgag200_g200ev_pipeline_init(struct mga_device *mdev)
{
struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc;
- struct drm_encoder *encoder = &mdev->encoder;
- struct drm_connector *connector = &mdev->connector;
- struct i2c_adapter *ddc;
int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0,
@@ -274,35 +258,13 @@ static int mgag200_g200ev_pipeline_init(struct mga_device *mdev)
drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
- encoder->possible_crtcs = drm_crtc_mask(crtc);
- ret = drm_encoder_init(dev, encoder, &mgag200_g200ev_dac_encoder_funcs,
- DRM_MODE_ENCODER_DAC, NULL);
- if (ret) {
- drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
- return ret;
- }
-
- ddc = mgag200_ddc_create(mdev);
- if (IS_ERR(ddc)) {
- ret = PTR_ERR(ddc);
- drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ ret = mgag200_vga_output_init(mdev);
+ if (ret)
return ret;
- }
- ret = drm_connector_init_with_ddc(dev, connector,
- &mgag200_g200ev_vga_connector_funcs,
- DRM_MODE_CONNECTOR_VGA, ddc);
- if (ret) {
- drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
- return ret;
- }
- drm_connector_helper_add(connector, &mgag200_g200ev_vga_connector_helper_funcs);
-
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret) {
- drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+ if (ret)
return ret;
- }
return 0;
}
@@ -359,6 +321,7 @@ struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const stru
return ERR_PTR(ret);
drm_mode_config_reset(dev);
+ drm_kms_helper_poll_init(dev);
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
index 525b7f75e622..839401e8b465 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
@@ -8,7 +8,6 @@
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h>
-#include "mgag200_ddc.h"
#include "mgag200_drv.h"
static void mgag200_g200ew3_init_registers(struct mga_device *mdev)
@@ -96,26 +95,11 @@ static const struct drm_crtc_funcs mgag200_g200ew3_crtc_funcs = {
MGAG200_CRTC_FUNCS,
};
-static const struct drm_encoder_funcs mgag200_g200ew3_dac_encoder_funcs = {
- MGAG200_DAC_ENCODER_FUNCS,
-};
-
-static const struct drm_connector_helper_funcs mgag200_g200ew3_vga_connector_helper_funcs = {
- MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
-};
-
-static const struct drm_connector_funcs mgag200_g200ew3_vga_connector_funcs = {
- MGAG200_VGA_CONNECTOR_FUNCS,
-};
-
static int mgag200_g200ew3_pipeline_init(struct mga_device *mdev)
{
struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc;
- struct drm_encoder *encoder = &mdev->encoder;
- struct drm_connector *connector = &mdev->connector;
- struct i2c_adapter *ddc;
int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0,
@@ -143,35 +127,13 @@ static int mgag200_g200ew3_pipeline_init(struct mga_device *mdev)
drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
- encoder->possible_crtcs = drm_crtc_mask(crtc);
- ret = drm_encoder_init(dev, encoder, &mgag200_g200ew3_dac_encoder_funcs,
- DRM_MODE_ENCODER_DAC, NULL);
- if (ret) {
- drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
- return ret;
- }
-
- ddc = mgag200_ddc_create(mdev);
- if (IS_ERR(ddc)) {
- ret = PTR_ERR(ddc);
- drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ ret = mgag200_vga_output_init(mdev);
+ if (ret)
return ret;
- }
- ret = drm_connector_init_with_ddc(dev, connector,
- &mgag200_g200ew3_vga_connector_funcs,
- DRM_MODE_CONNECTOR_VGA, ddc);
- if (ret) {
- drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
- return ret;
- }
- drm_connector_helper_add(connector, &mgag200_g200ew3_vga_connector_helper_funcs);
-
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret) {
- drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+ if (ret)
return ret;
- }
return 0;
}
@@ -240,6 +202,7 @@ struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev,
return ERR_PTR(ret);
drm_mode_config_reset(dev);
+ drm_kms_helper_poll_init(dev);
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c
index ef7606b529ea..a824bb8ad579 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200se.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c
@@ -9,7 +9,6 @@
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h>
-#include "mgag200_ddc.h"
#include "mgag200_drv.h"
static int mgag200_g200se_init_pci_options(struct pci_dev *pdev)
@@ -358,26 +357,11 @@ static const struct drm_crtc_funcs mgag200_g200se_crtc_funcs = {
MGAG200_CRTC_FUNCS,
};
-static const struct drm_encoder_funcs mgag200_g200se_dac_encoder_funcs = {
- MGAG200_DAC_ENCODER_FUNCS,
-};
-
-static const struct drm_connector_helper_funcs mgag200_g200se_vga_connector_helper_funcs = {
- MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
-};
-
-static const struct drm_connector_funcs mgag200_g200se_vga_connector_funcs = {
- MGAG200_VGA_CONNECTOR_FUNCS,
-};
-
static int mgag200_g200se_pipeline_init(struct mga_device *mdev)
{
struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc;
- struct drm_encoder *encoder = &mdev->encoder;
- struct drm_connector *connector = &mdev->connector;
- struct i2c_adapter *ddc;
int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0,
@@ -405,35 +389,13 @@ static int mgag200_g200se_pipeline_init(struct mga_device *mdev)
drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
- encoder->possible_crtcs = drm_crtc_mask(crtc);
- ret = drm_encoder_init(dev, encoder, &mgag200_g200se_dac_encoder_funcs,
- DRM_MODE_ENCODER_DAC, NULL);
- if (ret) {
- drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
- return ret;
- }
-
- ddc = mgag200_ddc_create(mdev);
- if (IS_ERR(ddc)) {
- ret = PTR_ERR(ddc);
- drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ ret = mgag200_vga_output_init(mdev);
+ if (ret)
return ret;
- }
- ret = drm_connector_init_with_ddc(dev, connector,
- &mgag200_g200se_vga_connector_funcs,
- DRM_MODE_CONNECTOR_VGA, ddc);
- if (ret) {
- drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
- return ret;
- }
- drm_connector_helper_add(connector, &mgag200_g200se_vga_connector_helper_funcs);
-
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret) {
- drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+ if (ret)
return ret;
- }
return 0;
}
@@ -559,6 +521,7 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru
return ERR_PTR(ret);
drm_mode_config_reset(dev);
+ drm_kms_helper_poll_init(dev);
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c b/drivers/gpu/drm/mgag200/mgag200_g200wb.c
index e4def62b1e57..835df0f4fc13 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200wb.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c
@@ -9,7 +9,6 @@
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h>
-#include "mgag200_ddc.h"
#include "mgag200_drv.h"
void mgag200_g200wb_init_registers(struct mga_device *mdev)
@@ -230,26 +229,11 @@ static const struct drm_crtc_funcs mgag200_g200wb_crtc_funcs = {
MGAG200_CRTC_FUNCS,
};
-static const struct drm_encoder_funcs mgag200_g200wb_dac_encoder_funcs = {
- MGAG200_DAC_ENCODER_FUNCS,
-};
-
-static const struct drm_connector_helper_funcs mgag200_g200wb_vga_connector_helper_funcs = {
- MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
-};
-
-static const struct drm_connector_funcs mgag200_g200wb_vga_connector_funcs = {
- MGAG200_VGA_CONNECTOR_FUNCS,
-};
-
static int mgag200_g200wb_pipeline_init(struct mga_device *mdev)
{
struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc;
- struct drm_encoder *encoder = &mdev->encoder;
- struct drm_connector *connector = &mdev->connector;
- struct i2c_adapter *ddc;
int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0,
@@ -277,35 +261,13 @@ static int mgag200_g200wb_pipeline_init(struct mga_device *mdev)
drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
- encoder->possible_crtcs = drm_crtc_mask(crtc);
- ret = drm_encoder_init(dev, encoder, &mgag200_g200wb_dac_encoder_funcs,
- DRM_MODE_ENCODER_DAC, NULL);
- if (ret) {
- drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
- return ret;
- }
-
- ddc = mgag200_ddc_create(mdev);
- if (IS_ERR(ddc)) {
- ret = PTR_ERR(ddc);
- drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ ret = mgag200_vga_output_init(mdev);
+ if (ret)
return ret;
- }
- ret = drm_connector_init_with_ddc(dev, connector,
- &mgag200_g200wb_vga_connector_funcs,
- DRM_MODE_CONNECTOR_VGA, ddc);
- if (ret) {
- drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
- return ret;
- }
- drm_connector_helper_add(connector, &mgag200_g200wb_vga_connector_helper_funcs);
-
- ret = drm_connector_attach_encoder(connector, encoder);
- if (ret) {
- drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+ if (ret)
return ret;
- }
return 0;
}
@@ -364,6 +326,7 @@ struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const stru
return ERR_PTR(ret);
drm_mode_config_reset(dev);
+ drm_kms_helper_poll_init(dev);
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_vga.c b/drivers/gpu/drm/mgag200/mgag200_vga.c
new file mode 100644
index 000000000000..60568f32736d
--- /dev/null
+++ b/drivers/gpu/drm/mgag200/mgag200_vga.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_probe_helper.h>
+
+#include "mgag200_ddc.h"
+#include "mgag200_drv.h"
+
+static const struct drm_encoder_funcs mgag200_dac_encoder_funcs = {
+ .destroy = drm_encoder_cleanup
+};
+
+static const struct drm_connector_helper_funcs mgag200_vga_connector_helper_funcs = {
+ .get_modes = drm_connector_helper_get_modes,
+ .detect_ctx = drm_connector_helper_detect_from_ddc
+};
+
+static const struct drm_connector_funcs mgag200_vga_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
+};
+
+int mgag200_vga_output_init(struct mga_device *mdev)
+{
+ struct drm_device *dev = &mdev->base;
+ struct drm_crtc *crtc = &mdev->crtc;
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+ struct i2c_adapter *ddc;
+ int ret;
+
+ encoder = &mdev->output.vga.encoder;
+ ret = drm_encoder_init(dev, encoder, &mgag200_dac_encoder_funcs,
+ DRM_MODE_ENCODER_DAC, NULL);
+ if (ret) {
+ drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
+ return ret;
+ }
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+
+ ddc = mgag200_ddc_create(mdev);
+ if (IS_ERR(ddc)) {
+ ret = PTR_ERR(ddc);
+ drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ return ret;
+ }
+
+ connector = &mdev->output.vga.connector;
+ ret = drm_connector_init_with_ddc(dev, connector,
+ &mgag200_vga_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA, ddc);
+ if (ret) {
+ drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
+ return ret;
+ }
+ drm_connector_helper_add(connector, &mgag200_vga_connector_helper_funcs);
+
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT |
+ DRM_CONNECTOR_POLL_DISCONNECT;
+
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret) {
+ drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 70fb003a6666..0712d0b15170 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -898,7 +898,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict,
* Without this the operation can timeout and we'll fallback to a
* software copy, which might take several minutes to finish.
*/
- nouveau_fence_wait(fence, false, false);
+ nouveau_fence_wait(fence, false);
ret = ttm_bo_move_accel_cleanup(bo, &fence->base, evict, false,
new_reg);
nouveau_fence_unref(&fence);
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c
index 7c97b2886807..66fca95c10c7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -72,7 +72,7 @@ nouveau_channel_idle(struct nouveau_channel *chan)
ret = nouveau_fence_new(&fence, chan);
if (!ret) {
- ret = nouveau_fence_wait(fence, false, false);
+ ret = nouveau_fence_wait(fence, false);
nouveau_fence_unref(&fence);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_dmem.c b/drivers/gpu/drm/nouveau/nouveau_dmem.c
index 6fb65b01d778..6719353e2e13 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dmem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dmem.c
@@ -128,7 +128,7 @@ static void nouveau_dmem_page_free(struct page *page)
static void nouveau_dmem_fence_done(struct nouveau_fence **fence)
{
if (fence) {
- nouveau_fence_wait(*fence, true, false);
+ nouveau_fence_wait(*fence, false);
nouveau_fence_unref(fence);
} else {
/*
diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.c b/drivers/gpu/drm/nouveau/nouveau_exec.c
index e65c0ef23bc7..a0b5f1b16e8b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_exec.c
+++ b/drivers/gpu/drm/nouveau/nouveau_exec.c
@@ -188,7 +188,7 @@ nouveau_exec_job_timeout(struct nouveau_job *job)
return DRM_GPU_SCHED_STAT_NOMINAL;
}
-static struct nouveau_job_ops nouveau_exec_job_ops = {
+static const struct nouveau_job_ops nouveau_exec_job_ops = {
.submit = nouveau_exec_job_submit,
.armed_submit = nouveau_exec_job_armed_submit,
.run = nouveau_exec_job_run,
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 93f08f9479d8..ba469767a20f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -311,39 +311,11 @@ nouveau_fence_wait_legacy(struct dma_fence *f, bool intr, long wait)
return timeout - t;
}
-static int
-nouveau_fence_wait_busy(struct nouveau_fence *fence, bool intr)
-{
- int ret = 0;
-
- while (!nouveau_fence_done(fence)) {
- if (time_after_eq(jiffies, fence->timeout)) {
- ret = -EBUSY;
- break;
- }
-
- __set_current_state(intr ?
- TASK_INTERRUPTIBLE :
- TASK_UNINTERRUPTIBLE);
-
- if (intr && signal_pending(current)) {
- ret = -ERESTARTSYS;
- break;
- }
- }
-
- __set_current_state(TASK_RUNNING);
- return ret;
-}
-
int
-nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr)
+nouveau_fence_wait(struct nouveau_fence *fence, bool intr)
{
long ret;
- if (!lazy)
- return nouveau_fence_wait_busy(fence, intr);
-
ret = dma_fence_wait_timeout(&fence->base, intr, 15 * HZ);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h
index 8bc065acfe35..1b63197b744a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.h
@@ -23,7 +23,7 @@ void nouveau_fence_unref(struct nouveau_fence **);
int nouveau_fence_emit(struct nouveau_fence *);
bool nouveau_fence_done(struct nouveau_fence *);
-int nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr);
+int nouveau_fence_wait(struct nouveau_fence *, bool intr);
int nouveau_fence_sync(struct nouveau_bo *, struct nouveau_channel *, bool exclusive, bool intr);
struct nouveau_fence_chan {
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 5a887d67dc0e..2e535caa7d6e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -928,7 +928,7 @@ revalidate:
}
if (sync) {
- if (!(ret = nouveau_fence_wait(fence, false, false))) {
+ if (!(ret = nouveau_fence_wait(fence, false))) {
if ((ret = dma_fence_get_status(&fence->base)) == 1)
ret = 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.h b/drivers/gpu/drm/nouveau/nouveau_sched.h
index e1f01a23e6f6..20cd1da8db73 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sched.h
+++ b/drivers/gpu/drm/nouveau/nouveau_sched.h
@@ -42,7 +42,7 @@ struct nouveau_job_args {
u32 count;
} out_sync;
- struct nouveau_job_ops *ops;
+ const struct nouveau_job_ops *ops;
};
struct nouveau_job {
@@ -73,7 +73,7 @@ struct nouveau_job {
u32 count;
} out_sync;
- struct nouveau_job_ops {
+ const struct nouveau_job_ops {
/* If .submit() returns without any error, it is guaranteed that
* armed_submit() is called.
*/
diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
index ee02cd833c5e..9402fa320a7e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
@@ -1534,7 +1534,7 @@ nouveau_uvmm_bind_job_cleanup(struct nouveau_job *job)
nouveau_uvmm_bind_job_put(bind_job);
}
-static struct nouveau_job_ops nouveau_bind_job_ops = {
+static const struct nouveau_job_ops nouveau_bind_job_ops = {
.submit = nouveau_uvmm_bind_job_submit,
.armed_submit = nouveau_uvmm_bind_job_armed_submit,
.run = nouveau_uvmm_bind_job_run,
diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c
index 67ab6915d6e4..3a574a9b46e7 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1045,33 +1045,6 @@ static const struct panel_desc auo_b116xak01 = {
},
};
-static const struct drm_display_mode auo_b133han05_mode = {
- .clock = 142600,
- .hdisplay = 1920,
- .hsync_start = 1920 + 58,
- .hsync_end = 1920 + 58 + 42,
- .htotal = 1920 + 58 + 42 + 60,
- .vdisplay = 1080,
- .vsync_start = 1080 + 3,
- .vsync_end = 1080 + 3 + 5,
- .vtotal = 1080 + 3 + 5 + 54,
-};
-
-static const struct panel_desc auo_b133han05 = {
- .modes = &auo_b133han05_mode,
- .num_modes = 1,
- .bpc = 8,
- .size = {
- .width = 293,
- .height = 165,
- },
- .delay = {
- .hpd_reliable = 100,
- .enable = 20,
- .unprepare = 50,
- },
-};
-
static const struct drm_display_mode auo_b133htn01_mode = {
.clock = 150660,
.hdisplay = 1920,
@@ -1121,33 +1094,6 @@ static const struct panel_desc auo_b133xtn01 = {
},
};
-static const struct drm_display_mode auo_b140han06_mode = {
- .clock = 141000,
- .hdisplay = 1920,
- .hsync_start = 1920 + 16,
- .hsync_end = 1920 + 16 + 16,
- .htotal = 1920 + 16 + 16 + 152,
- .vdisplay = 1080,
- .vsync_start = 1080 + 3,
- .vsync_end = 1080 + 3 + 14,
- .vtotal = 1080 + 3 + 14 + 19,
-};
-
-static const struct panel_desc auo_b140han06 = {
- .modes = &auo_b140han06_mode,
- .num_modes = 1,
- .bpc = 8,
- .size = {
- .width = 309,
- .height = 174,
- },
- .delay = {
- .hpd_reliable = 100,
- .enable = 20,
- .unprepare = 50,
- },
-};
-
static const struct drm_display_mode boe_nv101wxmn51_modes[] = {
{
.clock = 71900,
@@ -1414,33 +1360,6 @@ static const struct panel_desc innolux_p120zdg_bf1 = {
},
};
-static const struct drm_display_mode ivo_m133nwf4_r0_mode = {
- .clock = 138778,
- .hdisplay = 1920,
- .hsync_start = 1920 + 24,
- .hsync_end = 1920 + 24 + 48,
- .htotal = 1920 + 24 + 48 + 88,
- .vdisplay = 1080,
- .vsync_start = 1080 + 3,
- .vsync_end = 1080 + 3 + 12,
- .vtotal = 1080 + 3 + 12 + 17,
- .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
-};
-
-static const struct panel_desc ivo_m133nwf4_r0 = {
- .modes = &ivo_m133nwf4_r0_mode,
- .num_modes = 1,
- .bpc = 8,
- .size = {
- .width = 294,
- .height = 165,
- },
- .delay = {
- .hpd_absent = 200,
- .unprepare = 500,
- },
-};
-
static const struct drm_display_mode kingdisplay_kd116n21_30nv_a010_mode = {
.clock = 81000,
.hdisplay = 1366,
@@ -1689,98 +1608,40 @@ static const struct panel_desc sharp_lq123p1jx31 = {
},
};
-static const struct drm_display_mode sharp_lq140m1jw46_mode[] = {
- {
- .clock = 346500,
- .hdisplay = 1920,
- .hsync_start = 1920 + 48,
- .hsync_end = 1920 + 48 + 32,
- .htotal = 1920 + 48 + 32 + 80,
- .vdisplay = 1080,
- .vsync_start = 1080 + 3,
- .vsync_end = 1080 + 3 + 5,
- .vtotal = 1080 + 3 + 5 + 69,
- .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
- }, {
- .clock = 144370,
- .hdisplay = 1920,
- .hsync_start = 1920 + 48,
- .hsync_end = 1920 + 48 + 32,
- .htotal = 1920 + 48 + 32 + 80,
- .vdisplay = 1080,
- .vsync_start = 1080 + 3,
- .vsync_end = 1080 + 3 + 5,
- .vtotal = 1080 + 3 + 5 + 69,
- .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
- },
-};
-
-static const struct panel_desc sharp_lq140m1jw46 = {
- .modes = sharp_lq140m1jw46_mode,
- .num_modes = ARRAY_SIZE(sharp_lq140m1jw46_mode),
- .bpc = 8,
- .size = {
- .width = 309,
- .height = 174,
- },
- .delay = {
- .hpd_absent = 80,
- .enable = 50,
- .unprepare = 500,
- },
-};
-
-static const struct drm_display_mode starry_kr122ea0sra_mode = {
- .clock = 147000,
- .hdisplay = 1920,
- .hsync_start = 1920 + 16,
- .hsync_end = 1920 + 16 + 16,
- .htotal = 1920 + 16 + 16 + 32,
- .vdisplay = 1200,
- .vsync_start = 1200 + 15,
- .vsync_end = 1200 + 15 + 2,
- .vtotal = 1200 + 15 + 2 + 18,
- .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
-};
-
-static const struct panel_desc starry_kr122ea0sra = {
- .modes = &starry_kr122ea0sra_mode,
- .num_modes = 1,
- .size = {
- .width = 263,
- .height = 164,
- },
- .delay = {
- /* TODO: should be hpd-absent and no-hpd should be set? */
- .hpd_reliable = 10 + 200,
- .enable = 50,
- .unprepare = 10 + 500,
- },
-};
-
static const struct of_device_id platform_of_match[] = {
{
/* Must be first */
.compatible = "edp-panel",
- }, {
+ },
+ /*
+ * Do not add panels to the list below unless they cannot be handled by
+ * the generic edp-panel compatible.
+ *
+ * The only two valid reasons are:
+ * - Because of the panel issues (e.g. broken EDID or broken
+ * identification).
+ * - Because the eDP drivers didn't wire up the AUX bus properly.
+ * NOTE that, though this is a marginally valid reason,
+ * some justification needs to be made for why the platform can't
+ * wire up the AUX bus properly.
+ *
+ * In all other cases the platform should use the aux-bus and declare
+ * the panel using the 'edp-panel' compatible as a device on the AUX
+ * bus.
+ */
+ {
.compatible = "auo,b101ean01",
.data = &auo_b101ean01,
}, {
.compatible = "auo,b116xa01",
.data = &auo_b116xak01,
}, {
- .compatible = "auo,b133han05",
- .data = &auo_b133han05,
- }, {
.compatible = "auo,b133htn01",
.data = &auo_b133htn01,
}, {
.compatible = "auo,b133xtn01",
.data = &auo_b133xtn01,
}, {
- .compatible = "auo,b140han06",
- .data = &auo_b140han06,
- }, {
.compatible = "boe,nv101wxmn51",
.data = &boe_nv101wxmn51,
}, {
@@ -1808,9 +1669,6 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "innolux,p120zdg-bf1",
.data = &innolux_p120zdg_bf1,
}, {
- .compatible = "ivo,m133nwf4-r0",
- .data = &ivo_m133nwf4_r0,
- }, {
.compatible = "kingdisplay,kd116n21-30nv-a010",
.data = &kingdisplay_kd116n21_30nv_a010,
}, {
@@ -1841,12 +1699,6 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "sharp,lq123p1jx31",
.data = &sharp_lq123p1jx31,
}, {
- .compatible = "sharp,lq140m1jw46",
- .data = &sharp_lq140m1jw46,
- }, {
- .compatible = "starry,kr122ea0sra",
- .data = &starry_kr122ea0sra,
- }, {
/* sentinel */
}
};
@@ -1897,6 +1749,12 @@ static const struct panel_delay delay_200_500_e80_d50 = {
.disable = 50,
};
+static const struct panel_delay delay_80_500_e50 = {
+ .hpd_absent = 80,
+ .unprepare = 500,
+ .enable = 50,
+};
+
static const struct panel_delay delay_100_500_e200 = {
.hpd_absent = 100,
.unprepare = 500,
@@ -2105,7 +1963,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('S', 'D', 'C', 0x416d, &delay_100_500_e200, "ATNA45AF01"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, "LQ140M1JW48"),
- EDP_PANEL_ENTRY('S', 'H', 'P', 0x1523, &sharp_lq140m1jw46.delay, "LQ140M1JW46"),
+ EDP_PANEL_ENTRY('S', 'H', 'P', 0x1523, &delay_80_500_e50, "LQ140M1JW46"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x153a, &delay_200_500_e50, "LQ140T1JH01"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"),
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index ef9f6c0716d5..b43557b10ae3 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -777,6 +777,15 @@ static const struct panfrost_compatible mediatek_mt8186_data = {
.pm_features = BIT(GPU_PM_CLK_DIS) | BIT(GPU_PM_VREG_OFF),
};
+/* MT8188 uses the same power domains and power supplies as MT8183 */
+static const struct panfrost_compatible mediatek_mt8188_data = {
+ .num_supplies = ARRAY_SIZE(mediatek_mt8183_b_supplies) - 1,
+ .supply_names = mediatek_mt8183_b_supplies,
+ .num_pm_domains = ARRAY_SIZE(mediatek_mt8183_pm_domains),
+ .pm_domain_names = mediatek_mt8183_pm_domains,
+ .pm_features = BIT(GPU_PM_CLK_DIS) | BIT(GPU_PM_VREG_OFF),
+};
+
static const char * const mediatek_mt8192_supplies[] = { "mali", NULL };
static const char * const mediatek_mt8192_pm_domains[] = { "core0", "core1", "core2",
"core3", "core4" };
@@ -808,6 +817,7 @@ static const struct of_device_id dt_match[] = {
{ .compatible = "mediatek,mt8183-mali", .data = &mediatek_mt8183_data },
{ .compatible = "mediatek,mt8183b-mali", .data = &mediatek_mt8183_b_data },
{ .compatible = "mediatek,mt8186-mali", .data = &mediatek_mt8186_data },
+ { .compatible = "mediatek,mt8188-mali", .data = &mediatek_mt8188_data },
{ .compatible = "mediatek,mt8192-mali", .data = &mediatek_mt8192_data },
{}
};
diff --git a/drivers/gpu/drm/tidss/tidss_plane.c b/drivers/gpu/drm/tidss/tidss_plane.c
index 68fed531f6a7..a5d86822c9e3 100644
--- a/drivers/gpu/drm/tidss/tidss_plane.c
+++ b/drivers/gpu/drm/tidss/tidss_plane.c
@@ -8,6 +8,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_fb_dma_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
@@ -166,6 +167,14 @@ static const struct drm_plane_helper_funcs tidss_plane_helper_funcs = {
.atomic_disable = tidss_plane_atomic_disable,
};
+static const struct drm_plane_helper_funcs tidss_primary_plane_helper_funcs = {
+ .atomic_check = tidss_plane_atomic_check,
+ .atomic_update = tidss_plane_atomic_update,
+ .atomic_enable = tidss_plane_atomic_enable,
+ .atomic_disable = tidss_plane_atomic_disable,
+ .get_scanout_buffer = drm_fb_dma_get_scanout_buffer,
+};
+
static const struct drm_plane_funcs tidss_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
@@ -211,7 +220,10 @@ struct tidss_plane *tidss_plane_create(struct tidss_device *tidss,
if (ret < 0)
goto err;
- drm_plane_helper_add(&tplane->plane, &tidss_plane_helper_funcs);
+ if (type == DRM_PLANE_TYPE_PRIMARY)
+ drm_plane_helper_add(&tplane->plane, &tidss_primary_plane_helper_funcs);
+ else
+ drm_plane_helper_add(&tplane->plane, &tidss_plane_helper_funcs);
drm_plane_create_zpos_property(&tplane->plane, tidss->num_planes, 0,
num_planes - 1);
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index 9df068a413f3..129beac4c073 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -256,10 +256,10 @@ struct zynqmp_dp_link_config {
* @fmt: format identifier string
*/
struct zynqmp_dp_mode {
+ const char *fmt;
+ int pclock;
u8 bw_code;
u8 lane_cnt;
- int pclock;
- const char *fmt;
};
/**
@@ -296,27 +296,27 @@ struct zynqmp_dp_config {
* @train_set: set of training data
*/
struct zynqmp_dp {
+ struct drm_dp_aux aux;
+ struct drm_bridge bridge;
+ struct work_struct hpd_work;
+
+ struct drm_bridge *next_bridge;
struct device *dev;
struct zynqmp_dpsub *dpsub;
void __iomem *iomem;
struct reset_control *reset;
- int irq;
-
- struct drm_bridge bridge;
- struct drm_bridge *next_bridge;
-
- struct zynqmp_dp_config config;
- struct drm_dp_aux aux;
struct phy *phy[ZYNQMP_DP_MAX_LANES];
- u8 num_lanes;
- struct delayed_work hpd_work;
+
enum drm_connector_status status;
+ int irq;
bool enabled;
- u8 dpcd[DP_RECEIVER_CAP_SIZE];
- struct zynqmp_dp_link_config link_config;
struct zynqmp_dp_mode mode;
+ struct zynqmp_dp_link_config link_config;
+ struct zynqmp_dp_config config;
+ u8 dpcd[DP_RECEIVER_CAP_SIZE];
u8 train_set[ZYNQMP_DP_MAX_LANES];
+ u8 num_lanes;
};
static inline struct zynqmp_dp *bridge_to_dp(struct drm_bridge *bridge)
@@ -1482,7 +1482,7 @@ static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge,
struct zynqmp_dp *dp = bridge_to_dp(bridge);
dp->enabled = false;
- cancel_delayed_work(&dp->hpd_work);
+ cancel_work(&dp->hpd_work);
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 0);
drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN,
@@ -1648,8 +1648,7 @@ void zynqmp_dp_disable_vblank(struct zynqmp_dp *dp)
static void zynqmp_dp_hpd_work_func(struct work_struct *work)
{
- struct zynqmp_dp *dp = container_of(work, struct zynqmp_dp,
- hpd_work.work);
+ struct zynqmp_dp *dp = container_of(work, struct zynqmp_dp, hpd_work);
enum drm_connector_status status;
status = zynqmp_dp_bridge_detect(&dp->bridge);
@@ -1685,7 +1684,7 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data)
zynqmp_dpsub_drm_handle_vblank(dp->dpsub);
if (status & ZYNQMP_DP_INT_HPD_EVENT)
- schedule_delayed_work(&dp->hpd_work, 0);
+ schedule_work(&dp->hpd_work);
if (status & ZYNQMP_DP_INT_HPD_IRQ) {
int ret;
@@ -1727,7 +1726,7 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub)
dp->dpsub = dpsub;
dp->status = connector_status_disconnected;
- INIT_DELAYED_WORK(&dp->hpd_work, zynqmp_dp_hpd_work_func);
+ INIT_WORK(&dp->hpd_work, zynqmp_dp_hpd_work_func);
/* Acquire all resources (IOMEM, IRQ and PHYs). */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dp");
@@ -1832,7 +1831,7 @@ void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub)
zynqmp_dp_write(dp, ZYNQMP_DP_INT_DS, ZYNQMP_DP_INT_ALL);
disable_irq(dp->irq);
- cancel_delayed_work_sync(&dp->hpd_work);
+ cancel_work_sync(&dp->hpd_work);
zynqmp_dp_write(dp, ZYNQMP_DP_TRANSMITTER_ENABLE, 0);
zynqmp_dp_write(dp, ZYNQMP_DP_INT_DS, 0xffffffff);
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c
index face8d6b2a6f..f5781939de9c 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c
@@ -269,6 +269,7 @@ static int zynqmp_dpsub_probe(struct platform_device *pdev)
return 0;
err_disp:
+ drm_bridge_remove(dpsub->bridge);
zynqmp_disp_remove(dpsub);
err_dp:
zynqmp_dp_remove(dpsub);
diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c
index 43bf416b33d5..bd1368df7870 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_kms.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c
@@ -120,9 +120,13 @@ static void zynqmp_dpsub_plane_atomic_update(struct drm_plane *plane,
zynqmp_disp_blend_set_global_alpha(dpsub->disp, true,
plane->state->alpha >> 8);
- /* Enable or re-enable the plane if the format has changed. */
- if (format_changed)
- zynqmp_disp_layer_enable(layer);
+ /*
+ * Unconditionally enable the layer, as it may have been disabled
+ * previously either explicitly to reconfigure layer format, or
+ * implicitly after DPSUB reset during display mode change. DRM
+ * framework calls this callback for enabled planes only.
+ */
+ zynqmp_disp_layer_enable(layer);
}
static const struct drm_plane_helper_funcs zynqmp_dpsub_plane_helper_funcs = {
@@ -433,23 +437,28 @@ static int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub)
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret) {
dev_err(dpsub->dev, "failed to attach bridge to encoder\n");
- return ret;
+ goto err_encoder;
}
/* Create the connector for the chain of bridges. */
connector = drm_bridge_connector_init(&dpsub->drm->dev, encoder);
if (IS_ERR(connector)) {
dev_err(dpsub->dev, "failed to created connector\n");
- return PTR_ERR(connector);
+ ret = PTR_ERR(connector);
+ goto err_encoder;
}
ret = drm_connector_attach_encoder(connector, encoder);
if (ret < 0) {
dev_err(dpsub->dev, "failed to attach connector to encoder\n");
- return ret;
+ goto err_encoder;
}
return 0;
+
+err_encoder:
+ drm_encoder_cleanup(encoder);
+ return ret;
}
static void zynqmp_dpsub_drm_release(struct drm_device *drm, void *res)
@@ -529,5 +538,6 @@ void zynqmp_dpsub_drm_cleanup(struct zynqmp_dpsub *dpsub)
drm_dev_unregister(drm);
drm_atomic_helper_shutdown(drm);
+ drm_encoder_cleanup(&dpsub->drm->encoder);
drm_kms_helper_poll_fini(drm);
}