Commit ab3d8479 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-misc-next-2024-06-20' of...

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: default avatarDave Airlie <airlied@redhat.com>

From: Maxime Ripard <mripard@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240620-heretic-honored-macaque-b40f8a@houat
parents 91c93e47 b9578c49
...@@ -31,13 +31,9 @@ properties: ...@@ -31,13 +31,9 @@ properties:
# AUO B116XAK01 eDP TFT LCD panel # AUO B116XAK01 eDP TFT LCD panel
- auo,b116xa01 - auo,b116xa01
# AU Optronics Corporation 13.3" FHD (1920x1080) color TFT-LCD panel # AU Optronics Corporation 13.3" FHD (1920x1080) color TFT-LCD panel
- auo,b133han05
# AU Optronics Corporation 13.3" FHD (1920x1080) color TFT-LCD panel
- auo,b133htn01 - auo,b133htn01
# AU Optronics Corporation 13.3" WXGA (1366x768) TFT LCD panel # AU Optronics Corporation 13.3" WXGA (1366x768) TFT LCD panel
- auo,b133xtn01 - auo,b133xtn01
# AU Optronics Corporation 14.0" FHD (1920x1080) color TFT-LCD panel
- auo,b140han06
# BOE OPTOELECTRONICS TECHNOLOGY 10.1" WXGA TFT LCD panel # BOE OPTOELECTRONICS TECHNOLOGY 10.1" WXGA TFT LCD panel
- boe,nv101wxmn51 - boe,nv101wxmn51
# BOE NV133FHM-N61 13.3" FHD (1920x1080) TFT LCD Panel # BOE NV133FHM-N61 13.3" FHD (1920x1080) TFT LCD Panel
...@@ -56,8 +52,6 @@ properties: ...@@ -56,8 +52,6 @@ properties:
- innolux,n125hce-gn1 - innolux,n125hce-gn1
# Innolux P120ZDG-BF1 12.02 inch eDP 2K display panel # Innolux P120ZDG-BF1 12.02 inch eDP 2K display panel
- innolux,p120zdg-bf1 - innolux,p120zdg-bf1
# InfoVision Optoelectronics M133NWF4 R0 13.3" FHD (1920x1080) TFT LCD panel
- ivo,m133nwf4-r0
# King & Display KD116N21-30NV-A010 eDP TFT LCD panel # King & Display KD116N21-30NV-A010 eDP TFT LCD panel
- kingdisplay,kd116n21-30nv-a010 - kingdisplay,kd116n21-30nv-a010
# LG LP079QX1-SP0V 7.9" (1536x2048 pixels) TFT LCD panel # LG LP079QX1-SP0V 7.9" (1536x2048 pixels) TFT LCD panel
...@@ -78,10 +72,6 @@ properties: ...@@ -78,10 +72,6 @@ properties:
- sharp,ld-d5116z01b - sharp,ld-d5116z01b
# Sharp 12.3" (2400x1600 pixels) TFT LCD panel # Sharp 12.3" (2400x1600 pixels) TFT LCD panel
- sharp,lq123p1jx31 - sharp,lq123p1jx31
# Sharp 14" (1920x1080 pixels) TFT LCD panel
- sharp,lq140m1jw46
# Starry 12.2" (1920x1200 pixels) TFT LCD panel
- starry,kr122ea0sra
backlight: true backlight: true
ddc-i2c-bus: true ddc-i2c-bus: true
......
...@@ -34,6 +34,7 @@ properties: ...@@ -34,6 +34,7 @@ properties:
- const: arm,mali-valhall-jm # Mali Valhall GPU model/revision is fully discoverable - const: arm,mali-valhall-jm # Mali Valhall GPU model/revision is fully discoverable
- items: - items:
- enum: - enum:
- mediatek,mt8188-mali
- mediatek,mt8192-mali - mediatek,mt8192-mali
- const: arm,mali-valhall-jm # Mali Valhall GPU model/revision is fully discoverable - const: arm,mali-valhall-jm # Mali Valhall GPU model/revision is fully discoverable
...@@ -195,7 +196,9 @@ allOf: ...@@ -195,7 +196,9 @@ allOf:
properties: properties:
compatible: compatible:
contains: contains:
const: mediatek,mt8183b-mali enum:
- mediatek,mt8183b-mali
- mediatek,mt8188-mali
then: then:
properties: properties:
power-domains: power-domains:
......
...@@ -7196,6 +7196,7 @@ L: dri-devel@lists.freedesktop.org ...@@ -7196,6 +7196,7 @@ L: dri-devel@lists.freedesktop.org
S: Maintained S: Maintained
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: Documentation/gpu/vkms.rst F: Documentation/gpu/vkms.rst
F: drivers/gpu/drm/ci/xfails/vkms*
F: drivers/gpu/drm/vkms/ F: drivers/gpu/drm/vkms/
DRM DRIVER FOR VIRTUALBOX VIRTUAL GPU DRM DRIVER FOR VIRTUALBOX VIRTUAL GPU
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (C) 2020-2023 Intel Corporation * Copyright (C) 2020-2024 Intel Corporation
*/ */
#include <linux/debugfs.h> #include <linux/debugfs.h>
...@@ -381,6 +381,39 @@ static const struct file_operations ivpu_resume_engine_fops = { ...@@ -381,6 +381,39 @@ static const struct file_operations ivpu_resume_engine_fops = {
.write = ivpu_resume_engine_fn, .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) void ivpu_debugfs_init(struct ivpu_device *vdev)
{ {
struct dentry *debugfs_root = vdev->drm.debugfs_root; struct dentry *debugfs_root = vdev->drm.debugfs_root;
...@@ -409,7 +442,9 @@ void ivpu_debugfs_init(struct ivpu_device *vdev) ...@@ -409,7 +442,9 @@ void ivpu_debugfs_init(struct ivpu_device *vdev)
debugfs_create_file("resume_engine", 0200, debugfs_root, vdev, debugfs_create_file("resume_engine", 0200, debugfs_root, vdev,
&ivpu_resume_engine_fops); &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_create_file("fw_profiling_freq_drive", 0200,
debugfs_root, vdev, &fw_profiling_freq_fops); debugfs_root, vdev, &fw_profiling_freq_fops);
debugfs_create_file("dct", 0644, debugfs_root, vdev, &ivpu_dct_fops);
}
} }
...@@ -58,11 +58,11 @@ module_param_named(sched_mode, ivpu_sched_mode, int, 0444); ...@@ -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"); MODULE_PARM_DESC(sched_mode, "Scheduler mode: 0 - Default scheduler, 1 - Force HW scheduler");
bool ivpu_disable_mmu_cont_pages; 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"); MODULE_PARM_DESC(disable_mmu_cont_pages, "Disable MMU contiguous pages optimization");
bool ivpu_force_snoop; 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"); 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) 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) ...@@ -391,8 +391,13 @@ int ivpu_boot(struct ivpu_device *vdev)
ivpu_hw_irq_enable(vdev); ivpu_hw_irq_enable(vdev);
ivpu_ipc_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 ivpu_hw_sched_init(vdev);
}
return 0; return 0;
} }
...@@ -446,6 +451,26 @@ static const struct drm_driver driver = { ...@@ -446,6 +451,26 @@ static const struct drm_driver driver = {
.minor = DRM_IVPU_DRIVER_MINOR, .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) static irqreturn_t ivpu_irq_thread_handler(int irq, void *arg)
{ {
struct ivpu_device *vdev = arg; struct ivpu_device *vdev = arg;
...@@ -459,6 +484,12 @@ static irqreturn_t ivpu_irq_thread_handler(int irq, void *arg) ...@@ -459,6 +484,12 @@ static irqreturn_t ivpu_irq_thread_handler(int irq, void *arg)
case IVPU_HW_IRQ_SRC_IPC: case IVPU_HW_IRQ_SRC_IPC:
ivpu_ipc_irq_thread_handler(vdev); ivpu_ipc_irq_thread_handler(vdev);
break; 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: default:
ivpu_err_ratelimited(vdev, "Unknown IRQ source: %u\n", irq_src); ivpu_err_ratelimited(vdev, "Unknown IRQ source: %u\n", irq_src);
break; break;
...@@ -664,14 +695,14 @@ static void ivpu_bo_unbind_all_user_contexts(struct ivpu_device *vdev) ...@@ -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) static void ivpu_dev_fini(struct ivpu_device *vdev)
{ {
ivpu_jobs_abort_all(vdev);
ivpu_pm_cancel_recovery(vdev);
ivpu_pm_disable(vdev); ivpu_pm_disable(vdev);
ivpu_prepare_for_reset(vdev); ivpu_prepare_for_reset(vdev);
ivpu_shutdown(vdev); ivpu_shutdown(vdev);
ivpu_ms_cleanup_all(vdev); ivpu_ms_cleanup_all(vdev);
ivpu_jobs_abort_all(vdev);
ivpu_job_done_consumer_fini(vdev); ivpu_job_done_consumer_fini(vdev);
ivpu_pm_cancel_recovery(vdev);
ivpu_bo_unbind_all_user_contexts(vdev); ivpu_bo_unbind_all_user_contexts(vdev);
ivpu_ipc_fini(vdev); ivpu_ipc_fini(vdev);
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#define IVPU_HW_IP_50XX 50 #define IVPU_HW_IP_50XX 50
#define IVPU_HW_IP_60XX 60 #define IVPU_HW_IP_60XX 60
#define IVPU_HW_IP_REV_LNL_B0 4
#define IVPU_HW_BTRS_MTL 1 #define IVPU_HW_BTRS_MTL 1
#define IVPU_HW_BTRS_LNL 2 #define IVPU_HW_BTRS_LNL 2
...@@ -102,6 +104,7 @@ struct ivpu_wa_table { ...@@ -102,6 +104,7 @@ struct ivpu_wa_table {
bool interrupt_clear_with_0; bool interrupt_clear_with_0;
bool disable_clock_relinquish; bool disable_clock_relinquish;
bool disable_d0i3_msg; bool disable_d0i3_msg;
bool wp0_during_power_up;
}; };
struct ivpu_hw_info; struct ivpu_hw_info;
...@@ -147,7 +150,6 @@ struct ivpu_device { ...@@ -147,7 +150,6 @@ struct ivpu_device {
int boot; int boot;
int jsm; int jsm;
int tdr; int tdr;
int reschedule_suspend;
int autosuspend; int autosuspend;
int d0i3_entry_msg; int d0i3_entry_msg;
} timeout; } timeout;
...@@ -168,6 +170,7 @@ struct ivpu_file_priv { ...@@ -168,6 +170,7 @@ struct ivpu_file_priv {
struct ivpu_bo *ms_info_bo; struct ivpu_bo *ms_info_bo;
bool has_mmu_faults; bool has_mmu_faults;
bool bound; bool bound;
bool aborted;
}; };
extern int ivpu_dbg_mask; extern int ivpu_dbg_mask;
...@@ -184,6 +187,7 @@ extern bool ivpu_force_snoop; ...@@ -184,6 +187,7 @@ extern bool ivpu_force_snoop;
#define IVPU_TEST_MODE_D0I3_MSG_ENABLE BIT(5) #define IVPU_TEST_MODE_D0I3_MSG_ENABLE BIT(5)
#define IVPU_TEST_MODE_PREEMPTION_DISABLE BIT(6) #define IVPU_TEST_MODE_PREEMPTION_DISABLE BIT(6)
#define IVPU_TEST_MODE_HWS_EXTRA_EVENTS BIT(7) #define IVPU_TEST_MODE_HWS_EXTRA_EVENTS BIT(7)
#define IVPU_TEST_MODE_DISABLE_TIMEOUTS BIT(8)
extern int ivpu_test_mode; extern int ivpu_test_mode;
struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv); struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv);
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (C) 2020-2023 Intel Corporation * Copyright (C) 2020-2024 Intel Corporation
*/ */
#include <linux/firmware.h> #include <linux/firmware.h>
...@@ -123,6 +123,14 @@ ivpu_fw_check_api_ver_lt(struct ivpu_device *vdev, const struct vpu_firmware_hea ...@@ -123,6 +123,14 @@ ivpu_fw_check_api_ver_lt(struct ivpu_device *vdev, const struct vpu_firmware_hea
return false; 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) static int ivpu_fw_parse(struct ivpu_device *vdev)
{ {
struct ivpu_fw_info *fw = vdev->fw; struct ivpu_fw_info *fw = vdev->fw;
...@@ -205,10 +213,24 @@ static int ivpu_fw_parse(struct ivpu_device *vdev) ...@@ -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->primary_preempt_buf_size = fw_hdr->preemption_buffer_1_size;
fw->secondary_preempt_buf_size = fw_hdr->preemption_buffer_2_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", 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); 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", 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); 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; return 0;
} }
...@@ -270,6 +292,13 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev) ...@@ -270,6 +292,13 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev)
return -ENOMEM; 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, fw->mem_log_crit = ivpu_bo_create_global(vdev, IVPU_FW_CRITICAL_BUFFER_SIZE,
DRM_IVPU_BO_CACHED | DRM_IVPU_BO_MAPPABLE); DRM_IVPU_BO_CACHED | DRM_IVPU_BO_MAPPABLE);
if (!fw->mem_log_crit) { if (!fw->mem_log_crit) {
......
...@@ -30,6 +30,8 @@ struct ivpu_fw_info { ...@@ -30,6 +30,8 @@ struct ivpu_fw_info {
u32 dvfs_mode; u32 dvfs_mode;
u32 primary_preempt_buf_size; u32 primary_preempt_buf_size;
u32 secondary_preempt_buf_size; u32 secondary_preempt_buf_size;
u64 read_only_addr;
u32 read_only_size;
}; };
int ivpu_fw_init(struct ivpu_device *vdev); int ivpu_fw_init(struct ivpu_device *vdev);
......
...@@ -61,37 +61,48 @@ static void wa_init(struct ivpu_device *vdev) ...@@ -61,37 +61,48 @@ static void wa_init(struct ivpu_device *vdev)
if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) 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); 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; 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(punit_disabled);
IVPU_PRINT_WA(clear_runtime_mem); IVPU_PRINT_WA(clear_runtime_mem);
IVPU_PRINT_WA(interrupt_clear_with_0); IVPU_PRINT_WA(interrupt_clear_with_0);
IVPU_PRINT_WA(disable_clock_relinquish); IVPU_PRINT_WA(disable_clock_relinquish);
IVPU_PRINT_WA(wp0_during_power_up);
} }
static void timeouts_init(struct ivpu_device *vdev) 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.boot = 100000;
vdev->timeout.jsm = 50000; vdev->timeout.jsm = 50000;
vdev->timeout.tdr = 2000000; vdev->timeout.tdr = 2000000;
vdev->timeout.reschedule_suspend = 1000;
vdev->timeout.autosuspend = -1; vdev->timeout.autosuspend = -1;
vdev->timeout.d0i3_entry_msg = 500; vdev->timeout.d0i3_entry_msg = 500;
} else if (ivpu_is_simics(vdev)) { } else if (ivpu_is_simics(vdev)) {
vdev->timeout.boot = 50; vdev->timeout.boot = 50;
vdev->timeout.jsm = 500; vdev->timeout.jsm = 500;
vdev->timeout.tdr = 10000; vdev->timeout.tdr = 10000;
vdev->timeout.reschedule_suspend = 10;
vdev->timeout.autosuspend = -1; vdev->timeout.autosuspend = -1;
vdev->timeout.d0i3_entry_msg = 100; vdev->timeout.d0i3_entry_msg = 100;
} else { } else {
vdev->timeout.boot = 1000; vdev->timeout.boot = 1000;
vdev->timeout.jsm = 500; vdev->timeout.jsm = 500;
vdev->timeout.tdr = 2000; vdev->timeout.tdr = 2000;
vdev->timeout.reschedule_suspend = 10; if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
vdev->timeout.autosuspend = 10; vdev->timeout.autosuspend = 10;
else
vdev->timeout.autosuspend = 100;
vdev->timeout.d0i3_entry_msg = 5; vdev->timeout.d0i3_entry_msg = 5;
} }
} }
...@@ -125,6 +136,13 @@ int ivpu_hw_power_up(struct ivpu_device *vdev) ...@@ -125,6 +136,13 @@ int ivpu_hw_power_up(struct ivpu_device *vdev)
{ {
int ret; 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); ret = ivpu_hw_btrs_d0i3_disable(vdev);
if (ret) if (ret)
ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret); ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret);
......
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* Copyright (C) 2020 - 2024 Intel Corporation * Copyright (C) 2020-2024 Intel Corporation
*/ */
#ifndef __IVPU_HW_H__ #ifndef __IVPU_HW_H__
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#define IVPU_HW_IRQ_FIFO_LENGTH 1024 #define IVPU_HW_IRQ_FIFO_LENGTH 1024
#define IVPU_HW_IRQ_SRC_IPC 1 #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 { struct ivpu_addr_range {
resource_size_t start; resource_size_t start;
......
...@@ -504,6 +504,8 @@ static int ip_reset_lnl(struct ivpu_device *vdev) ...@@ -504,6 +504,8 @@ static int ip_reset_lnl(struct ivpu_device *vdev)
int ret; int ret;
u32 val; u32 val;
ivpu_hw_btrs_clock_relinquish_disable_lnl(vdev);
ret = REGB_POLL_FLD(VPU_HW_BTRS_LNL_IP_RESET, TRIGGER, 0, TIMEOUT_US); ret = REGB_POLL_FLD(VPU_HW_BTRS_LNL_IP_RESET, TRIGGER, 0, TIMEOUT_US);
if (ret) { if (ret) {
ivpu_err(vdev, "Wait for *_TRIGGER timed out\n"); 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) ...@@ -641,8 +643,11 @@ bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq)
if (!status) if (!status)
return false; 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"); 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)) 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)); 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) ...@@ -692,21 +697,40 @@ bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq)
return true; 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); if (cmd != DCT_REQ) {
val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_PCODE_MAILBOX, PARAM1, ivpu_err_ratelimited(vdev, "Unsupported PCODE command: 0x%x\n", cmd);
dct_val ? DCT_ENABLE : DCT_DISABLE, val); return -EBADR;
val = REG_SET_FLD_NUM(VPU_HW_BTRS_LNL_PCODE_MAILBOX, PARAM2, dct_val, val); }
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) static u32 pll_ratio_to_freq_mtl(u32 ratio, u32 config)
......
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
#define PLL_PROFILING_FREQ_HIGH 400000000 #define PLL_PROFILING_FREQ_HIGH 400000000
#define PLL_RATIO_TO_FREQ(x) ((x) * PLL_REF_CLK_FREQ) #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); int ivpu_hw_btrs_info_init(struct ivpu_device *vdev);
void ivpu_hw_btrs_freq_ratios_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); 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); ...@@ -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); 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_mtl(struct ivpu_device *vdev, int irq);
bool ivpu_hw_btrs_irq_handler_lnl(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_pll_freq_get(struct ivpu_device *vdev);
u32 ivpu_hw_btrs_ratio_to_freq(struct ivpu_device *vdev, u32 ratio); u32 ivpu_hw_btrs_ratio_to_freq(struct ivpu_device *vdev, u32 ratio);
u32 ivpu_hw_btrs_telemetry_offset_get(struct ivpu_device *vdev); u32 ivpu_hw_btrs_telemetry_offset_get(struct ivpu_device *vdev);
......
...@@ -44,11 +44,11 @@ ...@@ -44,11 +44,11 @@
#define VPU_HW_BTRS_LNL_IMR_ERR_CFI1_HIGH 0x0000005cu #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_IMR_ERR_CFI1_CLEAR 0x00000060u
#define VPU_HW_BTRS_LNL_PCODE_MAILBOX 0x00000070u #define VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS 0x00000070u
#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_CMD_MASK GENMASK(7, 0) #define VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS_CMD_MASK GENMASK(7, 0)
#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_PARAM1_MASK GENMASK(15, 8) #define VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS_PARAM1_MASK GENMASK(15, 8)
#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_PARAM2_MASK GENMASK(23, 16) #define VPU_HW_BTRS_LNL_PCODE_MAILBOX_STATUS_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_PARAM3_MASK GENMASK(31, 24)
#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_SHADOW 0x00000074u #define VPU_HW_BTRS_LNL_PCODE_MAILBOX_SHADOW 0x00000074u
#define VPU_HW_BTRS_LNL_PCODE_MAILBOX_SHADOW_CMD_MASK GENMASK(7, 0) #define VPU_HW_BTRS_LNL_PCODE_MAILBOX_SHADOW_CMD_MASK GENMASK(7, 0)
......
...@@ -210,8 +210,7 @@ void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *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); ivpu_ipc_tx_release(vdev, cons->tx_vpu_addr);
} }
static int int ivpu_ipc_send(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct vpu_jsm_msg *req)
ivpu_ipc_send(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct vpu_jsm_msg *req)
{ {
struct ivpu_ipc_info *ipc = vdev->ipc; struct ivpu_ipc_info *ipc = vdev->ipc;
int ret; int ret;
......
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* Copyright (C) 2020-2023 Intel Corporation * Copyright (C) 2020-2024 Intel Corporation
*/ */
#ifndef __IVPU_IPC_H__ #ifndef __IVPU_IPC_H__
...@@ -96,6 +96,8 @@ void ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *c ...@@ -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); u32 channel, ivpu_ipc_rx_callback_t callback);
void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons); 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, 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, struct ivpu_ipc_hdr *ipc_buf, struct vpu_jsm_msg *jsm_msg,
unsigned long timeout_ms); unsigned long timeout_ms);
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (C) 2020-2023 Intel Corporation * Copyright (C) 2020-2024 Intel Corporation
*/ */
#include <drm/drm_file.h> #include <drm/drm_file.h>
...@@ -312,6 +312,33 @@ void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev) ...@@ -312,6 +312,33 @@ void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev)
mutex_unlock(&vdev->context_list_lock); 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) static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job)
{ {
struct ivpu_device *vdev = job->vdev; struct ivpu_device *vdev = job->vdev;
......
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* Copyright (C) 2020-2023 Intel Corporation * Copyright (C) 2020-2024 Intel Corporation
*/ */
#ifndef __IVPU_JOB_H__ #ifndef __IVPU_JOB_H__
...@@ -57,6 +57,8 @@ struct ivpu_job { ...@@ -57,6 +57,8 @@ struct ivpu_job {
int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file); 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_release_all_locked(struct ivpu_file_priv *file_priv);
void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev); void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev);
......
...@@ -103,14 +103,10 @@ int ivpu_jsm_register_db(struct ivpu_device *vdev, u32 ctx_id, u32 db_id, ...@@ -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, ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_REGISTER_DB_DONE, &resp,
VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
if (ret) { if (ret)
ivpu_err_ratelimited(vdev, "Failed to register doorbell %d: %d\n", db_id, ret); ivpu_err_ratelimited(vdev, "Failed to register doorbell %u: %d\n", db_id, ret);
return ret;
}
ivpu_dbg(vdev, JSM, "Doorbell %d registered to context %d\n", db_id, ctx_id);
return 0; return ret;
} }
int ivpu_jsm_unregister_db(struct ivpu_device *vdev, u32 db_id) 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) ...@@ -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, ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_UNREGISTER_DB_DONE, &resp,
VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
if (ret) { if (ret)
ivpu_warn_ratelimited(vdev, "Failed to unregister doorbell %d: %d\n", db_id, ret); ivpu_warn_ratelimited(vdev, "Failed to unregister doorbell %u: %d\n", db_id, ret);
return ret;
}
ivpu_dbg(vdev, JSM, "Doorbell %d unregistered\n", db_id);
return 0; return ret;
} }
int ivpu_jsm_get_heartbeat(struct ivpu_device *vdev, u32 engine, u64 *heartbeat) 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) ...@@ -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 req = { .type = VPU_JSM_MSG_SSID_RELEASE };
struct vpu_jsm_msg resp; struct vpu_jsm_msg resp;
int ret;
req.payload.ssid_release.host_ssid = host_ssid; req.payload.ssid_release.host_ssid = host_ssid;
return ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_SSID_RELEASE_DONE, &resp, ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_SSID_RELEASE_DONE, &resp,
VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); 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) 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 ...@@ -538,3 +535,26 @@ int ivpu_jsm_metric_streamer_info(struct ivpu_device *vdev, u64 metric_group_mas
return ret; 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);
}
...@@ -41,4 +41,6 @@ int ivpu_jsm_metric_streamer_update(struct ivpu_device *vdev, u64 metric_group_m ...@@ -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); 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, 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); 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 #endif
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (C) 2020-2023 Intel Corporation * Copyright (C) 2020-2024 Intel Corporation
*/ */
#include <linux/circ_buf.h> #include <linux/circ_buf.h>
...@@ -878,8 +878,9 @@ static void ivpu_mmu_dump_event(struct ivpu_device *vdev, u32 *event) ...@@ -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]; u64 in_addr = ((u64)event[5]) << 32 | event[4];
u32 sid = event[1]; 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", 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); 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) static u32 *ivpu_mmu_get_event(struct ivpu_device *vdev)
...@@ -915,6 +916,9 @@ void ivpu_mmu_irq_evtq_handler(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); ivpu_mmu_user_context_mark_invalid(vdev, ssid);
REGV_WR32(IVPU_MMU_REG_EVTQ_CONS_SEC, vdev->mmu->evtq.cons); 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) void ivpu_mmu_evtq_dump(struct ivpu_device *vdev)
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#define IVPU_MMU_ENTRY_FLAG_CONT BIT(52) #define IVPU_MMU_ENTRY_FLAG_CONT BIT(52)
#define IVPU_MMU_ENTRY_FLAG_NG BIT(11) #define IVPU_MMU_ENTRY_FLAG_NG BIT(11)
#define IVPU_MMU_ENTRY_FLAG_AF BIT(10) #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_USER BIT(6)
#define IVPU_MMU_ENTRY_FLAG_LLC_COHERENT BIT(2) #define IVPU_MMU_ENTRY_FLAG_LLC_COHERENT BIT(2)
#define IVPU_MMU_ENTRY_FLAG_TYPE_PAGE BIT(1) #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 ...@@ -319,6 +320,91 @@ ivpu_mmu_context_map_pages(struct ivpu_device *vdev, struct ivpu_mmu_context *ct
return 0; 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) static void ivpu_mmu_context_unmap_pages(struct ivpu_mmu_context *ctx, u64 vpu_addr, size_t size)
{ {
while (size) { while (size) {
......
...@@ -46,5 +46,7 @@ int ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context * ...@@ -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); 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, void ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
u64 vpu_addr, struct sg_table *sgt); 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__ */ #endif /* __IVPU_MMU_CONTEXT_H__ */
...@@ -237,33 +237,30 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev) ...@@ -237,33 +237,30 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev)
{ {
struct drm_device *drm = dev_get_drvdata(dev); struct drm_device *drm = dev_get_drvdata(dev);
struct ivpu_device *vdev = to_ivpu_device(drm); struct ivpu_device *vdev = to_ivpu_device(drm);
bool hw_is_idle = true; int ret, ret_d0i3;
int ret; bool is_idle;
drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa)); drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa));
drm_WARN_ON(&vdev->drm, work_pending(&vdev->pm->recovery_work)); drm_WARN_ON(&vdev->drm, work_pending(&vdev->pm->recovery_work));
ivpu_dbg(vdev, PM, "Runtime suspend..\n"); ivpu_dbg(vdev, PM, "Runtime suspend..\n");
if (!ivpu_hw_is_idle(vdev) && vdev->pm->suspend_reschedule_counter) { ivpu_mmu_disable(vdev);
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;
}
if (!vdev->pm->suspend_reschedule_counter) is_idle = ivpu_hw_is_idle(vdev) || vdev->pm->dct_active_percent;
hw_is_idle = false; if (!is_idle)
else if (ivpu_jsm_pwr_d0i3_enter(vdev)) ivpu_err(vdev, "NPU is not idle before autosuspend\n");
hw_is_idle = false;
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); ret = ivpu_suspend(vdev);
if (ret) if (ret)
ivpu_err(vdev, "Failed to suspend NPU: %d\n", ret); ivpu_err(vdev, "Failed to suspend NPU: %d\n", ret);
if (!hw_is_idle) { if (!is_idle || ret_d0i3) {
ivpu_err(vdev, "NPU failed to enter idle, force suspended.\n"); ivpu_err(vdev, "Forcing cold boot due to previous errors\n");
atomic_inc(&vdev->pm->reset_counter); atomic_inc(&vdev->pm->reset_counter);
ivpu_fw_log_dump(vdev); ivpu_fw_log_dump(vdev);
ivpu_pm_prepare_cold_boot(vdev); ivpu_pm_prepare_cold_boot(vdev);
...@@ -271,8 +268,6 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev) ...@@ -271,8 +268,6 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev)
ivpu_pm_prepare_warm_boot(vdev); ivpu_pm_prepare_warm_boot(vdev);
} }
vdev->pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT;
ivpu_dbg(vdev, PM, "Runtime suspend done.\n"); ivpu_dbg(vdev, PM, "Runtime suspend done.\n");
return 0; return 0;
...@@ -300,17 +295,6 @@ int ivpu_rpm_get(struct ivpu_device *vdev) ...@@ -300,17 +295,6 @@ int ivpu_rpm_get(struct ivpu_device *vdev)
int ret; int ret;
ret = pm_runtime_resume_and_get(vdev->drm.dev); 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); drm_WARN_ON(&vdev->drm, ret < 0);
return ret; return ret;
...@@ -365,7 +349,6 @@ void ivpu_pm_init(struct ivpu_device *vdev) ...@@ -365,7 +349,6 @@ void ivpu_pm_init(struct ivpu_device *vdev)
int delay; int delay;
pm->vdev = vdev; pm->vdev = vdev;
pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT;
init_rwsem(&pm->reset_lock); init_rwsem(&pm->reset_lock);
atomic_set(&pm->reset_pending, 0); atomic_set(&pm->reset_pending, 0);
...@@ -406,3 +389,68 @@ void ivpu_pm_disable(struct ivpu_device *vdev) ...@@ -406,3 +389,68 @@ void ivpu_pm_disable(struct ivpu_device *vdev)
pm_runtime_get_noresume(vdev->drm.dev); pm_runtime_get_noresume(vdev->drm.dev);
pm_runtime_forbid(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);
}
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* Copyright (C) 2020-2023 Intel Corporation * Copyright (C) 2020-2024 Intel Corporation
*/ */
#ifndef __IVPU_PM_H__ #ifndef __IVPU_PM_H__
...@@ -19,7 +19,7 @@ struct ivpu_pm_info { ...@@ -19,7 +19,7 @@ struct ivpu_pm_info {
atomic_t reset_counter; atomic_t reset_counter;
atomic_t reset_pending; atomic_t reset_pending;
bool is_warmboot; bool is_warmboot;
u32 suspend_reschedule_counter; u8 dct_active_percent;
}; };
void ivpu_pm_init(struct ivpu_device *vdev); void ivpu_pm_init(struct ivpu_device *vdev);
...@@ -36,11 +36,15 @@ void ivpu_pm_reset_prepare_cb(struct pci_dev *pdev); ...@@ -36,11 +36,15 @@ void ivpu_pm_reset_prepare_cb(struct pci_dev *pdev);
void ivpu_pm_reset_done_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(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_rpm_put(struct ivpu_device *vdev);
void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason); void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason);
void ivpu_start_job_timeout_detection(struct ivpu_device *vdev); void ivpu_start_job_timeout_detection(struct ivpu_device *vdev);
void ivpu_stop_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__ */ #endif /* __IVPU_PM_H__ */
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
* Minor version changes when API backward compatibility is preserved. * Minor version changes when API backward compatibility is preserved.
* Resets to 0 if Major version is incremented. * 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 * API header changed (field names, documentation, formatting) but API itself has not been changed
...@@ -80,6 +80,11 @@ struct vpu_firmware_header { ...@@ -80,6 +80,11 @@ struct vpu_firmware_header {
u32 preemption_buffer_2_size; u32 preemption_buffer_2_size;
/* Space reserved for future preemption-related fields. */ /* Space reserved for future preemption-related fields. */
u32 preemption_reserved[6]; 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 { ...@@ -333,7 +338,14 @@ struct vpu_boot_params {
* The KMD is required to update this value on every VPU reset. * The KMD is required to update this value on every VPU reset.
*/ */
u64 system_time_us; 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 */ /* Warm boot information: 0x400 - 0x43F */
u32 warm_boot_sections_count; u32 warm_boot_sections_count;
u32 warm_boot_start_address_reference; u32 warm_boot_start_address_reference;
......
...@@ -274,8 +274,8 @@ static const struct dma_buf_ops cma_heap_buf_ops = { ...@@ -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, static struct dma_buf *cma_heap_allocate(struct dma_heap *heap,
unsigned long len, unsigned long len,
unsigned long fd_flags, u32 fd_flags,
unsigned long heap_flags) u64 heap_flags)
{ {
struct cma_heap *cma_heap = dma_heap_get_drvdata(heap); struct cma_heap *cma_heap = dma_heap_get_drvdata(heap);
struct cma_heap_buffer *buffer; struct cma_heap_buffer *buffer;
......
...@@ -333,8 +333,8 @@ static struct page *alloc_largest_available(unsigned long size, ...@@ -333,8 +333,8 @@ static struct page *alloc_largest_available(unsigned long size,
static struct dma_buf *system_heap_allocate(struct dma_heap *heap, static struct dma_buf *system_heap_allocate(struct dma_heap *heap,
unsigned long len, unsigned long len,
unsigned long fd_flags, u32 fd_flags,
unsigned long heap_flags) u64 heap_flags)
{ {
struct system_heap_buffer *buffer; struct system_heap_buffer *buffer;
DEFINE_DMA_BUF_EXPORT_INFO(exp_info); DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
......
...@@ -107,7 +107,7 @@ config DRM_KMS_HELPER ...@@ -107,7 +107,7 @@ config DRM_KMS_HELPER
config DRM_PANIC config DRM_PANIC
bool "Display a user-friendly message when a kernel panic occurs" 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 DRM_KMS_HELPER
select FONT_SUPPORT select FONT_SUPPORT
help help
......
...@@ -163,6 +163,14 @@ ...@@ -163,6 +163,14 @@
#define SII902X_AUDIO_PORT_INDEX 3 #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 sii902x {
struct i2c_client *i2c; struct i2c_client *i2c;
struct regmap *regmap; struct regmap *regmap;
...@@ -310,20 +318,12 @@ static int sii902x_get_modes(struct drm_connector *connector) ...@@ -310,20 +318,12 @@ static int sii902x_get_modes(struct drm_connector *connector)
return num; 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 = { static const struct drm_connector_helper_funcs sii902x_connector_helper_funcs = {
.get_modes = sii902x_get_modes, .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); struct sii902x *sii902x = bridge_to_sii902x(bridge);
...@@ -336,7 +336,8 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge) ...@@ -336,7 +336,8 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge)
mutex_unlock(&sii902x->mutex); 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); struct sii902x *sii902x = bridge_to_sii902x(bridge);
...@@ -495,6 +496,10 @@ static int sii902x_bridge_atomic_check(struct drm_bridge *bridge, ...@@ -495,6 +496,10 @@ static int sii902x_bridge_atomic_check(struct drm_bridge *bridge,
struct drm_crtc_state *crtc_state, struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_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 * There might be flags negotiation supported in future but
* set the bus flags in atomic_check statically for now. * set the bus flags in atomic_check statically for now.
...@@ -504,11 +509,25 @@ static int sii902x_bridge_atomic_check(struct drm_bridge *bridge, ...@@ -504,11 +509,25 @@ static int sii902x_bridge_atomic_check(struct drm_bridge *bridge,
return 0; 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 = { static const struct drm_bridge_funcs sii902x_bridge_funcs = {
.attach = sii902x_bridge_attach, .attach = sii902x_bridge_attach,
.mode_set = sii902x_bridge_mode_set, .mode_set = sii902x_bridge_mode_set,
.disable = sii902x_bridge_disable, .atomic_disable = sii902x_bridge_atomic_disable,
.enable = sii902x_bridge_enable, .atomic_enable = sii902x_bridge_atomic_enable,
.detect = sii902x_bridge_detect, .detect = sii902x_bridge_detect,
.edid_read = sii902x_bridge_edid_read, .edid_read = sii902x_bridge_edid_read,
.atomic_reset = drm_atomic_helper_bridge_reset, .atomic_reset = drm_atomic_helper_bridge_reset,
...@@ -516,6 +535,7 @@ static const struct drm_bridge_funcs sii902x_bridge_funcs = { ...@@ -516,6 +535,7 @@ static const struct drm_bridge_funcs sii902x_bridge_funcs = {
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_get_input_bus_fmts = sii902x_bridge_atomic_get_input_bus_fmts, .atomic_get_input_bus_fmts = sii902x_bridge_atomic_get_input_bus_fmts,
.atomic_check = sii902x_bridge_atomic_check, .atomic_check = sii902x_bridge_atomic_check,
.mode_valid = sii902x_bridge_mode_valid,
}; };
static int sii902x_mute(struct sii902x *sii902x, bool mute) static int sii902x_mute(struct sii902x *sii902x, bool mute)
......
...@@ -170,7 +170,6 @@ static int simple_bridge_probe(struct platform_device *pdev) ...@@ -170,7 +170,6 @@ static int simple_bridge_probe(struct platform_device *pdev)
sbridge = devm_kzalloc(&pdev->dev, sizeof(*sbridge), GFP_KERNEL); sbridge = devm_kzalloc(&pdev->dev, sizeof(*sbridge), GFP_KERNEL);
if (!sbridge) if (!sbridge)
return -ENOMEM; return -ENOMEM;
platform_set_drvdata(pdev, sbridge);
sbridge->info = of_device_get_match_data(&pdev->dev); sbridge->info = of_device_get_match_data(&pdev->dev);
...@@ -208,16 +207,7 @@ static int simple_bridge_probe(struct platform_device *pdev) ...@@ -208,16 +207,7 @@ static int simple_bridge_probe(struct platform_device *pdev)
sbridge->bridge.of_node = pdev->dev.of_node; sbridge->bridge.of_node = pdev->dev.of_node;
sbridge->bridge.timings = sbridge->info->timings; sbridge->bridge.timings = sbridge->info->timings;
drm_bridge_add(&sbridge->bridge); return devm_drm_bridge_add(&pdev->dev, &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);
} }
/* /*
...@@ -294,7 +284,6 @@ MODULE_DEVICE_TABLE(of, simple_bridge_match); ...@@ -294,7 +284,6 @@ MODULE_DEVICE_TABLE(of, simple_bridge_match);
static struct platform_driver simple_bridge_driver = { static struct platform_driver simple_bridge_driver = {
.probe = simple_bridge_probe, .probe = simple_bridge_probe,
.remove_new = simple_bridge_remove,
.driver = { .driver = {
.name = "simple-bridge", .name = "simple-bridge",
.of_match_table = simple_bridge_match, .of_match_table = simple_bridge_match,
......
...@@ -160,7 +160,6 @@ fi ...@@ -160,7 +160,6 @@ fi
mkdir -p artifacts/install/lib mkdir -p artifacts/install/lib
mv install/* artifacts/install/. mv install/* artifacts/install/.
rm -rf artifacts/install/modules
ln -s common artifacts/install/ci-common ln -s common artifacts/install/ci-common
cp .config artifacts/${CI_JOB_NAME}_config cp .config artifacts/${CI_JOB_NAME}_config
......
...@@ -123,6 +123,7 @@ stages: ...@@ -123,6 +123,7 @@ stages:
- msm - msm
- rockchip - rockchip
- virtio-gpu - virtio-gpu
- software-driver
# YAML anchors for rule conditions # YAML anchors for rule conditions
# -------------------------------- # --------------------------------
......
...@@ -30,10 +30,10 @@ case "$DRIVER_NAME" in ...@@ -30,10 +30,10 @@ case "$DRIVER_NAME" in
export IGT_FORCE_DRIVER="panfrost" export IGT_FORCE_DRIVER="panfrost"
fi fi
;; ;;
amdgpu) amdgpu|vkms)
# Cannot use HWCI_KERNEL_MODULES as at that point we don't have the module in /lib # Cannot use HWCI_KERNEL_MODULES as at that point we don't have the module in /lib
mv /install/modules/lib/modules/* /lib/modules/. mv /install/modules/lib/modules/* /lib/modules/. || true
modprobe amdgpu modprobe --first-time $DRIVER_NAME
;; ;;
esac esac
......
...@@ -4,7 +4,7 @@ variables: ...@@ -4,7 +4,7 @@ variables:
DEBIAN_BASE_TAG: "${CONTAINER_TAG}" DEBIAN_BASE_TAG: "${CONTAINER_TAG}"
DEBIAN_X86_64_BUILD_IMAGE_PATH: "debian/x86_64_build" 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" KERNEL_ROOTFS_TAG: "2023-10-06-amd"
......
...@@ -338,7 +338,7 @@ meson:g12b: ...@@ -338,7 +338,7 @@ meson:g12b:
RUNNER_TAG: mesa-ci-x86-64-lava-meson-g12b-a311d-khadas-vim3 RUNNER_TAG: mesa-ci-x86-64-lava-meson-g12b-a311d-khadas-vim3
virtio_gpu:none: virtio_gpu:none:
stage: virtio-gpu stage: software-driver
variables: variables:
CROSVM_GALLIUM_DRIVER: llvmpipe CROSVM_GALLIUM_DRIVER: llvmpipe
DRIVER_NAME: virtio_gpu DRIVER_NAME: virtio_gpu
...@@ -358,3 +358,25 @@ virtio_gpu:none: ...@@ -358,3 +358,25 @@ virtio_gpu:none:
- debian/x86_64_test-gl - debian/x86_64_test-gl
- testing:x86_64 - testing:x86_64
- igt: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
...@@ -24,6 +24,7 @@ CONFIG_DRM=y ...@@ -24,6 +24,7 @@ CONFIG_DRM=y
CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_PWM_CROS_EC=y CONFIG_PWM_CROS_EC=y
CONFIG_BACKLIGHT_PWM=y CONFIG_BACKLIGHT_PWM=y
CONFIG_DRM_VKMS=m
# Strip out some stuff we don't need for graphics testing, to reduce # Strip out some stuff we don't need for graphics testing, to reduce
# the build. # the build.
......
...@@ -4,7 +4,6 @@ device_reset@unbind-cold-reset-rebind,Fail ...@@ -4,7 +4,6 @@ device_reset@unbind-cold-reset-rebind,Fail
device_reset@unbind-reset-rebind,Fail device_reset@unbind-reset-rebind,Fail
dumb_buffer@invalid-bpp,Fail dumb_buffer@invalid-bpp,Fail
kms_3d,Fail kms_3d,Fail
kms_addfb_basic@addfb25-bad-modifier,Fail
kms_cursor_legacy@forked-move,Fail kms_cursor_legacy@forked-move,Fail
kms_cursor_legacy@single-bo,Fail kms_cursor_legacy@single-bo,Fail
kms_cursor_legacy@torture-bo,Fail kms_cursor_legacy@torture-bo,Fail
......
...@@ -4,6 +4,5 @@ device_reset@unbind-cold-reset-rebind,Fail ...@@ -4,6 +4,5 @@ device_reset@unbind-cold-reset-rebind,Fail
device_reset@unbind-reset-rebind,Fail device_reset@unbind-reset-rebind,Fail
dumb_buffer@invalid-bpp,Fail dumb_buffer@invalid-bpp,Fail
kms_3d,Fail kms_3d,Fail
kms_addfb_basic@addfb25-bad-modifier,Fail
kms_lease@lease-uevent,Fail kms_lease@lease-uevent,Fail
tools_test@tools_test,Fail tools_test@tools_test,Fail
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
# 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
# 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_.*
...@@ -1087,6 +1087,7 @@ static const struct drm_prop_enum_list drm_tv_mode_enum_list[] = { ...@@ -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_M, "PAL-M" },
{ DRM_MODE_TV_MODE_PAL_N, "PAL-N" }, { DRM_MODE_TV_MODE_PAL_N, "PAL-N" },
{ DRM_MODE_TV_MODE_SECAM, "SECAM" }, { 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) 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); ...@@ -1858,6 +1859,12 @@ EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property);
* TV Mode is CCIR System B (aka 625-lines) together with * TV Mode is CCIR System B (aka 625-lines) together with
* the SECAM Color Encoding. * 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 * Drivers can set up this property by calling
* drm_mode_create_tv_properties(). * drm_mode_create_tv_properties().
*/ */
......
...@@ -531,7 +531,8 @@ static int fill_analog_mode(struct drm_device *dev, ...@@ -531,7 +531,8 @@ static int fill_analog_mode(struct drm_device *dev,
* @interlace: whether to compute an interlaced mode * @interlace: whether to compute an interlaced mode
* *
* This function creates a struct drm_display_mode instance suited for * 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 * Note that @hdisplay is larger than the usual constraints for the PAL
* and NTSC timings, and we'll choose to ignore most timings constraints * 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, ...@@ -569,6 +570,8 @@ struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev,
case DRM_MODE_TV_MODE_PAL_N: case DRM_MODE_TV_MODE_PAL_N:
fallthrough; fallthrough;
case DRM_MODE_TV_MODE_SECAM: case DRM_MODE_TV_MODE_SECAM:
fallthrough;
case DRM_MODE_TV_MODE_MONOCHROME:
analog = DRM_MODE_ANALOG_PAL; analog = DRM_MODE_ANALOG_PAL;
break; break;
......
...@@ -1259,8 +1259,9 @@ int drm_connector_helper_tv_get_modes(struct drm_connector *connector) ...@@ -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++) for (i = 0; i < tv_mode_property->num_values; i++)
supported_tv_modes |= BIT(tv_mode_property->values[i]); supported_tv_modes |= BIT(tv_mode_property->values[i]);
if ((supported_tv_modes & ntsc_modes) && if (((supported_tv_modes & ntsc_modes) &&
(supported_tv_modes & pal_modes)) { (supported_tv_modes & pal_modes)) ||
(supported_tv_modes & BIT(DRM_MODE_TV_MODE_MONOCHROME))) {
uint64_t default_mode; uint64_t default_mode;
if (drm_object_property_get_default_value(&connector->base, if (drm_object_property_get_default_value(&connector->base,
......
...@@ -11,6 +11,7 @@ mgag200-y := \ ...@@ -11,6 +11,7 @@ mgag200-y := \
mgag200_g200ew3.o \ mgag200_g200ew3.o \
mgag200_g200se.o \ mgag200_g200se.o \
mgag200_g200wb.o \ mgag200_g200wb.o \
mgag200_mode.o mgag200_mode.o \
mgag200_vga.o
obj-$(CONFIG_DRM_MGAG200) += mgag200.o obj-$(CONFIG_DRM_MGAG200) += mgag200.o
...@@ -2,8 +2,18 @@ ...@@ -2,8 +2,18 @@
#include <linux/delay.h> #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" #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) void mgag200_bmc_disable_vidrst(struct mga_device *mdev)
{ {
u8 tmp; u8 tmp;
...@@ -97,3 +107,100 @@ void mgag200_bmc_enable_vidrst(struct mga_device *mdev) ...@@ -97,3 +107,100 @@ void mgag200_bmc_enable_vidrst(struct mga_device *mdev)
tmp &= ~0x10; tmp &= ~0x10;
WREG_DAC(MGA1064_GEN_IO_DATA, tmp); 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;
}
...@@ -186,6 +186,11 @@ static inline struct mgag200_crtc_state *to_mgag200_crtc_state(struct drm_crtc_s ...@@ -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); 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 { enum mga_type {
G200_PCI, G200_PCI,
G200_AGP, G200_AGP,
...@@ -283,8 +288,16 @@ struct mga_device { ...@@ -283,8 +288,16 @@ struct mga_device {
struct drm_plane primary_plane; struct drm_plane primary_plane;
struct drm_crtc crtc; struct drm_crtc crtc;
struct drm_encoder encoder; struct {
struct drm_connector connector; 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) 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 ...@@ -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_duplicate_state = mgag200_crtc_atomic_duplicate_state, \
.atomic_destroy_state = mgag200_crtc_atomic_destroy_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_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_set_format_regs(struct mga_device *mdev, const struct drm_format_info *format);
void mgag200_enable_display(struct mga_device *mdev); void mgag200_enable_display(struct mga_device *mdev);
void mgag200_init_registers(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); 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 */ /* mgag200_bmc.c */
void mgag200_bmc_disable_vidrst(struct mga_device *mdev); void mgag200_bmc_disable_vidrst(struct mga_device *mdev);
void mgag200_bmc_enable_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__ */ #endif /* __MGAG200_DRV_H__ */
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include "mgag200_ddc.h"
#include "mgag200_drv.h" #include "mgag200_drv.h"
static int mgag200_g200_init_pci_options(struct pci_dev *pdev) 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 = { ...@@ -184,26 +183,11 @@ static const struct drm_crtc_funcs mgag200_g200_crtc_funcs = {
MGAG200_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) static int mgag200_g200_pipeline_init(struct mga_device *mdev)
{ {
struct drm_device *dev = &mdev->base; struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane; struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc; struct drm_crtc *crtc = &mdev->crtc;
struct drm_encoder *encoder = &mdev->encoder;
struct drm_connector *connector = &mdev->connector;
struct i2c_adapter *ddc;
int ret; int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0, ret = drm_universal_plane_init(dev, primary_plane, 0,
...@@ -231,35 +215,9 @@ static int mgag200_g200_pipeline_init(struct mga_device *mdev) ...@@ -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_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
encoder->possible_crtcs = drm_crtc_mask(crtc); ret = mgag200_vga_output_init(mdev);
ret = drm_encoder_init(dev, encoder, &mgag200_g200_dac_encoder_funcs, if (ret)
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);
return ret; return ret;
}
return 0; return 0;
} }
...@@ -443,6 +401,7 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct ...@@ -443,6 +401,7 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct
return ERR_PTR(ret); return ERR_PTR(ret);
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev);
return mdev; return mdev;
} }
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include "mgag200_ddc.h"
#include "mgag200_drv.h" #include "mgag200_drv.h"
void mgag200_g200eh_init_registers(struct mga_device *mdev) void mgag200_g200eh_init_registers(struct mga_device *mdev)
...@@ -183,26 +182,11 @@ static const struct drm_crtc_funcs mgag200_g200eh_crtc_funcs = { ...@@ -183,26 +182,11 @@ static const struct drm_crtc_funcs mgag200_g200eh_crtc_funcs = {
MGAG200_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) static int mgag200_g200eh_pipeline_init(struct mga_device *mdev)
{ {
struct drm_device *dev = &mdev->base; struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane; struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc; struct drm_crtc *crtc = &mdev->crtc;
struct drm_encoder *encoder = &mdev->encoder;
struct drm_connector *connector = &mdev->connector;
struct i2c_adapter *ddc;
int ret; int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0, ret = drm_universal_plane_init(dev, primary_plane, 0,
...@@ -230,35 +214,13 @@ static int mgag200_g200eh_pipeline_init(struct mga_device *mdev) ...@@ -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_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
encoder->possible_crtcs = drm_crtc_mask(crtc); ret = mgag200_vga_output_init(mdev);
ret = drm_encoder_init(dev, encoder, &mgag200_g200eh_dac_encoder_funcs, if (ret)
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; return ret;
}
ret = drm_connector_init_with_ddc(dev, connector, ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
&mgag200_g200eh_vga_connector_funcs, if (ret)
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);
return ret; return ret;
}
return 0; return 0;
} }
...@@ -315,6 +277,7 @@ struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const stru ...@@ -315,6 +277,7 @@ struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const stru
return ERR_PTR(ret); return ERR_PTR(ret);
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev);
return mdev; return mdev;
} }
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include "mgag200_ddc.h"
#include "mgag200_drv.h" #include "mgag200_drv.h"
/* /*
...@@ -87,26 +86,11 @@ static const struct drm_crtc_funcs mgag200_g200eh3_crtc_funcs = { ...@@ -87,26 +86,11 @@ static const struct drm_crtc_funcs mgag200_g200eh3_crtc_funcs = {
MGAG200_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) static int mgag200_g200eh3_pipeline_init(struct mga_device *mdev)
{ {
struct drm_device *dev = &mdev->base; struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane; struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc; struct drm_crtc *crtc = &mdev->crtc;
struct drm_encoder *encoder = &mdev->encoder;
struct drm_connector *connector = &mdev->connector;
struct i2c_adapter *ddc;
int ret; int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0, ret = drm_universal_plane_init(dev, primary_plane, 0,
...@@ -134,35 +118,13 @@ static int mgag200_g200eh3_pipeline_init(struct mga_device *mdev) ...@@ -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_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
encoder->possible_crtcs = drm_crtc_mask(crtc); ret = mgag200_vga_output_init(mdev);
ret = drm_encoder_init(dev, encoder, &mgag200_g200eh3_dac_encoder_funcs, if (ret)
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; return ret;
}
ret = drm_connector_init_with_ddc(dev, connector, ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
&mgag200_g200eh3_vga_connector_funcs, if (ret)
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);
return ret; return ret;
}
return 0; return 0;
} }
...@@ -220,6 +182,7 @@ struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, ...@@ -220,6 +182,7 @@ struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev,
return ERR_PTR(ret); return ERR_PTR(ret);
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev);
return mdev; return mdev;
} }
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include "mgag200_ddc.h"
#include "mgag200_drv.h" #include "mgag200_drv.h"
static void mgag200_g200er_init_registers(struct mga_device *mdev) static void mgag200_g200er_init_registers(struct mga_device *mdev)
...@@ -226,26 +225,11 @@ static const struct drm_crtc_funcs mgag200_g200er_crtc_funcs = { ...@@ -226,26 +225,11 @@ static const struct drm_crtc_funcs mgag200_g200er_crtc_funcs = {
MGAG200_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) static int mgag200_g200er_pipeline_init(struct mga_device *mdev)
{ {
struct drm_device *dev = &mdev->base; struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane; struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc; struct drm_crtc *crtc = &mdev->crtc;
struct drm_encoder *encoder = &mdev->encoder;
struct drm_connector *connector = &mdev->connector;
struct i2c_adapter *ddc;
int ret; int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0, ret = drm_universal_plane_init(dev, primary_plane, 0,
...@@ -273,35 +257,13 @@ static int mgag200_g200er_pipeline_init(struct mga_device *mdev) ...@@ -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_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
encoder->possible_crtcs = drm_crtc_mask(crtc); ret = mgag200_vga_output_init(mdev);
ret = drm_encoder_init(dev, encoder, &mgag200_g200er_dac_encoder_funcs, if (ret)
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; return ret;
}
ret = drm_connector_init_with_ddc(dev, connector, ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
&mgag200_g200er_vga_connector_funcs, if (ret)
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);
return ret; return ret;
}
return 0; return 0;
} }
...@@ -354,6 +316,7 @@ struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const stru ...@@ -354,6 +316,7 @@ struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const stru
return ERR_PTR(ret); return ERR_PTR(ret);
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev);
return mdev; return mdev;
} }
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include "mgag200_ddc.h"
#include "mgag200_drv.h" #include "mgag200_drv.h"
static void mgag200_g200ev_init_registers(struct mga_device *mdev) static void mgag200_g200ev_init_registers(struct mga_device *mdev)
...@@ -227,26 +226,11 @@ static const struct drm_crtc_funcs mgag200_g200ev_crtc_funcs = { ...@@ -227,26 +226,11 @@ static const struct drm_crtc_funcs mgag200_g200ev_crtc_funcs = {
MGAG200_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) static int mgag200_g200ev_pipeline_init(struct mga_device *mdev)
{ {
struct drm_device *dev = &mdev->base; struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane; struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc; struct drm_crtc *crtc = &mdev->crtc;
struct drm_encoder *encoder = &mdev->encoder;
struct drm_connector *connector = &mdev->connector;
struct i2c_adapter *ddc;
int ret; int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0, ret = drm_universal_plane_init(dev, primary_plane, 0,
...@@ -274,35 +258,13 @@ static int mgag200_g200ev_pipeline_init(struct mga_device *mdev) ...@@ -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_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
encoder->possible_crtcs = drm_crtc_mask(crtc); ret = mgag200_vga_output_init(mdev);
ret = drm_encoder_init(dev, encoder, &mgag200_g200ev_dac_encoder_funcs, if (ret)
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; return ret;
}
ret = drm_connector_init_with_ddc(dev, connector, ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
&mgag200_g200ev_vga_connector_funcs, if (ret)
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);
return ret; return ret;
}
return 0; return 0;
} }
...@@ -359,6 +321,7 @@ struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const stru ...@@ -359,6 +321,7 @@ struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const stru
return ERR_PTR(ret); return ERR_PTR(ret);
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev);
return mdev; return mdev;
} }
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include "mgag200_ddc.h"
#include "mgag200_drv.h" #include "mgag200_drv.h"
static void mgag200_g200ew3_init_registers(struct mga_device *mdev) static void mgag200_g200ew3_init_registers(struct mga_device *mdev)
...@@ -96,26 +95,11 @@ static const struct drm_crtc_funcs mgag200_g200ew3_crtc_funcs = { ...@@ -96,26 +95,11 @@ static const struct drm_crtc_funcs mgag200_g200ew3_crtc_funcs = {
MGAG200_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) static int mgag200_g200ew3_pipeline_init(struct mga_device *mdev)
{ {
struct drm_device *dev = &mdev->base; struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane; struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc; struct drm_crtc *crtc = &mdev->crtc;
struct drm_encoder *encoder = &mdev->encoder;
struct drm_connector *connector = &mdev->connector;
struct i2c_adapter *ddc;
int ret; int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0, ret = drm_universal_plane_init(dev, primary_plane, 0,
...@@ -143,35 +127,13 @@ static int mgag200_g200ew3_pipeline_init(struct mga_device *mdev) ...@@ -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_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
encoder->possible_crtcs = drm_crtc_mask(crtc); ret = mgag200_vga_output_init(mdev);
ret = drm_encoder_init(dev, encoder, &mgag200_g200ew3_dac_encoder_funcs, if (ret)
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; return ret;
}
ret = drm_connector_init_with_ddc(dev, connector, ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
&mgag200_g200ew3_vga_connector_funcs, if (ret)
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);
return ret; return ret;
}
return 0; return 0;
} }
...@@ -240,6 +202,7 @@ struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, ...@@ -240,6 +202,7 @@ struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev,
return ERR_PTR(ret); return ERR_PTR(ret);
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev);
return mdev; return mdev;
} }
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include "mgag200_ddc.h"
#include "mgag200_drv.h" #include "mgag200_drv.h"
static int mgag200_g200se_init_pci_options(struct pci_dev *pdev) 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 = { ...@@ -358,26 +357,11 @@ static const struct drm_crtc_funcs mgag200_g200se_crtc_funcs = {
MGAG200_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) static int mgag200_g200se_pipeline_init(struct mga_device *mdev)
{ {
struct drm_device *dev = &mdev->base; struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane; struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc; struct drm_crtc *crtc = &mdev->crtc;
struct drm_encoder *encoder = &mdev->encoder;
struct drm_connector *connector = &mdev->connector;
struct i2c_adapter *ddc;
int ret; int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0, ret = drm_universal_plane_init(dev, primary_plane, 0,
...@@ -405,35 +389,13 @@ static int mgag200_g200se_pipeline_init(struct mga_device *mdev) ...@@ -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_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
encoder->possible_crtcs = drm_crtc_mask(crtc); ret = mgag200_vga_output_init(mdev);
ret = drm_encoder_init(dev, encoder, &mgag200_g200se_dac_encoder_funcs, if (ret)
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; return ret;
}
ret = drm_connector_init_with_ddc(dev, connector, ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
&mgag200_g200se_vga_connector_funcs, if (ret)
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);
return ret; return ret;
}
return 0; return 0;
} }
...@@ -559,6 +521,7 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru ...@@ -559,6 +521,7 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru
return ERR_PTR(ret); return ERR_PTR(ret);
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev);
return mdev; return mdev;
} }
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include "mgag200_ddc.h"
#include "mgag200_drv.h" #include "mgag200_drv.h"
void mgag200_g200wb_init_registers(struct mga_device *mdev) void mgag200_g200wb_init_registers(struct mga_device *mdev)
...@@ -230,26 +229,11 @@ static const struct drm_crtc_funcs mgag200_g200wb_crtc_funcs = { ...@@ -230,26 +229,11 @@ static const struct drm_crtc_funcs mgag200_g200wb_crtc_funcs = {
MGAG200_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) static int mgag200_g200wb_pipeline_init(struct mga_device *mdev)
{ {
struct drm_device *dev = &mdev->base; struct drm_device *dev = &mdev->base;
struct drm_plane *primary_plane = &mdev->primary_plane; struct drm_plane *primary_plane = &mdev->primary_plane;
struct drm_crtc *crtc = &mdev->crtc; struct drm_crtc *crtc = &mdev->crtc;
struct drm_encoder *encoder = &mdev->encoder;
struct drm_connector *connector = &mdev->connector;
struct i2c_adapter *ddc;
int ret; int ret;
ret = drm_universal_plane_init(dev, primary_plane, 0, ret = drm_universal_plane_init(dev, primary_plane, 0,
...@@ -277,35 +261,13 @@ static int mgag200_g200wb_pipeline_init(struct mga_device *mdev) ...@@ -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_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
encoder->possible_crtcs = drm_crtc_mask(crtc); ret = mgag200_vga_output_init(mdev);
ret = drm_encoder_init(dev, encoder, &mgag200_g200wb_dac_encoder_funcs, if (ret)
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; return ret;
}
ret = drm_connector_init_with_ddc(dev, connector, ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
&mgag200_g200wb_vga_connector_funcs, if (ret)
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);
return ret; return ret;
}
return 0; return 0;
} }
...@@ -364,6 +326,7 @@ struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const stru ...@@ -364,6 +326,7 @@ struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const stru
return ERR_PTR(ret); return ERR_PTR(ret);
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
drm_kms_helper_poll_init(dev);
return mdev; return mdev;
} }
// 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;
}
...@@ -898,7 +898,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, ...@@ -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 * Without this the operation can timeout and we'll fallback to a
* software copy, which might take several minutes to finish. * 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, ret = ttm_bo_move_accel_cleanup(bo, &fence->base, evict, false,
new_reg); new_reg);
nouveau_fence_unref(&fence); nouveau_fence_unref(&fence);
......
...@@ -72,7 +72,7 @@ nouveau_channel_idle(struct nouveau_channel *chan) ...@@ -72,7 +72,7 @@ nouveau_channel_idle(struct nouveau_channel *chan)
ret = nouveau_fence_new(&fence, chan); ret = nouveau_fence_new(&fence, chan);
if (!ret) { if (!ret) {
ret = nouveau_fence_wait(fence, false, false); ret = nouveau_fence_wait(fence, false);
nouveau_fence_unref(&fence); nouveau_fence_unref(&fence);
} }
......
...@@ -128,7 +128,7 @@ static void nouveau_dmem_page_free(struct page *page) ...@@ -128,7 +128,7 @@ static void nouveau_dmem_page_free(struct page *page)
static void nouveau_dmem_fence_done(struct nouveau_fence **fence) static void nouveau_dmem_fence_done(struct nouveau_fence **fence)
{ {
if (fence) { if (fence) {
nouveau_fence_wait(*fence, true, false); nouveau_fence_wait(*fence, false);
nouveau_fence_unref(fence); nouveau_fence_unref(fence);
} else { } else {
/* /*
......
...@@ -188,7 +188,7 @@ nouveau_exec_job_timeout(struct nouveau_job *job) ...@@ -188,7 +188,7 @@ nouveau_exec_job_timeout(struct nouveau_job *job)
return DRM_GPU_SCHED_STAT_NOMINAL; 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, .submit = nouveau_exec_job_submit,
.armed_submit = nouveau_exec_job_armed_submit, .armed_submit = nouveau_exec_job_armed_submit,
.run = nouveau_exec_job_run, .run = nouveau_exec_job_run,
......
...@@ -311,39 +311,11 @@ nouveau_fence_wait_legacy(struct dma_fence *f, bool intr, long wait) ...@@ -311,39 +311,11 @@ nouveau_fence_wait_legacy(struct dma_fence *f, bool intr, long wait)
return timeout - t; 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 int
nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) nouveau_fence_wait(struct nouveau_fence *fence, bool intr)
{ {
long ret; long ret;
if (!lazy)
return nouveau_fence_wait_busy(fence, intr);
ret = dma_fence_wait_timeout(&fence->base, intr, 15 * HZ); ret = dma_fence_wait_timeout(&fence->base, intr, 15 * HZ);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -23,7 +23,7 @@ void nouveau_fence_unref(struct nouveau_fence **); ...@@ -23,7 +23,7 @@ void nouveau_fence_unref(struct nouveau_fence **);
int nouveau_fence_emit(struct nouveau_fence *); int nouveau_fence_emit(struct nouveau_fence *);
bool nouveau_fence_done(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); int nouveau_fence_sync(struct nouveau_bo *, struct nouveau_channel *, bool exclusive, bool intr);
struct nouveau_fence_chan { struct nouveau_fence_chan {
......
...@@ -928,7 +928,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, ...@@ -928,7 +928,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
} }
if (sync) { 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) if ((ret = dma_fence_get_status(&fence->base)) == 1)
ret = 0; ret = 0;
} }
......
...@@ -42,7 +42,7 @@ struct nouveau_job_args { ...@@ -42,7 +42,7 @@ struct nouveau_job_args {
u32 count; u32 count;
} out_sync; } out_sync;
struct nouveau_job_ops *ops; const struct nouveau_job_ops *ops;
}; };
struct nouveau_job { struct nouveau_job {
...@@ -73,7 +73,7 @@ struct nouveau_job { ...@@ -73,7 +73,7 @@ struct nouveau_job {
u32 count; u32 count;
} out_sync; } out_sync;
struct nouveau_job_ops { const struct nouveau_job_ops {
/* If .submit() returns without any error, it is guaranteed that /* If .submit() returns without any error, it is guaranteed that
* armed_submit() is called. * armed_submit() is called.
*/ */
......
...@@ -1534,7 +1534,7 @@ nouveau_uvmm_bind_job_cleanup(struct nouveau_job *job) ...@@ -1534,7 +1534,7 @@ nouveau_uvmm_bind_job_cleanup(struct nouveau_job *job)
nouveau_uvmm_bind_job_put(bind_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, .submit = nouveau_uvmm_bind_job_submit,
.armed_submit = nouveau_uvmm_bind_job_armed_submit, .armed_submit = nouveau_uvmm_bind_job_armed_submit,
.run = nouveau_uvmm_bind_job_run, .run = nouveau_uvmm_bind_job_run,
......
...@@ -1045,33 +1045,6 @@ static const struct panel_desc auo_b116xak01 = { ...@@ -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 = { static const struct drm_display_mode auo_b133htn01_mode = {
.clock = 150660, .clock = 150660,
.hdisplay = 1920, .hdisplay = 1920,
...@@ -1121,33 +1094,6 @@ static const struct panel_desc auo_b133xtn01 = { ...@@ -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[] = { static const struct drm_display_mode boe_nv101wxmn51_modes[] = {
{ {
.clock = 71900, .clock = 71900,
...@@ -1414,33 +1360,6 @@ static const struct panel_desc innolux_p120zdg_bf1 = { ...@@ -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 = { static const struct drm_display_mode kingdisplay_kd116n21_30nv_a010_mode = {
.clock = 81000, .clock = 81000,
.hdisplay = 1366, .hdisplay = 1366,
...@@ -1689,97 +1608,39 @@ static const struct panel_desc sharp_lq123p1jx31 = { ...@@ -1689,97 +1608,39 @@ 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[] = { static const struct of_device_id platform_of_match[] = {
{ {
/* Must be first */ /* Must be first */
.compatible = "edp-panel", .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", .compatible = "auo,b101ean01",
.data = &auo_b101ean01, .data = &auo_b101ean01,
}, { }, {
.compatible = "auo,b116xa01", .compatible = "auo,b116xa01",
.data = &auo_b116xak01, .data = &auo_b116xak01,
}, {
.compatible = "auo,b133han05",
.data = &auo_b133han05,
}, { }, {
.compatible = "auo,b133htn01", .compatible = "auo,b133htn01",
.data = &auo_b133htn01, .data = &auo_b133htn01,
}, { }, {
.compatible = "auo,b133xtn01", .compatible = "auo,b133xtn01",
.data = &auo_b133xtn01, .data = &auo_b133xtn01,
}, {
.compatible = "auo,b140han06",
.data = &auo_b140han06,
}, { }, {
.compatible = "boe,nv101wxmn51", .compatible = "boe,nv101wxmn51",
.data = &boe_nv101wxmn51, .data = &boe_nv101wxmn51,
...@@ -1807,9 +1668,6 @@ static const struct of_device_id platform_of_match[] = { ...@@ -1807,9 +1668,6 @@ static const struct of_device_id platform_of_match[] = {
}, { }, {
.compatible = "innolux,p120zdg-bf1", .compatible = "innolux,p120zdg-bf1",
.data = &innolux_p120zdg_bf1, .data = &innolux_p120zdg_bf1,
}, {
.compatible = "ivo,m133nwf4-r0",
.data = &ivo_m133nwf4_r0,
}, { }, {
.compatible = "kingdisplay,kd116n21-30nv-a010", .compatible = "kingdisplay,kd116n21-30nv-a010",
.data = &kingdisplay_kd116n21_30nv_a010, .data = &kingdisplay_kd116n21_30nv_a010,
...@@ -1840,12 +1698,6 @@ static const struct of_device_id platform_of_match[] = { ...@@ -1840,12 +1698,6 @@ static const struct of_device_id platform_of_match[] = {
}, { }, {
.compatible = "sharp,lq123p1jx31", .compatible = "sharp,lq123p1jx31",
.data = &sharp_lq123p1jx31, .data = &sharp_lq123p1jx31,
}, {
.compatible = "sharp,lq140m1jw46",
.data = &sharp_lq140m1jw46,
}, {
.compatible = "starry,kr122ea0sra",
.data = &starry_kr122ea0sra,
}, { }, {
/* sentinel */ /* sentinel */
} }
...@@ -1897,6 +1749,12 @@ static const struct panel_delay delay_200_500_e80_d50 = { ...@@ -1897,6 +1749,12 @@ static const struct panel_delay delay_200_500_e80_d50 = {
.disable = 50, .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 = { static const struct panel_delay delay_100_500_e200 = {
.hpd_absent = 100, .hpd_absent = 100,
.unprepare = 500, .unprepare = 500,
...@@ -2105,7 +1963,7 @@ static const struct edp_panel_entry edp_panels[] = { ...@@ -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', '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', 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', 0x153a, &delay_200_500_e50, "LQ140T1JH01"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"), EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"),
......
...@@ -777,6 +777,15 @@ static const struct panfrost_compatible mediatek_mt8186_data = { ...@@ -777,6 +777,15 @@ static const struct panfrost_compatible mediatek_mt8186_data = {
.pm_features = BIT(GPU_PM_CLK_DIS) | BIT(GPU_PM_VREG_OFF), .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_supplies[] = { "mali", NULL };
static const char * const mediatek_mt8192_pm_domains[] = { "core0", "core1", "core2", static const char * const mediatek_mt8192_pm_domains[] = { "core0", "core1", "core2",
"core3", "core4" }; "core3", "core4" };
...@@ -808,6 +817,7 @@ static const struct of_device_id dt_match[] = { ...@@ -808,6 +817,7 @@ static const struct of_device_id dt_match[] = {
{ .compatible = "mediatek,mt8183-mali", .data = &mediatek_mt8183_data }, { .compatible = "mediatek,mt8183-mali", .data = &mediatek_mt8183_data },
{ .compatible = "mediatek,mt8183b-mali", .data = &mediatek_mt8183_b_data }, { .compatible = "mediatek,mt8183b-mali", .data = &mediatek_mt8183_b_data },
{ .compatible = "mediatek,mt8186-mali", .data = &mediatek_mt8186_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 }, { .compatible = "mediatek,mt8192-mali", .data = &mediatek_mt8192_data },
{} {}
}; };
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h> #include <drm/drm_blend.h>
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
#include <drm/drm_fb_dma_helper.h>
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h> #include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_atomic_helper.h>
...@@ -166,6 +167,14 @@ static const struct drm_plane_helper_funcs tidss_plane_helper_funcs = { ...@@ -166,6 +167,14 @@ static const struct drm_plane_helper_funcs tidss_plane_helper_funcs = {
.atomic_disable = tidss_plane_atomic_disable, .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 = { static const struct drm_plane_funcs tidss_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane, .update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane, .disable_plane = drm_atomic_helper_disable_plane,
...@@ -211,7 +220,10 @@ struct tidss_plane *tidss_plane_create(struct tidss_device *tidss, ...@@ -211,7 +220,10 @@ struct tidss_plane *tidss_plane_create(struct tidss_device *tidss,
if (ret < 0) if (ret < 0)
goto err; 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, drm_plane_create_zpos_property(&tplane->plane, tidss->num_planes, 0,
num_planes - 1); num_planes - 1);
......
...@@ -256,10 +256,10 @@ struct zynqmp_dp_link_config { ...@@ -256,10 +256,10 @@ struct zynqmp_dp_link_config {
* @fmt: format identifier string * @fmt: format identifier string
*/ */
struct zynqmp_dp_mode { struct zynqmp_dp_mode {
const char *fmt;
int pclock;
u8 bw_code; u8 bw_code;
u8 lane_cnt; u8 lane_cnt;
int pclock;
const char *fmt;
}; };
/** /**
...@@ -296,27 +296,27 @@ struct zynqmp_dp_config { ...@@ -296,27 +296,27 @@ struct zynqmp_dp_config {
* @train_set: set of training data * @train_set: set of training data
*/ */
struct zynqmp_dp { 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 device *dev;
struct zynqmp_dpsub *dpsub; struct zynqmp_dpsub *dpsub;
void __iomem *iomem; void __iomem *iomem;
struct reset_control *reset; 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]; struct phy *phy[ZYNQMP_DP_MAX_LANES];
u8 num_lanes;
struct delayed_work hpd_work;
enum drm_connector_status status; enum drm_connector_status status;
int irq;
bool enabled; bool enabled;
u8 dpcd[DP_RECEIVER_CAP_SIZE];
struct zynqmp_dp_link_config link_config;
struct zynqmp_dp_mode mode; 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 train_set[ZYNQMP_DP_MAX_LANES];
u8 num_lanes;
}; };
static inline struct zynqmp_dp *bridge_to_dp(struct drm_bridge *bridge) 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, ...@@ -1482,7 +1482,7 @@ static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge,
struct zynqmp_dp *dp = bridge_to_dp(bridge); struct zynqmp_dp *dp = bridge_to_dp(bridge);
dp->enabled = false; dp->enabled = false;
cancel_delayed_work(&dp->hpd_work); cancel_work(&dp->hpd_work);
zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 0); zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 0);
drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D3); drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN, zynqmp_dp_write(dp, ZYNQMP_DP_TX_PHY_POWER_DOWN,
...@@ -1648,8 +1648,7 @@ void zynqmp_dp_disable_vblank(struct zynqmp_dp *dp) ...@@ -1648,8 +1648,7 @@ void zynqmp_dp_disable_vblank(struct zynqmp_dp *dp)
static void zynqmp_dp_hpd_work_func(struct work_struct *work) static void zynqmp_dp_hpd_work_func(struct work_struct *work)
{ {
struct zynqmp_dp *dp = container_of(work, struct zynqmp_dp, struct zynqmp_dp *dp = container_of(work, struct zynqmp_dp, hpd_work);
hpd_work.work);
enum drm_connector_status status; enum drm_connector_status status;
status = zynqmp_dp_bridge_detect(&dp->bridge); status = zynqmp_dp_bridge_detect(&dp->bridge);
...@@ -1685,7 +1684,7 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data) ...@@ -1685,7 +1684,7 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data)
zynqmp_dpsub_drm_handle_vblank(dp->dpsub); zynqmp_dpsub_drm_handle_vblank(dp->dpsub);
if (status & ZYNQMP_DP_INT_HPD_EVENT) 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) { if (status & ZYNQMP_DP_INT_HPD_IRQ) {
int ret; int ret;
...@@ -1727,7 +1726,7 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub) ...@@ -1727,7 +1726,7 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub)
dp->dpsub = dpsub; dp->dpsub = dpsub;
dp->status = connector_status_disconnected; 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). */ /* Acquire all resources (IOMEM, IRQ and PHYs). */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dp"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dp");
...@@ -1832,7 +1831,7 @@ void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub) ...@@ -1832,7 +1831,7 @@ void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub)
zynqmp_dp_write(dp, ZYNQMP_DP_INT_DS, ZYNQMP_DP_INT_ALL); zynqmp_dp_write(dp, ZYNQMP_DP_INT_DS, ZYNQMP_DP_INT_ALL);
disable_irq(dp->irq); 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_TRANSMITTER_ENABLE, 0);
zynqmp_dp_write(dp, ZYNQMP_DP_INT_DS, 0xffffffff); zynqmp_dp_write(dp, ZYNQMP_DP_INT_DS, 0xffffffff);
......
...@@ -269,6 +269,7 @@ static int zynqmp_dpsub_probe(struct platform_device *pdev) ...@@ -269,6 +269,7 @@ static int zynqmp_dpsub_probe(struct platform_device *pdev)
return 0; return 0;
err_disp: err_disp:
drm_bridge_remove(dpsub->bridge);
zynqmp_disp_remove(dpsub); zynqmp_disp_remove(dpsub);
err_dp: err_dp:
zynqmp_dp_remove(dpsub); zynqmp_dp_remove(dpsub);
......
...@@ -120,9 +120,13 @@ static void zynqmp_dpsub_plane_atomic_update(struct drm_plane *plane, ...@@ -120,9 +120,13 @@ static void zynqmp_dpsub_plane_atomic_update(struct drm_plane *plane,
zynqmp_disp_blend_set_global_alpha(dpsub->disp, true, zynqmp_disp_blend_set_global_alpha(dpsub->disp, true,
plane->state->alpha >> 8); plane->state->alpha >> 8);
/* Enable or re-enable the plane if the format has changed. */ /*
if (format_changed) * Unconditionally enable the layer, as it may have been disabled
zynqmp_disp_layer_enable(layer); * 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 = { 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) ...@@ -433,23 +437,28 @@ static int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub)
DRM_BRIDGE_ATTACH_NO_CONNECTOR); DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret) { if (ret) {
dev_err(dpsub->dev, "failed to attach bridge to encoder\n"); dev_err(dpsub->dev, "failed to attach bridge to encoder\n");
return ret; goto err_encoder;
} }
/* Create the connector for the chain of bridges. */ /* Create the connector for the chain of bridges. */
connector = drm_bridge_connector_init(&dpsub->drm->dev, encoder); connector = drm_bridge_connector_init(&dpsub->drm->dev, encoder);
if (IS_ERR(connector)) { if (IS_ERR(connector)) {
dev_err(dpsub->dev, "failed to created connector\n"); 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); ret = drm_connector_attach_encoder(connector, encoder);
if (ret < 0) { if (ret < 0) {
dev_err(dpsub->dev, "failed to attach connector to encoder\n"); dev_err(dpsub->dev, "failed to attach connector to encoder\n");
return ret; goto err_encoder;
} }
return 0; return 0;
err_encoder:
drm_encoder_cleanup(encoder);
return ret;
} }
static void zynqmp_dpsub_drm_release(struct drm_device *drm, void *res) 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) ...@@ -529,5 +538,6 @@ void zynqmp_dpsub_drm_cleanup(struct zynqmp_dpsub *dpsub)
drm_dev_unregister(drm); drm_dev_unregister(drm);
drm_atomic_helper_shutdown(drm); drm_atomic_helper_shutdown(drm);
drm_encoder_cleanup(&dpsub->drm->encoder);
drm_kms_helper_poll_fini(drm); drm_kms_helper_poll_fini(drm);
} }
...@@ -201,6 +201,13 @@ enum drm_connector_tv_mode { ...@@ -201,6 +201,13 @@ enum drm_connector_tv_mode {
*/ */
DRM_MODE_TV_MODE_SECAM, DRM_MODE_TV_MODE_SECAM,
/**
* @DRM_MODE_TV_MODE_MONOCHROME: Use timings appropriate to
* the DRM mode, including equalizing pulses for a 525-line
* or 625-line mode, with no pedestal or color encoding.
*/
DRM_MODE_TV_MODE_MONOCHROME,
/** /**
* @DRM_MODE_TV_MODE_MAX: Number of analog TV output modes. * @DRM_MODE_TV_MODE_MAX: Number of analog TV output modes.
* *
...@@ -929,6 +936,67 @@ struct drm_connector_hdmi_infoframe { ...@@ -929,6 +936,67 @@ struct drm_connector_hdmi_infoframe {
bool set; bool set;
}; };
/*
* struct drm_connector_hdmi_state - HDMI state container
*/
struct drm_connector_hdmi_state {
/**
* @broadcast_rgb: Connector property to pass the
* Broadcast RGB selection value.
*/
enum drm_hdmi_broadcast_rgb broadcast_rgb;
/**
* @infoframes: HDMI Infoframes matching that state
*/
struct {
/**
* @avi: AVI Infoframes structure matching our
* state.
*/
struct drm_connector_hdmi_infoframe avi;
/**
* @hdr_drm: DRM (Dynamic Range and Mastering)
* Infoframes structure matching our state.
*/
struct drm_connector_hdmi_infoframe hdr_drm;
/**
* @spd: SPD Infoframes structure matching our
* state.
*/
struct drm_connector_hdmi_infoframe spd;
/**
* @vendor: HDMI Vendor Infoframes structure
* matching our state.
*/
struct drm_connector_hdmi_infoframe hdmi;
} infoframes;
/**
* @is_limited_range: Is the output supposed to use a limited
* RGB Quantization Range or not?
*/
bool is_limited_range;
/**
* @output_bpc: Bits per color channel to output.
*/
unsigned int output_bpc;
/**
* @output_format: Pixel format to output in.
*/
enum hdmi_colorspace output_format;
/**
* @tmds_char_rate: TMDS Character Rate, in Hz.
*/
unsigned long long tmds_char_rate;
};
/** /**
* struct drm_connector_state - mutable connector state * struct drm_connector_state - mutable connector state
*/ */
...@@ -1078,63 +1146,7 @@ struct drm_connector_state { ...@@ -1078,63 +1146,7 @@ struct drm_connector_state {
* @hdmi: HDMI-related variable and properties. Filled by * @hdmi: HDMI-related variable and properties. Filled by
* @drm_atomic_helper_connector_hdmi_check(). * @drm_atomic_helper_connector_hdmi_check().
*/ */
struct { struct drm_connector_hdmi_state hdmi;
/**
* @broadcast_rgb: Connector property to pass the
* Broadcast RGB selection value.
*/
enum drm_hdmi_broadcast_rgb broadcast_rgb;
/**
* @infoframes: HDMI Infoframes matching that state
*/
struct {
/**
* @avi: AVI Infoframes structure matching our
* state.
*/
struct drm_connector_hdmi_infoframe avi;
/**
* @hdr_drm: DRM (Dynamic Range and Mastering)
* Infoframes structure matching our state.
*/
struct drm_connector_hdmi_infoframe hdr_drm;
/**
* @spd: SPD Infoframes structure matching our
* state.
*/
struct drm_connector_hdmi_infoframe spd;
/**
* @vendor: HDMI Vendor Infoframes structure
* matching our state.
*/
struct drm_connector_hdmi_infoframe hdmi;
} infoframes;
/**
* @is_limited_range: Is the output supposed to use a limited
* RGB Quantization Range or not?
*/
bool is_limited_range;
/**
* @output_bpc: Bits per color channel to output.
*/
unsigned int output_bpc;
/**
* @output_format: Pixel format to output in.
*/
enum hdmi_colorspace output_format;
/**
* @tmds_char_rate: TMDS Character Rate, in Hz.
*/
unsigned long long tmds_char_rate;
} hdmi;
}; };
/** /**
...@@ -1656,6 +1668,51 @@ struct drm_cmdline_mode { ...@@ -1656,6 +1668,51 @@ struct drm_cmdline_mode {
bool tv_mode_specified; bool tv_mode_specified;
}; };
/*
* struct drm_connector_hdmi - DRM Connector HDMI-related structure
*/
struct drm_connector_hdmi {
#define DRM_CONNECTOR_HDMI_VENDOR_LEN 8
/**
* @vendor: HDMI Controller Vendor Name
*/
unsigned char vendor[DRM_CONNECTOR_HDMI_VENDOR_LEN] __nonstring;
#define DRM_CONNECTOR_HDMI_PRODUCT_LEN 16
/**
* @product: HDMI Controller Product Name
*/
unsigned char product[DRM_CONNECTOR_HDMI_PRODUCT_LEN] __nonstring;
/**
* @supported_formats: Bitmask of @hdmi_colorspace
* supported by the controller.
*/
unsigned long supported_formats;
/**
* @funcs: HDMI connector Control Functions
*/
const struct drm_connector_hdmi_funcs *funcs;
/**
* @infoframes: Current Infoframes output by the connector
*/
struct {
/**
* @lock: Mutex protecting against concurrent access to
* the infoframes, most notably between KMS and ALSA.
*/
struct mutex lock;
/**
* @audio: Current Audio Infoframes structure. Protected
* by @lock.
*/
struct drm_connector_hdmi_infoframe audio;
} infoframes;
};
/** /**
* struct drm_connector - central DRM connector control structure * struct drm_connector - central DRM connector control structure
* *
...@@ -2068,47 +2125,7 @@ struct drm_connector { ...@@ -2068,47 +2125,7 @@ struct drm_connector {
/** /**
* @hdmi: HDMI-related variable and properties. * @hdmi: HDMI-related variable and properties.
*/ */
struct { struct drm_connector_hdmi hdmi;
#define DRM_CONNECTOR_HDMI_VENDOR_LEN 8
/**
* @vendor: HDMI Controller Vendor Name
*/
unsigned char vendor[DRM_CONNECTOR_HDMI_VENDOR_LEN] __nonstring;
#define DRM_CONNECTOR_HDMI_PRODUCT_LEN 16
/**
* @product: HDMI Controller Product Name
*/
unsigned char product[DRM_CONNECTOR_HDMI_PRODUCT_LEN] __nonstring;
/**
* @supported_formats: Bitmask of @hdmi_colorspace
* supported by the controller.
*/
unsigned long supported_formats;
/**
* @funcs: HDMI connector Control Functions
*/
const struct drm_connector_hdmi_funcs *funcs;
/**
* @infoframes: Current Infoframes output by the connector
*/
struct {
/**
* @lock: Mutex protecting against concurrent access to
* the infoframes, most notably between KMS and ALSA.
*/
struct mutex lock;
/**
* @audio: Current Audio Infoframes structure. Protected
* by @lock.
*/
struct drm_connector_hdmi_infoframe audio;
} infoframes;
} hdmi;
}; };
#define obj_to_connector(x) container_of(x, struct drm_connector, base) #define obj_to_connector(x) container_of(x, struct drm_connector, base)
......
...@@ -23,8 +23,8 @@ struct dma_heap; ...@@ -23,8 +23,8 @@ struct dma_heap;
struct dma_heap_ops { struct dma_heap_ops {
struct dma_buf *(*allocate)(struct dma_heap *heap, struct dma_buf *(*allocate)(struct dma_heap *heap,
unsigned long len, unsigned long len,
unsigned long fd_flags, u32 fd_flags,
unsigned long heap_flags); u64 heap_flags);
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment