mirror of
https://github.com/torvalds/linux.git
synced 2026-07-29 10:41:49 +02:00
drm-misc-next for 6.17:
UAPI Changes: Cross-subsystem Changes: Core Changes: Driver Changes: - amdgpu: debugfs improvements - ast: Improve hardware generations implementation - dma-buf heaps: - Give the CMA heap a stable name - panthor: fix UAF in debugfs - rockchip: Convert inno_hdmi to a bridge - sti: Convert to devm_drm_bridge_alloc() - vkms: Use faux_device - bridge: - Improve CEC handling code, convertions to devm_drm_bridge_alloc() -----BEGIN PGP SIGNATURE----- iJUEABMJAB0WIQTkHFbLp4ejekA/qfgnX84Zoj2+dgUCaG+QdQAKCRAnX84Zoj2+ dqDmAX4mWRXfUPA1o3UE0sXP2owyIoScyXMCb4d1BuzQRFTZRIT8oQ7QZscL5uYF XR+lDoIBgMf88uJYgiuUAiicS9eXOpqo9rQBZgKNuegZi/FzGMaVAwzR6sB2wxGh LPSuaRvFRA== =qXj8 -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2025-07-10' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next drm-misc-next for 6.17: UAPI Changes: Cross-subsystem Changes: Core Changes: Driver Changes: - amdgpu: debugfs improvements - ast: Improve hardware generations implementation - dma-buf heaps: - Give the CMA heap a stable name - panthor: fix UAF in debugfs - rockchip: Convert inno_hdmi to a bridge - sti: Convert to devm_drm_bridge_alloc() - vkms: Use faux_device - bridge: - Improve CEC handling code, convertions to devm_drm_bridge_alloc() Signed-off-by: Simona Vetter <simona.vetter@ffwll.ch> From: Maxime Ripard <mripard@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20250710-observant-elite-dingo-acfd6d@houat
This commit is contained in:
commit
6e85c1ec0e
|
|
@ -19,7 +19,10 @@ following heaps:
|
|||
- The ``cma`` heap allocates physically contiguous, cacheable,
|
||||
buffers. Only present if a CMA region is present. Such a region is
|
||||
usually created either through the kernel commandline through the
|
||||
`cma` parameter, a memory region Device-Tree node with the
|
||||
`linux,cma-default` property set, or through the `CMA_SIZE_MBYTES` or
|
||||
`CMA_SIZE_PERCENTAGE` Kconfig options. Depending on the platform, it
|
||||
might be called ``reserved``, ``linux,cma``, or ``default-pool``.
|
||||
``cma`` parameter, a memory region Device-Tree node with the
|
||||
``linux,cma-default`` property set, or through the ``CMA_SIZE_MBYTES`` or
|
||||
``CMA_SIZE_PERCENTAGE`` Kconfig options. The heap's name in devtmpfs is
|
||||
``default_cma_region``. For backwards compatibility, when the
|
||||
``DMABUF_HEAPS_CMA_LEGACY`` Kconfig option is set, a duplicate node is
|
||||
created following legacy naming conventions; the legacy name might be
|
||||
``reserved``, ``linux,cma``, or ``default-pool``.
|
||||
|
|
|
|||
|
|
@ -209,8 +209,6 @@ source "drivers/thunderbolt/Kconfig"
|
|||
|
||||
source "drivers/android/Kconfig"
|
||||
|
||||
source "drivers/gpu/trace/Kconfig"
|
||||
|
||||
source "drivers/nvdimm/Kconfig"
|
||||
|
||||
source "drivers/dax/Kconfig"
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
DEFINE_XARRAY_ALLOC(accel_minors_xa);
|
||||
|
||||
static struct dentry *accel_debugfs_root;
|
||||
|
||||
static const struct device_type accel_sysfs_device_minor = {
|
||||
.name = "accel_minor"
|
||||
};
|
||||
|
|
@ -73,17 +71,6 @@ static const struct drm_info_list accel_debugfs_list[] = {
|
|||
};
|
||||
#define ACCEL_DEBUGFS_ENTRIES ARRAY_SIZE(accel_debugfs_list)
|
||||
|
||||
/**
|
||||
* accel_debugfs_init() - Initialize debugfs for device
|
||||
* @dev: Pointer to the device instance.
|
||||
*
|
||||
* This function creates a root directory for the device in debugfs.
|
||||
*/
|
||||
void accel_debugfs_init(struct drm_device *dev)
|
||||
{
|
||||
drm_debugfs_dev_init(dev, accel_debugfs_root);
|
||||
}
|
||||
|
||||
/**
|
||||
* accel_debugfs_register() - Register debugfs for device
|
||||
* @dev: Pointer to the device instance.
|
||||
|
|
@ -194,7 +181,6 @@ static const struct file_operations accel_stub_fops = {
|
|||
void accel_core_exit(void)
|
||||
{
|
||||
unregister_chrdev(ACCEL_MAJOR, "accel");
|
||||
debugfs_remove(accel_debugfs_root);
|
||||
accel_sysfs_destroy();
|
||||
WARN_ON(!xa_empty(&accel_minors_xa));
|
||||
}
|
||||
|
|
@ -209,8 +195,6 @@ int __init accel_core_init(void)
|
|||
goto error;
|
||||
}
|
||||
|
||||
accel_debugfs_root = debugfs_create_dir("accel", NULL);
|
||||
|
||||
ret = register_chrdev(ACCEL_MAJOR, "accel", &accel_stub_fops);
|
||||
if (ret < 0)
|
||||
DRM_ERROR("Cannot register ACCEL major: %d\n", ret);
|
||||
|
|
|
|||
|
|
@ -12,3 +12,13 @@ config DMABUF_HEAPS_CMA
|
|||
Choose this option to enable dma-buf CMA heap. This heap is backed
|
||||
by the Contiguous Memory Allocator (CMA). If your system has these
|
||||
regions, you should say Y here.
|
||||
|
||||
config DMABUF_HEAPS_CMA_LEGACY
|
||||
bool "Legacy DMA-BUF CMA Heap"
|
||||
default y
|
||||
depends on DMABUF_HEAPS_CMA
|
||||
help
|
||||
Add a duplicate CMA-backed dma-buf heap with legacy naming derived
|
||||
from the CMA area's devicetree node, or "reserved" if the area is not
|
||||
defined in the devicetree. This uses the same underlying allocator as
|
||||
CONFIG_DMABUF_HEAPS_CMA.
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
* Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Andrew F. Davis <afd@ti.com>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "cma_heap: " fmt
|
||||
|
||||
#include <linux/cma.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/dma-heap.h>
|
||||
|
|
@ -22,6 +25,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#define DEFAULT_CMA_NAME "default_cma_region"
|
||||
|
||||
struct cma_heap {
|
||||
struct dma_heap *heap;
|
||||
|
|
@ -366,17 +370,17 @@ static const struct dma_heap_ops cma_heap_ops = {
|
|||
.allocate = cma_heap_allocate,
|
||||
};
|
||||
|
||||
static int __init __add_cma_heap(struct cma *cma, void *data)
|
||||
static int __init __add_cma_heap(struct cma *cma, const char *name)
|
||||
{
|
||||
struct cma_heap *cma_heap;
|
||||
struct dma_heap_export_info exp_info;
|
||||
struct cma_heap *cma_heap;
|
||||
|
||||
cma_heap = kzalloc(sizeof(*cma_heap), GFP_KERNEL);
|
||||
if (!cma_heap)
|
||||
return -ENOMEM;
|
||||
cma_heap->cma = cma;
|
||||
|
||||
exp_info.name = cma_get_name(cma);
|
||||
exp_info.name = name;
|
||||
exp_info.ops = &cma_heap_ops;
|
||||
exp_info.priv = cma_heap;
|
||||
|
||||
|
|
@ -394,12 +398,30 @@ static int __init __add_cma_heap(struct cma *cma, void *data)
|
|||
static int __init add_default_cma_heap(void)
|
||||
{
|
||||
struct cma *default_cma = dev_get_cma_area(NULL);
|
||||
int ret = 0;
|
||||
const char *legacy_cma_name;
|
||||
int ret;
|
||||
|
||||
if (default_cma)
|
||||
ret = __add_cma_heap(default_cma, NULL);
|
||||
if (!default_cma)
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
ret = __add_cma_heap(default_cma, DEFAULT_CMA_NAME);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (IS_ENABLED(CONFIG_DMABUF_HEAPS_CMA_LEGACY)) {
|
||||
legacy_cma_name = cma_get_name(default_cma);
|
||||
if (!strcmp(legacy_cma_name, DEFAULT_CMA_NAME)) {
|
||||
pr_warn("legacy name and default name are the same, skipping legacy heap\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = __add_cma_heap(default_cma, legacy_cma_name);
|
||||
if (ret)
|
||||
pr_warn("failed to add legacy heap: %pe\n",
|
||||
ERR_PTR(ret));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(add_default_cma_heap);
|
||||
MODULE_DESCRIPTION("DMA-BUF CMA Heap");
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ struct system_heap_buffer {
|
|||
|
||||
struct dma_heap_attachment {
|
||||
struct device *dev;
|
||||
struct sg_table *table;
|
||||
struct sg_table table;
|
||||
struct list_head list;
|
||||
bool mapped;
|
||||
};
|
||||
|
|
@ -52,29 +52,22 @@ static gfp_t order_flags[] = {HIGH_ORDER_GFP, HIGH_ORDER_GFP, LOW_ORDER_GFP};
|
|||
static const unsigned int orders[] = {8, 4, 0};
|
||||
#define NUM_ORDERS ARRAY_SIZE(orders)
|
||||
|
||||
static struct sg_table *dup_sg_table(struct sg_table *table)
|
||||
static int dup_sg_table(struct sg_table *from, struct sg_table *to)
|
||||
{
|
||||
struct sg_table *new_table;
|
||||
int ret, i;
|
||||
struct scatterlist *sg, *new_sg;
|
||||
int ret, i;
|
||||
|
||||
new_table = kzalloc(sizeof(*new_table), GFP_KERNEL);
|
||||
if (!new_table)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ret = sg_alloc_table(to, from->orig_nents, GFP_KERNEL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sg_alloc_table(new_table, table->orig_nents, GFP_KERNEL);
|
||||
if (ret) {
|
||||
kfree(new_table);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
new_sg = new_table->sgl;
|
||||
for_each_sgtable_sg(table, sg, i) {
|
||||
new_sg = to->sgl;
|
||||
for_each_sgtable_sg(from, sg, i) {
|
||||
sg_set_page(new_sg, sg_page(sg), sg->length, sg->offset);
|
||||
new_sg = sg_next(new_sg);
|
||||
}
|
||||
|
||||
return new_table;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int system_heap_attach(struct dma_buf *dmabuf,
|
||||
|
|
@ -82,19 +75,18 @@ static int system_heap_attach(struct dma_buf *dmabuf,
|
|||
{
|
||||
struct system_heap_buffer *buffer = dmabuf->priv;
|
||||
struct dma_heap_attachment *a;
|
||||
struct sg_table *table;
|
||||
int ret;
|
||||
|
||||
a = kzalloc(sizeof(*a), GFP_KERNEL);
|
||||
if (!a)
|
||||
return -ENOMEM;
|
||||
|
||||
table = dup_sg_table(&buffer->sg_table);
|
||||
if (IS_ERR(table)) {
|
||||
ret = dup_sg_table(&buffer->sg_table, &a->table);
|
||||
if (ret) {
|
||||
kfree(a);
|
||||
return -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
a->table = table;
|
||||
a->dev = attachment->dev;
|
||||
INIT_LIST_HEAD(&a->list);
|
||||
a->mapped = false;
|
||||
|
|
@ -118,8 +110,7 @@ static void system_heap_detach(struct dma_buf *dmabuf,
|
|||
list_del(&a->list);
|
||||
mutex_unlock(&buffer->lock);
|
||||
|
||||
sg_free_table(a->table);
|
||||
kfree(a->table);
|
||||
sg_free_table(&a->table);
|
||||
kfree(a);
|
||||
}
|
||||
|
||||
|
|
@ -127,7 +118,7 @@ static struct sg_table *system_heap_map_dma_buf(struct dma_buf_attachment *attac
|
|||
enum dma_data_direction direction)
|
||||
{
|
||||
struct dma_heap_attachment *a = attachment->priv;
|
||||
struct sg_table *table = a->table;
|
||||
struct sg_table *table = &a->table;
|
||||
int ret;
|
||||
|
||||
ret = dma_map_sgtable(attachment->dev, table, direction, 0);
|
||||
|
|
@ -162,7 +153,7 @@ static int system_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
|
|||
list_for_each_entry(a, &buffer->attachments, list) {
|
||||
if (!a->mapped)
|
||||
continue;
|
||||
dma_sync_sgtable_for_cpu(a->dev, a->table, direction);
|
||||
dma_sync_sgtable_for_cpu(a->dev, &a->table, direction);
|
||||
}
|
||||
mutex_unlock(&buffer->lock);
|
||||
|
||||
|
|
@ -183,7 +174,7 @@ static int system_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
|
|||
list_for_each_entry(a, &buffer->attachments, list) {
|
||||
if (!a->mapped)
|
||||
continue;
|
||||
dma_sync_sgtable_for_device(a->dev, a->table, direction);
|
||||
dma_sync_sgtable_for_device(a->dev, &a->table, direction);
|
||||
}
|
||||
mutex_unlock(&buffer->lock);
|
||||
|
||||
|
|
|
|||
|
|
@ -2131,6 +2131,55 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_pt_info_read(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_file *file;
|
||||
struct amdgpu_fpriv *fpriv;
|
||||
struct amdgpu_bo *root_bo;
|
||||
int r;
|
||||
|
||||
file = m->private;
|
||||
if (!file)
|
||||
return -EINVAL;
|
||||
|
||||
fpriv = file->driver_priv;
|
||||
if (!fpriv || !fpriv->vm.root.bo)
|
||||
return -ENODEV;
|
||||
|
||||
root_bo = amdgpu_bo_ref(fpriv->vm.root.bo);
|
||||
r = amdgpu_bo_reserve(root_bo, true);
|
||||
if (r) {
|
||||
amdgpu_bo_unref(&root_bo);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
seq_printf(m, "gpu_address: 0x%llx\n", amdgpu_bo_gpu_offset(fpriv->vm.root.bo));
|
||||
|
||||
amdgpu_bo_unreserve(root_bo);
|
||||
amdgpu_bo_unref(&root_bo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_pt_info_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, amdgpu_pt_info_read, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations amdgpu_pt_info_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = amdgpu_pt_info_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
void amdgpu_debugfs_vm_init(struct drm_file *file)
|
||||
{
|
||||
debugfs_create_file("vm_pagetable_info", 0444, file->debugfs_client, file,
|
||||
&amdgpu_pt_info_fops);
|
||||
}
|
||||
|
||||
#else
|
||||
int amdgpu_debugfs_init(struct amdgpu_device *adev)
|
||||
{
|
||||
|
|
@ -2140,4 +2189,7 @@ int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
void amdgpu_debugfs_vm_init(struct drm_file *file)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -33,4 +33,5 @@ void amdgpu_debugfs_fence_init(struct amdgpu_device *adev);
|
|||
void amdgpu_debugfs_firmware_init(struct amdgpu_device *adev);
|
||||
void amdgpu_debugfs_gem_init(struct amdgpu_device *adev);
|
||||
void amdgpu_debugfs_mes_event_log_init(struct amdgpu_device *adev);
|
||||
void amdgpu_debugfs_vm_init(struct drm_file *file);
|
||||
|
||||
|
|
|
|||
|
|
@ -1395,6 +1395,8 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
|
|||
if (r)
|
||||
goto error_pasid;
|
||||
|
||||
amdgpu_debugfs_vm_init(file_priv);
|
||||
|
||||
r = amdgpu_vm_init(adev, &fpriv->vm, fpriv->xcp_id);
|
||||
if (r)
|
||||
goto error_pasid;
|
||||
|
|
|
|||
|
|
@ -318,6 +318,10 @@ amdgpu_userq_destroy(struct drm_file *filp, int queue_id)
|
|||
amdgpu_bo_unreserve(queue->db_obj.obj);
|
||||
}
|
||||
amdgpu_bo_unref(&queue->db_obj.obj);
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
debugfs_remove_recursive(queue->debugfs_queue);
|
||||
#endif
|
||||
r = amdgpu_userq_unmap_helper(uq_mgr, queue);
|
||||
amdgpu_userq_cleanup(uq_mgr, queue, queue_id);
|
||||
mutex_unlock(&uq_mgr->userq_mutex);
|
||||
|
|
@ -343,6 +347,46 @@ static int amdgpu_userq_priority_permit(struct drm_file *filp,
|
|||
return -EACCES;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
static int amdgpu_mqd_info_read(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct amdgpu_usermode_queue *queue = m->private;
|
||||
struct amdgpu_bo *bo;
|
||||
int r;
|
||||
|
||||
if (!queue || !queue->mqd.obj)
|
||||
return -EINVAL;
|
||||
|
||||
bo = amdgpu_bo_ref(queue->mqd.obj);
|
||||
r = amdgpu_bo_reserve(bo, true);
|
||||
if (r) {
|
||||
amdgpu_bo_unref(&bo);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
seq_printf(m, "queue_type %d\n", queue->queue_type);
|
||||
seq_printf(m, "mqd_gpu_address: 0x%llx\n", amdgpu_bo_gpu_offset(queue->mqd.obj));
|
||||
|
||||
amdgpu_bo_unreserve(bo);
|
||||
amdgpu_bo_unref(&bo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_mqd_info_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, amdgpu_mqd_info_read, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations amdgpu_mqd_info_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = amdgpu_mqd_info_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int
|
||||
amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
||||
{
|
||||
|
|
@ -352,6 +396,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
const struct amdgpu_userq_funcs *uq_funcs;
|
||||
struct amdgpu_usermode_queue *queue;
|
||||
struct amdgpu_db_info db_info;
|
||||
char *queue_name;
|
||||
bool skip_map_queue;
|
||||
uint64_t index;
|
||||
int qid, r = 0;
|
||||
|
|
@ -475,6 +520,16 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
}
|
||||
}
|
||||
|
||||
queue_name = kasprintf(GFP_KERNEL, "queue-%d", qid);
|
||||
if (!queue_name)
|
||||
return -ENOMEM;
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
/* Queue dentry per client to hold MQD information */
|
||||
queue->debugfs_queue = debugfs_create_dir(queue_name, filp->debugfs_client);
|
||||
debugfs_create_file("mqd_info", 0444, queue->debugfs_queue, queue, &amdgpu_mqd_info_fops);
|
||||
#endif
|
||||
kfree(queue_name);
|
||||
|
||||
args->out.queue_id = qid;
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ struct amdgpu_usermode_queue {
|
|||
struct dma_fence *last_fence;
|
||||
u32 xcp_id;
|
||||
int priority;
|
||||
struct dentry *debugfs_queue;
|
||||
};
|
||||
|
||||
struct amdgpu_userq_funcs {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@
|
|||
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
||||
|
||||
ast-y := \
|
||||
ast_2000.o \
|
||||
ast_2100.o \
|
||||
ast_2300.o \
|
||||
ast_2500.o \
|
||||
ast_2600.o \
|
||||
ast_cursor.o \
|
||||
ast_ddc.o \
|
||||
ast_dp501.o \
|
||||
|
|
|
|||
149
drivers/gpu/drm/ast/ast_2000.c
Normal file
149
drivers/gpu/drm/ast/ast_2000.c
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*/
|
||||
/*
|
||||
* Authors: Dave Airlie <airlied@redhat.com>
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "ast_drv.h"
|
||||
#include "ast_post.h"
|
||||
|
||||
/*
|
||||
* POST
|
||||
*/
|
||||
|
||||
void ast_2000_set_def_ext_reg(struct ast_device *ast)
|
||||
{
|
||||
static const u8 extreginfo[] = { 0x0f, 0x04, 0x1c, 0xff };
|
||||
u8 i, index, reg;
|
||||
const u8 *ext_reg_info;
|
||||
|
||||
/* reset scratch */
|
||||
for (i = 0x81; i <= 0x9f; i++)
|
||||
ast_set_index_reg(ast, AST_IO_VGACRI, i, 0x00);
|
||||
|
||||
ext_reg_info = extreginfo;
|
||||
index = 0xa0;
|
||||
while (*ext_reg_info != 0xff) {
|
||||
ast_set_index_reg_mask(ast, AST_IO_VGACRI, index, 0x00, *ext_reg_info);
|
||||
index++;
|
||||
ext_reg_info++;
|
||||
}
|
||||
|
||||
/* disable standard IO/MEM decode if secondary */
|
||||
/* ast_set_index_reg-mask(ast, AST_IO_VGACRI, 0xa1, 0xff, 0x3); */
|
||||
|
||||
/* Set Ext. Default */
|
||||
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x8c, 0x00, 0x01);
|
||||
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb7, 0x00, 0x00);
|
||||
|
||||
/* Enable RAMDAC for A1 */
|
||||
reg = 0x04;
|
||||
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0xff, reg);
|
||||
}
|
||||
|
||||
static const struct ast_dramstruct ast2000_dram_table_data[] = {
|
||||
{ 0x0108, 0x00000000 },
|
||||
{ 0x0120, 0x00004a21 },
|
||||
AST_DRAMSTRUCT_UDELAY(67u),
|
||||
{ 0x0000, 0xFFFFFFFF },
|
||||
AST_DRAMSTRUCT_INIT(DRAM_TYPE, 0x00000089),
|
||||
{ 0x0008, 0x22331353 },
|
||||
{ 0x000C, 0x0d07000b },
|
||||
{ 0x0010, 0x11113333 },
|
||||
{ 0x0020, 0x00110350 },
|
||||
{ 0x0028, 0x1e0828f0 },
|
||||
{ 0x0024, 0x00000001 },
|
||||
{ 0x001C, 0x00000000 },
|
||||
{ 0x0014, 0x00000003 },
|
||||
AST_DRAMSTRUCT_UDELAY(67u),
|
||||
{ 0x0018, 0x00000131 },
|
||||
{ 0x0014, 0x00000001 },
|
||||
AST_DRAMSTRUCT_UDELAY(67u),
|
||||
{ 0x0018, 0x00000031 },
|
||||
{ 0x0014, 0x00000001 },
|
||||
AST_DRAMSTRUCT_UDELAY(67u),
|
||||
{ 0x0028, 0x1e0828f1 },
|
||||
{ 0x0024, 0x00000003 },
|
||||
{ 0x002C, 0x1f0f28fb },
|
||||
{ 0x0030, 0xFFFFFE01 },
|
||||
AST_DRAMSTRUCT_INVALID,
|
||||
};
|
||||
|
||||
static void ast_post_chip_2000(struct ast_device *ast)
|
||||
{
|
||||
u8 j;
|
||||
u32 temp, i;
|
||||
const struct ast_dramstruct *dram_reg_info;
|
||||
|
||||
j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff);
|
||||
|
||||
if ((j & 0x80) == 0) { /* VGA only */
|
||||
dram_reg_info = ast2000_dram_table_data;
|
||||
ast_write32(ast, 0xf004, 0x1e6e0000);
|
||||
ast_write32(ast, 0xf000, 0x1);
|
||||
ast_write32(ast, 0x10100, 0xa8);
|
||||
|
||||
do {
|
||||
;
|
||||
} while (ast_read32(ast, 0x10100) != 0xa8);
|
||||
|
||||
while (!AST_DRAMSTRUCT_IS(dram_reg_info, INVALID)) {
|
||||
if (AST_DRAMSTRUCT_IS(dram_reg_info, UDELAY)) {
|
||||
for (i = 0; i < 15; i++)
|
||||
udelay(dram_reg_info->data);
|
||||
} else {
|
||||
ast_write32(ast, 0x10000 + dram_reg_info->index,
|
||||
dram_reg_info->data);
|
||||
}
|
||||
dram_reg_info++;
|
||||
}
|
||||
|
||||
temp = ast_read32(ast, 0x10140);
|
||||
ast_write32(ast, 0x10140, temp | 0x40);
|
||||
}
|
||||
|
||||
/* wait ready */
|
||||
do {
|
||||
j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff);
|
||||
} while ((j & 0x40) == 0);
|
||||
}
|
||||
|
||||
int ast_2000_post(struct ast_device *ast)
|
||||
{
|
||||
ast_2000_set_def_ext_reg(ast);
|
||||
|
||||
if (ast->config_mode == ast_use_p2a) {
|
||||
ast_post_chip_2000(ast);
|
||||
} else {
|
||||
if (ast->tx_chip == AST_TX_SIL164) {
|
||||
/* Enable DVO */
|
||||
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
348
drivers/gpu/drm/ast/ast_2100.c
Normal file
348
drivers/gpu/drm/ast/ast_2100.c
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*/
|
||||
/*
|
||||
* Authors: Dave Airlie <airlied@redhat.com>
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "ast_drv.h"
|
||||
#include "ast_post.h"
|
||||
|
||||
/*
|
||||
* POST
|
||||
*/
|
||||
|
||||
static const struct ast_dramstruct ast1100_dram_table_data[] = {
|
||||
{ 0x2000, 0x1688a8a8 },
|
||||
{ 0x2020, 0x000041f0 },
|
||||
AST_DRAMSTRUCT_UDELAY(67u),
|
||||
{ 0x0000, 0xfc600309 },
|
||||
{ 0x006C, 0x00909090 },
|
||||
{ 0x0064, 0x00050000 },
|
||||
AST_DRAMSTRUCT_INIT(DRAM_TYPE, 0x00000585),
|
||||
{ 0x0008, 0x0011030f },
|
||||
{ 0x0010, 0x22201724 },
|
||||
{ 0x0018, 0x1e29011a },
|
||||
{ 0x0020, 0x00c82222 },
|
||||
{ 0x0014, 0x01001523 },
|
||||
{ 0x001C, 0x1024010d },
|
||||
{ 0x0024, 0x00cb2522 },
|
||||
{ 0x0038, 0xffffff82 },
|
||||
{ 0x003C, 0x00000000 },
|
||||
{ 0x0040, 0x00000000 },
|
||||
{ 0x0044, 0x00000000 },
|
||||
{ 0x0048, 0x00000000 },
|
||||
{ 0x004C, 0x00000000 },
|
||||
{ 0x0050, 0x00000000 },
|
||||
{ 0x0054, 0x00000000 },
|
||||
{ 0x0058, 0x00000000 },
|
||||
{ 0x005C, 0x00000000 },
|
||||
{ 0x0060, 0x032aa02a },
|
||||
{ 0x0064, 0x002d3000 },
|
||||
{ 0x0068, 0x00000000 },
|
||||
{ 0x0070, 0x00000000 },
|
||||
{ 0x0074, 0x00000000 },
|
||||
{ 0x0078, 0x00000000 },
|
||||
{ 0x007C, 0x00000000 },
|
||||
{ 0x0034, 0x00000001 },
|
||||
AST_DRAMSTRUCT_UDELAY(67u),
|
||||
{ 0x002C, 0x00000732 },
|
||||
{ 0x0030, 0x00000040 },
|
||||
{ 0x0028, 0x00000005 },
|
||||
{ 0x0028, 0x00000007 },
|
||||
{ 0x0028, 0x00000003 },
|
||||
{ 0x0028, 0x00000001 },
|
||||
{ 0x000C, 0x00005a08 },
|
||||
{ 0x002C, 0x00000632 },
|
||||
{ 0x0028, 0x00000001 },
|
||||
{ 0x0030, 0x000003c0 },
|
||||
{ 0x0028, 0x00000003 },
|
||||
{ 0x0030, 0x00000040 },
|
||||
{ 0x0028, 0x00000003 },
|
||||
{ 0x000C, 0x00005a21 },
|
||||
{ 0x0034, 0x00007c03 },
|
||||
{ 0x0120, 0x00004c41 },
|
||||
AST_DRAMSTRUCT_INVALID,
|
||||
};
|
||||
|
||||
static const struct ast_dramstruct ast2100_dram_table_data[] = {
|
||||
{ 0x2000, 0x1688a8a8 },
|
||||
{ 0x2020, 0x00004120 },
|
||||
AST_DRAMSTRUCT_UDELAY(67u),
|
||||
{ 0x0000, 0xfc600309 },
|
||||
{ 0x006C, 0x00909090 },
|
||||
{ 0x0064, 0x00070000 },
|
||||
AST_DRAMSTRUCT_INIT(DRAM_TYPE, 0x00000489),
|
||||
{ 0x0008, 0x0011030f },
|
||||
{ 0x0010, 0x32302926 },
|
||||
{ 0x0018, 0x274c0122 },
|
||||
{ 0x0020, 0x00ce2222 },
|
||||
{ 0x0014, 0x01001523 },
|
||||
{ 0x001C, 0x1024010d },
|
||||
{ 0x0024, 0x00cb2522 },
|
||||
{ 0x0038, 0xffffff82 },
|
||||
{ 0x003C, 0x00000000 },
|
||||
{ 0x0040, 0x00000000 },
|
||||
{ 0x0044, 0x00000000 },
|
||||
{ 0x0048, 0x00000000 },
|
||||
{ 0x004C, 0x00000000 },
|
||||
{ 0x0050, 0x00000000 },
|
||||
{ 0x0054, 0x00000000 },
|
||||
{ 0x0058, 0x00000000 },
|
||||
{ 0x005C, 0x00000000 },
|
||||
{ 0x0060, 0x0f2aa02a },
|
||||
{ 0x0064, 0x003f3005 },
|
||||
{ 0x0068, 0x02020202 },
|
||||
{ 0x0070, 0x00000000 },
|
||||
{ 0x0074, 0x00000000 },
|
||||
{ 0x0078, 0x00000000 },
|
||||
{ 0x007C, 0x00000000 },
|
||||
{ 0x0034, 0x00000001 },
|
||||
AST_DRAMSTRUCT_UDELAY(67u),
|
||||
{ 0x002C, 0x00000942 },
|
||||
{ 0x0030, 0x00000040 },
|
||||
{ 0x0028, 0x00000005 },
|
||||
{ 0x0028, 0x00000007 },
|
||||
{ 0x0028, 0x00000003 },
|
||||
{ 0x0028, 0x00000001 },
|
||||
{ 0x000C, 0x00005a08 },
|
||||
{ 0x002C, 0x00000842 },
|
||||
{ 0x0028, 0x00000001 },
|
||||
{ 0x0030, 0x000003c0 },
|
||||
{ 0x0028, 0x00000003 },
|
||||
{ 0x0030, 0x00000040 },
|
||||
{ 0x0028, 0x00000003 },
|
||||
{ 0x000C, 0x00005a21 },
|
||||
{ 0x0034, 0x00007c03 },
|
||||
{ 0x0120, 0x00005061 },
|
||||
AST_DRAMSTRUCT_INVALID,
|
||||
};
|
||||
|
||||
/*
|
||||
* AST2100/2150 DLL CBR Setting
|
||||
*/
|
||||
#define CBR_SIZE_AST2150 ((16 << 10) - 1)
|
||||
#define CBR_PASSNUM_AST2150 5
|
||||
#define CBR_THRESHOLD_AST2150 10
|
||||
#define CBR_THRESHOLD2_AST2150 10
|
||||
#define TIMEOUT_AST2150 5000000
|
||||
|
||||
#define CBR_PATNUM_AST2150 8
|
||||
|
||||
static const u32 pattern_AST2150[14] = {
|
||||
0xFF00FF00,
|
||||
0xCC33CC33,
|
||||
0xAA55AA55,
|
||||
0xFFFE0001,
|
||||
0x683501FE,
|
||||
0x0F1929B0,
|
||||
0x2D0B4346,
|
||||
0x60767F02,
|
||||
0x6FBE36A6,
|
||||
0x3A253035,
|
||||
0x3019686D,
|
||||
0x41C6167E,
|
||||
0x620152BF,
|
||||
0x20F050E0
|
||||
};
|
||||
|
||||
static u32 mmctestburst2_ast2150(struct ast_device *ast, u32 datagen)
|
||||
{
|
||||
u32 data, timeout;
|
||||
|
||||
ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
|
||||
ast_moutdwm(ast, 0x1e6e0070, 0x00000001 | (datagen << 3));
|
||||
timeout = 0;
|
||||
do {
|
||||
data = ast_mindwm(ast, 0x1e6e0070) & 0x40;
|
||||
if (++timeout > TIMEOUT_AST2150) {
|
||||
ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
|
||||
return 0xffffffff;
|
||||
}
|
||||
} while (!data);
|
||||
ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
|
||||
ast_moutdwm(ast, 0x1e6e0070, 0x00000003 | (datagen << 3));
|
||||
timeout = 0;
|
||||
do {
|
||||
data = ast_mindwm(ast, 0x1e6e0070) & 0x40;
|
||||
if (++timeout > TIMEOUT_AST2150) {
|
||||
ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
|
||||
return 0xffffffff;
|
||||
}
|
||||
} while (!data);
|
||||
data = (ast_mindwm(ast, 0x1e6e0070) & 0x80) >> 7;
|
||||
ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
|
||||
return data;
|
||||
}
|
||||
|
||||
static int cbrtest_ast2150(struct ast_device *ast)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
if (mmctestburst2_ast2150(ast, i))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cbrscan_ast2150(struct ast_device *ast, int busw)
|
||||
{
|
||||
u32 patcnt, loop;
|
||||
|
||||
for (patcnt = 0; patcnt < CBR_PATNUM_AST2150; patcnt++) {
|
||||
ast_moutdwm(ast, 0x1e6e007c, pattern_AST2150[patcnt]);
|
||||
for (loop = 0; loop < CBR_PASSNUM_AST2150; loop++) {
|
||||
if (cbrtest_ast2150(ast))
|
||||
break;
|
||||
}
|
||||
if (loop == CBR_PASSNUM_AST2150)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void cbrdlli_ast2150(struct ast_device *ast, int busw)
|
||||
{
|
||||
u32 dll_min[4], dll_max[4], dlli, data, passcnt;
|
||||
|
||||
cbr_start:
|
||||
dll_min[0] = 0xff;
|
||||
dll_min[1] = 0xff;
|
||||
dll_min[2] = 0xff;
|
||||
dll_min[3] = 0xff;
|
||||
dll_max[0] = 0x00;
|
||||
dll_max[1] = 0x00;
|
||||
dll_max[2] = 0x00;
|
||||
dll_max[3] = 0x00;
|
||||
passcnt = 0;
|
||||
|
||||
for (dlli = 0; dlli < 100; dlli++) {
|
||||
ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24));
|
||||
data = cbrscan_ast2150(ast, busw);
|
||||
if (data != 0) {
|
||||
if (data & 0x1) {
|
||||
if (dll_min[0] > dlli)
|
||||
dll_min[0] = dlli;
|
||||
if (dll_max[0] < dlli)
|
||||
dll_max[0] = dlli;
|
||||
}
|
||||
passcnt++;
|
||||
} else if (passcnt >= CBR_THRESHOLD_AST2150) {
|
||||
goto cbr_start;
|
||||
}
|
||||
}
|
||||
if (dll_max[0] == 0 || (dll_max[0] - dll_min[0]) < CBR_THRESHOLD_AST2150)
|
||||
goto cbr_start;
|
||||
|
||||
dlli = dll_min[0] + (((dll_max[0] - dll_min[0]) * 7) >> 4);
|
||||
ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24));
|
||||
}
|
||||
|
||||
static void ast_post_chip_2100(struct ast_device *ast)
|
||||
{
|
||||
u8 j;
|
||||
u32 data, temp, i;
|
||||
const struct ast_dramstruct *dram_reg_info;
|
||||
|
||||
j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff);
|
||||
|
||||
if ((j & 0x80) == 0) { /* VGA only */
|
||||
if (ast->chip == AST2100 || ast->chip == AST2200)
|
||||
dram_reg_info = ast2100_dram_table_data;
|
||||
else
|
||||
dram_reg_info = ast1100_dram_table_data;
|
||||
|
||||
ast_write32(ast, 0xf004, 0x1e6e0000);
|
||||
ast_write32(ast, 0xf000, 0x1);
|
||||
ast_write32(ast, 0x12000, 0x1688A8A8);
|
||||
do {
|
||||
;
|
||||
} while (ast_read32(ast, 0x12000) != 0x01);
|
||||
|
||||
ast_write32(ast, 0x10000, 0xfc600309);
|
||||
do {
|
||||
;
|
||||
} while (ast_read32(ast, 0x10000) != 0x01);
|
||||
|
||||
while (!AST_DRAMSTRUCT_IS(dram_reg_info, INVALID)) {
|
||||
if (AST_DRAMSTRUCT_IS(dram_reg_info, UDELAY)) {
|
||||
for (i = 0; i < 15; i++)
|
||||
udelay(dram_reg_info->data);
|
||||
} else if (AST_DRAMSTRUCT_IS(dram_reg_info, DRAM_TYPE)) {
|
||||
data = dram_reg_info->data;
|
||||
if (ast->dram_type == AST_DRAM_1Gx16)
|
||||
data = 0x00000d89;
|
||||
else if (ast->dram_type == AST_DRAM_1Gx32)
|
||||
data = 0x00000c8d;
|
||||
|
||||
temp = ast_read32(ast, 0x12070);
|
||||
temp &= 0xc;
|
||||
temp <<= 2;
|
||||
ast_write32(ast, 0x10000 + dram_reg_info->index, data | temp);
|
||||
} else {
|
||||
ast_write32(ast, 0x10000 + dram_reg_info->index,
|
||||
dram_reg_info->data);
|
||||
}
|
||||
dram_reg_info++;
|
||||
}
|
||||
|
||||
/* AST 2100/2150 DRAM calibration */
|
||||
data = ast_read32(ast, 0x10120);
|
||||
if (data == 0x5061) { /* 266Mhz */
|
||||
data = ast_read32(ast, 0x10004);
|
||||
if (data & 0x40)
|
||||
cbrdlli_ast2150(ast, 16); /* 16 bits */
|
||||
else
|
||||
cbrdlli_ast2150(ast, 32); /* 32 bits */
|
||||
}
|
||||
|
||||
temp = ast_read32(ast, 0x1200c);
|
||||
ast_write32(ast, 0x1200c, temp & 0xfffffffd);
|
||||
temp = ast_read32(ast, 0x12040);
|
||||
ast_write32(ast, 0x12040, temp | 0x40);
|
||||
}
|
||||
|
||||
/* wait ready */
|
||||
do {
|
||||
j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff);
|
||||
} while ((j & 0x40) == 0);
|
||||
}
|
||||
|
||||
int ast_2100_post(struct ast_device *ast)
|
||||
{
|
||||
ast_2000_set_def_ext_reg(ast);
|
||||
|
||||
if (ast->config_mode == ast_use_p2a) {
|
||||
ast_post_chip_2100(ast);
|
||||
} else {
|
||||
if (ast->tx_chip == AST_TX_SIL164) {
|
||||
/* Enable DVO */
|
||||
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
1328
drivers/gpu/drm/ast/ast_2300.c
Normal file
1328
drivers/gpu/drm/ast/ast_2300.c
Normal file
File diff suppressed because it is too large
Load Diff
569
drivers/gpu/drm/ast/ast_2500.c
Normal file
569
drivers/gpu/drm/ast/ast_2500.c
Normal file
|
|
@ -0,0 +1,569 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*/
|
||||
/*
|
||||
* Authors: Dave Airlie <airlied@redhat.com>
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "ast_drv.h"
|
||||
#include "ast_post.h"
|
||||
|
||||
/*
|
||||
* POST
|
||||
*/
|
||||
|
||||
/*
|
||||
* AST2500 DRAM settings modules
|
||||
*/
|
||||
|
||||
#define REGTBL_NUM 17
|
||||
#define REGIDX_010 0
|
||||
#define REGIDX_014 1
|
||||
#define REGIDX_018 2
|
||||
#define REGIDX_020 3
|
||||
#define REGIDX_024 4
|
||||
#define REGIDX_02C 5
|
||||
#define REGIDX_030 6
|
||||
#define REGIDX_214 7
|
||||
#define REGIDX_2E0 8
|
||||
#define REGIDX_2E4 9
|
||||
#define REGIDX_2E8 10
|
||||
#define REGIDX_2EC 11
|
||||
#define REGIDX_2F0 12
|
||||
#define REGIDX_2F4 13
|
||||
#define REGIDX_2F8 14
|
||||
#define REGIDX_RFC 15
|
||||
#define REGIDX_PLL 16
|
||||
|
||||
static const u32 ast2500_ddr3_1600_timing_table[REGTBL_NUM] = {
|
||||
0x64604D38, /* 0x010 */
|
||||
0x29690599, /* 0x014 */
|
||||
0x00000300, /* 0x018 */
|
||||
0x00000000, /* 0x020 */
|
||||
0x00000000, /* 0x024 */
|
||||
0x02181E70, /* 0x02C */
|
||||
0x00000040, /* 0x030 */
|
||||
0x00000024, /* 0x214 */
|
||||
0x02001300, /* 0x2E0 */
|
||||
0x0E0000A0, /* 0x2E4 */
|
||||
0x000E001B, /* 0x2E8 */
|
||||
0x35B8C105, /* 0x2EC */
|
||||
0x08090408, /* 0x2F0 */
|
||||
0x9B000800, /* 0x2F4 */
|
||||
0x0E400A00, /* 0x2F8 */
|
||||
0x9971452F, /* tRFC */
|
||||
0x000071C1 /* PLL */
|
||||
};
|
||||
|
||||
static const u32 ast2500_ddr4_1600_timing_table[REGTBL_NUM] = {
|
||||
0x63604E37, /* 0x010 */
|
||||
0xE97AFA99, /* 0x014 */
|
||||
0x00019000, /* 0x018 */
|
||||
0x08000000, /* 0x020 */
|
||||
0x00000400, /* 0x024 */
|
||||
0x00000410, /* 0x02C */
|
||||
0x00000101, /* 0x030 */
|
||||
0x00000024, /* 0x214 */
|
||||
0x03002900, /* 0x2E0 */
|
||||
0x0E0000A0, /* 0x2E4 */
|
||||
0x000E001C, /* 0x2E8 */
|
||||
0x35B8C106, /* 0x2EC */
|
||||
0x08080607, /* 0x2F0 */
|
||||
0x9B000900, /* 0x2F4 */
|
||||
0x0E400A00, /* 0x2F8 */
|
||||
0x99714545, /* tRFC */
|
||||
0x000071C1 /* PLL */
|
||||
};
|
||||
|
||||
#define TIMEOUT 5000000
|
||||
|
||||
void ast_2500_patch_ahb(void __iomem *regs)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
/* Clear bus lock condition */
|
||||
__ast_moutdwm(regs, 0x1e600000, 0xAEED1A03);
|
||||
__ast_moutdwm(regs, 0x1e600084, 0x00010000);
|
||||
__ast_moutdwm(regs, 0x1e600088, 0x00000000);
|
||||
__ast_moutdwm(regs, 0x1e6e2000, 0x1688A8A8);
|
||||
|
||||
data = __ast_mindwm(regs, 0x1e6e2070);
|
||||
if (data & 0x08000000) { /* check fast reset */
|
||||
/*
|
||||
* If "Fast restet" is enabled for ARM-ICE debugger,
|
||||
* then WDT needs to enable, that
|
||||
* WDT04 is WDT#1 Reload reg.
|
||||
* WDT08 is WDT#1 counter restart reg to avoid system deadlock
|
||||
* WDT0C is WDT#1 control reg
|
||||
* [6:5]:= 01:Full chip
|
||||
* [4]:= 1:1MHz clock source
|
||||
* [1]:= 1:WDT will be cleeared and disabled after timeout occurs
|
||||
* [0]:= 1:WDT enable
|
||||
*/
|
||||
__ast_moutdwm(regs, 0x1E785004, 0x00000010);
|
||||
__ast_moutdwm(regs, 0x1E785008, 0x00004755);
|
||||
__ast_moutdwm(regs, 0x1E78500c, 0x00000033);
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
do {
|
||||
__ast_moutdwm(regs, 0x1e6e2000, 0x1688A8A8);
|
||||
data = __ast_mindwm(regs, 0x1e6e2000);
|
||||
} while (data != 1);
|
||||
|
||||
__ast_moutdwm(regs, 0x1e6e207c, 0x08000000); /* clear fast reset */
|
||||
}
|
||||
|
||||
static bool mmc_test_single_2500(struct ast_device *ast, u32 datagen)
|
||||
{
|
||||
return mmc_test(ast, datagen, 0x85);
|
||||
}
|
||||
|
||||
static bool cbr_test_2500(struct ast_device *ast)
|
||||
{
|
||||
ast_moutdwm(ast, 0x1E6E0074, 0x0000FFFF);
|
||||
ast_moutdwm(ast, 0x1E6E007C, 0xFF00FF00);
|
||||
if (!mmc_test_burst(ast, 0))
|
||||
return false;
|
||||
if (!mmc_test_single_2500(ast, 0))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ddr_test_2500(struct ast_device *ast)
|
||||
{
|
||||
ast_moutdwm(ast, 0x1E6E0074, 0x0000FFFF);
|
||||
ast_moutdwm(ast, 0x1E6E007C, 0xFF00FF00);
|
||||
if (!mmc_test_burst(ast, 0))
|
||||
return false;
|
||||
if (!mmc_test_burst(ast, 1))
|
||||
return false;
|
||||
if (!mmc_test_burst(ast, 2))
|
||||
return false;
|
||||
if (!mmc_test_burst(ast, 3))
|
||||
return false;
|
||||
if (!mmc_test_single_2500(ast, 0))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ddr_init_common_2500(struct ast_device *ast)
|
||||
{
|
||||
ast_moutdwm(ast, 0x1E6E0034, 0x00020080);
|
||||
ast_moutdwm(ast, 0x1E6E0008, 0x2003000F);
|
||||
ast_moutdwm(ast, 0x1E6E0038, 0x00000FFF);
|
||||
ast_moutdwm(ast, 0x1E6E0040, 0x88448844);
|
||||
ast_moutdwm(ast, 0x1E6E0044, 0x24422288);
|
||||
ast_moutdwm(ast, 0x1E6E0048, 0x22222222);
|
||||
ast_moutdwm(ast, 0x1E6E004C, 0x22222222);
|
||||
ast_moutdwm(ast, 0x1E6E0050, 0x80000000);
|
||||
ast_moutdwm(ast, 0x1E6E0208, 0x00000000);
|
||||
ast_moutdwm(ast, 0x1E6E0218, 0x00000000);
|
||||
ast_moutdwm(ast, 0x1E6E0220, 0x00000000);
|
||||
ast_moutdwm(ast, 0x1E6E0228, 0x00000000);
|
||||
ast_moutdwm(ast, 0x1E6E0230, 0x00000000);
|
||||
ast_moutdwm(ast, 0x1E6E02A8, 0x00000000);
|
||||
ast_moutdwm(ast, 0x1E6E02B0, 0x00000000);
|
||||
ast_moutdwm(ast, 0x1E6E0240, 0x86000000);
|
||||
ast_moutdwm(ast, 0x1E6E0244, 0x00008600);
|
||||
ast_moutdwm(ast, 0x1E6E0248, 0x80000000);
|
||||
ast_moutdwm(ast, 0x1E6E024C, 0x80808080);
|
||||
}
|
||||
|
||||
static void ddr_phy_init_2500(struct ast_device *ast)
|
||||
{
|
||||
u32 data, pass, timecnt;
|
||||
|
||||
pass = 0;
|
||||
ast_moutdwm(ast, 0x1E6E0060, 0x00000005);
|
||||
while (!pass) {
|
||||
for (timecnt = 0; timecnt < TIMEOUT; timecnt++) {
|
||||
data = ast_mindwm(ast, 0x1E6E0060) & 0x1;
|
||||
if (!data)
|
||||
break;
|
||||
}
|
||||
if (timecnt != TIMEOUT) {
|
||||
data = ast_mindwm(ast, 0x1E6E0300) & 0x000A0000;
|
||||
if (!data)
|
||||
pass = 1;
|
||||
}
|
||||
if (!pass) {
|
||||
ast_moutdwm(ast, 0x1E6E0060, 0x00000000);
|
||||
udelay(10); /* delay 10 us */
|
||||
ast_moutdwm(ast, 0x1E6E0060, 0x00000005);
|
||||
}
|
||||
}
|
||||
|
||||
ast_moutdwm(ast, 0x1E6E0060, 0x00000006);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check DRAM Size
|
||||
* 1Gb : 0x80000000 ~ 0x87FFFFFF
|
||||
* 2Gb : 0x80000000 ~ 0x8FFFFFFF
|
||||
* 4Gb : 0x80000000 ~ 0x9FFFFFFF
|
||||
* 8Gb : 0x80000000 ~ 0xBFFFFFFF
|
||||
*/
|
||||
static void check_dram_size_2500(struct ast_device *ast, u32 tRFC)
|
||||
{
|
||||
u32 reg_04, reg_14;
|
||||
|
||||
reg_04 = ast_mindwm(ast, 0x1E6E0004) & 0xfffffffc;
|
||||
reg_14 = ast_mindwm(ast, 0x1E6E0014) & 0xffffff00;
|
||||
|
||||
ast_moutdwm(ast, 0xA0100000, 0x41424344);
|
||||
ast_moutdwm(ast, 0x90100000, 0x35363738);
|
||||
ast_moutdwm(ast, 0x88100000, 0x292A2B2C);
|
||||
ast_moutdwm(ast, 0x80100000, 0x1D1E1F10);
|
||||
|
||||
/* Check 8Gbit */
|
||||
if (ast_mindwm(ast, 0xA0100000) == 0x41424344) {
|
||||
reg_04 |= 0x03;
|
||||
reg_14 |= (tRFC >> 24) & 0xFF;
|
||||
/* Check 4Gbit */
|
||||
} else if (ast_mindwm(ast, 0x90100000) == 0x35363738) {
|
||||
reg_04 |= 0x02;
|
||||
reg_14 |= (tRFC >> 16) & 0xFF;
|
||||
/* Check 2Gbit */
|
||||
} else if (ast_mindwm(ast, 0x88100000) == 0x292A2B2C) {
|
||||
reg_04 |= 0x01;
|
||||
reg_14 |= (tRFC >> 8) & 0xFF;
|
||||
} else {
|
||||
reg_14 |= tRFC & 0xFF;
|
||||
}
|
||||
ast_moutdwm(ast, 0x1E6E0004, reg_04);
|
||||
ast_moutdwm(ast, 0x1E6E0014, reg_14);
|
||||
}
|
||||
|
||||
static void enable_cache_2500(struct ast_device *ast)
|
||||
{
|
||||
u32 reg_04, data;
|
||||
|
||||
reg_04 = ast_mindwm(ast, 0x1E6E0004);
|
||||
ast_moutdwm(ast, 0x1E6E0004, reg_04 | 0x1000);
|
||||
|
||||
do
|
||||
data = ast_mindwm(ast, 0x1E6E0004);
|
||||
while (!(data & 0x80000));
|
||||
ast_moutdwm(ast, 0x1E6E0004, reg_04 | 0x400);
|
||||
}
|
||||
|
||||
static void set_mpll_2500(struct ast_device *ast)
|
||||
{
|
||||
u32 addr, data, param;
|
||||
|
||||
/* Reset MMC */
|
||||
ast_moutdwm(ast, 0x1E6E0000, 0xFC600309);
|
||||
ast_moutdwm(ast, 0x1E6E0034, 0x00020080);
|
||||
for (addr = 0x1e6e0004; addr < 0x1e6e0090;) {
|
||||
ast_moutdwm(ast, addr, 0x0);
|
||||
addr += 4;
|
||||
}
|
||||
ast_moutdwm(ast, 0x1E6E0034, 0x00020000);
|
||||
|
||||
ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8);
|
||||
data = ast_mindwm(ast, 0x1E6E2070) & 0x00800000;
|
||||
if (data) {
|
||||
/* CLKIN = 25MHz */
|
||||
param = 0x930023E0;
|
||||
ast_moutdwm(ast, 0x1E6E2160, 0x00011320);
|
||||
} else {
|
||||
/* CLKIN = 24MHz */
|
||||
param = 0x93002400;
|
||||
}
|
||||
ast_moutdwm(ast, 0x1E6E2020, param);
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
static void reset_mmc_2500(struct ast_device *ast)
|
||||
{
|
||||
ast_moutdwm(ast, 0x1E78505C, 0x00000004);
|
||||
ast_moutdwm(ast, 0x1E785044, 0x00000001);
|
||||
ast_moutdwm(ast, 0x1E785048, 0x00004755);
|
||||
ast_moutdwm(ast, 0x1E78504C, 0x00000013);
|
||||
mdelay(100);
|
||||
ast_moutdwm(ast, 0x1E785054, 0x00000077);
|
||||
ast_moutdwm(ast, 0x1E6E0000, 0xFC600309);
|
||||
}
|
||||
|
||||
static void ddr3_init_2500(struct ast_device *ast, const u32 *ddr_table)
|
||||
{
|
||||
ast_moutdwm(ast, 0x1E6E0004, 0x00000303);
|
||||
ast_moutdwm(ast, 0x1E6E0010, ddr_table[REGIDX_010]);
|
||||
ast_moutdwm(ast, 0x1E6E0014, ddr_table[REGIDX_014]);
|
||||
ast_moutdwm(ast, 0x1E6E0018, ddr_table[REGIDX_018]);
|
||||
ast_moutdwm(ast, 0x1E6E0020, ddr_table[REGIDX_020]); /* MODEREG4/6 */
|
||||
ast_moutdwm(ast, 0x1E6E0024, ddr_table[REGIDX_024]); /* MODEREG5 */
|
||||
ast_moutdwm(ast, 0x1E6E002C, ddr_table[REGIDX_02C] | 0x100); /* MODEREG0/2 */
|
||||
ast_moutdwm(ast, 0x1E6E0030, ddr_table[REGIDX_030]); /* MODEREG1/3 */
|
||||
|
||||
/* DDR PHY Setting */
|
||||
ast_moutdwm(ast, 0x1E6E0200, 0x02492AAE);
|
||||
ast_moutdwm(ast, 0x1E6E0204, 0x00001001);
|
||||
ast_moutdwm(ast, 0x1E6E020C, 0x55E00B0B);
|
||||
ast_moutdwm(ast, 0x1E6E0210, 0x20000000);
|
||||
ast_moutdwm(ast, 0x1E6E0214, ddr_table[REGIDX_214]);
|
||||
ast_moutdwm(ast, 0x1E6E02E0, ddr_table[REGIDX_2E0]);
|
||||
ast_moutdwm(ast, 0x1E6E02E4, ddr_table[REGIDX_2E4]);
|
||||
ast_moutdwm(ast, 0x1E6E02E8, ddr_table[REGIDX_2E8]);
|
||||
ast_moutdwm(ast, 0x1E6E02EC, ddr_table[REGIDX_2EC]);
|
||||
ast_moutdwm(ast, 0x1E6E02F0, ddr_table[REGIDX_2F0]);
|
||||
ast_moutdwm(ast, 0x1E6E02F4, ddr_table[REGIDX_2F4]);
|
||||
ast_moutdwm(ast, 0x1E6E02F8, ddr_table[REGIDX_2F8]);
|
||||
ast_moutdwm(ast, 0x1E6E0290, 0x00100008);
|
||||
ast_moutdwm(ast, 0x1E6E02C0, 0x00000006);
|
||||
|
||||
/* Controller Setting */
|
||||
ast_moutdwm(ast, 0x1E6E0034, 0x00020091);
|
||||
|
||||
/* Wait DDR PHY init done */
|
||||
ddr_phy_init_2500(ast);
|
||||
|
||||
ast_moutdwm(ast, 0x1E6E0120, ddr_table[REGIDX_PLL]);
|
||||
ast_moutdwm(ast, 0x1E6E000C, 0x42AA5C81);
|
||||
ast_moutdwm(ast, 0x1E6E0034, 0x0001AF93);
|
||||
|
||||
check_dram_size_2500(ast, ddr_table[REGIDX_RFC]);
|
||||
enable_cache_2500(ast);
|
||||
ast_moutdwm(ast, 0x1E6E001C, 0x00000008);
|
||||
ast_moutdwm(ast, 0x1E6E0038, 0xFFFFFF00);
|
||||
}
|
||||
|
||||
static void ddr4_init_2500(struct ast_device *ast, const u32 *ddr_table)
|
||||
{
|
||||
u32 data, data2, pass, retrycnt;
|
||||
u32 ddr_vref, phy_vref;
|
||||
u32 min_ddr_vref = 0, min_phy_vref = 0;
|
||||
u32 max_ddr_vref = 0, max_phy_vref = 0;
|
||||
|
||||
ast_moutdwm(ast, 0x1E6E0004, 0x00000313);
|
||||
ast_moutdwm(ast, 0x1E6E0010, ddr_table[REGIDX_010]);
|
||||
ast_moutdwm(ast, 0x1E6E0014, ddr_table[REGIDX_014]);
|
||||
ast_moutdwm(ast, 0x1E6E0018, ddr_table[REGIDX_018]);
|
||||
ast_moutdwm(ast, 0x1E6E0020, ddr_table[REGIDX_020]); /* MODEREG4/6 */
|
||||
ast_moutdwm(ast, 0x1E6E0024, ddr_table[REGIDX_024]); /* MODEREG5 */
|
||||
ast_moutdwm(ast, 0x1E6E002C, ddr_table[REGIDX_02C] | 0x100); /* MODEREG0/2 */
|
||||
ast_moutdwm(ast, 0x1E6E0030, ddr_table[REGIDX_030]); /* MODEREG1/3 */
|
||||
|
||||
/* DDR PHY Setting */
|
||||
ast_moutdwm(ast, 0x1E6E0200, 0x42492AAE);
|
||||
ast_moutdwm(ast, 0x1E6E0204, 0x09002000);
|
||||
ast_moutdwm(ast, 0x1E6E020C, 0x55E00B0B);
|
||||
ast_moutdwm(ast, 0x1E6E0210, 0x20000000);
|
||||
ast_moutdwm(ast, 0x1E6E0214, ddr_table[REGIDX_214]);
|
||||
ast_moutdwm(ast, 0x1E6E02E0, ddr_table[REGIDX_2E0]);
|
||||
ast_moutdwm(ast, 0x1E6E02E4, ddr_table[REGIDX_2E4]);
|
||||
ast_moutdwm(ast, 0x1E6E02E8, ddr_table[REGIDX_2E8]);
|
||||
ast_moutdwm(ast, 0x1E6E02EC, ddr_table[REGIDX_2EC]);
|
||||
ast_moutdwm(ast, 0x1E6E02F0, ddr_table[REGIDX_2F0]);
|
||||
ast_moutdwm(ast, 0x1E6E02F4, ddr_table[REGIDX_2F4]);
|
||||
ast_moutdwm(ast, 0x1E6E02F8, ddr_table[REGIDX_2F8]);
|
||||
ast_moutdwm(ast, 0x1E6E0290, 0x00100008);
|
||||
ast_moutdwm(ast, 0x1E6E02C4, 0x3C183C3C);
|
||||
ast_moutdwm(ast, 0x1E6E02C8, 0x00631E0E);
|
||||
|
||||
/* Controller Setting */
|
||||
ast_moutdwm(ast, 0x1E6E0034, 0x0001A991);
|
||||
|
||||
/* Train PHY Vref first */
|
||||
pass = 0;
|
||||
|
||||
for (retrycnt = 0; retrycnt < 4 && pass == 0; retrycnt++) {
|
||||
max_phy_vref = 0x0;
|
||||
pass = 0;
|
||||
ast_moutdwm(ast, 0x1E6E02C0, 0x00001C06);
|
||||
for (phy_vref = 0x40; phy_vref < 0x80; phy_vref++) {
|
||||
ast_moutdwm(ast, 0x1E6E000C, 0x00000000);
|
||||
ast_moutdwm(ast, 0x1E6E0060, 0x00000000);
|
||||
ast_moutdwm(ast, 0x1E6E02CC, phy_vref | (phy_vref << 8));
|
||||
/* Fire DFI Init */
|
||||
ddr_phy_init_2500(ast);
|
||||
ast_moutdwm(ast, 0x1E6E000C, 0x00005C01);
|
||||
if (cbr_test_2500(ast)) {
|
||||
pass++;
|
||||
data = ast_mindwm(ast, 0x1E6E03D0);
|
||||
data2 = data >> 8;
|
||||
data = data & 0xff;
|
||||
if (data > data2)
|
||||
data = data2;
|
||||
if (max_phy_vref < data) {
|
||||
max_phy_vref = data;
|
||||
min_phy_vref = phy_vref;
|
||||
}
|
||||
} else if (pass > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast_moutdwm(ast, 0x1E6E02CC, min_phy_vref | (min_phy_vref << 8));
|
||||
|
||||
/* Train DDR Vref next */
|
||||
pass = 0;
|
||||
|
||||
for (retrycnt = 0; retrycnt < 4 && pass == 0; retrycnt++) {
|
||||
min_ddr_vref = 0xFF;
|
||||
max_ddr_vref = 0x0;
|
||||
pass = 0;
|
||||
for (ddr_vref = 0x00; ddr_vref < 0x40; ddr_vref++) {
|
||||
ast_moutdwm(ast, 0x1E6E000C, 0x00000000);
|
||||
ast_moutdwm(ast, 0x1E6E0060, 0x00000000);
|
||||
ast_moutdwm(ast, 0x1E6E02C0, 0x00000006 | (ddr_vref << 8));
|
||||
/* Fire DFI Init */
|
||||
ddr_phy_init_2500(ast);
|
||||
ast_moutdwm(ast, 0x1E6E000C, 0x00005C01);
|
||||
if (cbr_test_2500(ast)) {
|
||||
pass++;
|
||||
if (min_ddr_vref > ddr_vref)
|
||||
min_ddr_vref = ddr_vref;
|
||||
if (max_ddr_vref < ddr_vref)
|
||||
max_ddr_vref = ddr_vref;
|
||||
} else if (pass != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ast_moutdwm(ast, 0x1E6E000C, 0x00000000);
|
||||
ast_moutdwm(ast, 0x1E6E0060, 0x00000000);
|
||||
ddr_vref = (min_ddr_vref + max_ddr_vref + 1) >> 1;
|
||||
ast_moutdwm(ast, 0x1E6E02C0, 0x00000006 | (ddr_vref << 8));
|
||||
|
||||
/* Wait DDR PHY init done */
|
||||
ddr_phy_init_2500(ast);
|
||||
|
||||
ast_moutdwm(ast, 0x1E6E0120, ddr_table[REGIDX_PLL]);
|
||||
ast_moutdwm(ast, 0x1E6E000C, 0x42AA5C81);
|
||||
ast_moutdwm(ast, 0x1E6E0034, 0x0001AF93);
|
||||
|
||||
check_dram_size_2500(ast, ddr_table[REGIDX_RFC]);
|
||||
enable_cache_2500(ast);
|
||||
ast_moutdwm(ast, 0x1E6E001C, 0x00000008);
|
||||
ast_moutdwm(ast, 0x1E6E0038, 0xFFFFFF00);
|
||||
}
|
||||
|
||||
static bool ast_dram_init_2500(struct ast_device *ast)
|
||||
{
|
||||
u32 data;
|
||||
u32 max_tries = 5;
|
||||
|
||||
do {
|
||||
if (max_tries-- == 0)
|
||||
return false;
|
||||
set_mpll_2500(ast);
|
||||
reset_mmc_2500(ast);
|
||||
ddr_init_common_2500(ast);
|
||||
|
||||
data = ast_mindwm(ast, 0x1E6E2070);
|
||||
if (data & 0x01000000)
|
||||
ddr4_init_2500(ast, ast2500_ddr4_1600_timing_table);
|
||||
else
|
||||
ddr3_init_2500(ast, ast2500_ddr3_1600_timing_table);
|
||||
} while (!ddr_test_2500(ast));
|
||||
|
||||
ast_moutdwm(ast, 0x1E6E2040, ast_mindwm(ast, 0x1E6E2040) | 0x41);
|
||||
|
||||
/* Patch code */
|
||||
data = ast_mindwm(ast, 0x1E6E200C) & 0xF9FFFFFF;
|
||||
ast_moutdwm(ast, 0x1E6E200C, data | 0x10000000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ast_post_chip_2500(struct ast_device *ast)
|
||||
{
|
||||
struct drm_device *dev = &ast->base;
|
||||
u32 temp;
|
||||
u8 reg;
|
||||
|
||||
reg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff);
|
||||
if ((reg & AST_IO_VGACRD0_VRAM_INIT_STATUS_MASK) == 0) {/* vga only */
|
||||
/* Clear bus lock condition */
|
||||
ast_2500_patch_ahb(ast->regs);
|
||||
|
||||
/* Disable watchdog */
|
||||
ast_moutdwm(ast, 0x1E78502C, 0x00000000);
|
||||
ast_moutdwm(ast, 0x1E78504C, 0x00000000);
|
||||
|
||||
/*
|
||||
* Reset USB port to patch USB unknown device issue
|
||||
* SCU90 is Multi-function Pin Control #5
|
||||
* [29]:= 1:Enable USB2.0 Host port#1 (that the mutually shared USB2.0 Hub
|
||||
* port).
|
||||
* SCU94 is Multi-function Pin Control #6
|
||||
* [14:13]:= 1x:USB2.0 Host2 controller
|
||||
* SCU70 is Hardware Strap reg
|
||||
* [23]:= 1:CLKIN is 25MHz and USBCK1 = 24/48 MHz (determined by
|
||||
* [18]: 0(24)/1(48) MHz)
|
||||
* SCU7C is Write clear reg to SCU70
|
||||
* [23]:= write 1 and then SCU70[23] will be clear as 0b.
|
||||
*/
|
||||
ast_moutdwm(ast, 0x1E6E2090, 0x20000000);
|
||||
ast_moutdwm(ast, 0x1E6E2094, 0x00004000);
|
||||
if (ast_mindwm(ast, 0x1E6E2070) & 0x00800000) {
|
||||
ast_moutdwm(ast, 0x1E6E207C, 0x00800000);
|
||||
mdelay(100);
|
||||
ast_moutdwm(ast, 0x1E6E2070, 0x00800000);
|
||||
}
|
||||
/* Modify eSPI reset pin */
|
||||
temp = ast_mindwm(ast, 0x1E6E2070);
|
||||
if (temp & 0x02000000)
|
||||
ast_moutdwm(ast, 0x1E6E207C, 0x00004000);
|
||||
|
||||
/* Slow down CPU/AHB CLK in VGA only mode */
|
||||
temp = ast_read32(ast, 0x12008);
|
||||
temp |= 0x73;
|
||||
ast_write32(ast, 0x12008, temp);
|
||||
|
||||
if (!ast_dram_init_2500(ast))
|
||||
drm_err(dev, "DRAM init failed !\n");
|
||||
|
||||
temp = ast_mindwm(ast, 0x1e6e2040);
|
||||
ast_moutdwm(ast, 0x1e6e2040, temp | 0x40);
|
||||
}
|
||||
|
||||
/* wait ready */
|
||||
do {
|
||||
reg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff);
|
||||
} while ((reg & 0x40) == 0);
|
||||
}
|
||||
|
||||
int ast_2500_post(struct ast_device *ast)
|
||||
{
|
||||
ast_2300_set_def_ext_reg(ast);
|
||||
|
||||
if (ast->config_mode == ast_use_p2a) {
|
||||
ast_post_chip_2500(ast);
|
||||
} else {
|
||||
if (ast->tx_chip == AST_TX_SIL164) {
|
||||
/* Enable DVO */
|
||||
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
44
drivers/gpu/drm/ast/ast_2600.c
Normal file
44
drivers/gpu/drm/ast/ast_2600.c
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright 2012 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*/
|
||||
/*
|
||||
* Authors: Dave Airlie <airlied@redhat.com>
|
||||
*/
|
||||
|
||||
#include "ast_drv.h"
|
||||
#include "ast_post.h"
|
||||
|
||||
/*
|
||||
* POST
|
||||
*/
|
||||
|
||||
int ast_2600_post(struct ast_device *ast)
|
||||
{
|
||||
ast_2300_set_def_ext_reg(ast);
|
||||
|
||||
if (ast->tx_chip == AST_TX_ASTDP)
|
||||
return ast_dp_launch(ast);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,207 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef AST_DRAM_TABLES_H
|
||||
#define AST_DRAM_TABLES_H
|
||||
|
||||
/* DRAM timing tables */
|
||||
struct ast_dramstruct {
|
||||
u16 index;
|
||||
u32 data;
|
||||
};
|
||||
|
||||
static const struct ast_dramstruct ast2000_dram_table_data[] = {
|
||||
{ 0x0108, 0x00000000 },
|
||||
{ 0x0120, 0x00004a21 },
|
||||
{ 0xFF00, 0x00000043 },
|
||||
{ 0x0000, 0xFFFFFFFF },
|
||||
{ 0x0004, 0x00000089 },
|
||||
{ 0x0008, 0x22331353 },
|
||||
{ 0x000C, 0x0d07000b },
|
||||
{ 0x0010, 0x11113333 },
|
||||
{ 0x0020, 0x00110350 },
|
||||
{ 0x0028, 0x1e0828f0 },
|
||||
{ 0x0024, 0x00000001 },
|
||||
{ 0x001C, 0x00000000 },
|
||||
{ 0x0014, 0x00000003 },
|
||||
{ 0xFF00, 0x00000043 },
|
||||
{ 0x0018, 0x00000131 },
|
||||
{ 0x0014, 0x00000001 },
|
||||
{ 0xFF00, 0x00000043 },
|
||||
{ 0x0018, 0x00000031 },
|
||||
{ 0x0014, 0x00000001 },
|
||||
{ 0xFF00, 0x00000043 },
|
||||
{ 0x0028, 0x1e0828f1 },
|
||||
{ 0x0024, 0x00000003 },
|
||||
{ 0x002C, 0x1f0f28fb },
|
||||
{ 0x0030, 0xFFFFFE01 },
|
||||
{ 0xFFFF, 0xFFFFFFFF }
|
||||
};
|
||||
|
||||
static const struct ast_dramstruct ast1100_dram_table_data[] = {
|
||||
{ 0x2000, 0x1688a8a8 },
|
||||
{ 0x2020, 0x000041f0 },
|
||||
{ 0xFF00, 0x00000043 },
|
||||
{ 0x0000, 0xfc600309 },
|
||||
{ 0x006C, 0x00909090 },
|
||||
{ 0x0064, 0x00050000 },
|
||||
{ 0x0004, 0x00000585 },
|
||||
{ 0x0008, 0x0011030f },
|
||||
{ 0x0010, 0x22201724 },
|
||||
{ 0x0018, 0x1e29011a },
|
||||
{ 0x0020, 0x00c82222 },
|
||||
{ 0x0014, 0x01001523 },
|
||||
{ 0x001C, 0x1024010d },
|
||||
{ 0x0024, 0x00cb2522 },
|
||||
{ 0x0038, 0xffffff82 },
|
||||
{ 0x003C, 0x00000000 },
|
||||
{ 0x0040, 0x00000000 },
|
||||
{ 0x0044, 0x00000000 },
|
||||
{ 0x0048, 0x00000000 },
|
||||
{ 0x004C, 0x00000000 },
|
||||
{ 0x0050, 0x00000000 },
|
||||
{ 0x0054, 0x00000000 },
|
||||
{ 0x0058, 0x00000000 },
|
||||
{ 0x005C, 0x00000000 },
|
||||
{ 0x0060, 0x032aa02a },
|
||||
{ 0x0064, 0x002d3000 },
|
||||
{ 0x0068, 0x00000000 },
|
||||
{ 0x0070, 0x00000000 },
|
||||
{ 0x0074, 0x00000000 },
|
||||
{ 0x0078, 0x00000000 },
|
||||
{ 0x007C, 0x00000000 },
|
||||
{ 0x0034, 0x00000001 },
|
||||
{ 0xFF00, 0x00000043 },
|
||||
{ 0x002C, 0x00000732 },
|
||||
{ 0x0030, 0x00000040 },
|
||||
{ 0x0028, 0x00000005 },
|
||||
{ 0x0028, 0x00000007 },
|
||||
{ 0x0028, 0x00000003 },
|
||||
{ 0x0028, 0x00000001 },
|
||||
{ 0x000C, 0x00005a08 },
|
||||
{ 0x002C, 0x00000632 },
|
||||
{ 0x0028, 0x00000001 },
|
||||
{ 0x0030, 0x000003c0 },
|
||||
{ 0x0028, 0x00000003 },
|
||||
{ 0x0030, 0x00000040 },
|
||||
{ 0x0028, 0x00000003 },
|
||||
{ 0x000C, 0x00005a21 },
|
||||
{ 0x0034, 0x00007c03 },
|
||||
{ 0x0120, 0x00004c41 },
|
||||
{ 0xffff, 0xffffffff },
|
||||
};
|
||||
|
||||
static const struct ast_dramstruct ast2100_dram_table_data[] = {
|
||||
{ 0x2000, 0x1688a8a8 },
|
||||
{ 0x2020, 0x00004120 },
|
||||
{ 0xFF00, 0x00000043 },
|
||||
{ 0x0000, 0xfc600309 },
|
||||
{ 0x006C, 0x00909090 },
|
||||
{ 0x0064, 0x00070000 },
|
||||
{ 0x0004, 0x00000489 },
|
||||
{ 0x0008, 0x0011030f },
|
||||
{ 0x0010, 0x32302926 },
|
||||
{ 0x0018, 0x274c0122 },
|
||||
{ 0x0020, 0x00ce2222 },
|
||||
{ 0x0014, 0x01001523 },
|
||||
{ 0x001C, 0x1024010d },
|
||||
{ 0x0024, 0x00cb2522 },
|
||||
{ 0x0038, 0xffffff82 },
|
||||
{ 0x003C, 0x00000000 },
|
||||
{ 0x0040, 0x00000000 },
|
||||
{ 0x0044, 0x00000000 },
|
||||
{ 0x0048, 0x00000000 },
|
||||
{ 0x004C, 0x00000000 },
|
||||
{ 0x0050, 0x00000000 },
|
||||
{ 0x0054, 0x00000000 },
|
||||
{ 0x0058, 0x00000000 },
|
||||
{ 0x005C, 0x00000000 },
|
||||
{ 0x0060, 0x0f2aa02a },
|
||||
{ 0x0064, 0x003f3005 },
|
||||
{ 0x0068, 0x02020202 },
|
||||
{ 0x0070, 0x00000000 },
|
||||
{ 0x0074, 0x00000000 },
|
||||
{ 0x0078, 0x00000000 },
|
||||
{ 0x007C, 0x00000000 },
|
||||
{ 0x0034, 0x00000001 },
|
||||
{ 0xFF00, 0x00000043 },
|
||||
{ 0x002C, 0x00000942 },
|
||||
{ 0x0030, 0x00000040 },
|
||||
{ 0x0028, 0x00000005 },
|
||||
{ 0x0028, 0x00000007 },
|
||||
{ 0x0028, 0x00000003 },
|
||||
{ 0x0028, 0x00000001 },
|
||||
{ 0x000C, 0x00005a08 },
|
||||
{ 0x002C, 0x00000842 },
|
||||
{ 0x0028, 0x00000001 },
|
||||
{ 0x0030, 0x000003c0 },
|
||||
{ 0x0028, 0x00000003 },
|
||||
{ 0x0030, 0x00000040 },
|
||||
{ 0x0028, 0x00000003 },
|
||||
{ 0x000C, 0x00005a21 },
|
||||
{ 0x0034, 0x00007c03 },
|
||||
{ 0x0120, 0x00005061 },
|
||||
{ 0xffff, 0xffffffff },
|
||||
};
|
||||
|
||||
/*
|
||||
* AST2500 DRAM settings modules
|
||||
*/
|
||||
#define REGTBL_NUM 17
|
||||
#define REGIDX_010 0
|
||||
#define REGIDX_014 1
|
||||
#define REGIDX_018 2
|
||||
#define REGIDX_020 3
|
||||
#define REGIDX_024 4
|
||||
#define REGIDX_02C 5
|
||||
#define REGIDX_030 6
|
||||
#define REGIDX_214 7
|
||||
#define REGIDX_2E0 8
|
||||
#define REGIDX_2E4 9
|
||||
#define REGIDX_2E8 10
|
||||
#define REGIDX_2EC 11
|
||||
#define REGIDX_2F0 12
|
||||
#define REGIDX_2F4 13
|
||||
#define REGIDX_2F8 14
|
||||
#define REGIDX_RFC 15
|
||||
#define REGIDX_PLL 16
|
||||
|
||||
static const u32 ast2500_ddr3_1600_timing_table[REGTBL_NUM] = {
|
||||
0x64604D38, /* 0x010 */
|
||||
0x29690599, /* 0x014 */
|
||||
0x00000300, /* 0x018 */
|
||||
0x00000000, /* 0x020 */
|
||||
0x00000000, /* 0x024 */
|
||||
0x02181E70, /* 0x02C */
|
||||
0x00000040, /* 0x030 */
|
||||
0x00000024, /* 0x214 */
|
||||
0x02001300, /* 0x2E0 */
|
||||
0x0E0000A0, /* 0x2E4 */
|
||||
0x000E001B, /* 0x2E8 */
|
||||
0x35B8C105, /* 0x2EC */
|
||||
0x08090408, /* 0x2F0 */
|
||||
0x9B000800, /* 0x2F4 */
|
||||
0x0E400A00, /* 0x2F8 */
|
||||
0x9971452F, /* tRFC */
|
||||
0x000071C1 /* PLL */
|
||||
};
|
||||
|
||||
static const u32 ast2500_ddr4_1600_timing_table[REGTBL_NUM] = {
|
||||
0x63604E37, /* 0x010 */
|
||||
0xE97AFA99, /* 0x014 */
|
||||
0x00019000, /* 0x018 */
|
||||
0x08000000, /* 0x020 */
|
||||
0x00000400, /* 0x024 */
|
||||
0x00000410, /* 0x02C */
|
||||
0x00000101, /* 0x030 */
|
||||
0x00000024, /* 0x214 */
|
||||
0x03002900, /* 0x2E0 */
|
||||
0x0E0000A0, /* 0x2E4 */
|
||||
0x000E001C, /* 0x2E8 */
|
||||
0x35B8C106, /* 0x2EC */
|
||||
0x08080607, /* 0x2F0 */
|
||||
0x9B000900, /* 0x2F4 */
|
||||
0x0E400A00, /* 0x2F8 */
|
||||
0x99714545, /* tRFC */
|
||||
0x000071C1 /* PLL */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -64,7 +64,7 @@ static const struct drm_driver ast_driver = {
|
|||
.minor = DRIVER_MINOR,
|
||||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
|
||||
DRM_GEM_SHMEM_DRIVER_OPS_NO_MAP_SGT,
|
||||
DRM_GEM_SHMEM_DRIVER_OPS,
|
||||
DRM_FBDEV_SHMEM_DRIVER_OPS,
|
||||
};
|
||||
|
||||
|
|
@ -171,7 +171,7 @@ static int ast_detect_chip(struct pci_dev *pdev,
|
|||
/* Patch AST2500/AST2510 */
|
||||
if ((pdev->revision & 0xf0) == 0x40) {
|
||||
if (!(vgacrd0 & AST_IO_VGACRD0_VRAM_INIT_STATUS_MASK))
|
||||
ast_patch_ahb_2500(regs);
|
||||
ast_2500_patch_ahb(regs);
|
||||
}
|
||||
|
||||
/* Double check that it's actually working */
|
||||
|
|
|
|||
|
|
@ -417,11 +417,26 @@ struct ast_crtc_state {
|
|||
|
||||
int ast_mm_init(struct ast_device *ast);
|
||||
|
||||
/* ast_2000.c */
|
||||
int ast_2000_post(struct ast_device *ast);
|
||||
|
||||
/* ast_2100.c */
|
||||
int ast_2100_post(struct ast_device *ast);
|
||||
|
||||
/* ast_2300.c */
|
||||
int ast_2300_post(struct ast_device *ast);
|
||||
|
||||
/* ast_2500.c */
|
||||
void ast_2500_patch_ahb(void __iomem *regs);
|
||||
int ast_2500_post(struct ast_device *ast);
|
||||
|
||||
/* ast_2600.c */
|
||||
int ast_2600_post(struct ast_device *ast);
|
||||
|
||||
/* ast post */
|
||||
int ast_post_gpu(struct ast_device *ast);
|
||||
u32 ast_mindwm(struct ast_device *ast, u32 r);
|
||||
void ast_moutdwm(struct ast_device *ast, u32 r, u32 v);
|
||||
void ast_patch_ahb_2500(void __iomem *regs);
|
||||
|
||||
int ast_vga_output_init(struct ast_device *ast);
|
||||
int ast_sil164_output_init(struct ast_device *ast);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
50
drivers/gpu/drm/ast/ast_post.h
Normal file
50
drivers/gpu/drm/ast/ast_post.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef AST_POST_H
|
||||
#define AST_POST_H
|
||||
|
||||
#include <linux/limits.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct ast_device;
|
||||
|
||||
/* DRAM timing tables */
|
||||
struct ast_dramstruct {
|
||||
u16 index;
|
||||
u32 data;
|
||||
};
|
||||
|
||||
/* hardware fields */
|
||||
#define __AST_DRAMSTRUCT_DRAM_TYPE 0x0004
|
||||
|
||||
/* control commands */
|
||||
#define __AST_DRAMSTRUCT_UDELAY 0xff00
|
||||
#define __AST_DRAMSTRUCT_INVALID 0xffff
|
||||
|
||||
#define __AST_DRAMSTRUCT_INDEX(_name) \
|
||||
(__AST_DRAMSTRUCT_ ## _name)
|
||||
|
||||
#define AST_DRAMSTRUCT_INIT(_name, _value) \
|
||||
{ __AST_DRAMSTRUCT_INDEX(_name), (_value) }
|
||||
|
||||
#define AST_DRAMSTRUCT_UDELAY(_usecs) \
|
||||
AST_DRAMSTRUCT_INIT(UDELAY, _usecs)
|
||||
#define AST_DRAMSTRUCT_INVALID \
|
||||
AST_DRAMSTRUCT_INIT(INVALID, U32_MAX)
|
||||
|
||||
#define AST_DRAMSTRUCT_IS(_entry, _name) \
|
||||
((_entry)->index == __AST_DRAMSTRUCT_INDEX(_name))
|
||||
|
||||
u32 __ast_mindwm(void __iomem *regs, u32 r);
|
||||
void __ast_moutdwm(void __iomem *regs, u32 r, u32 v);
|
||||
|
||||
bool mmc_test(struct ast_device *ast, u32 datagen, u8 test_ctl);
|
||||
bool mmc_test_burst(struct ast_device *ast, u32 datagen);
|
||||
|
||||
/* ast_2000.c */
|
||||
void ast_2000_set_def_ext_reg(struct ast_device *ast);
|
||||
|
||||
/* ast_2300.c */
|
||||
void ast_2300_set_def_ext_reg(struct ast_device *ast);
|
||||
|
||||
#endif
|
||||
|
|
@ -1262,9 +1262,7 @@ static int adv7511_probe(struct i2c_client *i2c)
|
|||
|
||||
adv7511->bridge.ops = DRM_BRIDGE_OP_DETECT |
|
||||
DRM_BRIDGE_OP_EDID |
|
||||
DRM_BRIDGE_OP_HDMI |
|
||||
DRM_BRIDGE_OP_HDMI_AUDIO |
|
||||
DRM_BRIDGE_OP_HDMI_CEC_ADAPTER;
|
||||
DRM_BRIDGE_OP_HDMI;
|
||||
if (adv7511->i2c_main->irq)
|
||||
adv7511->bridge.ops |= DRM_BRIDGE_OP_HPD;
|
||||
|
||||
|
|
@ -1272,6 +1270,7 @@ static int adv7511_probe(struct i2c_client *i2c)
|
|||
adv7511->bridge.product = adv7511->info->name;
|
||||
|
||||
#ifdef CONFIG_DRM_I2C_ADV7511_AUDIO
|
||||
adv7511->bridge.ops |= DRM_BRIDGE_OP_HDMI_AUDIO;
|
||||
adv7511->bridge.hdmi_audio_dev = dev;
|
||||
adv7511->bridge.hdmi_audio_max_i2s_playback_channels = 2;
|
||||
adv7511->bridge.hdmi_audio_i2s_formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
|
|
@ -1284,6 +1283,7 @@ static int adv7511_probe(struct i2c_client *i2c)
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_I2C_ADV7511_CEC
|
||||
adv7511->bridge.ops |= DRM_BRIDGE_OP_HDMI_CEC_ADAPTER;
|
||||
adv7511->bridge.hdmi_cec_dev = dev;
|
||||
adv7511->bridge.hdmi_cec_adapter_name = dev_name(dev);
|
||||
adv7511->bridge.hdmi_cec_available_las = ADV7511_MAX_ADDRS;
|
||||
|
|
|
|||
|
|
@ -1041,7 +1041,7 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge,
|
|||
struct drm_encoder *encoder,
|
||||
enum drm_bridge_attach_flags flags)
|
||||
{
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
struct analogix_dp_device *dp = to_dp(bridge);
|
||||
struct drm_connector *connector = NULL;
|
||||
int ret = 0;
|
||||
|
||||
|
|
@ -1125,7 +1125,7 @@ struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp,
|
|||
static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *old_state)
|
||||
{
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
struct analogix_dp_device *dp = to_dp(bridge);
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
|
||||
|
|
@ -1180,7 +1180,7 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
|
|||
static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *old_state)
|
||||
{
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
struct analogix_dp_device *dp = to_dp(bridge);
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
int timeout_loop = 0;
|
||||
|
|
@ -1217,7 +1217,7 @@ static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
|
|||
|
||||
static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
struct analogix_dp_device *dp = to_dp(bridge);
|
||||
|
||||
if (dp->dpms_mode != DRM_MODE_DPMS_ON)
|
||||
return;
|
||||
|
|
@ -1240,7 +1240,7 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
|
|||
static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *old_state)
|
||||
{
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
struct analogix_dp_device *dp = to_dp(bridge);
|
||||
struct drm_crtc *old_crtc, *new_crtc;
|
||||
struct drm_crtc_state *old_crtc_state = NULL;
|
||||
struct drm_crtc_state *new_crtc_state = NULL;
|
||||
|
|
@ -1278,7 +1278,7 @@ static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
|
|||
static void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *old_state)
|
||||
{
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
struct analogix_dp_device *dp = to_dp(bridge);
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
int ret;
|
||||
|
|
@ -1300,7 +1300,7 @@ static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge,
|
|||
const struct drm_display_mode *orig_mode,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
struct analogix_dp_device *dp = to_dp(bridge);
|
||||
struct drm_display_info *display_info = &dp->connector.display_info;
|
||||
struct video_info *video = &dp->video_info;
|
||||
struct device_node *dp_node = dp->dev->of_node;
|
||||
|
|
@ -1385,25 +1385,6 @@ static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
|
|||
.attach = analogix_dp_bridge_attach,
|
||||
};
|
||||
|
||||
static int analogix_dp_create_bridge(struct drm_device *drm_dev,
|
||||
struct analogix_dp_device *dp)
|
||||
{
|
||||
struct drm_bridge *bridge;
|
||||
|
||||
bridge = devm_kzalloc(drm_dev->dev, sizeof(*bridge), GFP_KERNEL);
|
||||
if (!bridge) {
|
||||
DRM_ERROR("failed to allocate for drm bridge\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dp->bridge = bridge;
|
||||
|
||||
bridge->driver_private = dp;
|
||||
bridge->funcs = &analogix_dp_bridge_funcs;
|
||||
|
||||
return drm_bridge_attach(dp->encoder, bridge, NULL, 0);
|
||||
}
|
||||
|
||||
static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
|
||||
{
|
||||
struct device_node *dp_node = dp->dev->of_node;
|
||||
|
|
@ -1491,7 +1472,8 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
|
|||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
dp = devm_kzalloc(dev, sizeof(struct analogix_dp_device), GFP_KERNEL);
|
||||
dp = devm_drm_bridge_alloc(dev, struct analogix_dp_device, bridge,
|
||||
&analogix_dp_bridge_funcs);
|
||||
if (!dp)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
|
@ -1643,7 +1625,7 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = analogix_dp_create_bridge(drm_dev, dp);
|
||||
ret = drm_bridge_attach(dp->encoder, &dp->bridge, NULL, 0);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to create bridge (%d)\n", ret);
|
||||
goto err_unregister_aux;
|
||||
|
|
@ -1660,7 +1642,7 @@ EXPORT_SYMBOL_GPL(analogix_dp_bind);
|
|||
|
||||
void analogix_dp_unbind(struct analogix_dp_device *dp)
|
||||
{
|
||||
analogix_dp_bridge_disable(dp->bridge);
|
||||
analogix_dp_bridge_disable(&dp->bridge);
|
||||
dp->connector.funcs->destroy(&dp->connector);
|
||||
|
||||
drm_panel_unprepare(dp->plat_data->panel);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <drm/display/drm_dp_helper.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
|
||||
#define DP_TIMEOUT_LOOP_COUNT 100
|
||||
#define MAX_CR_LOOP 5
|
||||
|
|
@ -154,7 +155,7 @@ struct analogix_dp_device {
|
|||
struct device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
struct drm_connector connector;
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_bridge bridge;
|
||||
struct drm_dp_aux aux;
|
||||
struct clk *clock;
|
||||
unsigned int irq;
|
||||
|
|
|
|||
|
|
@ -2422,6 +2422,7 @@ static int tc_probe_bridge_endpoint(struct tc_data *tc, enum tc_mode mode)
|
|||
struct device_node *node = NULL;
|
||||
|
||||
for_each_endpoint_of_node(dev->of_node, node) {
|
||||
of_graph_parse_endpoint(node, &endpoint);
|
||||
if (endpoint.port == 2) {
|
||||
of_property_read_u8_array(node, "toshiba,pre-emphasis",
|
||||
tc->pre_emphasis,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <drm/clients/drm_client_setup.h>
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
|
|
@ -33,6 +34,10 @@ MODULE_PARM_DESC(active,
|
|||
*/
|
||||
void drm_client_setup(struct drm_device *dev, const struct drm_format_info *format)
|
||||
{
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
drm_dbg(dev, "driver does not support mode-setting, skipping DRM clients\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRM_FBDEV_EMULATION
|
||||
if (!strcmp(drm_client_default, "fbdev")) {
|
||||
|
|
|
|||
|
|
@ -4245,14 +4245,14 @@ drm_edp_backlight_probe_state(struct drm_dp_aux *aux, struct drm_edp_backlight_i
|
|||
"%s: Failed to read backlight level: %d\n",
|
||||
aux->name, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Incase luminance is set we want to send the value back in nits but since
|
||||
* DP_EDP_PANEL_TARGET_LUMINANCE stores values in millinits we need to divide
|
||||
* by 1000.
|
||||
*/
|
||||
return (buf[0] | buf[1] << 8 | buf[2] << 16) / 1000;
|
||||
/*
|
||||
* Incase luminance is set we want to send the value back in nits but
|
||||
* since DP_EDP_PANEL_TARGET_LUMINANCE stores values in millinits we
|
||||
* need to divide by 1000.
|
||||
*/
|
||||
return (buf[0] | buf[1] << 8 | buf[2] << 16) / 1000;
|
||||
} else {
|
||||
ret = drm_dp_dpcd_read_data(aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB,
|
||||
buf, size);
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ static void drm_connector_hdmi_cec_adapter_unregister(struct drm_device *dev, vo
|
|||
struct drm_connector *connector = res;
|
||||
struct drm_connector_hdmi_cec_data *data = connector->cec.data;
|
||||
|
||||
cec_delete_adapter(data->adapter);
|
||||
cec_unregister_adapter(data->adapter);
|
||||
|
||||
if (data->funcs->uninit)
|
||||
data->funcs->uninit(connector);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@
|
|||
#include "drm_crtc_internal.h"
|
||||
#include "drm_internal.h"
|
||||
|
||||
static struct dentry *accel_debugfs_root;
|
||||
static struct dentry *drm_debugfs_root;
|
||||
|
||||
/***************************************************
|
||||
* Initialization, etc.
|
||||
**************************************************/
|
||||
|
|
@ -287,16 +290,120 @@ int drm_debugfs_remove_files(const struct drm_info_list *files, int count,
|
|||
}
|
||||
EXPORT_SYMBOL(drm_debugfs_remove_files);
|
||||
|
||||
void drm_debugfs_bridge_params(void)
|
||||
{
|
||||
drm_bridge_debugfs_params(drm_debugfs_root);
|
||||
}
|
||||
|
||||
void drm_debugfs_init_root(void)
|
||||
{
|
||||
drm_debugfs_root = debugfs_create_dir("dri", NULL);
|
||||
#if IS_ENABLED(CONFIG_DRM_ACCEL)
|
||||
accel_debugfs_root = debugfs_create_dir("accel", NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void drm_debugfs_remove_root(void)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_DRM_ACCEL)
|
||||
debugfs_remove(accel_debugfs_root);
|
||||
#endif
|
||||
debugfs_remove(drm_debugfs_root);
|
||||
}
|
||||
|
||||
static int drm_debugfs_proc_info_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct pid *pid;
|
||||
struct task_struct *task;
|
||||
struct drm_file *file = m->private;
|
||||
|
||||
if (!file)
|
||||
return -EINVAL;
|
||||
|
||||
rcu_read_lock();
|
||||
pid = rcu_dereference(file->pid);
|
||||
task = pid_task(pid, PIDTYPE_TGID);
|
||||
|
||||
seq_printf(m, "pid: %d\n", task ? task->pid : 0);
|
||||
seq_printf(m, "comm: %s\n", task ? task->comm : "Unset");
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_debufs_proc_info_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, drm_debugfs_proc_info_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations drm_debugfs_proc_info_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_debufs_proc_info_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* drm_debugfs_clients_add - Add a per client debugfs directory
|
||||
* @file: drm_file for a client
|
||||
*
|
||||
* Create the debugfs directory for each client. This will be used to populate
|
||||
* driver specific data for each client.
|
||||
*
|
||||
* Also add the process information debugfs file for each client to tag
|
||||
* which client belongs to which process.
|
||||
*/
|
||||
void drm_debugfs_clients_add(struct drm_file *file)
|
||||
{
|
||||
char *client;
|
||||
|
||||
client = kasprintf(GFP_KERNEL, "client-%llu", file->client_id);
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
/* Create a debugfs directory for the client in root on drm debugfs */
|
||||
file->debugfs_client = debugfs_create_dir(client, drm_debugfs_root);
|
||||
kfree(client);
|
||||
|
||||
debugfs_create_file("proc_info", 0444, file->debugfs_client, file,
|
||||
&drm_debugfs_proc_info_fops);
|
||||
|
||||
client = kasprintf(GFP_KERNEL, "../%s", file->minor->dev->unique);
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
/* Create a link from client_id to the drm device this client id belongs to */
|
||||
debugfs_create_symlink("device", file->debugfs_client, client);
|
||||
kfree(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_debugfs_clients_remove - removes all debugfs directories and files
|
||||
* @file: drm_file for a client
|
||||
*
|
||||
* Removes the debugfs directories recursively from the client directory.
|
||||
*
|
||||
* There is also a possibility that debugfs files are open while the drm_file
|
||||
* is released.
|
||||
*/
|
||||
void drm_debugfs_clients_remove(struct drm_file *file)
|
||||
{
|
||||
debugfs_remove_recursive(file->debugfs_client);
|
||||
file->debugfs_client = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_debugfs_dev_init - create debugfs directory for the device
|
||||
* @dev: the device which we want to create the directory for
|
||||
* @root: the parent directory depending on the device type
|
||||
*
|
||||
* Creates the debugfs directory for the device under the given root directory.
|
||||
*/
|
||||
void drm_debugfs_dev_init(struct drm_device *dev, struct dentry *root)
|
||||
void drm_debugfs_dev_init(struct drm_device *dev)
|
||||
{
|
||||
dev->debugfs_root = debugfs_create_dir(dev->unique, root);
|
||||
if (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL))
|
||||
dev->debugfs_root = debugfs_create_dir(dev->unique, accel_debugfs_root);
|
||||
else
|
||||
dev->debugfs_root = debugfs_create_dir(dev->unique, drm_debugfs_root);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -323,14 +430,13 @@ void drm_debugfs_dev_register(struct drm_device *dev)
|
|||
drm_atomic_debugfs_init(dev);
|
||||
}
|
||||
|
||||
int drm_debugfs_register(struct drm_minor *minor, int minor_id,
|
||||
struct dentry *root)
|
||||
int drm_debugfs_register(struct drm_minor *minor, int minor_id)
|
||||
{
|
||||
struct drm_device *dev = minor->dev;
|
||||
char name[64];
|
||||
|
||||
sprintf(name, "%d", minor_id);
|
||||
minor->debugfs_symlink = debugfs_create_symlink(name, root,
|
||||
minor->debugfs_symlink = debugfs_create_symlink(name, drm_debugfs_root,
|
||||
dev->unique);
|
||||
|
||||
/* TODO: Only for compatibility with drivers */
|
||||
|
|
|
|||
|
|
@ -72,8 +72,6 @@ DEFINE_XARRAY_ALLOC(drm_minors_xa);
|
|||
*/
|
||||
static bool drm_core_init_complete;
|
||||
|
||||
static struct dentry *drm_debugfs_root;
|
||||
|
||||
DEFINE_STATIC_SRCU(drm_unplug_srcu);
|
||||
|
||||
/*
|
||||
|
|
@ -186,8 +184,7 @@ static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type)
|
|||
return 0;
|
||||
|
||||
if (minor->type != DRM_MINOR_ACCEL) {
|
||||
ret = drm_debugfs_register(minor, minor->index,
|
||||
drm_debugfs_root);
|
||||
ret = drm_debugfs_register(minor, minor->index);
|
||||
if (ret) {
|
||||
DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
|
||||
goto err_debugfs;
|
||||
|
|
@ -787,10 +784,7 @@ static int drm_dev_init(struct drm_device *dev,
|
|||
goto err;
|
||||
}
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL))
|
||||
accel_debugfs_init(dev);
|
||||
else
|
||||
drm_debugfs_dev_init(dev, drm_debugfs_root);
|
||||
drm_debugfs_dev_init(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
@ -1230,7 +1224,7 @@ static void drm_core_exit(void)
|
|||
drm_panic_exit();
|
||||
accel_core_exit();
|
||||
unregister_chrdev(DRM_MAJOR, "drm");
|
||||
debugfs_remove(drm_debugfs_root);
|
||||
drm_debugfs_remove_root();
|
||||
drm_sysfs_destroy();
|
||||
WARN_ON(!xa_empty(&drm_minors_xa));
|
||||
drm_connector_ida_destroy();
|
||||
|
|
@ -1249,8 +1243,8 @@ static int __init drm_core_init(void)
|
|||
goto error;
|
||||
}
|
||||
|
||||
drm_debugfs_root = debugfs_create_dir("dri", NULL);
|
||||
drm_bridge_debugfs_params(drm_debugfs_root);
|
||||
drm_debugfs_init_root();
|
||||
drm_debugfs_bridge_params();
|
||||
|
||||
ret = register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops);
|
||||
if (ret < 0)
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_debugfs.h>
|
||||
|
||||
#include "drm_crtc_internal.h"
|
||||
#include "drm_internal.h"
|
||||
|
|
@ -168,6 +169,9 @@ struct drm_file *drm_file_alloc(struct drm_minor *minor)
|
|||
|
||||
drm_prime_init_file_private(&file->prime);
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL))
|
||||
drm_debugfs_clients_add(file);
|
||||
|
||||
if (dev->driver->open) {
|
||||
ret = dev->driver->open(dev, file);
|
||||
if (ret < 0)
|
||||
|
|
@ -182,6 +186,10 @@ struct drm_file *drm_file_alloc(struct drm_minor *minor)
|
|||
drm_syncobj_release(file);
|
||||
if (drm_core_check_feature(dev, DRIVER_GEM))
|
||||
drm_gem_release(dev, file);
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL))
|
||||
drm_debugfs_clients_remove(file);
|
||||
|
||||
put_pid(rcu_access_pointer(file->pid));
|
||||
kfree(file);
|
||||
|
||||
|
|
@ -236,6 +244,9 @@ void drm_file_free(struct drm_file *file)
|
|||
(long)old_encode_dev(file->minor->kdev->devt),
|
||||
atomic_read(&dev->open_count));
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL))
|
||||
drm_debugfs_clients_remove(file);
|
||||
|
||||
drm_events_release(file);
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
|
|
|
|||
|
|
@ -182,8 +182,7 @@ void drm_gem_vunmap_locked(struct drm_gem_object *obj, struct iosys_map *map);
|
|||
#if defined(CONFIG_DEBUG_FS)
|
||||
void drm_debugfs_dev_fini(struct drm_device *dev);
|
||||
void drm_debugfs_dev_register(struct drm_device *dev);
|
||||
int drm_debugfs_register(struct drm_minor *minor, int minor_id,
|
||||
struct dentry *root);
|
||||
int drm_debugfs_register(struct drm_minor *minor, int minor_id);
|
||||
void drm_debugfs_unregister(struct drm_minor *minor);
|
||||
void drm_debugfs_connector_add(struct drm_connector *connector);
|
||||
void drm_debugfs_connector_remove(struct drm_connector *connector);
|
||||
|
|
@ -201,8 +200,7 @@ static inline void drm_debugfs_dev_register(struct drm_device *dev)
|
|||
{
|
||||
}
|
||||
|
||||
static inline int drm_debugfs_register(struct drm_minor *minor, int minor_id,
|
||||
struct dentry *root)
|
||||
static inline int drm_debugfs_register(struct drm_minor *minor, int minor_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
//! * <https://github.com/erwanvivien/fast_qr>
|
||||
//! * <https://github.com/bjguillot/qr>
|
||||
|
||||
use kernel::{prelude::*, str::CStr};
|
||||
use kernel::prelude::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
|
||||
struct Version(usize);
|
||||
|
|
|
|||
|
|
@ -340,6 +340,63 @@ pvr_power_device_idle(struct device *dev)
|
|||
return pvr_power_is_idle(pvr_dev) ? 0 : -EBUSY;
|
||||
}
|
||||
|
||||
static int
|
||||
pvr_power_clear_error(struct pvr_device *pvr_dev)
|
||||
{
|
||||
struct device *dev = from_pvr_device(pvr_dev)->dev;
|
||||
int err;
|
||||
|
||||
/* Ensure the device state is known and nothing is happening past this point */
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
/* Attempt to clear the runtime PM error by setting the current state again */
|
||||
if (pm_runtime_status_suspended(dev))
|
||||
err = pm_runtime_set_suspended(dev);
|
||||
else
|
||||
err = pm_runtime_set_active(dev);
|
||||
|
||||
if (err) {
|
||||
drm_err(from_pvr_device(pvr_dev),
|
||||
"%s: Failed to clear runtime PM error (new error %d)\n",
|
||||
__func__, err);
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* pvr_power_get_clear() - Acquire a power reference, correcting any errors
|
||||
* @pvr_dev: Device pointer
|
||||
*
|
||||
* Attempt to acquire a power reference on the device. If the runtime PM
|
||||
* is in error state, attempt to clear the error and retry.
|
||||
*
|
||||
* Returns:
|
||||
* * 0 on success, or
|
||||
* * Any error code returned by pvr_power_get() or the runtime PM API.
|
||||
*/
|
||||
static int
|
||||
pvr_power_get_clear(struct pvr_device *pvr_dev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pvr_power_get(pvr_dev);
|
||||
if (err == 0)
|
||||
return err;
|
||||
|
||||
drm_warn(from_pvr_device(pvr_dev),
|
||||
"%s: pvr_power_get returned error %d, attempting recovery\n",
|
||||
__func__, err);
|
||||
|
||||
err = pvr_power_clear_error(pvr_dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return pvr_power_get(pvr_dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* pvr_power_reset() - Reset the GPU
|
||||
* @pvr_dev: Device pointer
|
||||
|
|
@ -364,7 +421,7 @@ pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset)
|
|||
* Take a power reference during the reset. This should prevent any interference with the
|
||||
* power state during reset.
|
||||
*/
|
||||
WARN_ON(pvr_power_get(pvr_dev));
|
||||
WARN_ON(pvr_power_get_clear(pvr_dev));
|
||||
|
||||
down_write(&pvr_dev->reset_sem);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,10 +16,15 @@
|
|||
#include "panthor_mmu.h"
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static void panthor_gem_debugfs_bo_add(struct panthor_device *ptdev,
|
||||
struct panthor_gem_object *bo)
|
||||
static void panthor_gem_debugfs_bo_init(struct panthor_gem_object *bo)
|
||||
{
|
||||
INIT_LIST_HEAD(&bo->debugfs.node);
|
||||
}
|
||||
|
||||
static void panthor_gem_debugfs_bo_add(struct panthor_gem_object *bo)
|
||||
{
|
||||
struct panthor_device *ptdev = container_of(bo->base.base.dev,
|
||||
struct panthor_device, base);
|
||||
|
||||
bo->debugfs.creator.tgid = current->group_leader->pid;
|
||||
get_task_comm(bo->debugfs.creator.process_name, current->group_leader);
|
||||
|
|
@ -44,14 +49,13 @@ static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo)
|
|||
|
||||
static void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags)
|
||||
{
|
||||
bo->debugfs.flags = usage_flags | PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED;
|
||||
bo->debugfs.flags = usage_flags;
|
||||
panthor_gem_debugfs_bo_add(bo);
|
||||
}
|
||||
#else
|
||||
static void panthor_gem_debugfs_bo_add(struct panthor_device *ptdev,
|
||||
struct panthor_gem_object *bo)
|
||||
{}
|
||||
static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo) {}
|
||||
static void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) {}
|
||||
static void panthor_gem_debugfs_bo_init(struct panthor_gem_object *bo) {}
|
||||
#endif
|
||||
|
||||
static void panthor_gem_free_object(struct drm_gem_object *obj)
|
||||
|
|
@ -246,7 +250,7 @@ struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t
|
|||
drm_gem_gpuva_set_lock(&obj->base.base, &obj->gpuva_list_lock);
|
||||
mutex_init(&obj->label.lock);
|
||||
|
||||
panthor_gem_debugfs_bo_add(ptdev, obj);
|
||||
panthor_gem_debugfs_bo_init(obj);
|
||||
|
||||
return &obj->base.base;
|
||||
}
|
||||
|
|
@ -285,6 +289,8 @@ panthor_gem_create_with_handle(struct drm_file *file,
|
|||
bo->base.base.resv = bo->exclusive_vm_root_gem->resv;
|
||||
}
|
||||
|
||||
panthor_gem_debugfs_set_usage_flags(bo, 0);
|
||||
|
||||
/*
|
||||
* Allocate an id of idr table where the obj is registered
|
||||
* and handle has the id what user can see.
|
||||
|
|
@ -296,12 +302,6 @@ panthor_gem_create_with_handle(struct drm_file *file,
|
|||
/* drop reference from allocate - handle holds it now. */
|
||||
drm_gem_object_put(&shmem->base);
|
||||
|
||||
/*
|
||||
* No explicit flags are needed in the call below, since the
|
||||
* function internally sets the INITIALIZED bit for us.
|
||||
*/
|
||||
panthor_gem_debugfs_set_usage_flags(bo, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -387,7 +387,7 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo,
|
|||
unsigned int refcount = kref_read(&bo->base.base.refcount);
|
||||
char creator_info[32] = {};
|
||||
size_t resident_size;
|
||||
u32 gem_usage_flags = bo->debugfs.flags & (u32)~PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED;
|
||||
u32 gem_usage_flags = bo->debugfs.flags;
|
||||
u32 gem_state_flags = 0;
|
||||
|
||||
/* Skip BOs being destroyed. */
|
||||
|
|
@ -436,8 +436,7 @@ void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev,
|
|||
|
||||
scoped_guard(mutex, &ptdev->gems.lock) {
|
||||
list_for_each_entry(bo, &ptdev->gems.node, debugfs.node) {
|
||||
if (bo->debugfs.flags & PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED)
|
||||
panthor_gem_debugfs_bo_print(bo, m, &totals);
|
||||
panthor_gem_debugfs_bo_print(bo, m, &totals);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,9 +35,6 @@ enum panthor_debugfs_gem_usage_flags {
|
|||
|
||||
/** @PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED: BO is mapped on the FW VM. */
|
||||
PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED = BIT(PANTHOR_DEBUGFS_GEM_USAGE_FW_MAPPED_BIT),
|
||||
|
||||
/** @PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED: BO is ready for DebugFS display. */
|
||||
PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED = BIT(31),
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@
|
|||
#include <sound/hdmi-codec.h>
|
||||
|
||||
#include <drm/display/drm_dp_helper.h>
|
||||
#include <drm/display/drm_hdmi_audio_helper.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge_connector.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
|
@ -25,9 +27,9 @@
|
|||
#include "cdn-dp-core.h"
|
||||
#include "cdn-dp-reg.h"
|
||||
|
||||
static inline struct cdn_dp_device *connector_to_dp(struct drm_connector *connector)
|
||||
static inline struct cdn_dp_device *bridge_to_dp(struct drm_bridge *bridge)
|
||||
{
|
||||
return container_of(connector, struct cdn_dp_device, connector);
|
||||
return container_of(bridge, struct cdn_dp_device, bridge);
|
||||
}
|
||||
|
||||
static inline struct cdn_dp_device *encoder_to_dp(struct drm_encoder *encoder)
|
||||
|
|
@ -231,9 +233,9 @@ static bool cdn_dp_check_sink_connection(struct cdn_dp_device *dp)
|
|||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
cdn_dp_connector_detect(struct drm_connector *connector, bool force)
|
||||
cdn_dp_bridge_detect(struct drm_bridge *bridge)
|
||||
{
|
||||
struct cdn_dp_device *dp = connector_to_dp(connector);
|
||||
struct cdn_dp_device *dp = bridge_to_dp(bridge);
|
||||
enum drm_connector_status status = connector_status_disconnected;
|
||||
|
||||
mutex_lock(&dp->lock);
|
||||
|
|
@ -244,41 +246,25 @@ cdn_dp_connector_detect(struct drm_connector *connector, bool force)
|
|||
return status;
|
||||
}
|
||||
|
||||
static void cdn_dp_connector_destroy(struct drm_connector *connector)
|
||||
static const struct drm_edid *
|
||||
cdn_dp_bridge_edid_read(struct drm_bridge *bridge, struct drm_connector *connector)
|
||||
{
|
||||
drm_connector_unregister(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs cdn_dp_atomic_connector_funcs = {
|
||||
.detect = cdn_dp_connector_detect,
|
||||
.destroy = cdn_dp_connector_destroy,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
static int cdn_dp_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct cdn_dp_device *dp = connector_to_dp(connector);
|
||||
int ret = 0;
|
||||
struct cdn_dp_device *dp = bridge_to_dp(bridge);
|
||||
const struct drm_edid *drm_edid;
|
||||
|
||||
mutex_lock(&dp->lock);
|
||||
|
||||
ret = drm_edid_connector_add_modes(connector);
|
||||
|
||||
drm_edid = drm_edid_read_custom(connector, cdn_dp_get_edid_block, dp);
|
||||
mutex_unlock(&dp->lock);
|
||||
|
||||
return ret;
|
||||
return drm_edid;
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
cdn_dp_connector_mode_valid(struct drm_connector *connector,
|
||||
const struct drm_display_mode *mode)
|
||||
cdn_dp_bridge_mode_valid(struct drm_bridge *bridge,
|
||||
const struct drm_display_info *display_info,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct cdn_dp_device *dp = connector_to_dp(connector);
|
||||
struct drm_display_info *display_info = &dp->connector.display_info;
|
||||
struct cdn_dp_device *dp = bridge_to_dp(bridge);
|
||||
u32 requested, actual, rate, sink_max, source_max = 0;
|
||||
u8 lanes, bpc;
|
||||
|
||||
|
|
@ -323,11 +309,6 @@ cdn_dp_connector_mode_valid(struct drm_connector *connector,
|
|||
return MODE_OK;
|
||||
}
|
||||
|
||||
static struct drm_connector_helper_funcs cdn_dp_connector_helper_funcs = {
|
||||
.get_modes = cdn_dp_connector_get_modes,
|
||||
.mode_valid = cdn_dp_connector_mode_valid,
|
||||
};
|
||||
|
||||
static int cdn_dp_firmware_init(struct cdn_dp_device *dp)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -360,7 +341,6 @@ static int cdn_dp_firmware_init(struct cdn_dp_device *dp)
|
|||
|
||||
static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp)
|
||||
{
|
||||
const struct drm_display_info *info = &dp->connector.display_info;
|
||||
int ret;
|
||||
|
||||
if (!cdn_dp_check_sink_connection(dp))
|
||||
|
|
@ -373,17 +353,6 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp)
|
|||
return ret;
|
||||
}
|
||||
|
||||
drm_edid_free(dp->drm_edid);
|
||||
dp->drm_edid = drm_edid_read_custom(&dp->connector,
|
||||
cdn_dp_get_edid_block, dp);
|
||||
drm_edid_connector_update(&dp->connector, dp->drm_edid);
|
||||
|
||||
dp->sink_has_audio = info->has_audio;
|
||||
|
||||
if (dp->drm_edid)
|
||||
DRM_DEV_DEBUG_KMS(dp->dev, "got edid: width[%d] x height[%d]\n",
|
||||
info->width_mm / 10, info->height_mm / 10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -488,10 +457,6 @@ static int cdn_dp_disable(struct cdn_dp_device *dp)
|
|||
dp->active = false;
|
||||
dp->max_lanes = 0;
|
||||
dp->max_rate = 0;
|
||||
if (!dp->connected) {
|
||||
drm_edid_free(dp->drm_edid);
|
||||
dp->drm_edid = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -546,26 +511,13 @@ static int cdn_dp_enable(struct cdn_dp_device *dp)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted)
|
||||
static void cdn_dp_bridge_mode_set(struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
const struct drm_display_mode *adjusted)
|
||||
{
|
||||
struct cdn_dp_device *dp = encoder_to_dp(encoder);
|
||||
struct drm_display_info *display_info = &dp->connector.display_info;
|
||||
struct cdn_dp_device *dp = bridge_to_dp(bridge);
|
||||
struct video_info *video = &dp->video_info;
|
||||
|
||||
switch (display_info->bpc) {
|
||||
case 10:
|
||||
video->color_depth = 10;
|
||||
break;
|
||||
case 6:
|
||||
video->color_depth = 6;
|
||||
break;
|
||||
default:
|
||||
video->color_depth = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
video->color_fmt = PXL_RGB;
|
||||
video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
|
||||
video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
|
||||
|
|
@ -592,19 +544,37 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp)
|
|||
return drm_dp_channel_eq_ok(link_status, min(port->lanes, sink_lanes));
|
||||
}
|
||||
|
||||
static void cdn_dp_audio_handle_plugged_change(struct cdn_dp_device *dp,
|
||||
bool plugged)
|
||||
static void cdn_dp_display_info_update(struct cdn_dp_device *dp,
|
||||
struct drm_display_info *display_info)
|
||||
{
|
||||
if (dp->codec_dev)
|
||||
dp->plugged_cb(dp->codec_dev, plugged);
|
||||
struct video_info *video = &dp->video_info;
|
||||
|
||||
switch (display_info->bpc) {
|
||||
case 10:
|
||||
video->color_depth = 10;
|
||||
break;
|
||||
case 6:
|
||||
video->color_depth = 6;
|
||||
break;
|
||||
default:
|
||||
video->color_depth = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
|
||||
static void cdn_dp_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_atomic_state *state)
|
||||
{
|
||||
struct cdn_dp_device *dp = encoder_to_dp(encoder);
|
||||
struct cdn_dp_device *dp = bridge_to_dp(bridge);
|
||||
struct drm_connector *connector;
|
||||
int ret, val;
|
||||
|
||||
ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
|
||||
connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
|
||||
if (!connector)
|
||||
return;
|
||||
|
||||
cdn_dp_display_info_update(dp, &connector->display_info);
|
||||
|
||||
ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, &dp->encoder.encoder);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret);
|
||||
return;
|
||||
|
|
@ -625,7 +595,7 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
|
|||
|
||||
ret = cdn_dp_enable(dp);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dp->dev, "Failed to enable encoder %d\n",
|
||||
DRM_DEV_ERROR(dp->dev, "Failed to enable bridge %d\n",
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -655,24 +625,21 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
|
|||
goto out;
|
||||
}
|
||||
|
||||
cdn_dp_audio_handle_plugged_change(dp, true);
|
||||
|
||||
out:
|
||||
mutex_unlock(&dp->lock);
|
||||
}
|
||||
|
||||
static void cdn_dp_encoder_disable(struct drm_encoder *encoder)
|
||||
static void cdn_dp_bridge_atomic_disable(struct drm_bridge *bridge, struct drm_atomic_state *state)
|
||||
{
|
||||
struct cdn_dp_device *dp = encoder_to_dp(encoder);
|
||||
struct cdn_dp_device *dp = bridge_to_dp(bridge);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dp->lock);
|
||||
cdn_dp_audio_handle_plugged_change(dp, false);
|
||||
|
||||
if (dp->active) {
|
||||
ret = cdn_dp_disable(dp);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dp->dev, "Failed to disable encoder %d\n",
|
||||
DRM_DEV_ERROR(dp->dev, "Failed to disable bridge %d\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
|
@ -704,9 +671,6 @@ static int cdn_dp_encoder_atomic_check(struct drm_encoder *encoder,
|
|||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs cdn_dp_encoder_helper_funcs = {
|
||||
.mode_set = cdn_dp_encoder_mode_set,
|
||||
.enable = cdn_dp_encoder_enable,
|
||||
.disable = cdn_dp_encoder_disable,
|
||||
.atomic_check = cdn_dp_encoder_atomic_check,
|
||||
};
|
||||
|
||||
|
|
@ -779,11 +743,12 @@ static int cdn_dp_parse_dt(struct cdn_dp_device *dp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cdn_dp_audio_hw_params(struct device *dev, void *data,
|
||||
struct hdmi_codec_daifmt *daifmt,
|
||||
struct hdmi_codec_params *params)
|
||||
static int cdn_dp_audio_prepare(struct drm_connector *connector,
|
||||
struct drm_bridge *bridge,
|
||||
struct hdmi_codec_daifmt *daifmt,
|
||||
struct hdmi_codec_params *params)
|
||||
{
|
||||
struct cdn_dp_device *dp = dev_get_drvdata(dev);
|
||||
struct cdn_dp_device *dp = bridge_to_dp(bridge);
|
||||
struct audio_info audio = {
|
||||
.sample_width = params->sample_width,
|
||||
.sample_rate = params->sample_rate,
|
||||
|
|
@ -805,7 +770,7 @@ static int cdn_dp_audio_hw_params(struct device *dev, void *data,
|
|||
audio.format = AFMT_SPDIF;
|
||||
break;
|
||||
default:
|
||||
DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt);
|
||||
drm_err(bridge->dev, "Invalid format %d\n", daifmt->fmt);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -819,9 +784,10 @@ static int cdn_dp_audio_hw_params(struct device *dev, void *data,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void cdn_dp_audio_shutdown(struct device *dev, void *data)
|
||||
static void cdn_dp_audio_shutdown(struct drm_connector *connector,
|
||||
struct drm_bridge *bridge)
|
||||
{
|
||||
struct cdn_dp_device *dp = dev_get_drvdata(dev);
|
||||
struct cdn_dp_device *dp = bridge_to_dp(bridge);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dp->lock);
|
||||
|
|
@ -835,10 +801,11 @@ static void cdn_dp_audio_shutdown(struct device *dev, void *data)
|
|||
mutex_unlock(&dp->lock);
|
||||
}
|
||||
|
||||
static int cdn_dp_audio_mute_stream(struct device *dev, void *data,
|
||||
static int cdn_dp_audio_mute_stream(struct drm_connector *connector,
|
||||
struct drm_bridge *bridge,
|
||||
bool enable, int direction)
|
||||
{
|
||||
struct cdn_dp_device *dp = dev_get_drvdata(dev);
|
||||
struct cdn_dp_device *dp = bridge_to_dp(bridge);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dp->lock);
|
||||
|
|
@ -854,57 +821,22 @@ static int cdn_dp_audio_mute_stream(struct device *dev, void *data,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int cdn_dp_audio_get_eld(struct device *dev, void *data,
|
||||
u8 *buf, size_t len)
|
||||
{
|
||||
struct cdn_dp_device *dp = dev_get_drvdata(dev);
|
||||
static const struct drm_bridge_funcs cdn_dp_bridge_funcs = {
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_reset = drm_atomic_helper_bridge_reset,
|
||||
.detect = cdn_dp_bridge_detect,
|
||||
.edid_read = cdn_dp_bridge_edid_read,
|
||||
.atomic_enable = cdn_dp_bridge_atomic_enable,
|
||||
.atomic_disable = cdn_dp_bridge_atomic_disable,
|
||||
.mode_valid = cdn_dp_bridge_mode_valid,
|
||||
.mode_set = cdn_dp_bridge_mode_set,
|
||||
|
||||
memcpy(buf, dp->connector.eld, min(sizeof(dp->connector.eld), len));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdn_dp_audio_hook_plugged_cb(struct device *dev, void *data,
|
||||
hdmi_codec_plugged_cb fn,
|
||||
struct device *codec_dev)
|
||||
{
|
||||
struct cdn_dp_device *dp = dev_get_drvdata(dev);
|
||||
|
||||
mutex_lock(&dp->lock);
|
||||
dp->plugged_cb = fn;
|
||||
dp->codec_dev = codec_dev;
|
||||
cdn_dp_audio_handle_plugged_change(dp, dp->connected);
|
||||
mutex_unlock(&dp->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hdmi_codec_ops audio_codec_ops = {
|
||||
.hw_params = cdn_dp_audio_hw_params,
|
||||
.audio_shutdown = cdn_dp_audio_shutdown,
|
||||
.mute_stream = cdn_dp_audio_mute_stream,
|
||||
.get_eld = cdn_dp_audio_get_eld,
|
||||
.hook_plugged_cb = cdn_dp_audio_hook_plugged_cb,
|
||||
.dp_audio_prepare = cdn_dp_audio_prepare,
|
||||
.dp_audio_mute_stream = cdn_dp_audio_mute_stream,
|
||||
.dp_audio_shutdown = cdn_dp_audio_shutdown,
|
||||
};
|
||||
|
||||
static int cdn_dp_audio_codec_init(struct cdn_dp_device *dp,
|
||||
struct device *dev)
|
||||
{
|
||||
struct hdmi_codec_pdata codec_data = {
|
||||
.i2s = 1,
|
||||
.spdif = 1,
|
||||
.ops = &audio_codec_ops,
|
||||
.max_i2s_channels = 8,
|
||||
.no_capture_mute = 1,
|
||||
};
|
||||
|
||||
dp->audio_pdev = platform_device_register_data(
|
||||
dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO,
|
||||
&codec_data, sizeof(codec_data));
|
||||
|
||||
return PTR_ERR_OR_ZERO(dp->audio_pdev);
|
||||
}
|
||||
|
||||
static int cdn_dp_request_firmware(struct cdn_dp_device *dp)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -1006,7 +938,9 @@ static void cdn_dp_pd_event_work(struct work_struct *work)
|
|||
|
||||
out:
|
||||
mutex_unlock(&dp->lock);
|
||||
drm_connector_helper_hpd_irq_event(&dp->connector);
|
||||
drm_bridge_hpd_notify(&dp->bridge,
|
||||
dp->connected ? connector_status_connected
|
||||
: connector_status_disconnected);
|
||||
}
|
||||
|
||||
static int cdn_dp_pd_event(struct notifier_block *nb,
|
||||
|
|
@ -1062,25 +996,34 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
|
|||
|
||||
drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs);
|
||||
|
||||
connector = &dp->connector;
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
connector->dpms = DRM_MODE_DPMS_OFF;
|
||||
dp->bridge.ops =
|
||||
DRM_BRIDGE_OP_DETECT |
|
||||
DRM_BRIDGE_OP_EDID |
|
||||
DRM_BRIDGE_OP_HPD |
|
||||
DRM_BRIDGE_OP_DP_AUDIO;
|
||||
dp->bridge.of_node = dp->dev->of_node;
|
||||
dp->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
|
||||
dp->bridge.hdmi_audio_dev = dp->dev;
|
||||
dp->bridge.hdmi_audio_max_i2s_playback_channels = 8;
|
||||
dp->bridge.hdmi_audio_spdif_playback = 1;
|
||||
dp->bridge.hdmi_audio_dai_port = -1;
|
||||
|
||||
ret = drm_connector_init(drm_dev, connector,
|
||||
&cdn_dp_atomic_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_DisplayPort);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to initialize connector with drm\n");
|
||||
goto err_free_encoder;
|
||||
ret = devm_drm_bridge_add(dev, &dp->bridge);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_bridge_attach(encoder, &dp->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
connector = drm_bridge_connector_init(drm_dev, encoder);
|
||||
if (IS_ERR(connector)) {
|
||||
ret = PTR_ERR(connector);
|
||||
dev_err(dp->dev, "failed to init bridge connector: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_connector_helper_add(connector, &cdn_dp_connector_helper_funcs);
|
||||
|
||||
ret = drm_connector_attach_encoder(connector, encoder);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to attach connector and encoder\n");
|
||||
goto err_free_connector;
|
||||
}
|
||||
drm_connector_attach_encoder(connector, encoder);
|
||||
|
||||
for (i = 0; i < dp->ports; i++) {
|
||||
port = dp->port[i];
|
||||
|
|
@ -1092,7 +1035,7 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
|
|||
if (ret) {
|
||||
DRM_DEV_ERROR(dev,
|
||||
"register EXTCON_DISP_DP notifier err\n");
|
||||
goto err_free_connector;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1101,30 +1044,19 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
|
|||
schedule_work(&dp->event_work);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_connector:
|
||||
drm_connector_cleanup(connector);
|
||||
err_free_encoder:
|
||||
drm_encoder_cleanup(encoder);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cdn_dp_unbind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct cdn_dp_device *dp = dev_get_drvdata(dev);
|
||||
struct drm_encoder *encoder = &dp->encoder.encoder;
|
||||
struct drm_connector *connector = &dp->connector;
|
||||
|
||||
cancel_work_sync(&dp->event_work);
|
||||
cdn_dp_encoder_disable(encoder);
|
||||
encoder->funcs->destroy(encoder);
|
||||
connector->funcs->destroy(connector);
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
if (dp->fw_loaded)
|
||||
release_firmware(dp->fw);
|
||||
drm_edid_free(dp->drm_edid);
|
||||
dp->drm_edid = NULL;
|
||||
}
|
||||
|
||||
static const struct component_ops cdn_dp_component_ops = {
|
||||
|
|
@ -1171,9 +1103,10 @@ static int cdn_dp_probe(struct platform_device *pdev)
|
|||
int ret;
|
||||
int i;
|
||||
|
||||
dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
|
||||
if (!dp)
|
||||
return -ENOMEM;
|
||||
dp = devm_drm_bridge_alloc(dev, struct cdn_dp_device, bridge,
|
||||
&cdn_dp_bridge_funcs);
|
||||
if (IS_ERR(dp))
|
||||
return PTR_ERR(dp);
|
||||
dp->dev = dev;
|
||||
|
||||
match = of_match_node(cdn_dp_dt_ids, pdev->dev.of_node);
|
||||
|
|
@ -1209,19 +1142,11 @@ static int cdn_dp_probe(struct platform_device *pdev)
|
|||
mutex_init(&dp->lock);
|
||||
dev_set_drvdata(dev, dp);
|
||||
|
||||
ret = cdn_dp_audio_codec_init(dp, dev);
|
||||
ret = component_add(dev, &cdn_dp_component_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = component_add(dev, &cdn_dp_component_ops);
|
||||
if (ret)
|
||||
goto err_audio_deinit;
|
||||
|
||||
return 0;
|
||||
|
||||
err_audio_deinit:
|
||||
platform_device_unregister(dp->audio_pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cdn_dp_remove(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#define _CDN_DP_CORE_H
|
||||
|
||||
#include <drm/display/drm_dp_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <sound/hdmi-codec.h>
|
||||
|
|
@ -65,12 +66,11 @@ struct cdn_dp_port {
|
|||
struct cdn_dp_device {
|
||||
struct device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
struct drm_connector connector;
|
||||
struct drm_bridge bridge;
|
||||
struct rockchip_encoder encoder;
|
||||
struct drm_display_mode mode;
|
||||
struct platform_device *audio_pdev;
|
||||
struct work_struct event_work;
|
||||
const struct drm_edid *drm_edid;
|
||||
|
||||
struct mutex lock;
|
||||
bool connected;
|
||||
|
|
@ -101,9 +101,5 @@ struct cdn_dp_device {
|
|||
int active_port;
|
||||
|
||||
u8 dpcd[DP_RECEIVER_CAP_SIZE];
|
||||
bool sink_has_audio;
|
||||
|
||||
hdmi_codec_plugged_cb plugged_cb;
|
||||
struct device *codec_dev;
|
||||
};
|
||||
#endif /* _CDN_DP_CORE_H */
|
||||
|
|
|
|||
|
|
@ -213,17 +213,13 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
|
|||
|
||||
if (IS_ERR(hdmi->ref_clk)) {
|
||||
ret = PTR_ERR(hdmi->ref_clk);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(hdmi->dev, "failed to get reference clock\n");
|
||||
return ret;
|
||||
return dev_err_probe(hdmi->dev, ret, "failed to get reference clock\n");
|
||||
}
|
||||
|
||||
hdmi->grf_clk = devm_clk_get_optional(hdmi->dev, "grf");
|
||||
if (IS_ERR(hdmi->grf_clk)) {
|
||||
ret = PTR_ERR(hdmi->grf_clk);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(hdmi->dev, "failed to get grf clock\n");
|
||||
return ret;
|
||||
return dev_err_probe(hdmi->dev, ret, "failed to get grf clock\n");
|
||||
}
|
||||
|
||||
ret = devm_regulator_get_enable(hdmi->dev, "avdd-0v9");
|
||||
|
|
@ -573,17 +569,13 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
|
|||
|
||||
ret = rockchip_hdmi_parse_dt(hdmi);
|
||||
if (ret) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(hdmi->dev, "Unable to parse OF data\n");
|
||||
return ret;
|
||||
return dev_err_probe(hdmi->dev, ret, "Unable to parse OF data\n");
|
||||
}
|
||||
|
||||
hdmi->phy = devm_phy_optional_get(dev, "hdmi");
|
||||
if (IS_ERR(hdmi->phy)) {
|
||||
ret = PTR_ERR(hdmi->phy);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(hdmi->dev, "failed to get phy\n");
|
||||
return ret;
|
||||
return dev_err_probe(hdmi->dev, ret, "failed to get phy\n");
|
||||
}
|
||||
|
||||
if (hdmi->phy) {
|
||||
|
|
|
|||
|
|
@ -29,12 +29,361 @@
|
|||
|
||||
#include "rockchip_drm_drv.h"
|
||||
|
||||
#include "inno_hdmi.h"
|
||||
#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U
|
||||
|
||||
#define DDC_SEGMENT_ADDR 0x30
|
||||
|
||||
#define HDMI_SCL_RATE (100 * 1000)
|
||||
|
||||
#define DDC_BUS_FREQ_L 0x4b
|
||||
#define DDC_BUS_FREQ_H 0x4c
|
||||
|
||||
#define HDMI_SYS_CTRL 0x00
|
||||
#define m_RST_ANALOG BIT(6)
|
||||
#define v_RST_ANALOG (0 << 6)
|
||||
#define v_NOT_RST_ANALOG BIT(6)
|
||||
#define m_RST_DIGITAL BIT(5)
|
||||
#define v_RST_DIGITAL (0 << 5)
|
||||
#define v_NOT_RST_DIGITAL BIT(5)
|
||||
#define m_REG_CLK_INV BIT(4)
|
||||
#define v_REG_CLK_NOT_INV (0 << 4)
|
||||
#define v_REG_CLK_INV BIT(4)
|
||||
#define m_VCLK_INV BIT(3)
|
||||
#define v_VCLK_NOT_INV (0 << 3)
|
||||
#define v_VCLK_INV BIT(3)
|
||||
#define m_REG_CLK_SOURCE BIT(2)
|
||||
#define v_REG_CLK_SOURCE_TMDS (0 << 2)
|
||||
#define v_REG_CLK_SOURCE_SYS BIT(2)
|
||||
#define m_POWER BIT(1)
|
||||
#define v_PWR_ON (0 << 1)
|
||||
#define v_PWR_OFF BIT(1)
|
||||
#define m_INT_POL BIT(0)
|
||||
#define v_INT_POL_HIGH 1
|
||||
#define v_INT_POL_LOW 0
|
||||
|
||||
#define HDMI_VIDEO_CONTRL1 0x01
|
||||
#define m_VIDEO_INPUT_FORMAT (7 << 1)
|
||||
#define m_DE_SOURCE BIT(0)
|
||||
#define v_VIDEO_INPUT_FORMAT(n) ((n) << 1)
|
||||
#define v_DE_EXTERNAL 1
|
||||
#define v_DE_INTERNAL 0
|
||||
enum {
|
||||
VIDEO_INPUT_SDR_RGB444 = 0,
|
||||
VIDEO_INPUT_DDR_RGB444 = 5,
|
||||
VIDEO_INPUT_DDR_YCBCR422 = 6
|
||||
};
|
||||
|
||||
#define HDMI_VIDEO_CONTRL2 0x02
|
||||
#define m_VIDEO_OUTPUT_COLOR (3 << 6)
|
||||
#define m_VIDEO_INPUT_BITS (3 << 4)
|
||||
#define m_VIDEO_INPUT_CSP BIT(0)
|
||||
#define v_VIDEO_OUTPUT_COLOR(n) (((n) & 0x3) << 6)
|
||||
#define v_VIDEO_INPUT_BITS(n) ((n) << 4)
|
||||
#define v_VIDEO_INPUT_CSP(n) ((n) << 0)
|
||||
enum {
|
||||
VIDEO_INPUT_12BITS = 0,
|
||||
VIDEO_INPUT_10BITS = 1,
|
||||
VIDEO_INPUT_REVERT = 2,
|
||||
VIDEO_INPUT_8BITS = 3,
|
||||
};
|
||||
|
||||
#define HDMI_VIDEO_CONTRL 0x03
|
||||
#define m_VIDEO_AUTO_CSC BIT(7)
|
||||
#define v_VIDEO_AUTO_CSC(n) ((n) << 7)
|
||||
#define m_VIDEO_C0_C2_SWAP BIT(0)
|
||||
#define v_VIDEO_C0_C2_SWAP(n) ((n) << 0)
|
||||
enum {
|
||||
C0_C2_CHANGE_ENABLE = 0,
|
||||
C0_C2_CHANGE_DISABLE = 1,
|
||||
AUTO_CSC_DISABLE = 0,
|
||||
AUTO_CSC_ENABLE = 1,
|
||||
};
|
||||
|
||||
#define HDMI_VIDEO_CONTRL3 0x04
|
||||
#define m_COLOR_DEPTH_NOT_INDICATED BIT(4)
|
||||
#define m_SOF BIT(3)
|
||||
#define m_COLOR_RANGE BIT(2)
|
||||
#define m_CSC BIT(0)
|
||||
#define v_COLOR_DEPTH_NOT_INDICATED(n) ((n) << 4)
|
||||
#define v_SOF_ENABLE (0 << 3)
|
||||
#define v_SOF_DISABLE BIT(3)
|
||||
#define v_COLOR_RANGE_FULL BIT(2)
|
||||
#define v_COLOR_RANGE_LIMITED (0 << 2)
|
||||
#define v_CSC_ENABLE 1
|
||||
#define v_CSC_DISABLE 0
|
||||
|
||||
#define HDMI_AV_MUTE 0x05
|
||||
#define m_AVMUTE_CLEAR BIT(7)
|
||||
#define m_AVMUTE_ENABLE BIT(6)
|
||||
#define m_AUDIO_MUTE BIT(1)
|
||||
#define m_VIDEO_BLACK BIT(0)
|
||||
#define v_AVMUTE_CLEAR(n) ((n) << 7)
|
||||
#define v_AVMUTE_ENABLE(n) ((n) << 6)
|
||||
#define v_AUDIO_MUTE(n) ((n) << 1)
|
||||
#define v_VIDEO_MUTE(n) ((n) << 0)
|
||||
|
||||
#define HDMI_VIDEO_TIMING_CTL 0x08
|
||||
#define v_HSYNC_POLARITY(n) ((n) << 3)
|
||||
#define v_VSYNC_POLARITY(n) ((n) << 2)
|
||||
#define v_INETLACE(n) ((n) << 1)
|
||||
#define v_EXTERANL_VIDEO(n) ((n) << 0)
|
||||
|
||||
#define HDMI_VIDEO_EXT_HTOTAL_L 0x09
|
||||
#define HDMI_VIDEO_EXT_HTOTAL_H 0x0a
|
||||
#define HDMI_VIDEO_EXT_HBLANK_L 0x0b
|
||||
#define HDMI_VIDEO_EXT_HBLANK_H 0x0c
|
||||
#define HDMI_VIDEO_EXT_HDELAY_L 0x0d
|
||||
#define HDMI_VIDEO_EXT_HDELAY_H 0x0e
|
||||
#define HDMI_VIDEO_EXT_HDURATION_L 0x0f
|
||||
#define HDMI_VIDEO_EXT_HDURATION_H 0x10
|
||||
#define HDMI_VIDEO_EXT_VTOTAL_L 0x11
|
||||
#define HDMI_VIDEO_EXT_VTOTAL_H 0x12
|
||||
#define HDMI_VIDEO_EXT_VBLANK 0x13
|
||||
#define HDMI_VIDEO_EXT_VDELAY 0x14
|
||||
#define HDMI_VIDEO_EXT_VDURATION 0x15
|
||||
|
||||
#define HDMI_VIDEO_CSC_COEF 0x18
|
||||
|
||||
#define HDMI_AUDIO_CTRL1 0x35
|
||||
enum {
|
||||
CTS_SOURCE_INTERNAL = 0,
|
||||
CTS_SOURCE_EXTERNAL = 1,
|
||||
};
|
||||
|
||||
#define v_CTS_SOURCE(n) ((n) << 7)
|
||||
|
||||
enum {
|
||||
DOWNSAMPLE_DISABLE = 0,
|
||||
DOWNSAMPLE_1_2 = 1,
|
||||
DOWNSAMPLE_1_4 = 2,
|
||||
};
|
||||
|
||||
#define v_DOWN_SAMPLE(n) ((n) << 5)
|
||||
|
||||
enum {
|
||||
AUDIO_SOURCE_IIS = 0,
|
||||
AUDIO_SOURCE_SPDIF = 1,
|
||||
};
|
||||
|
||||
#define v_AUDIO_SOURCE(n) ((n) << 3)
|
||||
|
||||
#define v_MCLK_ENABLE(n) ((n) << 2)
|
||||
|
||||
enum {
|
||||
MCLK_128FS = 0,
|
||||
MCLK_256FS = 1,
|
||||
MCLK_384FS = 2,
|
||||
MCLK_512FS = 3,
|
||||
};
|
||||
|
||||
#define v_MCLK_RATIO(n) (n)
|
||||
|
||||
#define AUDIO_SAMPLE_RATE 0x37
|
||||
|
||||
enum {
|
||||
AUDIO_32K = 0x3,
|
||||
AUDIO_441K = 0x0,
|
||||
AUDIO_48K = 0x2,
|
||||
AUDIO_882K = 0x8,
|
||||
AUDIO_96K = 0xa,
|
||||
AUDIO_1764K = 0xc,
|
||||
AUDIO_192K = 0xe,
|
||||
};
|
||||
|
||||
#define AUDIO_I2S_MODE 0x38
|
||||
|
||||
enum {
|
||||
I2S_CHANNEL_1_2 = 1,
|
||||
I2S_CHANNEL_3_4 = 3,
|
||||
I2S_CHANNEL_5_6 = 7,
|
||||
I2S_CHANNEL_7_8 = 0xf
|
||||
};
|
||||
|
||||
#define v_I2S_CHANNEL(n) ((n) << 2)
|
||||
|
||||
enum {
|
||||
I2S_STANDARD = 0,
|
||||
I2S_LEFT_JUSTIFIED = 1,
|
||||
I2S_RIGHT_JUSTIFIED = 2,
|
||||
};
|
||||
|
||||
#define v_I2S_MODE(n) (n)
|
||||
|
||||
#define AUDIO_I2S_MAP 0x39
|
||||
#define AUDIO_I2S_SWAPS_SPDIF 0x3a
|
||||
#define v_SPIDF_FREQ(n) (n)
|
||||
|
||||
#define N_32K 0x1000
|
||||
#define N_441K 0x1880
|
||||
#define N_882K 0x3100
|
||||
#define N_1764K 0x6200
|
||||
#define N_48K 0x1800
|
||||
#define N_96K 0x3000
|
||||
#define N_192K 0x6000
|
||||
|
||||
#define HDMI_AUDIO_CHANNEL_STATUS 0x3e
|
||||
#define m_AUDIO_STATUS_NLPCM BIT(7)
|
||||
#define m_AUDIO_STATUS_USE BIT(6)
|
||||
#define m_AUDIO_STATUS_COPYRIGHT BIT(5)
|
||||
#define m_AUDIO_STATUS_ADDITION (3 << 2)
|
||||
#define m_AUDIO_STATUS_CLK_ACCURACY (2 << 0)
|
||||
#define v_AUDIO_STATUS_NLPCM(n) (((n) & 1) << 7)
|
||||
#define AUDIO_N_H 0x3f
|
||||
#define AUDIO_N_M 0x40
|
||||
#define AUDIO_N_L 0x41
|
||||
|
||||
#define HDMI_AUDIO_CTS_H 0x45
|
||||
#define HDMI_AUDIO_CTS_M 0x46
|
||||
#define HDMI_AUDIO_CTS_L 0x47
|
||||
|
||||
#define HDMI_DDC_CLK_L 0x4b
|
||||
#define HDMI_DDC_CLK_H 0x4c
|
||||
|
||||
#define HDMI_EDID_SEGMENT_POINTER 0x4d
|
||||
#define HDMI_EDID_WORD_ADDR 0x4e
|
||||
#define HDMI_EDID_FIFO_OFFSET 0x4f
|
||||
#define HDMI_EDID_FIFO_ADDR 0x50
|
||||
|
||||
#define HDMI_PACKET_SEND_MANUAL 0x9c
|
||||
#define HDMI_PACKET_SEND_AUTO 0x9d
|
||||
#define m_PACKET_GCP_EN BIT(7)
|
||||
#define m_PACKET_MSI_EN BIT(6)
|
||||
#define m_PACKET_SDI_EN BIT(5)
|
||||
#define m_PACKET_VSI_EN BIT(4)
|
||||
#define v_PACKET_GCP_EN(n) (((n) & 1) << 7)
|
||||
#define v_PACKET_MSI_EN(n) (((n) & 1) << 6)
|
||||
#define v_PACKET_SDI_EN(n) (((n) & 1) << 5)
|
||||
#define v_PACKET_VSI_EN(n) (((n) & 1) << 4)
|
||||
|
||||
#define HDMI_CONTROL_PACKET_BUF_INDEX 0x9f
|
||||
|
||||
enum {
|
||||
INFOFRAME_VSI = 0x05,
|
||||
INFOFRAME_AVI = 0x06,
|
||||
INFOFRAME_AAI = 0x08,
|
||||
};
|
||||
|
||||
#define HDMI_CONTROL_PACKET_ADDR 0xa0
|
||||
#define HDMI_MAXIMUM_INFO_FRAME_SIZE 0x11
|
||||
|
||||
enum {
|
||||
AVI_COLOR_MODE_RGB = 0,
|
||||
AVI_COLOR_MODE_YCBCR422 = 1,
|
||||
AVI_COLOR_MODE_YCBCR444 = 2,
|
||||
AVI_COLORIMETRY_NO_DATA = 0,
|
||||
|
||||
AVI_COLORIMETRY_SMPTE_170M = 1,
|
||||
AVI_COLORIMETRY_ITU709 = 2,
|
||||
AVI_COLORIMETRY_EXTENDED = 3,
|
||||
|
||||
AVI_CODED_FRAME_ASPECT_NO_DATA = 0,
|
||||
AVI_CODED_FRAME_ASPECT_4_3 = 1,
|
||||
AVI_CODED_FRAME_ASPECT_16_9 = 2,
|
||||
|
||||
ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME = 0x08,
|
||||
ACTIVE_ASPECT_RATE_4_3 = 0x09,
|
||||
ACTIVE_ASPECT_RATE_16_9 = 0x0A,
|
||||
ACTIVE_ASPECT_RATE_14_9 = 0x0B,
|
||||
};
|
||||
|
||||
#define HDMI_HDCP_CTRL 0x52
|
||||
#define m_HDMI_DVI BIT(1)
|
||||
#define v_HDMI_DVI(n) ((n) << 1)
|
||||
|
||||
#define HDMI_INTERRUPT_MASK1 0xc0
|
||||
#define HDMI_INTERRUPT_STATUS1 0xc1
|
||||
#define m_INT_ACTIVE_VSYNC BIT(5)
|
||||
#define m_INT_EDID_READY BIT(2)
|
||||
|
||||
#define HDMI_INTERRUPT_MASK2 0xc2
|
||||
#define HDMI_INTERRUPT_STATUS2 0xc3
|
||||
#define m_INT_HDCP_ERR BIT(7)
|
||||
#define m_INT_BKSV_FLAG BIT(6)
|
||||
#define m_INT_HDCP_OK BIT(4)
|
||||
|
||||
#define HDMI_STATUS 0xc8
|
||||
#define m_HOTPLUG BIT(7)
|
||||
#define m_MASK_INT_HOTPLUG BIT(5)
|
||||
#define m_INT_HOTPLUG BIT(1)
|
||||
#define v_MASK_INT_HOTPLUG(n) (((n) & 0x1) << 5)
|
||||
|
||||
#define HDMI_COLORBAR 0xc9
|
||||
|
||||
#define HDMI_PHY_SYNC 0xce
|
||||
#define HDMI_PHY_SYS_CTL 0xe0
|
||||
#define m_TMDS_CLK_SOURCE BIT(5)
|
||||
#define v_TMDS_FROM_PLL (0 << 5)
|
||||
#define v_TMDS_FROM_GEN BIT(5)
|
||||
#define m_PHASE_CLK BIT(4)
|
||||
#define v_DEFAULT_PHASE (0 << 4)
|
||||
#define v_SYNC_PHASE BIT(4)
|
||||
#define m_TMDS_CURRENT_PWR BIT(3)
|
||||
#define v_TURN_ON_CURRENT (0 << 3)
|
||||
#define v_CAT_OFF_CURRENT BIT(3)
|
||||
#define m_BANDGAP_PWR BIT(2)
|
||||
#define v_BANDGAP_PWR_UP (0 << 2)
|
||||
#define v_BANDGAP_PWR_DOWN BIT(2)
|
||||
#define m_PLL_PWR BIT(1)
|
||||
#define v_PLL_PWR_UP (0 << 1)
|
||||
#define v_PLL_PWR_DOWN BIT(1)
|
||||
#define m_TMDS_CHG_PWR BIT(0)
|
||||
#define v_TMDS_CHG_PWR_UP (0 << 0)
|
||||
#define v_TMDS_CHG_PWR_DOWN BIT(0)
|
||||
|
||||
#define HDMI_PHY_CHG_PWR 0xe1
|
||||
#define v_CLK_CHG_PWR(n) (((n) & 1) << 3)
|
||||
#define v_DATA_CHG_PWR(n) (((n) & 7) << 0)
|
||||
|
||||
#define HDMI_PHY_DRIVER 0xe2
|
||||
#define v_CLK_MAIN_DRIVER(n) ((n) << 4)
|
||||
#define v_DATA_MAIN_DRIVER(n) ((n) << 0)
|
||||
|
||||
#define HDMI_PHY_PRE_EMPHASIS 0xe3
|
||||
#define v_PRE_EMPHASIS(n) (((n) & 7) << 4)
|
||||
#define v_CLK_PRE_DRIVER(n) (((n) & 3) << 2)
|
||||
#define v_DATA_PRE_DRIVER(n) (((n) & 3) << 0)
|
||||
|
||||
#define HDMI_PHY_FEEDBACK_DIV_RATIO_LOW 0xe7
|
||||
#define v_FEEDBACK_DIV_LOW(n) ((n) & 0xff)
|
||||
#define HDMI_PHY_FEEDBACK_DIV_RATIO_HIGH 0xe8
|
||||
#define v_FEEDBACK_DIV_HIGH(n) ((n) & 1)
|
||||
|
||||
#define HDMI_PHY_PRE_DIV_RATIO 0xed
|
||||
#define v_PRE_DIV_RATIO(n) ((n) & 0x1f)
|
||||
|
||||
#define HDMI_CEC_CTRL 0xd0
|
||||
#define m_ADJUST_FOR_HISENSE BIT(6)
|
||||
#define m_REJECT_RX_BROADCAST BIT(5)
|
||||
#define m_BUSFREETIME_ENABLE BIT(2)
|
||||
#define m_REJECT_RX BIT(1)
|
||||
#define m_START_TX BIT(0)
|
||||
|
||||
#define HDMI_CEC_DATA 0xd1
|
||||
#define HDMI_CEC_TX_OFFSET 0xd2
|
||||
#define HDMI_CEC_RX_OFFSET 0xd3
|
||||
#define HDMI_CEC_CLK_H 0xd4
|
||||
#define HDMI_CEC_CLK_L 0xd5
|
||||
#define HDMI_CEC_TX_LENGTH 0xd6
|
||||
#define HDMI_CEC_RX_LENGTH 0xd7
|
||||
#define HDMI_CEC_TX_INT_MASK 0xd8
|
||||
#define m_TX_DONE BIT(3)
|
||||
#define m_TX_NOACK BIT(2)
|
||||
#define m_TX_BROADCAST_REJ BIT(1)
|
||||
#define m_TX_BUSNOTFREE BIT(0)
|
||||
|
||||
#define HDMI_CEC_RX_INT_MASK 0xd9
|
||||
#define m_RX_LA_ERR BIT(4)
|
||||
#define m_RX_GLITCH BIT(3)
|
||||
#define m_RX_DONE BIT(0)
|
||||
|
||||
#define HDMI_CEC_TX_INT 0xda
|
||||
#define HDMI_CEC_RX_INT 0xdb
|
||||
#define HDMI_CEC_BUSFREETIME_L 0xdc
|
||||
#define HDMI_CEC_BUSFREETIME_H 0xdd
|
||||
#define HDMI_CEC_LOGICADDR 0xde
|
||||
|
||||
#define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16)
|
||||
|
||||
#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U
|
||||
|
||||
#define RK3036_GRF_SOC_CON2 0x148
|
||||
#define RK3036_HDMI_PHSYNC BIT(4)
|
||||
#define RK3036_HDMI_PVSYNC BIT(5)
|
||||
|
|
@ -255,22 +604,37 @@ static void inno_hdmi_power_up(struct inno_hdmi *hdmi,
|
|||
inno_hdmi_sys_power(hdmi, true);
|
||||
};
|
||||
|
||||
static void inno_hdmi_reset(struct inno_hdmi *hdmi)
|
||||
static void inno_hdmi_init_hw(struct inno_hdmi *hdmi)
|
||||
{
|
||||
u32 val;
|
||||
u32 msk;
|
||||
|
||||
hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_DIGITAL, v_NOT_RST_DIGITAL);
|
||||
udelay(100);
|
||||
usleep_range(100, 150);
|
||||
|
||||
hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_ANALOG, v_NOT_RST_ANALOG);
|
||||
udelay(100);
|
||||
usleep_range(100, 150);
|
||||
|
||||
msk = m_REG_CLK_INV | m_REG_CLK_SOURCE | m_POWER | m_INT_POL;
|
||||
val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH;
|
||||
hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val);
|
||||
|
||||
inno_hdmi_standby(hdmi);
|
||||
|
||||
/*
|
||||
* When the controller isn't configured to an accurate
|
||||
* video timing and there is no reference clock available,
|
||||
* then the TMDS clock source would be switched to PCLK_HDMI,
|
||||
* so we need to init the TMDS rate to PCLK rate, and
|
||||
* reconfigure the DDC clock.
|
||||
*/
|
||||
if (hdmi->refclk)
|
||||
inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->refclk));
|
||||
else
|
||||
inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->pclk));
|
||||
|
||||
/* Unmute hotplug interrupt */
|
||||
hdmi_modb(hdmi, HDMI_STATUS, m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(1));
|
||||
}
|
||||
|
||||
static int inno_hdmi_disable_frame(struct drm_connector *connector,
|
||||
|
|
@ -775,8 +1139,7 @@ static int inno_hdmi_i2c_write(struct inno_hdmi *hdmi, struct i2c_msg *msgs)
|
|||
* we assume that each word write to this i2c adapter
|
||||
* should be the offset of EDID word address.
|
||||
*/
|
||||
if ((msgs->len != 1) ||
|
||||
((msgs->addr != DDC_ADDR) && (msgs->addr != DDC_SEGMENT_ADDR)))
|
||||
if (msgs->len != 1 || (msgs->addr != DDC_ADDR && msgs->addr != DDC_SEGMENT_ADDR))
|
||||
return -EINVAL;
|
||||
|
||||
reinit_completion(&hdmi->i2c->cmp);
|
||||
|
|
@ -867,10 +1230,9 @@ static struct i2c_adapter *inno_hdmi_i2c_adapter(struct inno_hdmi *hdmi)
|
|||
strscpy(adap->name, "Inno HDMI", sizeof(adap->name));
|
||||
i2c_set_adapdata(adap, hdmi);
|
||||
|
||||
ret = i2c_add_adapter(adap);
|
||||
ret = devm_i2c_add_adapter(hdmi->dev, adap);
|
||||
if (ret) {
|
||||
dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name);
|
||||
devm_kfree(hdmi->dev, i2c);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
|
|
@ -907,71 +1269,37 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
|
|||
if (IS_ERR(hdmi->regs))
|
||||
return PTR_ERR(hdmi->regs);
|
||||
|
||||
hdmi->pclk = devm_clk_get(hdmi->dev, "pclk");
|
||||
hdmi->pclk = devm_clk_get_enabled(hdmi->dev, "pclk");
|
||||
if (IS_ERR(hdmi->pclk))
|
||||
return dev_err_probe(dev, PTR_ERR(hdmi->pclk), "Unable to get HDMI pclk\n");
|
||||
|
||||
ret = clk_prepare_enable(hdmi->pclk);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Cannot enable HDMI pclk: %d\n", ret);
|
||||
|
||||
hdmi->refclk = devm_clk_get_optional(hdmi->dev, "ref");
|
||||
if (IS_ERR(hdmi->refclk)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(hdmi->refclk), "Unable to get HDMI refclk\n");
|
||||
goto err_disable_pclk;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(hdmi->refclk);
|
||||
if (ret) {
|
||||
ret = dev_err_probe(dev, ret, "Cannot enable HDMI refclk: %d\n", ret);
|
||||
goto err_disable_pclk;
|
||||
}
|
||||
hdmi->refclk = devm_clk_get_optional_enabled(hdmi->dev, "ref");
|
||||
if (IS_ERR(hdmi->refclk))
|
||||
return dev_err_probe(dev, PTR_ERR(hdmi->refclk), "Unable to get HDMI refclk\n");
|
||||
|
||||
if (hdmi->variant->dev_type == RK3036_HDMI) {
|
||||
hdmi->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
|
||||
if (IS_ERR(hdmi->grf)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(hdmi->grf),
|
||||
"Unable to get rockchip,grf\n");
|
||||
goto err_disable_clk;
|
||||
}
|
||||
if (IS_ERR(hdmi->grf))
|
||||
return dev_err_probe(dev,
|
||||
PTR_ERR(hdmi->grf), "Unable to get rockchip,grf\n");
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
ret = irq;
|
||||
goto err_disable_clk;
|
||||
}
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
inno_hdmi_reset(hdmi);
|
||||
inno_hdmi_init_hw(hdmi);
|
||||
|
||||
hdmi->ddc = inno_hdmi_i2c_adapter(hdmi);
|
||||
if (IS_ERR(hdmi->ddc)) {
|
||||
ret = PTR_ERR(hdmi->ddc);
|
||||
hdmi->ddc = NULL;
|
||||
goto err_disable_clk;
|
||||
}
|
||||
|
||||
/*
|
||||
* When the controller isn't configured to an accurate
|
||||
* video timing and there is no reference clock available,
|
||||
* then the TMDS clock source would be switched to PCLK_HDMI,
|
||||
* so we need to init the TMDS rate to PCLK rate, and
|
||||
* reconfigure the DDC clock.
|
||||
*/
|
||||
if (hdmi->refclk)
|
||||
inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->refclk));
|
||||
else
|
||||
inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->pclk));
|
||||
if (IS_ERR(hdmi->ddc))
|
||||
return PTR_ERR(hdmi->ddc);
|
||||
|
||||
ret = inno_hdmi_register(drm, hdmi);
|
||||
if (ret)
|
||||
goto err_put_adapter;
|
||||
return ret;
|
||||
|
||||
dev_set_drvdata(dev, hdmi);
|
||||
|
||||
/* Unmute hotplug interrupt */
|
||||
hdmi_modb(hdmi, HDMI_STATUS, m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(1));
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, inno_hdmi_hardirq,
|
||||
inno_hdmi_irq, IRQF_SHARED,
|
||||
dev_name(dev), hdmi);
|
||||
|
|
@ -982,12 +1310,6 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
|
|||
err_cleanup_hdmi:
|
||||
hdmi->connector.funcs->destroy(&hdmi->connector);
|
||||
hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
|
||||
err_put_adapter:
|
||||
i2c_put_adapter(hdmi->ddc);
|
||||
err_disable_clk:
|
||||
clk_disable_unprepare(hdmi->refclk);
|
||||
err_disable_pclk:
|
||||
clk_disable_unprepare(hdmi->pclk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -998,10 +1320,6 @@ static void inno_hdmi_unbind(struct device *dev, struct device *master,
|
|||
|
||||
hdmi->connector.funcs->destroy(&hdmi->connector);
|
||||
hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
|
||||
|
||||
i2c_put_adapter(hdmi->ddc);
|
||||
clk_disable_unprepare(hdmi->refclk);
|
||||
clk_disable_unprepare(hdmi->pclk);
|
||||
}
|
||||
|
||||
static const struct component_ops inno_hdmi_ops = {
|
||||
|
|
|
|||
|
|
@ -1,349 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) Rockchip Electronics Co., Ltd.
|
||||
* Zheng Yang <zhengyang@rock-chips.com>
|
||||
* Yakir Yang <ykk@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef __INNO_HDMI_H__
|
||||
#define __INNO_HDMI_H__
|
||||
|
||||
#define DDC_SEGMENT_ADDR 0x30
|
||||
|
||||
#define HDMI_SCL_RATE (100*1000)
|
||||
#define DDC_BUS_FREQ_L 0x4b
|
||||
#define DDC_BUS_FREQ_H 0x4c
|
||||
|
||||
#define HDMI_SYS_CTRL 0x00
|
||||
#define m_RST_ANALOG (1 << 6)
|
||||
#define v_RST_ANALOG (0 << 6)
|
||||
#define v_NOT_RST_ANALOG (1 << 6)
|
||||
#define m_RST_DIGITAL (1 << 5)
|
||||
#define v_RST_DIGITAL (0 << 5)
|
||||
#define v_NOT_RST_DIGITAL (1 << 5)
|
||||
#define m_REG_CLK_INV (1 << 4)
|
||||
#define v_REG_CLK_NOT_INV (0 << 4)
|
||||
#define v_REG_CLK_INV (1 << 4)
|
||||
#define m_VCLK_INV (1 << 3)
|
||||
#define v_VCLK_NOT_INV (0 << 3)
|
||||
#define v_VCLK_INV (1 << 3)
|
||||
#define m_REG_CLK_SOURCE (1 << 2)
|
||||
#define v_REG_CLK_SOURCE_TMDS (0 << 2)
|
||||
#define v_REG_CLK_SOURCE_SYS (1 << 2)
|
||||
#define m_POWER (1 << 1)
|
||||
#define v_PWR_ON (0 << 1)
|
||||
#define v_PWR_OFF (1 << 1)
|
||||
#define m_INT_POL (1 << 0)
|
||||
#define v_INT_POL_HIGH 1
|
||||
#define v_INT_POL_LOW 0
|
||||
|
||||
#define HDMI_VIDEO_CONTRL1 0x01
|
||||
#define m_VIDEO_INPUT_FORMAT (7 << 1)
|
||||
#define m_DE_SOURCE (1 << 0)
|
||||
#define v_VIDEO_INPUT_FORMAT(n) (n << 1)
|
||||
#define v_DE_EXTERNAL 1
|
||||
#define v_DE_INTERNAL 0
|
||||
enum {
|
||||
VIDEO_INPUT_SDR_RGB444 = 0,
|
||||
VIDEO_INPUT_DDR_RGB444 = 5,
|
||||
VIDEO_INPUT_DDR_YCBCR422 = 6
|
||||
};
|
||||
|
||||
#define HDMI_VIDEO_CONTRL2 0x02
|
||||
#define m_VIDEO_OUTPUT_COLOR (3 << 6)
|
||||
#define m_VIDEO_INPUT_BITS (3 << 4)
|
||||
#define m_VIDEO_INPUT_CSP (1 << 0)
|
||||
#define v_VIDEO_OUTPUT_COLOR(n) (((n) & 0x3) << 6)
|
||||
#define v_VIDEO_INPUT_BITS(n) (n << 4)
|
||||
#define v_VIDEO_INPUT_CSP(n) (n << 0)
|
||||
enum {
|
||||
VIDEO_INPUT_12BITS = 0,
|
||||
VIDEO_INPUT_10BITS = 1,
|
||||
VIDEO_INPUT_REVERT = 2,
|
||||
VIDEO_INPUT_8BITS = 3,
|
||||
};
|
||||
|
||||
#define HDMI_VIDEO_CONTRL 0x03
|
||||
#define m_VIDEO_AUTO_CSC (1 << 7)
|
||||
#define v_VIDEO_AUTO_CSC(n) (n << 7)
|
||||
#define m_VIDEO_C0_C2_SWAP (1 << 0)
|
||||
#define v_VIDEO_C0_C2_SWAP(n) (n << 0)
|
||||
enum {
|
||||
C0_C2_CHANGE_ENABLE = 0,
|
||||
C0_C2_CHANGE_DISABLE = 1,
|
||||
AUTO_CSC_DISABLE = 0,
|
||||
AUTO_CSC_ENABLE = 1,
|
||||
};
|
||||
|
||||
#define HDMI_VIDEO_CONTRL3 0x04
|
||||
#define m_COLOR_DEPTH_NOT_INDICATED (1 << 4)
|
||||
#define m_SOF (1 << 3)
|
||||
#define m_COLOR_RANGE (1 << 2)
|
||||
#define m_CSC (1 << 0)
|
||||
#define v_COLOR_DEPTH_NOT_INDICATED(n) ((n) << 4)
|
||||
#define v_SOF_ENABLE (0 << 3)
|
||||
#define v_SOF_DISABLE (1 << 3)
|
||||
#define v_COLOR_RANGE_FULL (1 << 2)
|
||||
#define v_COLOR_RANGE_LIMITED (0 << 2)
|
||||
#define v_CSC_ENABLE 1
|
||||
#define v_CSC_DISABLE 0
|
||||
|
||||
#define HDMI_AV_MUTE 0x05
|
||||
#define m_AVMUTE_CLEAR (1 << 7)
|
||||
#define m_AVMUTE_ENABLE (1 << 6)
|
||||
#define m_AUDIO_MUTE (1 << 1)
|
||||
#define m_VIDEO_BLACK (1 << 0)
|
||||
#define v_AVMUTE_CLEAR(n) (n << 7)
|
||||
#define v_AVMUTE_ENABLE(n) (n << 6)
|
||||
#define v_AUDIO_MUTE(n) (n << 1)
|
||||
#define v_VIDEO_MUTE(n) (n << 0)
|
||||
|
||||
#define HDMI_VIDEO_TIMING_CTL 0x08
|
||||
#define v_HSYNC_POLARITY(n) (n << 3)
|
||||
#define v_VSYNC_POLARITY(n) (n << 2)
|
||||
#define v_INETLACE(n) (n << 1)
|
||||
#define v_EXTERANL_VIDEO(n) (n << 0)
|
||||
|
||||
#define HDMI_VIDEO_EXT_HTOTAL_L 0x09
|
||||
#define HDMI_VIDEO_EXT_HTOTAL_H 0x0a
|
||||
#define HDMI_VIDEO_EXT_HBLANK_L 0x0b
|
||||
#define HDMI_VIDEO_EXT_HBLANK_H 0x0c
|
||||
#define HDMI_VIDEO_EXT_HDELAY_L 0x0d
|
||||
#define HDMI_VIDEO_EXT_HDELAY_H 0x0e
|
||||
#define HDMI_VIDEO_EXT_HDURATION_L 0x0f
|
||||
#define HDMI_VIDEO_EXT_HDURATION_H 0x10
|
||||
#define HDMI_VIDEO_EXT_VTOTAL_L 0x11
|
||||
#define HDMI_VIDEO_EXT_VTOTAL_H 0x12
|
||||
#define HDMI_VIDEO_EXT_VBLANK 0x13
|
||||
#define HDMI_VIDEO_EXT_VDELAY 0x14
|
||||
#define HDMI_VIDEO_EXT_VDURATION 0x15
|
||||
|
||||
#define HDMI_VIDEO_CSC_COEF 0x18
|
||||
|
||||
#define HDMI_AUDIO_CTRL1 0x35
|
||||
enum {
|
||||
CTS_SOURCE_INTERNAL = 0,
|
||||
CTS_SOURCE_EXTERNAL = 1,
|
||||
};
|
||||
#define v_CTS_SOURCE(n) (n << 7)
|
||||
|
||||
enum {
|
||||
DOWNSAMPLE_DISABLE = 0,
|
||||
DOWNSAMPLE_1_2 = 1,
|
||||
DOWNSAMPLE_1_4 = 2,
|
||||
};
|
||||
#define v_DOWN_SAMPLE(n) (n << 5)
|
||||
|
||||
enum {
|
||||
AUDIO_SOURCE_IIS = 0,
|
||||
AUDIO_SOURCE_SPDIF = 1,
|
||||
};
|
||||
#define v_AUDIO_SOURCE(n) (n << 3)
|
||||
|
||||
#define v_MCLK_ENABLE(n) (n << 2)
|
||||
enum {
|
||||
MCLK_128FS = 0,
|
||||
MCLK_256FS = 1,
|
||||
MCLK_384FS = 2,
|
||||
MCLK_512FS = 3,
|
||||
};
|
||||
#define v_MCLK_RATIO(n) (n)
|
||||
|
||||
#define AUDIO_SAMPLE_RATE 0x37
|
||||
enum {
|
||||
AUDIO_32K = 0x3,
|
||||
AUDIO_441K = 0x0,
|
||||
AUDIO_48K = 0x2,
|
||||
AUDIO_882K = 0x8,
|
||||
AUDIO_96K = 0xa,
|
||||
AUDIO_1764K = 0xc,
|
||||
AUDIO_192K = 0xe,
|
||||
};
|
||||
|
||||
#define AUDIO_I2S_MODE 0x38
|
||||
enum {
|
||||
I2S_CHANNEL_1_2 = 1,
|
||||
I2S_CHANNEL_3_4 = 3,
|
||||
I2S_CHANNEL_5_6 = 7,
|
||||
I2S_CHANNEL_7_8 = 0xf
|
||||
};
|
||||
#define v_I2S_CHANNEL(n) ((n) << 2)
|
||||
enum {
|
||||
I2S_STANDARD = 0,
|
||||
I2S_LEFT_JUSTIFIED = 1,
|
||||
I2S_RIGHT_JUSTIFIED = 2,
|
||||
};
|
||||
#define v_I2S_MODE(n) (n)
|
||||
|
||||
#define AUDIO_I2S_MAP 0x39
|
||||
#define AUDIO_I2S_SWAPS_SPDIF 0x3a
|
||||
#define v_SPIDF_FREQ(n) (n)
|
||||
|
||||
#define N_32K 0x1000
|
||||
#define N_441K 0x1880
|
||||
#define N_882K 0x3100
|
||||
#define N_1764K 0x6200
|
||||
#define N_48K 0x1800
|
||||
#define N_96K 0x3000
|
||||
#define N_192K 0x6000
|
||||
|
||||
#define HDMI_AUDIO_CHANNEL_STATUS 0x3e
|
||||
#define m_AUDIO_STATUS_NLPCM (1 << 7)
|
||||
#define m_AUDIO_STATUS_USE (1 << 6)
|
||||
#define m_AUDIO_STATUS_COPYRIGHT (1 << 5)
|
||||
#define m_AUDIO_STATUS_ADDITION (3 << 2)
|
||||
#define m_AUDIO_STATUS_CLK_ACCURACY (2 << 0)
|
||||
#define v_AUDIO_STATUS_NLPCM(n) ((n & 1) << 7)
|
||||
#define AUDIO_N_H 0x3f
|
||||
#define AUDIO_N_M 0x40
|
||||
#define AUDIO_N_L 0x41
|
||||
|
||||
#define HDMI_AUDIO_CTS_H 0x45
|
||||
#define HDMI_AUDIO_CTS_M 0x46
|
||||
#define HDMI_AUDIO_CTS_L 0x47
|
||||
|
||||
#define HDMI_DDC_CLK_L 0x4b
|
||||
#define HDMI_DDC_CLK_H 0x4c
|
||||
|
||||
#define HDMI_EDID_SEGMENT_POINTER 0x4d
|
||||
#define HDMI_EDID_WORD_ADDR 0x4e
|
||||
#define HDMI_EDID_FIFO_OFFSET 0x4f
|
||||
#define HDMI_EDID_FIFO_ADDR 0x50
|
||||
|
||||
#define HDMI_PACKET_SEND_MANUAL 0x9c
|
||||
#define HDMI_PACKET_SEND_AUTO 0x9d
|
||||
#define m_PACKET_GCP_EN (1 << 7)
|
||||
#define m_PACKET_MSI_EN (1 << 6)
|
||||
#define m_PACKET_SDI_EN (1 << 5)
|
||||
#define m_PACKET_VSI_EN (1 << 4)
|
||||
#define v_PACKET_GCP_EN(n) ((n & 1) << 7)
|
||||
#define v_PACKET_MSI_EN(n) ((n & 1) << 6)
|
||||
#define v_PACKET_SDI_EN(n) ((n & 1) << 5)
|
||||
#define v_PACKET_VSI_EN(n) ((n & 1) << 4)
|
||||
|
||||
#define HDMI_CONTROL_PACKET_BUF_INDEX 0x9f
|
||||
enum {
|
||||
INFOFRAME_VSI = 0x05,
|
||||
INFOFRAME_AVI = 0x06,
|
||||
INFOFRAME_AAI = 0x08,
|
||||
};
|
||||
|
||||
#define HDMI_CONTROL_PACKET_ADDR 0xa0
|
||||
#define HDMI_MAXIMUM_INFO_FRAME_SIZE 0x11
|
||||
enum {
|
||||
AVI_COLOR_MODE_RGB = 0,
|
||||
AVI_COLOR_MODE_YCBCR422 = 1,
|
||||
AVI_COLOR_MODE_YCBCR444 = 2,
|
||||
AVI_COLORIMETRY_NO_DATA = 0,
|
||||
|
||||
AVI_COLORIMETRY_SMPTE_170M = 1,
|
||||
AVI_COLORIMETRY_ITU709 = 2,
|
||||
AVI_COLORIMETRY_EXTENDED = 3,
|
||||
|
||||
AVI_CODED_FRAME_ASPECT_NO_DATA = 0,
|
||||
AVI_CODED_FRAME_ASPECT_4_3 = 1,
|
||||
AVI_CODED_FRAME_ASPECT_16_9 = 2,
|
||||
|
||||
ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME = 0x08,
|
||||
ACTIVE_ASPECT_RATE_4_3 = 0x09,
|
||||
ACTIVE_ASPECT_RATE_16_9 = 0x0A,
|
||||
ACTIVE_ASPECT_RATE_14_9 = 0x0B,
|
||||
};
|
||||
|
||||
#define HDMI_HDCP_CTRL 0x52
|
||||
#define m_HDMI_DVI (1 << 1)
|
||||
#define v_HDMI_DVI(n) (n << 1)
|
||||
|
||||
#define HDMI_INTERRUPT_MASK1 0xc0
|
||||
#define HDMI_INTERRUPT_STATUS1 0xc1
|
||||
#define m_INT_ACTIVE_VSYNC (1 << 5)
|
||||
#define m_INT_EDID_READY (1 << 2)
|
||||
|
||||
#define HDMI_INTERRUPT_MASK2 0xc2
|
||||
#define HDMI_INTERRUPT_STATUS2 0xc3
|
||||
#define m_INT_HDCP_ERR (1 << 7)
|
||||
#define m_INT_BKSV_FLAG (1 << 6)
|
||||
#define m_INT_HDCP_OK (1 << 4)
|
||||
|
||||
#define HDMI_STATUS 0xc8
|
||||
#define m_HOTPLUG (1 << 7)
|
||||
#define m_MASK_INT_HOTPLUG (1 << 5)
|
||||
#define m_INT_HOTPLUG (1 << 1)
|
||||
#define v_MASK_INT_HOTPLUG(n) ((n & 0x1) << 5)
|
||||
|
||||
#define HDMI_COLORBAR 0xc9
|
||||
|
||||
#define HDMI_PHY_SYNC 0xce
|
||||
#define HDMI_PHY_SYS_CTL 0xe0
|
||||
#define m_TMDS_CLK_SOURCE (1 << 5)
|
||||
#define v_TMDS_FROM_PLL (0 << 5)
|
||||
#define v_TMDS_FROM_GEN (1 << 5)
|
||||
#define m_PHASE_CLK (1 << 4)
|
||||
#define v_DEFAULT_PHASE (0 << 4)
|
||||
#define v_SYNC_PHASE (1 << 4)
|
||||
#define m_TMDS_CURRENT_PWR (1 << 3)
|
||||
#define v_TURN_ON_CURRENT (0 << 3)
|
||||
#define v_CAT_OFF_CURRENT (1 << 3)
|
||||
#define m_BANDGAP_PWR (1 << 2)
|
||||
#define v_BANDGAP_PWR_UP (0 << 2)
|
||||
#define v_BANDGAP_PWR_DOWN (1 << 2)
|
||||
#define m_PLL_PWR (1 << 1)
|
||||
#define v_PLL_PWR_UP (0 << 1)
|
||||
#define v_PLL_PWR_DOWN (1 << 1)
|
||||
#define m_TMDS_CHG_PWR (1 << 0)
|
||||
#define v_TMDS_CHG_PWR_UP (0 << 0)
|
||||
#define v_TMDS_CHG_PWR_DOWN (1 << 0)
|
||||
|
||||
#define HDMI_PHY_CHG_PWR 0xe1
|
||||
#define v_CLK_CHG_PWR(n) ((n & 1) << 3)
|
||||
#define v_DATA_CHG_PWR(n) ((n & 7) << 0)
|
||||
|
||||
#define HDMI_PHY_DRIVER 0xe2
|
||||
#define v_CLK_MAIN_DRIVER(n) (n << 4)
|
||||
#define v_DATA_MAIN_DRIVER(n) (n << 0)
|
||||
|
||||
#define HDMI_PHY_PRE_EMPHASIS 0xe3
|
||||
#define v_PRE_EMPHASIS(n) ((n & 7) << 4)
|
||||
#define v_CLK_PRE_DRIVER(n) ((n & 3) << 2)
|
||||
#define v_DATA_PRE_DRIVER(n) ((n & 3) << 0)
|
||||
|
||||
#define HDMI_PHY_FEEDBACK_DIV_RATIO_LOW 0xe7
|
||||
#define v_FEEDBACK_DIV_LOW(n) (n & 0xff)
|
||||
#define HDMI_PHY_FEEDBACK_DIV_RATIO_HIGH 0xe8
|
||||
#define v_FEEDBACK_DIV_HIGH(n) (n & 1)
|
||||
|
||||
#define HDMI_PHY_PRE_DIV_RATIO 0xed
|
||||
#define v_PRE_DIV_RATIO(n) (n & 0x1f)
|
||||
|
||||
#define HDMI_CEC_CTRL 0xd0
|
||||
#define m_ADJUST_FOR_HISENSE (1 << 6)
|
||||
#define m_REJECT_RX_BROADCAST (1 << 5)
|
||||
#define m_BUSFREETIME_ENABLE (1 << 2)
|
||||
#define m_REJECT_RX (1 << 1)
|
||||
#define m_START_TX (1 << 0)
|
||||
|
||||
#define HDMI_CEC_DATA 0xd1
|
||||
#define HDMI_CEC_TX_OFFSET 0xd2
|
||||
#define HDMI_CEC_RX_OFFSET 0xd3
|
||||
#define HDMI_CEC_CLK_H 0xd4
|
||||
#define HDMI_CEC_CLK_L 0xd5
|
||||
#define HDMI_CEC_TX_LENGTH 0xd6
|
||||
#define HDMI_CEC_RX_LENGTH 0xd7
|
||||
#define HDMI_CEC_TX_INT_MASK 0xd8
|
||||
#define m_TX_DONE (1 << 3)
|
||||
#define m_TX_NOACK (1 << 2)
|
||||
#define m_TX_BROADCAST_REJ (1 << 1)
|
||||
#define m_TX_BUSNOTFREE (1 << 0)
|
||||
|
||||
#define HDMI_CEC_RX_INT_MASK 0xd9
|
||||
#define m_RX_LA_ERR (1 << 4)
|
||||
#define m_RX_GLITCH (1 << 3)
|
||||
#define m_RX_DONE (1 << 0)
|
||||
|
||||
#define HDMI_CEC_TX_INT 0xda
|
||||
#define HDMI_CEC_RX_INT 0xdb
|
||||
#define HDMI_CEC_BUSFREETIME_L 0xdc
|
||||
#define HDMI_CEC_BUSFREETIME_H 0xdd
|
||||
#define HDMI_CEC_LOGICADDR 0xde
|
||||
|
||||
#endif /* __INNO_HDMI_H__ */
|
||||
|
|
@ -146,25 +146,6 @@ static void vop2_unlock(struct vop2 *vop2)
|
|||
mutex_unlock(&vop2->vop2_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note:
|
||||
* The write mask function is documented but missing on rk3566/8, writes
|
||||
* to these bits have no effect. For newer soc(rk3588 and following) the
|
||||
* write mask is needed for register writes.
|
||||
*
|
||||
* GLB_CFG_DONE_EN has no write mask bit.
|
||||
*
|
||||
*/
|
||||
static void vop2_cfg_done(struct vop2_video_port *vp)
|
||||
{
|
||||
struct vop2 *vop2 = vp->vop2;
|
||||
u32 val = RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN;
|
||||
|
||||
val |= BIT(vp->id) | (BIT(vp->id) << 16);
|
||||
|
||||
regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, val);
|
||||
}
|
||||
|
||||
static void vop2_win_disable(struct vop2_win *win)
|
||||
{
|
||||
vop2_win_write(win, VOP2_WIN_ENABLE, 0);
|
||||
|
|
@ -854,6 +835,11 @@ static void vop2_enable(struct vop2 *vop2)
|
|||
if (vop2->version == VOP_VERSION_RK3588)
|
||||
rk3588_vop2_power_domain_enable_all(vop2);
|
||||
|
||||
if (vop2->version <= VOP_VERSION_RK3588) {
|
||||
vop2->old_layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
|
||||
vop2->old_port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL);
|
||||
}
|
||||
|
||||
vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
|
||||
|
||||
/*
|
||||
|
|
@ -2422,6 +2408,10 @@ static int vop2_create_crtcs(struct vop2 *vop2)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vp->primary_plane)
|
||||
return dev_err_probe(drm->dev, -ENOENT,
|
||||
"no primary plane for vp %d\n", i);
|
||||
}
|
||||
|
||||
/* Register all unused window as overlay plane */
|
||||
|
|
@ -2724,6 +2714,7 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
|
|||
return dev_err_probe(drm->dev, vop2->irq, "cannot find irq for vop2\n");
|
||||
|
||||
mutex_init(&vop2->vop2_lock);
|
||||
mutex_init(&vop2->ovl_lock);
|
||||
|
||||
ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -334,6 +334,19 @@ struct vop2 {
|
|||
/* optional internal rgb encoder */
|
||||
struct rockchip_rgb *rgb;
|
||||
|
||||
/*
|
||||
* Used to record layer selection configuration on rk356x/rk3588
|
||||
* as register RK3568_OVL_LAYER_SEL and RK3568_OVL_PORT_SEL are
|
||||
* shared for all the Video Ports.
|
||||
*/
|
||||
u32 old_layer_sel;
|
||||
u32 old_port_sel;
|
||||
/*
|
||||
* Ensure that the updates to these two registers(RKK3568_OVL_LAYER_SEL/RK3568_OVL_PORT_SEL)
|
||||
* take effect in sequence.
|
||||
*/
|
||||
struct mutex ovl_lock;
|
||||
|
||||
/* must be put at the end of the struct */
|
||||
struct vop2_win win[];
|
||||
};
|
||||
|
|
@ -727,6 +740,7 @@ enum dst_factor_mode {
|
|||
#define RK3588_OVL_PORT_SEL__CLUSTER2 GENMASK(21, 20)
|
||||
#define RK3568_OVL_PORT_SEL__CLUSTER1 GENMASK(19, 18)
|
||||
#define RK3568_OVL_PORT_SEL__CLUSTER0 GENMASK(17, 16)
|
||||
#define RK3588_OVL_PORT_SET__PORT3_MUX GENMASK(15, 12)
|
||||
#define RK3568_OVL_PORT_SET__PORT2_MUX GENMASK(11, 8)
|
||||
#define RK3568_OVL_PORT_SET__PORT1_MUX GENMASK(7, 4)
|
||||
#define RK3568_OVL_PORT_SET__PORT0_MUX GENMASK(3, 0)
|
||||
|
|
@ -831,4 +845,23 @@ static inline struct vop2_win *to_vop2_win(struct drm_plane *p)
|
|||
return container_of(p, struct vop2_win, base);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note:
|
||||
* The write mask function is documented but missing on rk3566/8, writes
|
||||
* to these bits have no effect. For newer soc(rk3588 and following) the
|
||||
* write mask is needed for register writes.
|
||||
*
|
||||
* GLB_CFG_DONE_EN has no write mask bit.
|
||||
*
|
||||
*/
|
||||
static inline void vop2_cfg_done(struct vop2_video_port *vp)
|
||||
{
|
||||
struct vop2 *vop2 = vp->vop2;
|
||||
u32 val = RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN;
|
||||
|
||||
val |= BIT(vp->id) | (BIT(vp->id) << 16);
|
||||
|
||||
regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, val);
|
||||
}
|
||||
|
||||
#endif /* _ROCKCHIP_DRM_VOP2_H */
|
||||
|
|
|
|||
|
|
@ -56,14 +56,13 @@ struct rockchip_lvds {
|
|||
struct drm_device *drm_dev;
|
||||
struct drm_panel *panel;
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_connector connector;
|
||||
struct rockchip_encoder encoder;
|
||||
struct dev_pin_info *pins;
|
||||
};
|
||||
|
||||
static inline struct rockchip_lvds *connector_to_lvds(struct drm_connector *connector)
|
||||
static inline struct rockchip_lvds *brige_to_lvds(struct drm_bridge *bridge)
|
||||
{
|
||||
return container_of(connector, struct rockchip_lvds, connector);
|
||||
return (struct rockchip_lvds *)bridge->driver_private;
|
||||
}
|
||||
|
||||
static inline struct rockchip_lvds *encoder_to_lvds(struct drm_encoder *encoder)
|
||||
|
|
@ -106,25 +105,21 @@ static inline int rockchip_lvds_name_to_output(const char *s)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs rockchip_lvds_connector_funcs = {
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = drm_connector_cleanup,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
static int rockchip_lvds_connector_get_modes(struct drm_connector *connector)
|
||||
static int
|
||||
rockchip_lvds_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *connector)
|
||||
{
|
||||
struct rockchip_lvds *lvds = connector_to_lvds(connector);
|
||||
struct rockchip_lvds *lvds = brige_to_lvds(bridge);
|
||||
struct drm_panel *panel = lvds->panel;
|
||||
|
||||
return drm_panel_get_modes(panel, connector);
|
||||
}
|
||||
|
||||
static const
|
||||
struct drm_connector_helper_funcs rockchip_lvds_connector_helper_funcs = {
|
||||
.get_modes = rockchip_lvds_connector_get_modes,
|
||||
struct drm_bridge_funcs rockchip_lvds_bridge_funcs = {
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_reset = drm_atomic_helper_bridge_reset,
|
||||
.get_modes = rockchip_lvds_bridge_get_modes,
|
||||
};
|
||||
|
||||
static int
|
||||
|
|
@ -606,26 +601,23 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
|
|||
}
|
||||
|
||||
drm_encoder_helper_add(encoder, lvds->soc_data->helper_funcs);
|
||||
connector = &lvds->connector;
|
||||
|
||||
if (lvds->panel) {
|
||||
connector->dpms = DRM_MODE_DPMS_OFF;
|
||||
ret = drm_connector_init(drm_dev, connector,
|
||||
&rockchip_lvds_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_LVDS);
|
||||
if (ret < 0) {
|
||||
drm_err(drm_dev,
|
||||
"failed to initialize connector: %d\n", ret);
|
||||
lvds->bridge = drm_panel_bridge_add_typed(lvds->panel, DRM_MODE_CONNECTOR_LVDS);
|
||||
if (IS_ERR(lvds->bridge)) {
|
||||
ret = PTR_ERR(lvds->bridge);
|
||||
goto err_free_encoder;
|
||||
}
|
||||
}
|
||||
|
||||
drm_connector_helper_add(connector,
|
||||
&rockchip_lvds_connector_helper_funcs);
|
||||
} else {
|
||||
ret = drm_bridge_attach(encoder, lvds->bridge, NULL,
|
||||
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
|
||||
if (lvds->bridge) {
|
||||
lvds->bridge->driver_private = lvds;
|
||||
lvds->bridge->ops = DRM_BRIDGE_OP_MODES;
|
||||
lvds->bridge->funcs = &rockchip_lvds_bridge_funcs;
|
||||
|
||||
ret = drm_bridge_attach(encoder, lvds->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
|
||||
if (ret)
|
||||
goto err_free_encoder;
|
||||
goto err_free_bridge;
|
||||
|
||||
connector = drm_bridge_connector_init(lvds->drm_dev, encoder);
|
||||
if (IS_ERR(connector)) {
|
||||
|
|
@ -633,14 +625,14 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
|
|||
"failed to initialize bridge connector: %pe\n",
|
||||
connector);
|
||||
ret = PTR_ERR(connector);
|
||||
goto err_free_encoder;
|
||||
goto err_free_bridge;
|
||||
}
|
||||
}
|
||||
|
||||
ret = drm_connector_attach_encoder(connector, encoder);
|
||||
if (ret < 0) {
|
||||
drm_err(drm_dev, "failed to attach encoder: %d\n", ret);
|
||||
goto err_free_connector;
|
||||
ret = drm_connector_attach_encoder(connector, encoder);
|
||||
if (ret < 0) {
|
||||
drm_err(drm_dev, "failed to attach encoder: %d\n", ret);
|
||||
goto err_free_bridge;
|
||||
}
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
|
@ -649,8 +641,8 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
|
|||
|
||||
return 0;
|
||||
|
||||
err_free_connector:
|
||||
drm_connector_cleanup(connector);
|
||||
err_free_bridge:
|
||||
drm_panel_bridge_remove(lvds->bridge);
|
||||
err_free_encoder:
|
||||
drm_encoder_cleanup(encoder);
|
||||
err_put_remote:
|
||||
|
|
@ -670,8 +662,6 @@ static void rockchip_lvds_unbind(struct device *dev, struct device *master,
|
|||
encoder_funcs = lvds->soc_data->helper_funcs;
|
||||
encoder_funcs->disable(&lvds->encoder.encoder);
|
||||
pm_runtime_disable(dev);
|
||||
drm_connector_cleanup(&lvds->connector);
|
||||
drm_encoder_cleanup(&lvds->encoder.encoder);
|
||||
}
|
||||
|
||||
static const struct component_ops rockchip_lvds_component_ops = {
|
||||
|
|
|
|||
|
|
@ -2052,12 +2052,55 @@ static void vop2_setup_alpha(struct vop2_video_port *vp)
|
|||
}
|
||||
}
|
||||
|
||||
static u32 rk3568_vop2_read_port_mux(struct vop2 *vop2)
|
||||
{
|
||||
return vop2_readl(vop2, RK3568_OVL_PORT_SEL);
|
||||
}
|
||||
|
||||
static void rk3568_vop2_wait_for_port_mux_done(struct vop2 *vop2)
|
||||
{
|
||||
u32 port_mux_sel;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Spin until the previous port_mux figuration is done.
|
||||
*/
|
||||
ret = readx_poll_timeout_atomic(rk3568_vop2_read_port_mux, vop2, port_mux_sel,
|
||||
port_mux_sel == vop2->old_port_sel, 0, 50 * 1000);
|
||||
if (ret)
|
||||
DRM_DEV_ERROR(vop2->dev, "wait port_mux done timeout: 0x%x--0x%x\n",
|
||||
port_mux_sel, vop2->old_port_sel);
|
||||
}
|
||||
|
||||
static u32 rk3568_vop2_read_layer_cfg(struct vop2 *vop2)
|
||||
{
|
||||
return vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
|
||||
}
|
||||
|
||||
static void rk3568_vop2_wait_for_layer_cfg_done(struct vop2 *vop2, u32 cfg)
|
||||
{
|
||||
u32 atv_layer_cfg;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Spin until the previous layer configuration is done.
|
||||
*/
|
||||
ret = readx_poll_timeout_atomic(rk3568_vop2_read_layer_cfg, vop2, atv_layer_cfg,
|
||||
atv_layer_cfg == cfg, 0, 50 * 1000);
|
||||
if (ret)
|
||||
DRM_DEV_ERROR(vop2->dev, "wait layer cfg done timeout: 0x%x--0x%x\n",
|
||||
atv_layer_cfg, cfg);
|
||||
}
|
||||
|
||||
static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
|
||||
{
|
||||
struct vop2 *vop2 = vp->vop2;
|
||||
struct drm_plane *plane;
|
||||
u32 layer_sel = 0;
|
||||
u32 port_sel;
|
||||
u32 old_layer_sel = 0;
|
||||
u32 atv_layer_sel = 0;
|
||||
u32 old_port_sel = 0;
|
||||
u8 layer_id;
|
||||
u8 old_layer_id;
|
||||
u8 layer_sel_id;
|
||||
|
|
@ -2069,19 +2112,18 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
|
|||
struct vop2_video_port *vp2 = &vop2->vps[2];
|
||||
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state);
|
||||
|
||||
mutex_lock(&vop2->ovl_lock);
|
||||
ovl_ctrl = vop2_readl(vop2, RK3568_OVL_CTRL);
|
||||
ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD;
|
||||
ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL;
|
||||
ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id);
|
||||
|
||||
if (vcstate->yuv_overlay)
|
||||
ovl_ctrl |= RK3568_OVL_CTRL__YUV_MODE(vp->id);
|
||||
else
|
||||
ovl_ctrl &= ~RK3568_OVL_CTRL__YUV_MODE(vp->id);
|
||||
|
||||
vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl);
|
||||
|
||||
port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL);
|
||||
old_port_sel = vop2->old_port_sel;
|
||||
port_sel = old_port_sel;
|
||||
port_sel &= RK3568_OVL_PORT_SEL__SEL_PORT;
|
||||
|
||||
if (vp0->nlayers)
|
||||
|
|
@ -2102,7 +2144,13 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
|
|||
else
|
||||
port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX, 8);
|
||||
|
||||
layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
|
||||
/* Fixed value for rk3588 */
|
||||
if (vop2->version == VOP_VERSION_RK3588)
|
||||
port_sel |= FIELD_PREP(RK3588_OVL_PORT_SET__PORT3_MUX, 7);
|
||||
|
||||
atv_layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
|
||||
old_layer_sel = vop2->old_layer_sel;
|
||||
layer_sel = old_layer_sel;
|
||||
|
||||
ofs = 0;
|
||||
for (i = 0; i < vp->id; i++)
|
||||
|
|
@ -2186,8 +2234,37 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
|
|||
old_win->data->layer_sel_id[vp->id]);
|
||||
}
|
||||
|
||||
vop2->old_layer_sel = layer_sel;
|
||||
vop2->old_port_sel = port_sel;
|
||||
/*
|
||||
* As the RK3568_OVL_LAYER_SEL and RK3568_OVL_PORT_SEL are shared by all Video Ports,
|
||||
* and the configuration take effect by one Video Port's vsync.
|
||||
* When performing layer migration or change the zpos of layers, there are two things
|
||||
* to be observed and followed:
|
||||
* 1. When a layer is migrated from one VP to another, the configuration of the layer
|
||||
* can only take effect after the Port mux configuration is enabled.
|
||||
*
|
||||
* 2. When we change the zpos of layers, we must ensure that the change for the previous
|
||||
* VP takes effect before we proceed to change the next VP. Otherwise, the new
|
||||
* configuration might overwrite the previous one for the previous VP, or it could
|
||||
* lead to the configuration of the previous VP being take effect along with the VSYNC
|
||||
* of the new VP.
|
||||
*/
|
||||
if (layer_sel != old_layer_sel || port_sel != old_port_sel)
|
||||
ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id);
|
||||
vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl);
|
||||
|
||||
if (port_sel != old_port_sel) {
|
||||
vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
|
||||
vop2_cfg_done(vp);
|
||||
rk3568_vop2_wait_for_port_mux_done(vop2);
|
||||
}
|
||||
|
||||
if (layer_sel != old_layer_sel && atv_layer_sel != old_layer_sel)
|
||||
rk3568_vop2_wait_for_layer_cfg_done(vop2, vop2->old_layer_sel);
|
||||
|
||||
vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel);
|
||||
vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
|
||||
mutex_unlock(&vop2->ovl_lock);
|
||||
}
|
||||
|
||||
static void rk3568_vop2_setup_dly_for_windows(struct vop2_video_port *vp)
|
||||
|
|
|
|||
|
|
@ -84,12 +84,6 @@
|
|||
#define CREATE_TRACE_POINTS
|
||||
#include "gpu_scheduler_trace.h"
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
static struct lockdep_map drm_sched_lockdep_map = {
|
||||
.name = "drm_sched_lockdep_map"
|
||||
};
|
||||
#endif
|
||||
|
||||
int drm_sched_policy = DRM_SCHED_POLICY_FIFO;
|
||||
|
||||
/**
|
||||
|
|
@ -269,38 +263,14 @@ drm_sched_rq_select_entity_rr(struct drm_gpu_scheduler *sched,
|
|||
entity = rq->current_entity;
|
||||
if (entity) {
|
||||
list_for_each_entry_continue(entity, &rq->entities, list) {
|
||||
if (drm_sched_entity_is_ready(entity)) {
|
||||
/* If we can't queue yet, preserve the current
|
||||
* entity in terms of fairness.
|
||||
*/
|
||||
if (!drm_sched_can_queue(sched, entity)) {
|
||||
spin_unlock(&rq->lock);
|
||||
return ERR_PTR(-ENOSPC);
|
||||
}
|
||||
|
||||
rq->current_entity = entity;
|
||||
reinit_completion(&entity->entity_idle);
|
||||
spin_unlock(&rq->lock);
|
||||
return entity;
|
||||
}
|
||||
if (drm_sched_entity_is_ready(entity))
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(entity, &rq->entities, list) {
|
||||
if (drm_sched_entity_is_ready(entity)) {
|
||||
/* If we can't queue yet, preserve the current entity in
|
||||
* terms of fairness.
|
||||
*/
|
||||
if (!drm_sched_can_queue(sched, entity)) {
|
||||
spin_unlock(&rq->lock);
|
||||
return ERR_PTR(-ENOSPC);
|
||||
}
|
||||
|
||||
rq->current_entity = entity;
|
||||
reinit_completion(&entity->entity_idle);
|
||||
spin_unlock(&rq->lock);
|
||||
return entity;
|
||||
}
|
||||
if (drm_sched_entity_is_ready(entity))
|
||||
goto found;
|
||||
|
||||
if (entity == rq->current_entity)
|
||||
break;
|
||||
|
|
@ -309,6 +279,22 @@ drm_sched_rq_select_entity_rr(struct drm_gpu_scheduler *sched,
|
|||
spin_unlock(&rq->lock);
|
||||
|
||||
return NULL;
|
||||
|
||||
found:
|
||||
if (!drm_sched_can_queue(sched, entity)) {
|
||||
/*
|
||||
* If scheduler cannot take more jobs signal the caller to not
|
||||
* consider lower priority queues.
|
||||
*/
|
||||
entity = ERR_PTR(-ENOSPC);
|
||||
} else {
|
||||
rq->current_entity = entity;
|
||||
reinit_completion(&entity->entity_idle);
|
||||
}
|
||||
|
||||
spin_unlock(&rq->lock);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1261,6 +1247,25 @@ static void drm_sched_run_job_work(struct work_struct *w)
|
|||
drm_sched_run_job_queue(sched);
|
||||
}
|
||||
|
||||
static struct workqueue_struct *drm_sched_alloc_wq(const char *name)
|
||||
{
|
||||
#if (IS_ENABLED(CONFIG_LOCKDEP))
|
||||
static struct lockdep_map map = {
|
||||
.name = "drm_sched_lockdep_map"
|
||||
};
|
||||
|
||||
/*
|
||||
* Avoid leaking a lockdep map on each drm sched creation and
|
||||
* destruction by using a single lockdep map for all drm sched
|
||||
* allocated submit_wq.
|
||||
*/
|
||||
|
||||
return alloc_ordered_workqueue_lockdep_map(name, WQ_MEM_RECLAIM, &map);
|
||||
#else
|
||||
return alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_sched_init - Init a gpu scheduler instance
|
||||
*
|
||||
|
|
@ -1301,13 +1306,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, const struct drm_sched_init_
|
|||
sched->submit_wq = args->submit_wq;
|
||||
sched->own_submit_wq = false;
|
||||
} else {
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
sched->submit_wq = alloc_ordered_workqueue_lockdep_map(args->name,
|
||||
WQ_MEM_RECLAIM,
|
||||
&drm_sched_lockdep_map);
|
||||
#else
|
||||
sched->submit_wq = alloc_ordered_workqueue(args->name, WQ_MEM_RECLAIM);
|
||||
#endif
|
||||
sched->submit_wq = drm_sched_alloc_wq(args->name);
|
||||
if (!sched->submit_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -246,6 +246,7 @@ struct sti_hda {
|
|||
struct device dev;
|
||||
struct drm_device *drm_dev;
|
||||
struct drm_display_mode mode;
|
||||
struct drm_bridge bridge;
|
||||
void __iomem *regs;
|
||||
void __iomem *video_dacs_ctrl;
|
||||
struct clk *clk_pix;
|
||||
|
|
@ -262,6 +263,11 @@ struct sti_hda_connector {
|
|||
#define to_sti_hda_connector(x) \
|
||||
container_of(x, struct sti_hda_connector, drm_connector)
|
||||
|
||||
static struct sti_hda *drm_bridge_to_sti_hda(struct drm_bridge *bridge)
|
||||
{
|
||||
return container_of(bridge, struct sti_hda, bridge);
|
||||
}
|
||||
|
||||
static u32 hda_read(struct sti_hda *hda, int offset)
|
||||
{
|
||||
return readl(hda->regs + offset);
|
||||
|
|
@ -401,7 +407,7 @@ static void sti_hda_configure_awg(struct sti_hda *hda, u32 *awg_instr, int nb)
|
|||
|
||||
static void sti_hda_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct sti_hda *hda = bridge->driver_private;
|
||||
struct sti_hda *hda = drm_bridge_to_sti_hda(bridge);
|
||||
u32 val;
|
||||
|
||||
if (!hda->enabled)
|
||||
|
|
@ -426,7 +432,7 @@ static void sti_hda_disable(struct drm_bridge *bridge)
|
|||
|
||||
static void sti_hda_pre_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct sti_hda *hda = bridge->driver_private;
|
||||
struct sti_hda *hda = drm_bridge_to_sti_hda(bridge);
|
||||
u32 val, i, mode_idx;
|
||||
u32 src_filter_y, src_filter_c;
|
||||
u32 *coef_y, *coef_c;
|
||||
|
|
@ -517,7 +523,7 @@ static void sti_hda_set_mode(struct drm_bridge *bridge,
|
|||
const struct drm_display_mode *mode,
|
||||
const struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct sti_hda *hda = bridge->driver_private;
|
||||
struct sti_hda *hda = drm_bridge_to_sti_hda(bridge);
|
||||
u32 mode_idx;
|
||||
int hddac_rate;
|
||||
int ret;
|
||||
|
|
@ -677,7 +683,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
|
|||
struct drm_encoder *encoder;
|
||||
struct sti_hda_connector *connector;
|
||||
struct drm_connector *drm_connector;
|
||||
struct drm_bridge *bridge;
|
||||
int err;
|
||||
|
||||
/* Set the drm device handle */
|
||||
|
|
@ -693,13 +698,7 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
|
|||
|
||||
connector->hda = hda;
|
||||
|
||||
bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
bridge->driver_private = hda;
|
||||
bridge->funcs = &sti_hda_bridge_funcs;
|
||||
drm_bridge_attach(encoder, bridge, NULL, 0);
|
||||
drm_bridge_attach(encoder, &hda->bridge, NULL, 0);
|
||||
|
||||
connector->encoder = encoder;
|
||||
|
||||
|
|
@ -745,9 +744,9 @@ static int sti_hda_probe(struct platform_device *pdev)
|
|||
|
||||
DRM_INFO("%s\n", __func__);
|
||||
|
||||
hda = devm_kzalloc(dev, sizeof(*hda), GFP_KERNEL);
|
||||
if (!hda)
|
||||
return -ENOMEM;
|
||||
hda = devm_drm_bridge_alloc(dev, struct sti_hda, bridge, &sti_hda_bridge_funcs);
|
||||
if (IS_ERR(hda))
|
||||
return PTR_ERR(hda);
|
||||
|
||||
hda->dev = pdev->dev;
|
||||
hda->regs = devm_platform_ioremap_resource_byname(pdev, "hda-reg");
|
||||
|
|
|
|||
|
|
@ -168,6 +168,11 @@ struct sti_hdmi_connector {
|
|||
#define to_sti_hdmi_connector(x) \
|
||||
container_of(x, struct sti_hdmi_connector, drm_connector)
|
||||
|
||||
static struct sti_hdmi *drm_bridge_to_sti_hdmi(struct drm_bridge *bridge)
|
||||
{
|
||||
return container_of(bridge, struct sti_hdmi, bridge);
|
||||
}
|
||||
|
||||
static const struct drm_prop_enum_list colorspace_mode_names[] = {
|
||||
{ HDMI_COLORSPACE_RGB, "rgb" },
|
||||
{ HDMI_COLORSPACE_YUV422, "yuv422" },
|
||||
|
|
@ -749,7 +754,7 @@ static void hdmi_debugfs_init(struct sti_hdmi *hdmi, struct drm_minor *minor)
|
|||
|
||||
static void sti_hdmi_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct sti_hdmi *hdmi = bridge->driver_private;
|
||||
struct sti_hdmi *hdmi = drm_bridge_to_sti_hdmi(bridge);
|
||||
|
||||
u32 val = hdmi_read(hdmi, HDMI_CFG);
|
||||
|
||||
|
|
@ -881,7 +886,7 @@ static int hdmi_audio_configure(struct sti_hdmi *hdmi)
|
|||
|
||||
static void sti_hdmi_pre_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct sti_hdmi *hdmi = bridge->driver_private;
|
||||
struct sti_hdmi *hdmi = drm_bridge_to_sti_hdmi(bridge);
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
||||
|
|
@ -936,7 +941,7 @@ static void sti_hdmi_set_mode(struct drm_bridge *bridge,
|
|||
const struct drm_display_mode *mode,
|
||||
const struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct sti_hdmi *hdmi = bridge->driver_private;
|
||||
struct sti_hdmi *hdmi = drm_bridge_to_sti_hdmi(bridge);
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
|
@ -1273,7 +1278,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
|
|||
struct sti_hdmi_connector *connector;
|
||||
struct cec_connector_info conn_info;
|
||||
struct drm_connector *drm_connector;
|
||||
struct drm_bridge *bridge;
|
||||
int err;
|
||||
|
||||
/* Set the drm device handle */
|
||||
|
|
@ -1289,13 +1293,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
|
|||
|
||||
connector->hdmi = hdmi;
|
||||
|
||||
bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
|
||||
if (!bridge)
|
||||
return -EINVAL;
|
||||
|
||||
bridge->driver_private = hdmi;
|
||||
bridge->funcs = &sti_hdmi_bridge_funcs;
|
||||
drm_bridge_attach(encoder, bridge, NULL, 0);
|
||||
drm_bridge_attach(encoder, &hdmi->bridge, NULL, 0);
|
||||
|
||||
connector->encoder = encoder;
|
||||
|
||||
|
|
@ -1385,9 +1383,9 @@ static int sti_hdmi_probe(struct platform_device *pdev)
|
|||
|
||||
DRM_INFO("%s\n", __func__);
|
||||
|
||||
hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
|
||||
if (!hdmi)
|
||||
return -ENOMEM;
|
||||
hdmi = devm_drm_bridge_alloc(dev, struct sti_hdmi, bridge, &sti_hdmi_bridge_funcs);
|
||||
if (IS_ERR(hdmi))
|
||||
return PTR_ERR(hdmi);
|
||||
|
||||
ddc = of_parse_phandle(pdev->dev.of_node, "ddc", 0);
|
||||
if (ddc) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <media/cec-notifier.h>
|
||||
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_property.h>
|
||||
|
||||
|
|
@ -86,6 +87,7 @@ struct sti_hdmi {
|
|||
struct hdmi_audio_params audio;
|
||||
struct drm_connector *drm_connector;
|
||||
struct cec_notifier *notifier;
|
||||
struct drm_bridge bridge;
|
||||
};
|
||||
|
||||
u32 hdmi_read(struct sti_hdmi *hdmi, int offset);
|
||||
|
|
|
|||
|
|
@ -523,10 +523,10 @@ void tegra_bo_free_object(struct drm_gem_object *gem)
|
|||
if (tegra->domain) {
|
||||
tegra_bo_iommu_unmap(tegra, bo);
|
||||
|
||||
if (gem->import_attach) {
|
||||
if (drm_gem_is_imported(gem)) {
|
||||
dma_buf_unmap_attachment_unlocked(gem->import_attach, bo->sgt,
|
||||
DMA_TO_DEVICE);
|
||||
dma_buf_detach(gem->import_attach->dmabuf, gem->import_attach);
|
||||
dma_buf_detach(gem->dma_buf, gem->import_attach);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ static const struct drm_driver driver = {
|
|||
|
||||
/* GEM hooks */
|
||||
.fops = &udl_driver_fops,
|
||||
DRM_GEM_SHMEM_DRIVER_OPS_NO_MAP_SGT,
|
||||
DRM_GEM_SHMEM_DRIVER_OPS,
|
||||
DRM_FBDEV_SHMEM_DRIVER_OPS,
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/device/faux.h>
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
|
||||
static struct vgem_device {
|
||||
struct drm_device drm;
|
||||
struct platform_device *platform;
|
||||
struct faux_device *faux_dev;
|
||||
} *vgem_device;
|
||||
|
||||
static int vgem_open(struct drm_device *dev, struct drm_file *file)
|
||||
|
|
@ -127,27 +127,27 @@ static const struct drm_driver vgem_driver = {
|
|||
static int __init vgem_init(void)
|
||||
{
|
||||
int ret;
|
||||
struct platform_device *pdev;
|
||||
struct faux_device *fdev;
|
||||
|
||||
pdev = platform_device_register_simple("vgem", -1, NULL, 0);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
fdev = faux_device_create("vgem", NULL, NULL);
|
||||
if (!fdev)
|
||||
return -ENODEV;
|
||||
|
||||
if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) {
|
||||
if (!devres_open_group(&fdev->dev, NULL, GFP_KERNEL)) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unregister;
|
||||
}
|
||||
|
||||
dma_coerce_mask_and_coherent(&pdev->dev,
|
||||
dma_coerce_mask_and_coherent(&fdev->dev,
|
||||
DMA_BIT_MASK(64));
|
||||
|
||||
vgem_device = devm_drm_dev_alloc(&pdev->dev, &vgem_driver,
|
||||
vgem_device = devm_drm_dev_alloc(&fdev->dev, &vgem_driver,
|
||||
struct vgem_device, drm);
|
||||
if (IS_ERR(vgem_device)) {
|
||||
ret = PTR_ERR(vgem_device);
|
||||
goto out_devres;
|
||||
}
|
||||
vgem_device->platform = pdev;
|
||||
vgem_device->faux_dev = fdev;
|
||||
|
||||
/* Final step: expose the device/driver to userspace */
|
||||
ret = drm_dev_register(&vgem_device->drm, 0);
|
||||
|
|
@ -157,19 +157,19 @@ static int __init vgem_init(void)
|
|||
return 0;
|
||||
|
||||
out_devres:
|
||||
devres_release_group(&pdev->dev, NULL);
|
||||
devres_release_group(&fdev->dev, NULL);
|
||||
out_unregister:
|
||||
platform_device_unregister(pdev);
|
||||
faux_device_destroy(fdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit vgem_exit(void)
|
||||
{
|
||||
struct platform_device *pdev = vgem_device->platform;
|
||||
struct faux_device *fdev = vgem_device->faux_dev;
|
||||
|
||||
drm_dev_unregister(&vgem_device->drm);
|
||||
devres_release_group(&pdev->dev, NULL);
|
||||
platform_device_unregister(pdev);
|
||||
devres_release_group(&fdev->dev, NULL);
|
||||
faux_device_destroy(fdev);
|
||||
}
|
||||
|
||||
module_init(vgem_init);
|
||||
|
|
|
|||
|
|
@ -302,8 +302,6 @@ struct vkms_output *vkms_crtc_init(struct drm_device *dev, struct drm_plane *pri
|
|||
vkms_out->composer_workq = drmm_alloc_ordered_workqueue(dev, "vkms_composer", 0);
|
||||
if (IS_ERR(vkms_out->composer_workq))
|
||||
return ERR_CAST(vkms_out->composer_workq);
|
||||
if (!vkms_out->composer_workq)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
return vkms_out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/device/faux.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <drm/clients/drm_client_setup.h>
|
||||
|
|
@ -149,27 +149,27 @@ static int vkms_modeset_init(struct vkms_device *vkmsdev)
|
|||
static int vkms_create(struct vkms_config *config)
|
||||
{
|
||||
int ret;
|
||||
struct platform_device *pdev;
|
||||
struct faux_device *fdev;
|
||||
struct vkms_device *vkms_device;
|
||||
const char *dev_name;
|
||||
|
||||
dev_name = vkms_config_get_device_name(config);
|
||||
pdev = platform_device_register_simple(dev_name, -1, NULL, 0);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
fdev = faux_device_create(dev_name, NULL, NULL);
|
||||
if (!fdev)
|
||||
return -ENODEV;
|
||||
|
||||
if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) {
|
||||
if (!devres_open_group(&fdev->dev, NULL, GFP_KERNEL)) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unregister;
|
||||
}
|
||||
|
||||
vkms_device = devm_drm_dev_alloc(&pdev->dev, &vkms_driver,
|
||||
vkms_device = devm_drm_dev_alloc(&fdev->dev, &vkms_driver,
|
||||
struct vkms_device, drm);
|
||||
if (IS_ERR(vkms_device)) {
|
||||
ret = PTR_ERR(vkms_device);
|
||||
goto out_devres;
|
||||
}
|
||||
vkms_device->platform = pdev;
|
||||
vkms_device->faux_dev = fdev;
|
||||
vkms_device->config = config;
|
||||
config->dev = vkms_device;
|
||||
|
||||
|
|
@ -203,9 +203,9 @@ static int vkms_create(struct vkms_config *config)
|
|||
return 0;
|
||||
|
||||
out_devres:
|
||||
devres_release_group(&pdev->dev, NULL);
|
||||
devres_release_group(&fdev->dev, NULL);
|
||||
out_unregister:
|
||||
platform_device_unregister(pdev);
|
||||
faux_device_destroy(fdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -231,19 +231,19 @@ static int __init vkms_init(void)
|
|||
|
||||
static void vkms_destroy(struct vkms_config *config)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct faux_device *fdev;
|
||||
|
||||
if (!config->dev) {
|
||||
DRM_INFO("vkms_device is NULL.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pdev = config->dev->platform;
|
||||
fdev = config->dev->faux_dev;
|
||||
|
||||
drm_dev_unregister(&config->dev->drm);
|
||||
drm_atomic_helper_shutdown(&config->dev->drm);
|
||||
devres_release_group(&pdev->dev, NULL);
|
||||
platform_device_unregister(pdev);
|
||||
devres_release_group(&fdev->dev, NULL);
|
||||
faux_device_destroy(fdev);
|
||||
|
||||
config->dev = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -232,13 +232,13 @@ struct vkms_config;
|
|||
* struct vkms_device - Description of a VKMS device
|
||||
*
|
||||
* @drm - Base device in DRM
|
||||
* @platform - Associated platform device
|
||||
* @faux_dev - Associated faux device
|
||||
* @output - Configuration and sub-components of the VKMS device
|
||||
* @config: Configuration used in this VKMS device
|
||||
*/
|
||||
struct vkms_device {
|
||||
struct drm_device drm;
|
||||
struct platform_device *platform;
|
||||
struct faux_device *faux_dev;
|
||||
const struct vkms_config *config;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,13 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
config TRACE_GPU_MEM
|
||||
bool
|
||||
bool "Enable GPU memory usage tracepoints"
|
||||
default n
|
||||
help
|
||||
Choose this option to enable tracepoints for tracking
|
||||
global and per-process GPU memory usage. Intended for
|
||||
performance profiling and required for Android.
|
||||
|
||||
Tracepoint availability varies by GPU driver.
|
||||
|
||||
If in doubt, say "N".
|
||||
|
|
|
|||
|
|
@ -87,4 +87,6 @@ if FB_CORE || SGI_NEWPORT_CONSOLE
|
|||
|
||||
endif
|
||||
|
||||
source "drivers/gpu/trace/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
|
|
|||
|
|
@ -953,13 +953,13 @@ static const char *fbcon_startup(void)
|
|||
int rows, cols;
|
||||
|
||||
/*
|
||||
* If num_registered_fb is zero, this is a call for the dummy part.
|
||||
* If fbcon_num_registered_fb is zero, this is a call for the dummy part.
|
||||
* The frame buffer devices weren't initialized yet.
|
||||
*/
|
||||
if (!fbcon_num_registered_fb || info_idx == -1)
|
||||
return display_desc;
|
||||
/*
|
||||
* Instead of blindly using registered_fb[0], we use info_idx, set by
|
||||
* Instead of blindly using fbcon_registered_fb[0], we use info_idx, set by
|
||||
* fbcon_fb_registered();
|
||||
*/
|
||||
info = fbcon_registered_fb[info_idx];
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ void accel_core_exit(void);
|
|||
int accel_core_init(void);
|
||||
void accel_set_device_instance_params(struct device *kdev, int index);
|
||||
int accel_open(struct inode *inode, struct file *filp);
|
||||
void accel_debugfs_init(struct drm_device *dev);
|
||||
void accel_debugfs_register(struct drm_device *dev);
|
||||
|
||||
#else
|
||||
|
|
@ -77,10 +76,6 @@ static inline void accel_set_device_instance_params(struct device *kdev, int ind
|
|||
{
|
||||
}
|
||||
|
||||
static inline void accel_debugfs_init(struct drm_device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void accel_debugfs_register(struct drm_device *dev)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1051,7 +1051,7 @@ enum drm_bridge_ops {
|
|||
*/
|
||||
DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER = BIT(7),
|
||||
/**
|
||||
* @DRM_BRIDGE_OP_HDMI_CEC_ADAPTER: The bridge requires CEC notifier
|
||||
* @DRM_BRIDGE_OP_HDMI_CEC_ADAPTER: The bridge requires CEC adapter
|
||||
* to be present.
|
||||
*/
|
||||
DRM_BRIDGE_OP_HDMI_CEC_ADAPTER = BIT(8),
|
||||
|
|
|
|||
|
|
@ -153,6 +153,9 @@ void drm_debugfs_add_files(struct drm_device *dev,
|
|||
|
||||
int drm_debugfs_gpuva_info(struct seq_file *m,
|
||||
struct drm_gpuvm *gpuvm);
|
||||
|
||||
void drm_debugfs_clients_add(struct drm_file *file);
|
||||
void drm_debugfs_clients_remove(struct drm_file *file);
|
||||
#else
|
||||
static inline void drm_debugfs_create_files(const struct drm_info_list *files,
|
||||
int count, struct dentry *root,
|
||||
|
|
@ -181,6 +184,14 @@ static inline int drm_debugfs_gpuva_info(struct seq_file *m,
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void drm_debugfs_clients_add(struct drm_file *file)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void drm_debugfs_clients_remove(struct drm_file *file)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DRM_DEBUGFS_H_ */
|
||||
|
|
|
|||
|
|
@ -572,9 +572,24 @@ static inline bool drm_firmware_drivers_only(void)
|
|||
}
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
void drm_debugfs_dev_init(struct drm_device *dev, struct dentry *root);
|
||||
void drm_debugfs_dev_init(struct drm_device *dev);
|
||||
void drm_debugfs_init_root(void);
|
||||
void drm_debugfs_remove_root(void);
|
||||
void drm_debugfs_bridge_params(void);
|
||||
#else
|
||||
static inline void drm_debugfs_dev_init(struct drm_device *dev, struct dentry *root)
|
||||
static inline void drm_debugfs_dev_init(struct drm_device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void drm_debugfs_init_root(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void drm_debugfs_remove_root(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void drm_debugfs_bridge_params(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -400,6 +400,13 @@ struct drm_file {
|
|||
* @client_name_lock: Protects @client_name.
|
||||
*/
|
||||
struct mutex client_name_lock;
|
||||
|
||||
/**
|
||||
* @debugfs_client:
|
||||
*
|
||||
* debugfs directory for each client under a drm node.
|
||||
*/
|
||||
struct dentry *debugfs_client;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -293,23 +293,11 @@ struct drm_gem_object *drm_gem_shmem_prime_import_no_map(struct drm_device *dev,
|
|||
/**
|
||||
* DRM_GEM_SHMEM_DRIVER_OPS - Default shmem GEM operations
|
||||
*
|
||||
* This macro provides a shortcut for setting the shmem GEM operations in
|
||||
* the &drm_driver structure.
|
||||
* This macro provides a shortcut for setting the shmem GEM operations
|
||||
* in the &drm_driver structure. Drivers that do not require an s/g table
|
||||
* for imported buffers should use this.
|
||||
*/
|
||||
#define DRM_GEM_SHMEM_DRIVER_OPS \
|
||||
.gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, \
|
||||
.dumb_create = drm_gem_shmem_dumb_create
|
||||
|
||||
/**
|
||||
* DRM_GEM_SHMEM_DRIVER_OPS_NO_MAP_SGT - shmem GEM operations
|
||||
* without mapping sg_table on
|
||||
* imported buffer.
|
||||
*
|
||||
* This macro provides a shortcut for setting the shmem GEM operations in
|
||||
* the &drm_driver structure for drivers that do not require a sg_table on
|
||||
* imported buffers.
|
||||
*/
|
||||
#define DRM_GEM_SHMEM_DRIVER_OPS_NO_MAP_SGT \
|
||||
.gem_prime_import = drm_gem_shmem_prime_import_no_map, \
|
||||
.dumb_create = drm_gem_shmem_dumb_create
|
||||
|
||||
|
|
|
|||
|
|
@ -129,14 +129,25 @@ void __drmm_mutex_release(struct drm_device *dev, void *res);
|
|||
|
||||
void __drmm_workqueue_release(struct drm_device *device, void *wq);
|
||||
|
||||
/**
|
||||
* drmm_alloc_ordered_workqueue - &drm_device managed alloc_ordered_workqueue()
|
||||
* @dev: DRM device
|
||||
* @fmt: printf format for the name of the workqueue
|
||||
* @flags: WQ_* flags (only WQ_FREEZABLE and WQ_MEM_RECLAIM are meaningful)
|
||||
* @args: args for @fmt
|
||||
*
|
||||
* This is a &drm_device-managed version of alloc_ordered_workqueue(). The
|
||||
* allocated workqueue is automatically destroyed on the final drm_dev_put().
|
||||
*
|
||||
* Returns: workqueue on success, negative ERR_PTR otherwise.
|
||||
*/
|
||||
#define drmm_alloc_ordered_workqueue(dev, fmt, flags, args...) \
|
||||
({ \
|
||||
struct workqueue_struct *wq = alloc_ordered_workqueue(fmt, flags, ##args); \
|
||||
wq ? ({ \
|
||||
int ret = drmm_add_action_or_reset(dev, __drmm_workqueue_release, wq); \
|
||||
ret ? ERR_PTR(ret) : wq; \
|
||||
}) : \
|
||||
wq; \
|
||||
}) : ERR_PTR(-ENOMEM); \
|
||||
})
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
drm,
|
||||
error::{to_result, Result},
|
||||
prelude::*,
|
||||
str::CStr,
|
||||
types::ARef,
|
||||
};
|
||||
use macros::vtable;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user