Merge tag 'drm-misc-next-2024-04-10' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next
drm-misc-next for v6.10: Cross-subsystem Changes: - Add Tomi as Xilinx maintainer. - Add sound bindings to DT. Core Changes: - Make DP helper depend on KMS helper. Driver Changes: - Assorted small fixes to bridge/dw-hdmi, bridge/cdns-mhdp8456, xlnx, omap, tilcdc, bridge/imx8mp-hdmi-pvi. - Add debugfs entries to qaic. - Add conservative fallback to panel eDP. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/dc690de5-17da-4af6-93a9-8078c99245fd@linux.intel.com
This commit is contained in:
@@ -9,6 +9,9 @@ title: ITE it6505
|
||||
maintainers:
|
||||
- Allen Chen <allen.chen@ite.com.tw>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/sound/dai-common.yaml#
|
||||
|
||||
description: |
|
||||
The IT6505 is a high-performance DisplayPort 1.1a transmitter,
|
||||
fully compliant with DisplayPort 1.1a, HDCP 1.3 specifications.
|
||||
@@ -52,6 +55,9 @@ properties:
|
||||
maxItems: 1
|
||||
description: extcon specifier for the Power Delivery
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
@@ -105,7 +111,7 @@ required:
|
||||
- extcon
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
||||
@@ -7380,6 +7380,7 @@ F: drivers/gpu/drm/xen/
|
||||
|
||||
DRM DRIVERS FOR XILINX
|
||||
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
M: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
S: Maintained
|
||||
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
|
||||
|
||||
@@ -11,3 +11,5 @@ qaic-y := \
|
||||
qaic_data.o \
|
||||
qaic_drv.o \
|
||||
qaic_timesync.o
|
||||
|
||||
qaic-$(CONFIG_DEBUG_FS) += qaic_debugfs.o
|
||||
|
||||
@@ -153,6 +153,14 @@ struct qaic_device {
|
||||
struct mhi_device *qts_ch;
|
||||
/* Work queue for tasks related to MHI "QAIC_TIMESYNC" channel */
|
||||
struct workqueue_struct *qts_wq;
|
||||
/* Head of list of page allocated by MHI bootlog device */
|
||||
struct list_head bootlog;
|
||||
/* MHI bootlog channel device */
|
||||
struct mhi_device *bootlog_ch;
|
||||
/* Work queue for tasks related to MHI bootlog device */
|
||||
struct workqueue_struct *bootlog_wq;
|
||||
/* Synchronizes access of pages in MHI bootlog device */
|
||||
struct mutex bootlog_mutex;
|
||||
};
|
||||
|
||||
struct qaic_drm_device {
|
||||
@@ -280,6 +288,7 @@ int disable_dbc(struct qaic_device *qdev, u32 dbc_id, struct qaic_user *usr);
|
||||
void enable_dbc(struct qaic_device *qdev, u32 dbc_id, struct qaic_user *usr);
|
||||
void wakeup_dbc(struct qaic_device *qdev, u32 dbc_id);
|
||||
void release_dbc(struct qaic_device *qdev, u32 dbc_id);
|
||||
void qaic_data_get_fifo_info(struct dma_bridge_chan *dbc, u32 *head, u32 *tail);
|
||||
|
||||
void wake_all_cntl(struct qaic_device *qdev);
|
||||
void qaic_dev_reset_clean_local_state(struct qaic_device *qdev);
|
||||
|
||||
@@ -1981,3 +1981,12 @@ void release_dbc(struct qaic_device *qdev, u32 dbc_id)
|
||||
dbc->in_use = false;
|
||||
wake_up(&dbc->dbc_release);
|
||||
}
|
||||
|
||||
void qaic_data_get_fifo_info(struct dma_bridge_chan *dbc, u32 *head, u32 *tail)
|
||||
{
|
||||
if (!dbc || !head || !tail)
|
||||
return;
|
||||
|
||||
*head = readl(dbc->dbc_base + REQHP_OFF);
|
||||
*tail = readl(dbc->dbc_base + REQTP_OFF);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,338 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
/* Copyright (c) 2020, The Linux Foundation. All rights reserved. */
|
||||
/* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mhi.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/sprintf.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "qaic.h"
|
||||
#include "qaic_debugfs.h"
|
||||
|
||||
#define BOOTLOG_POOL_SIZE 16
|
||||
#define BOOTLOG_MSG_SIZE 512
|
||||
#define QAIC_DBC_DIR_NAME 9
|
||||
|
||||
struct bootlog_msg {
|
||||
/* Buffer for bootlog messages */
|
||||
char str[BOOTLOG_MSG_SIZE];
|
||||
/* Root struct of device, used to access device resources */
|
||||
struct qaic_device *qdev;
|
||||
/* Work struct to schedule work coming on QAIC_LOGGING channel */
|
||||
struct work_struct work;
|
||||
};
|
||||
|
||||
struct bootlog_page {
|
||||
/* Node in list of bootlog pages maintained by root device struct */
|
||||
struct list_head node;
|
||||
/* Total size of the buffer that holds the bootlogs. It is PAGE_SIZE */
|
||||
unsigned int size;
|
||||
/* Offset for the next bootlog */
|
||||
unsigned int offset;
|
||||
};
|
||||
|
||||
static int bootlog_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct bootlog_page *page;
|
||||
struct qaic_device *qdev;
|
||||
void *page_end;
|
||||
void *log;
|
||||
|
||||
qdev = s->private;
|
||||
mutex_lock(&qdev->bootlog_mutex);
|
||||
list_for_each_entry(page, &qdev->bootlog, node) {
|
||||
log = page + 1;
|
||||
page_end = (void *)page + page->offset;
|
||||
while (log < page_end) {
|
||||
seq_printf(s, "%s", (char *)log);
|
||||
log += strlen(log) + 1;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&qdev->bootlog_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bootlog_fops_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, bootlog_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations bootlog_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = bootlog_fops_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int read_dbc_fifo_size(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dma_bridge_chan *dbc = s->private;
|
||||
|
||||
seq_printf(s, "%u\n", dbc->nelem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fifo_size_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, read_dbc_fifo_size, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fifo_size_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = fifo_size_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int read_dbc_queued(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dma_bridge_chan *dbc = s->private;
|
||||
u32 tail = 0, head = 0;
|
||||
|
||||
qaic_data_get_fifo_info(dbc, &head, &tail);
|
||||
|
||||
if (head == U32_MAX || tail == U32_MAX)
|
||||
seq_printf(s, "%u\n", 0);
|
||||
else if (head > tail)
|
||||
seq_printf(s, "%u\n", dbc->nelem - head + tail);
|
||||
else
|
||||
seq_printf(s, "%u\n", tail - head);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int queued_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, read_dbc_queued, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations queued_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = queued_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
void qaic_debugfs_init(struct qaic_drm_device *qddev)
|
||||
{
|
||||
struct qaic_device *qdev = qddev->qdev;
|
||||
struct dentry *debugfs_root;
|
||||
struct dentry *debugfs_dir;
|
||||
char name[QAIC_DBC_DIR_NAME];
|
||||
u32 i;
|
||||
|
||||
debugfs_root = to_drm(qddev)->debugfs_root;
|
||||
|
||||
debugfs_create_file("bootlog", 0400, debugfs_root, qdev, &bootlog_fops);
|
||||
/*
|
||||
* 256 dbcs per device is likely the max we will ever see and lets static checking see a
|
||||
* reasonable range.
|
||||
*/
|
||||
for (i = 0; i < qdev->num_dbc && i < 256; ++i) {
|
||||
snprintf(name, QAIC_DBC_DIR_NAME, "dbc%03u", i);
|
||||
debugfs_dir = debugfs_create_dir(name, debugfs_root);
|
||||
debugfs_create_file("fifo_size", 0400, debugfs_dir, &qdev->dbc[i], &fifo_size_fops);
|
||||
debugfs_create_file("queued", 0400, debugfs_dir, &qdev->dbc[i], &queued_fops);
|
||||
}
|
||||
}
|
||||
|
||||
static struct bootlog_page *alloc_bootlog_page(struct qaic_device *qdev)
|
||||
{
|
||||
struct bootlog_page *page;
|
||||
|
||||
page = (struct bootlog_page *)devm_get_free_pages(&qdev->pdev->dev, GFP_KERNEL, 0);
|
||||
if (!page)
|
||||
return page;
|
||||
|
||||
page->size = PAGE_SIZE;
|
||||
page->offset = sizeof(*page);
|
||||
list_add_tail(&page->node, &qdev->bootlog);
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
static int reset_bootlog(struct qaic_device *qdev)
|
||||
{
|
||||
struct bootlog_page *page;
|
||||
struct bootlog_page *i;
|
||||
|
||||
mutex_lock(&qdev->bootlog_mutex);
|
||||
list_for_each_entry_safe(page, i, &qdev->bootlog, node) {
|
||||
list_del(&page->node);
|
||||
devm_free_pages(&qdev->pdev->dev, (unsigned long)page);
|
||||
}
|
||||
|
||||
page = alloc_bootlog_page(qdev);
|
||||
mutex_unlock(&qdev->bootlog_mutex);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *bootlog_get_space(struct qaic_device *qdev, unsigned int size)
|
||||
{
|
||||
struct bootlog_page *page;
|
||||
|
||||
page = list_last_entry(&qdev->bootlog, struct bootlog_page, node);
|
||||
|
||||
if (size_add(size, sizeof(*page)) > page->size)
|
||||
return NULL;
|
||||
|
||||
if (page->offset + size > page->size) {
|
||||
page = alloc_bootlog_page(qdev);
|
||||
if (!page)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (void *)page + page->offset;
|
||||
}
|
||||
|
||||
static void bootlog_commit(struct qaic_device *qdev, unsigned int size)
|
||||
{
|
||||
struct bootlog_page *page;
|
||||
|
||||
page = list_last_entry(&qdev->bootlog, struct bootlog_page, node);
|
||||
|
||||
page->offset += size;
|
||||
}
|
||||
|
||||
static void bootlog_log(struct work_struct *work)
|
||||
{
|
||||
struct bootlog_msg *msg = container_of(work, struct bootlog_msg, work);
|
||||
unsigned int len = strlen(msg->str) + 1;
|
||||
struct qaic_device *qdev = msg->qdev;
|
||||
void *log;
|
||||
|
||||
mutex_lock(&qdev->bootlog_mutex);
|
||||
log = bootlog_get_space(qdev, len);
|
||||
if (log) {
|
||||
memcpy(log, msg, len);
|
||||
bootlog_commit(qdev, len);
|
||||
}
|
||||
mutex_unlock(&qdev->bootlog_mutex);
|
||||
|
||||
if (mhi_queue_buf(qdev->bootlog_ch, DMA_FROM_DEVICE, msg, BOOTLOG_MSG_SIZE, MHI_EOT))
|
||||
devm_kfree(&qdev->pdev->dev, msg);
|
||||
}
|
||||
|
||||
static int qaic_bootlog_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id)
|
||||
{
|
||||
struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(mhi_dev->mhi_cntrl->cntrl_dev));
|
||||
struct bootlog_msg *msg;
|
||||
int i, ret;
|
||||
|
||||
qdev->bootlog_wq = alloc_ordered_workqueue("qaic_bootlog", 0);
|
||||
if (!qdev->bootlog_wq) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = reset_bootlog(qdev);
|
||||
if (ret)
|
||||
goto destroy_workqueue;
|
||||
|
||||
ret = mhi_prepare_for_transfer(mhi_dev);
|
||||
if (ret)
|
||||
goto destroy_workqueue;
|
||||
|
||||
for (i = 0; i < BOOTLOG_POOL_SIZE; i++) {
|
||||
msg = devm_kzalloc(&qdev->pdev->dev, sizeof(*msg), GFP_KERNEL);
|
||||
if (!msg) {
|
||||
ret = -ENOMEM;
|
||||
goto mhi_unprepare;
|
||||
}
|
||||
|
||||
msg->qdev = qdev;
|
||||
INIT_WORK(&msg->work, bootlog_log);
|
||||
|
||||
ret = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, msg, BOOTLOG_MSG_SIZE, MHI_EOT);
|
||||
if (ret)
|
||||
goto mhi_unprepare;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&mhi_dev->dev, qdev);
|
||||
qdev->bootlog_ch = mhi_dev;
|
||||
return 0;
|
||||
|
||||
mhi_unprepare:
|
||||
mhi_unprepare_from_transfer(mhi_dev);
|
||||
destroy_workqueue:
|
||||
flush_workqueue(qdev->bootlog_wq);
|
||||
destroy_workqueue(qdev->bootlog_wq);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qaic_bootlog_mhi_remove(struct mhi_device *mhi_dev)
|
||||
{
|
||||
struct qaic_device *qdev;
|
||||
|
||||
qdev = dev_get_drvdata(&mhi_dev->dev);
|
||||
|
||||
mhi_unprepare_from_transfer(qdev->bootlog_ch);
|
||||
flush_workqueue(qdev->bootlog_wq);
|
||||
destroy_workqueue(qdev->bootlog_wq);
|
||||
qdev->bootlog_ch = NULL;
|
||||
}
|
||||
|
||||
static void qaic_bootlog_mhi_ul_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result)
|
||||
{
|
||||
}
|
||||
|
||||
static void qaic_bootlog_mhi_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result)
|
||||
{
|
||||
struct qaic_device *qdev = dev_get_drvdata(&mhi_dev->dev);
|
||||
struct bootlog_msg *msg = mhi_result->buf_addr;
|
||||
|
||||
if (mhi_result->transaction_status) {
|
||||
devm_kfree(&qdev->pdev->dev, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Force a null at the end of the transferred string */
|
||||
msg->str[mhi_result->bytes_xferd - 1] = 0;
|
||||
|
||||
queue_work(qdev->bootlog_wq, &msg->work);
|
||||
}
|
||||
|
||||
static const struct mhi_device_id qaic_bootlog_mhi_match_table[] = {
|
||||
{ .chan = "QAIC_LOGGING", },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct mhi_driver qaic_bootlog_mhi_driver = {
|
||||
.id_table = qaic_bootlog_mhi_match_table,
|
||||
.remove = qaic_bootlog_mhi_remove,
|
||||
.probe = qaic_bootlog_mhi_probe,
|
||||
.ul_xfer_cb = qaic_bootlog_mhi_ul_xfer_cb,
|
||||
.dl_xfer_cb = qaic_bootlog_mhi_dl_xfer_cb,
|
||||
.driver = {
|
||||
.name = "qaic_bootlog",
|
||||
},
|
||||
};
|
||||
|
||||
int qaic_bootlog_register(void)
|
||||
{
|
||||
return mhi_driver_register(&qaic_bootlog_mhi_driver);
|
||||
}
|
||||
|
||||
void qaic_bootlog_unregister(void)
|
||||
{
|
||||
mhi_driver_unregister(&qaic_bootlog_mhi_driver);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
/* Copyright (c) 2020, The Linux Foundation. All rights reserved. */
|
||||
/* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */
|
||||
|
||||
#ifndef __QAIC_DEBUGFS_H__
|
||||
#define __QAIC_DEBUGFS_H__
|
||||
|
||||
#include <drm/drm_file.h>
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
int qaic_bootlog_register(void);
|
||||
void qaic_bootlog_unregister(void);
|
||||
void qaic_debugfs_init(struct qaic_drm_device *qddev);
|
||||
#else
|
||||
int qaic_bootlog_register(void) { return 0; }
|
||||
void qaic_bootlog_unregister(void) {}
|
||||
void qaic_debugfs_init(struct qaic_drm_device *qddev) {}
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
#endif /* __QAIC_DEBUGFS_H__ */
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "mhi_controller.h"
|
||||
#include "qaic.h"
|
||||
#include "qaic_debugfs.h"
|
||||
#include "qaic_timesync.h"
|
||||
|
||||
MODULE_IMPORT_NS(DMA_BUF);
|
||||
@@ -229,8 +230,12 @@ static int qaic_create_drm_device(struct qaic_device *qdev, s32 partition_id)
|
||||
qddev->partition_id = partition_id;
|
||||
|
||||
ret = drm_dev_register(drm, 0);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
pci_dbg(qdev->pdev, "drm_dev_register failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
qaic_debugfs_init(qddev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -380,6 +385,9 @@ static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_de
|
||||
if (ret)
|
||||
return NULL;
|
||||
ret = drmm_mutex_init(drm, &qdev->cntl_mutex);
|
||||
if (ret)
|
||||
return NULL;
|
||||
ret = drmm_mutex_init(drm, &qdev->bootlog_mutex);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
@@ -399,6 +407,7 @@ static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_de
|
||||
qddev->qdev = qdev;
|
||||
|
||||
INIT_LIST_HEAD(&qdev->cntl_xfer_list);
|
||||
INIT_LIST_HEAD(&qdev->bootlog);
|
||||
INIT_LIST_HEAD(&qddev->users);
|
||||
|
||||
for (i = 0; i < qdev->num_dbc; ++i) {
|
||||
@@ -639,6 +648,10 @@ static int __init qaic_init(void)
|
||||
if (ret)
|
||||
pr_debug("qaic: qaic_timesync_init failed %d\n", ret);
|
||||
|
||||
ret = qaic_bootlog_register();
|
||||
if (ret)
|
||||
pr_debug("qaic: qaic_bootlog_register failed %d\n", ret);
|
||||
|
||||
return 0;
|
||||
|
||||
free_pci:
|
||||
@@ -664,6 +677,7 @@ static void __exit qaic_exit(void)
|
||||
* reinitializing the link_up state after the cleanup is done.
|
||||
*/
|
||||
link_up = true;
|
||||
qaic_bootlog_unregister();
|
||||
qaic_timesync_deinit();
|
||||
mhi_driver_unregister(&qaic_mhi_driver);
|
||||
pci_unregister_driver(&qaic_pci_driver);
|
||||
|
||||
@@ -2059,6 +2059,9 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge,
|
||||
mhdp_state = to_cdns_mhdp_bridge_state(new_state);
|
||||
|
||||
mhdp_state->current_mode = drm_mode_duplicate(bridge->dev, mode);
|
||||
if (!mhdp_state->current_mode)
|
||||
return;
|
||||
|
||||
drm_mode_set_name(mhdp_state->current_mode);
|
||||
|
||||
dev_dbg(mhdp->dev, "%s: Enabling mode %s\n", __func__, mode->name);
|
||||
|
||||
@@ -173,15 +173,13 @@ static int imx8mp_hdmi_pvi_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx8mp_hdmi_pvi_remove(struct platform_device *pdev)
|
||||
static void imx8mp_hdmi_pvi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct imx8mp_hdmi_pvi *pvi = platform_get_drvdata(pdev);
|
||||
|
||||
drm_bridge_remove(&pvi->bridge);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id imx8mp_hdmi_pvi_match[] = {
|
||||
@@ -195,7 +193,7 @@ MODULE_DEVICE_TABLE(of, imx8mp_hdmi_pvi_match);
|
||||
|
||||
static struct platform_driver imx8mp_hdmi_pvi_driver = {
|
||||
.probe = imx8mp_hdmi_pvi_probe,
|
||||
.remove = imx8mp_hdmi_pvi_remove,
|
||||
.remove_new = imx8mp_hdmi_pvi_remove,
|
||||
.driver = {
|
||||
.name = "imx-hdmi-pvi",
|
||||
.of_match_table = imx8mp_hdmi_pvi_match,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config DRM_DW_HDMI
|
||||
tristate
|
||||
tristate "Synopsys Designware HDMI TX Controller"
|
||||
depends on DRM_DISPLAY_HDMI_HELPER
|
||||
depends on DRM_DISPLAY_HELPER
|
||||
select DRM_KMS_HELPER
|
||||
|
||||
@@ -39,6 +39,7 @@ config DRM_DISPLAY_DP_AUX_CHARDEV
|
||||
config DRM_DISPLAY_DP_HELPER
|
||||
bool "DRM DisplayPort Helpers"
|
||||
depends on DRM_DISPLAY_HELPER
|
||||
select DRM_KMS_HELPER
|
||||
default y
|
||||
help
|
||||
DRM display helpers for DisplayPort.
|
||||
|
||||
@@ -1212,7 +1212,6 @@ struct platform_driver omap_dmm_driver = {
|
||||
.probe = omap_dmm_probe,
|
||||
.remove_new = omap_dmm_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DMM_DRIVER_NAME,
|
||||
.of_match_table = of_match_ptr(dmm_of_match),
|
||||
.pm = &omap_dmm_pm_ops,
|
||||
|
||||
@@ -760,6 +760,25 @@ static void panel_edp_parse_panel_timing_node(struct device *dev,
|
||||
|
||||
static const struct edp_panel_entry *find_edp_panel(u32 panel_id, const struct drm_edid *edid);
|
||||
|
||||
static void panel_edp_set_conservative_timings(struct panel_edp *panel, struct panel_desc *desc)
|
||||
{
|
||||
/*
|
||||
* It's highly likely that the panel will work if we use very
|
||||
* conservative timings, so let's do that.
|
||||
*
|
||||
* Nearly all panels have a "unprepare" delay of 500 ms though
|
||||
* there are a few with 1000. Let's stick 2000 in just to be
|
||||
* super conservative.
|
||||
*
|
||||
* An "enable" delay of 80 ms seems the most common, but we'll
|
||||
* throw in 200 ms to be safe.
|
||||
*/
|
||||
desc->delay.unprepare = 2000;
|
||||
desc->delay.enable = 200;
|
||||
|
||||
panel->detected_panel = ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
|
||||
{
|
||||
struct panel_desc *desc;
|
||||
@@ -789,7 +808,10 @@ static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
|
||||
/* Power the panel on so we can read the EDID */
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Couldn't power on panel to read EDID: %d\n", ret);
|
||||
dev_err(dev,
|
||||
"Couldn't power on panel to ID it; using conservative timings: %d\n",
|
||||
ret);
|
||||
panel_edp_set_conservative_timings(panel, desc);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -797,8 +819,8 @@ static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
|
||||
if (base_block) {
|
||||
panel_id = drm_edid_get_panel_id(base_block);
|
||||
} else {
|
||||
dev_err(dev, "Couldn't identify panel via EDID\n");
|
||||
ret = -EIO;
|
||||
dev_err(dev, "Couldn't read EDID for ID; using conservative timings\n");
|
||||
panel_edp_set_conservative_timings(panel, desc);
|
||||
goto exit;
|
||||
}
|
||||
drm_edid_decode_panel_id(panel_id, vend, &product_id);
|
||||
@@ -816,26 +838,7 @@ static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
|
||||
dev_warn(dev,
|
||||
"Unknown panel %s %#06x, using conservative timings\n",
|
||||
vend, product_id);
|
||||
|
||||
/*
|
||||
* It's highly likely that the panel will work if we use very
|
||||
* conservative timings, so let's do that. We already know that
|
||||
* the HPD-related delays must have worked since we got this
|
||||
* far, so we really just need the "unprepare" / "enable"
|
||||
* delays. We don't need "prepare_to_enable" since that
|
||||
* overlaps the "enable" delay anyway.
|
||||
*
|
||||
* Nearly all panels have a "unprepare" delay of 500 ms though
|
||||
* there are a few with 1000. Let's stick 2000 in just to be
|
||||
* super conservative.
|
||||
*
|
||||
* An "enable" delay of 80 ms seems the most common, but we'll
|
||||
* throw in 200 ms to be safe.
|
||||
*/
|
||||
desc->delay.unprepare = 2000;
|
||||
desc->delay.enable = 200;
|
||||
|
||||
panel->detected_panel = ERR_PTR(-EINVAL);
|
||||
panel_edp_set_conservative_timings(panel, desc);
|
||||
} else {
|
||||
dev_info(dev, "Detected %s %s (%#06x)\n",
|
||||
vend, panel->detected_panel->ident.name, product_id);
|
||||
@@ -844,12 +847,11 @@ static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
|
||||
desc->delay = *panel->detected_panel->delay;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
exit:
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int panel_edp_probe(struct device *dev, const struct panel_desc *desc,
|
||||
@@ -942,8 +944,14 @@ static int panel_edp_probe(struct device *dev, const struct panel_desc *desc,
|
||||
err = drm_panel_dp_aux_backlight(&panel->base, panel->aux);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
/*
|
||||
* Warn if we get an error, but don't consider it fatal. Having
|
||||
* a panel where we can't control the backlight is better than
|
||||
* no panel.
|
||||
*/
|
||||
if (err)
|
||||
goto err_finished_pm_runtime;
|
||||
dev_warn(dev, "failed to register dp aux backlight: %d\n", err);
|
||||
}
|
||||
|
||||
drm_panel_add(&panel->base);
|
||||
|
||||
@@ -328,9 +328,14 @@ static int atana33xc20_probe(struct dp_aux_ep_device *aux_ep)
|
||||
ret = drm_panel_dp_aux_backlight(&panel->base, aux_ep->aux);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
/*
|
||||
* Warn if we get an error, but don't consider it fatal. Having
|
||||
* a panel where we can't control the backlight is better than
|
||||
* no panel.
|
||||
*/
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to register dp aux backlight\n");
|
||||
dev_warn(dev, "failed to register dp aux backlight: %d\n", ret);
|
||||
|
||||
drm_panel_add(&panel->base);
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <video/display_timing.h>
|
||||
@@ -308,7 +307,6 @@ static int panel_probe(struct platform_device *pdev)
|
||||
struct backlight_device *backlight;
|
||||
struct panel_module *panel_mod;
|
||||
struct tilcdc_module *mod;
|
||||
struct pinctrl *pinctrl;
|
||||
int ret;
|
||||
|
||||
/* bail out early if no DT data: */
|
||||
@@ -342,10 +340,6 @@ static int panel_probe(struct platform_device *pdev)
|
||||
|
||||
tilcdc_module_init(mod, "panel", &panel_module_ops);
|
||||
|
||||
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
|
||||
if (IS_ERR(pinctrl))
|
||||
dev_warn(&pdev->dev, "pins are not configured\n");
|
||||
|
||||
panel_mod->timings = of_get_display_timings(node);
|
||||
if (!panel_mod->timings) {
|
||||
dev_err(&pdev->dev, "could not get panel timings\n");
|
||||
|
||||
@@ -1716,7 +1716,7 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub)
|
||||
|
||||
ret = zynqmp_dp_reset(dp, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err_free;
|
||||
|
||||
ret = zynqmp_dp_reset(dp, false);
|
||||
if (ret < 0)
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/**************************************************************************
|
||||
* Copyright (c) 2007-2011, Intel Corporation.
|
||||
* All Rights Reserved.
|
||||
* Copyright (c) 2008, Tungsten Graphics Inc. Cedar Park, TX., USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef _GMA_DRM_H_
|
||||
#define _GMA_DRM_H_
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user