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:
Simona Vetter 2025-07-11 11:00:32 +02:00
commit 6e85c1ec0e
67 changed files with 3761 additions and 3169 deletions

View File

@ -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``.

View File

@ -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"

View File

@ -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);

View File

@ -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.

View File

@ -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");

View File

@ -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);

View File

@ -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

View File

@ -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);

View 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;

View File

@ -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;

View File

@ -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 {

View File

@ -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 \

View 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;
}

View 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;
}

File diff suppressed because it is too large Load Diff

View 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;
}

View 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;
}

View File

@ -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

View File

@ -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 */

View File

@ -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

View 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

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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")) {

View File

@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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)

View File

@ -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)) {

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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),
};
/**

View File

@ -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)

View File

@ -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 */

View File

@ -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) {

View File

@ -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 = {

View File

@ -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__ */

View File

@ -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)

View File

@ -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 */

View File

@ -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 = {

View File

@ -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)

View File

@ -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;

View File

@ -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");

View File

@ -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) {

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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".

View File

@ -87,4 +87,6 @@ if FB_CORE || SGI_NEWPORT_CONSOLE
endif
source "drivers/gpu/trace/Kconfig"
endmenu

View File

@ -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];

View File

@ -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)
{
}

View File

@ -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),

View File

@ -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_ */

View File

@ -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

View File

@ -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;
};
/**

View File

@ -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

View File

@ -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

View File

@ -10,7 +10,6 @@
drm,
error::{to_result, Result},
prelude::*,
str::CStr,
types::ARef,
};
use macros::vtable;