diff options
67 files changed, 3762 insertions, 3170 deletions
diff --git a/Documentation/userspace-api/dma-buf-heaps.rst b/Documentation/userspace-api/dma-buf-heaps.rst index 535f49047ce6..1dfe5e7acd5a 100644 --- a/Documentation/userspace-api/dma-buf-heaps.rst +++ b/Documentation/userspace-api/dma-buf-heaps.rst @@ -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``. diff --git a/drivers/Kconfig b/drivers/Kconfig index 7c556c5ac4fd..c5edbd2288a1 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -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" diff --git a/drivers/accel/drm_accel.c b/drivers/accel/drm_accel.c index aa826033b0ce..ca3357acd127 100644 --- a/drivers/accel/drm_accel.c +++ b/drivers/accel/drm_accel.c @@ -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" }; @@ -74,17 +72,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); diff --git a/drivers/dma-buf/heaps/Kconfig b/drivers/dma-buf/heaps/Kconfig index a5eef06c4226..bb369b38b001 100644 --- a/drivers/dma-buf/heaps/Kconfig +++ b/drivers/dma-buf/heaps/Kconfig @@ -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. diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c index 9512d050563a..0df007111975 100644 --- a/drivers/dma-buf/heaps/cma_heap.c +++ b/drivers/dma-buf/heaps/cma_heap.c @@ -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"); diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c index 82b1b714300d..bbe7881f1360 100644 --- a/drivers/dma-buf/heaps/system_heap.c +++ b/drivers/dma-buf/heaps/system_heap.c @@ -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(new_table, table->orig_nents, GFP_KERNEL); - if (ret) { - kfree(new_table); - return ERR_PTR(-ENOMEM); - } + ret = sg_alloc_table(to, from->orig_nents, GFP_KERNEL); + if (ret) + return ret; - 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); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index 83f211903425..0e6e2e2acf5b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -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 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h index 0425432d8659..e7b3c38e5186 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h @@ -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); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 195ed81d39ff..4c072451a8a1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 295e7186e156..b1b80efc7993 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h index ec040c2fd6c9..b1ca91b7cda4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h @@ -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 { diff --git a/drivers/gpu/drm/ast/Makefile b/drivers/gpu/drm/ast/Makefile index 8d09ba5d5889..2547613155da 100644 --- a/drivers/gpu/drm/ast/Makefile +++ b/drivers/gpu/drm/ast/Makefile @@ -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 \ diff --git a/drivers/gpu/drm/ast/ast_2000.c b/drivers/gpu/drm/ast/ast_2000.c new file mode 100644 index 000000000000..41c2aa1e425a --- /dev/null +++ b/drivers/gpu/drm/ast/ast_2000.c @@ -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; +} diff --git a/drivers/gpu/drm/ast/ast_2100.c b/drivers/gpu/drm/ast/ast_2100.c new file mode 100644 index 000000000000..477ee15eff5d --- /dev/null +++ b/drivers/gpu/drm/ast/ast_2100.c @@ -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; +} diff --git a/drivers/gpu/drm/ast/ast_2300.c b/drivers/gpu/drm/ast/ast_2300.c new file mode 100644 index 000000000000..dc2a32244689 --- /dev/null +++ b/drivers/gpu/drm/ast/ast_2300.c @@ -0,0 +1,1328 @@ +// 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_2300_set_def_ext_reg(struct ast_device *ast) +{ + static const u8 extreginfo[] = { 0x0f, 0x04, 0x1f, 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; + reg |= 0x20; + ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0xff, reg); +} + +/* AST 2300 DRAM settings */ +#define AST_DDR3 0 +#define AST_DDR2 1 + +struct ast2300_dram_param { + u32 dram_type; + u32 dram_chipid; + u32 dram_freq; + u32 vram_size; + u32 odt; + u32 wodt; + u32 rodt; + u32 dram_config; + u32 reg_PERIOD; + u32 reg_MADJ; + u32 reg_SADJ; + u32 reg_MRS; + u32 reg_EMRS; + u32 reg_AC1; + u32 reg_AC2; + u32 reg_DQSIC; + u32 reg_DRV; + u32 reg_IOZ; + u32 reg_DQIDLY; + u32 reg_FREQ; + u32 madj_max; + u32 dll2_finetune_step; +}; + +/* + * DQSI DLL CBR Setting + */ +#define CBR_SIZE0 ((1 << 10) - 1) +#define CBR_SIZE1 ((4 << 10) - 1) +#define CBR_SIZE2 ((64 << 10) - 1) +#define CBR_PASSNUM 5 +#define CBR_PASSNUM2 5 +#define CBR_THRESHOLD 10 +#define CBR_THRESHOLD2 10 +#define TIMEOUT 5000000 +#define CBR_PATNUM 8 + +static const u32 pattern[8] = { + 0xFF00FF00, + 0xCC33CC33, + 0xAA55AA55, + 0x88778877, + 0x92CC4D6E, + 0x543D3CDE, + 0xF1E843C7, + 0x7C61D253 +}; + +static u32 mmc_test2(struct ast_device *ast, u32 datagen, u8 test_ctl) +{ + u32 data, timeout; + + ast_moutdwm(ast, 0x1e6e0070, 0x00000000); + ast_moutdwm(ast, 0x1e6e0070, (datagen << 3) | test_ctl); + timeout = 0; + do { + data = ast_mindwm(ast, 0x1e6e0070) & 0x1000; + if (++timeout > TIMEOUT) { + ast_moutdwm(ast, 0x1e6e0070, 0x0); + return 0xffffffff; + } + } while (!data); + data = ast_mindwm(ast, 0x1e6e0078); + data = (data | (data >> 16)) & 0xffff; + ast_moutdwm(ast, 0x1e6e0070, 0x00000000); + return data; +} + +static u32 mmc_test_burst2(struct ast_device *ast, u32 datagen) +{ + return mmc_test2(ast, datagen, 0x41); +} + +static bool mmc_test_single(struct ast_device *ast, u32 datagen) +{ + return mmc_test(ast, datagen, 0xc5); +} + +static u32 mmc_test_single2(struct ast_device *ast, u32 datagen) +{ + return mmc_test2(ast, datagen, 0x05); +} + +static int cbr_test(struct ast_device *ast) +{ + u32 data; + int i; + + data = mmc_test_single2(ast, 0); + if ((data & 0xff) && (data & 0xff00)) + return 0; + for (i = 0; i < 8; i++) { + data = mmc_test_burst2(ast, i); + if ((data & 0xff) && (data & 0xff00)) + return 0; + } + if (!data) + return 3; + else if (data & 0xff) + return 2; + return 1; +} + +static int cbr_scan(struct ast_device *ast) +{ + u32 data, data2, patcnt, loop; + + data2 = 3; + for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) { + ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]); + for (loop = 0; loop < CBR_PASSNUM2; loop++) { + data = cbr_test(ast); + if (data != 0) { + data2 &= data; + if (!data2) + return 0; + break; + } + } + if (loop == CBR_PASSNUM2) + return 0; + } + return data2; +} + +static u32 cbr_test2(struct ast_device *ast) +{ + u32 data; + + data = mmc_test_burst2(ast, 0); + if (data == 0xffff) + return 0; + data |= mmc_test_single2(ast, 0); + if (data == 0xffff) + return 0; + + return ~data & 0xffff; +} + +static u32 cbr_scan2(struct ast_device *ast) +{ + u32 data, data2, patcnt, loop; + + data2 = 0xffff; + for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) { + ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]); + for (loop = 0; loop < CBR_PASSNUM2; loop++) { + data = cbr_test2(ast); + if (data != 0) { + data2 &= data; + if (!data2) + return 0; + break; + } + } + if (loop == CBR_PASSNUM2) + return 0; + } + return data2; +} + +static bool cbr_test3(struct ast_device *ast) +{ + if (!mmc_test_burst(ast, 0)) + return false; + if (!mmc_test_single(ast, 0)) + return false; + return true; +} + +static bool cbr_scan3(struct ast_device *ast) +{ + u32 patcnt, loop; + + for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) { + ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]); + for (loop = 0; loop < 2; loop++) { + if (cbr_test3(ast)) + break; + } + if (loop == 2) + return false; + } + return true; +} + +static bool finetuneDQI_L(struct ast_device *ast, struct ast2300_dram_param *param) +{ + u32 gold_sadj[2], dllmin[16], dllmax[16], dlli, data, cnt, mask, passcnt, retry = 0; + bool status = false; +FINETUNE_START: + for (cnt = 0; cnt < 16; cnt++) { + dllmin[cnt] = 0xff; + dllmax[cnt] = 0x0; + } + passcnt = 0; + for (dlli = 0; dlli < 76; dlli++) { + ast_moutdwm(ast, 0x1E6E0068, 0x00001400 | (dlli << 16) | (dlli << 24)); + ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE1); + data = cbr_scan2(ast); + if (data != 0) { + mask = 0x00010001; + for (cnt = 0; cnt < 16; cnt++) { + if (data & mask) { + if (dllmin[cnt] > dlli) + dllmin[cnt] = dlli; + if (dllmax[cnt] < dlli) + dllmax[cnt] = dlli; + } + mask <<= 1; + } + passcnt++; + } else if (passcnt >= CBR_THRESHOLD2) { + break; + } + } + gold_sadj[0] = 0x0; + passcnt = 0; + for (cnt = 0; cnt < 16; cnt++) { + if ((dllmax[cnt] > dllmin[cnt]) && + ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { + gold_sadj[0] += dllmin[cnt]; + passcnt++; + } + } + if (retry++ > 10) + goto FINETUNE_DONE; + if (passcnt != 16) + goto FINETUNE_START; + status = true; +FINETUNE_DONE: + gold_sadj[0] = gold_sadj[0] >> 4; + gold_sadj[1] = gold_sadj[0]; + + data = 0; + for (cnt = 0; cnt < 8; cnt++) { + data >>= 3; + if ((dllmax[cnt] > dllmin[cnt]) && + ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { + dlli = dllmin[cnt]; + if (gold_sadj[0] >= dlli) { + dlli = ((gold_sadj[0] - dlli) * 19) >> 5; + if (dlli > 3) + dlli = 3; + } else { + dlli = ((dlli - gold_sadj[0]) * 19) >> 5; + if (dlli > 4) + dlli = 4; + dlli = (8 - dlli) & 0x7; + } + data |= dlli << 21; + } + } + ast_moutdwm(ast, 0x1E6E0080, data); + + data = 0; + for (cnt = 8; cnt < 16; cnt++) { + data >>= 3; + if ((dllmax[cnt] > dllmin[cnt]) && + ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { + dlli = dllmin[cnt]; + if (gold_sadj[1] >= dlli) { + dlli = ((gold_sadj[1] - dlli) * 19) >> 5; + if (dlli > 3) + dlli = 3; + else + dlli = (dlli - 1) & 0x7; + } else { + dlli = ((dlli - gold_sadj[1]) * 19) >> 5; + dlli += 1; + if (dlli > 4) + dlli = 4; + dlli = (8 - dlli) & 0x7; + } + data |= dlli << 21; + } + } + ast_moutdwm(ast, 0x1E6E0084, data); + return status; +} /* finetuneDQI_L */ + +static void finetuneDQSI(struct ast_device *ast) +{ + u32 dlli, dqsip, dqidly; + u32 reg_mcr18, reg_mcr0c, passcnt[2], diff; + u32 g_dqidly, g_dqsip, g_margin, g_side; + u16 pass[32][2][2]; + char tag[2][76]; + + /* Disable DQI CBR */ + reg_mcr0c = ast_mindwm(ast, 0x1E6E000C); + reg_mcr18 = ast_mindwm(ast, 0x1E6E0018); + reg_mcr18 &= 0x0000ffff; + ast_moutdwm(ast, 0x1E6E0018, reg_mcr18); + + for (dlli = 0; dlli < 76; dlli++) { + tag[0][dlli] = 0x0; + tag[1][dlli] = 0x0; + } + for (dqidly = 0; dqidly < 32; dqidly++) { + pass[dqidly][0][0] = 0xff; + pass[dqidly][0][1] = 0x0; + pass[dqidly][1][0] = 0xff; + pass[dqidly][1][1] = 0x0; + } + for (dqidly = 0; dqidly < 32; dqidly++) { + passcnt[0] = 0; + passcnt[1] = 0; + for (dqsip = 0; dqsip < 2; dqsip++) { + ast_moutdwm(ast, 0x1E6E000C, 0); + ast_moutdwm(ast, 0x1E6E0018, reg_mcr18 | (dqidly << 16) | (dqsip << 23)); + ast_moutdwm(ast, 0x1E6E000C, reg_mcr0c); + for (dlli = 0; dlli < 76; dlli++) { + ast_moutdwm(ast, 0x1E6E0068, + 0x00001300 | (dlli << 16) | (dlli << 24)); + ast_moutdwm(ast, 0x1E6E0070, 0); + ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE0); + if (cbr_scan3(ast)) { + if (dlli == 0) + break; + passcnt[dqsip]++; + tag[dqsip][dlli] = 'P'; + if (dlli < pass[dqidly][dqsip][0]) + pass[dqidly][dqsip][0] = (u16)dlli; + if (dlli > pass[dqidly][dqsip][1]) + pass[dqidly][dqsip][1] = (u16)dlli; + } else if (passcnt[dqsip] >= 5) { + break; + } else { + pass[dqidly][dqsip][0] = 0xff; + pass[dqidly][dqsip][1] = 0x0; + } + } + } + if (passcnt[0] == 0 && passcnt[1] == 0) + dqidly++; + } + /* Search margin */ + g_dqidly = 0; + g_dqsip = 0; + g_margin = 0; + g_side = 0; + + for (dqidly = 0; dqidly < 32; dqidly++) { + for (dqsip = 0; dqsip < 2; dqsip++) { + if (pass[dqidly][dqsip][0] > pass[dqidly][dqsip][1]) + continue; + diff = pass[dqidly][dqsip][1] - pass[dqidly][dqsip][0]; + if ((diff + 2) < g_margin) + continue; + passcnt[0] = 0; + passcnt[1] = 0; + for (dlli = pass[dqidly][dqsip][0]; + dlli > 0 && tag[dqsip][dlli] != 0; + dlli--, passcnt[0]++) { + } + for (dlli = pass[dqidly][dqsip][1]; + dlli < 76 && tag[dqsip][dlli] != 0; + dlli++, passcnt[1]++) { + } + if (passcnt[0] > passcnt[1]) + passcnt[0] = passcnt[1]; + passcnt[1] = 0; + if (passcnt[0] > g_side) + passcnt[1] = passcnt[0] - g_side; + if (diff > (g_margin + 1) && (passcnt[1] > 0 || passcnt[0] > 8)) { + g_margin = diff; + g_dqidly = dqidly; + g_dqsip = dqsip; + g_side = passcnt[0]; + } else if (passcnt[1] > 1 && g_side < 8) { + if (diff > g_margin) + g_margin = diff; + g_dqidly = dqidly; + g_dqsip = dqsip; + g_side = passcnt[0]; + } + } + } + reg_mcr18 = reg_mcr18 | (g_dqidly << 16) | (g_dqsip << 23); + ast_moutdwm(ast, 0x1E6E0018, reg_mcr18); +} + +static bool cbr_dll2(struct ast_device *ast, struct ast2300_dram_param *param) +{ + u32 dllmin[2], dllmax[2], dlli, data, passcnt, retry = 0; + bool status = false; + + finetuneDQSI(ast); + if (finetuneDQI_L(ast, param) == false) + return status; + +CBR_START2: + dllmin[0] = 0xff; + dllmin[1] = 0xff; + dllmax[0] = 0x0; + dllmax[1] = 0x0; + passcnt = 0; + for (dlli = 0; dlli < 76; dlli++) { + ast_moutdwm(ast, 0x1E6E0068, 0x00001300 | (dlli << 16) | (dlli << 24)); + ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE2); + data = cbr_scan(ast); + if (data != 0) { + if (data & 0x1) { + if (dllmin[0] > dlli) + dllmin[0] = dlli; + if (dllmax[0] < dlli) + dllmax[0] = dlli; + } + if (data & 0x2) { + if (dllmin[1] > dlli) + dllmin[1] = dlli; + if (dllmax[1] < dlli) + dllmax[1] = dlli; + } + passcnt++; + } else if (passcnt >= CBR_THRESHOLD) { + break; + } + } + if (retry++ > 10) + goto CBR_DONE2; + if (dllmax[0] == 0 || (dllmax[0] - dllmin[0]) < CBR_THRESHOLD) + goto CBR_START2; + if (dllmax[1] == 0 || (dllmax[1] - dllmin[1]) < CBR_THRESHOLD) + goto CBR_START2; + status = true; +CBR_DONE2: + dlli = (dllmin[1] + dllmax[1]) >> 1; + dlli <<= 8; + dlli += (dllmin[0] + dllmax[0]) >> 1; + ast_moutdwm(ast, 0x1E6E0068, ast_mindwm(ast, 0x1E720058) | (dlli << 16)); + return status; +} /* CBRDLL2 */ + +static void get_ddr3_info(struct ast_device *ast, struct ast2300_dram_param *param) +{ + u32 trap, trap_AC2, trap_MRS; + + ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8); + + /* Ger trap info */ + trap = (ast_mindwm(ast, 0x1E6E2070) >> 25) & 0x3; + trap_AC2 = 0x00020000 + (trap << 16); + trap_AC2 |= 0x00300000 + ((trap & 0x2) << 19); + trap_MRS = 0x00000010 + (trap << 4); + trap_MRS |= ((trap & 0x2) << 18); + + param->reg_MADJ = 0x00034C4C; + param->reg_SADJ = 0x00001800; + param->reg_DRV = 0x000000F0; + param->reg_PERIOD = param->dram_freq; + param->rodt = 0; + + switch (param->dram_freq) { + case 336: + ast_moutdwm(ast, 0x1E6E2020, 0x0190); + param->wodt = 0; + param->reg_AC1 = 0x22202725; + param->reg_AC2 = 0xAA007613 | trap_AC2; + param->reg_DQSIC = 0x000000BA; + param->reg_MRS = 0x04001400 | trap_MRS; + param->reg_EMRS = 0x00000000; + param->reg_IOZ = 0x00000023; + param->reg_DQIDLY = 0x00000074; + param->reg_FREQ = 0x00004DC0; + param->madj_max = 96; + param->dll2_finetune_step = 3; + switch (param->dram_chipid) { + default: + case AST_DRAM_512Mx16: + case AST_DRAM_1Gx16: + param->reg_AC2 = 0xAA007613 | trap_AC2; + break; + case AST_DRAM_2Gx16: + param->reg_AC2 = 0xAA00761C | trap_AC2; + break; + case AST_DRAM_4Gx16: + param->reg_AC2 = 0xAA007636 | trap_AC2; + break; + } + break; + default: + case 396: + ast_moutdwm(ast, 0x1E6E2020, 0x03F1); + param->wodt = 1; + param->reg_AC1 = 0x33302825; + param->reg_AC2 = 0xCC009617 | trap_AC2; + param->reg_DQSIC = 0x000000E2; + param->reg_MRS = 0x04001600 | trap_MRS; + param->reg_EMRS = 0x00000000; + param->reg_IOZ = 0x00000034; + param->reg_DRV = 0x000000FA; + param->reg_DQIDLY = 0x00000089; + param->reg_FREQ = 0x00005040; + param->madj_max = 96; + param->dll2_finetune_step = 4; + + switch (param->dram_chipid) { + default: + case AST_DRAM_512Mx16: + case AST_DRAM_1Gx16: + param->reg_AC2 = 0xCC009617 | trap_AC2; + break; + case AST_DRAM_2Gx16: + param->reg_AC2 = 0xCC009622 | trap_AC2; + break; + case AST_DRAM_4Gx16: + param->reg_AC2 = 0xCC00963F | trap_AC2; + break; + } + break; + + case 408: + ast_moutdwm(ast, 0x1E6E2020, 0x01F0); + param->wodt = 1; + param->reg_AC1 = 0x33302825; + param->reg_AC2 = 0xCC009617 | trap_AC2; + param->reg_DQSIC = 0x000000E2; + param->reg_MRS = 0x04001600 | trap_MRS; + param->reg_EMRS = 0x00000000; + param->reg_IOZ = 0x00000023; + param->reg_DRV = 0x000000FA; + param->reg_DQIDLY = 0x00000089; + param->reg_FREQ = 0x000050C0; + param->madj_max = 96; + param->dll2_finetune_step = 4; + + switch (param->dram_chipid) { + default: + case AST_DRAM_512Mx16: + case AST_DRAM_1Gx16: + param->reg_AC2 = 0xCC009617 | trap_AC2; + break; + case AST_DRAM_2Gx16: + param->reg_AC2 = 0xCC009622 | trap_AC2; + break; + case AST_DRAM_4Gx16: + param->reg_AC2 = 0xCC00963F | trap_AC2; + break; + } + + break; + case 456: + ast_moutdwm(ast, 0x1E6E2020, 0x0230); + param->wodt = 0; + param->reg_AC1 = 0x33302926; + param->reg_AC2 = 0xCD44961A; + param->reg_DQSIC = 0x000000FC; + param->reg_MRS = 0x00081830; + param->reg_EMRS = 0x00000000; + param->reg_IOZ = 0x00000045; + param->reg_DQIDLY = 0x00000097; + param->reg_FREQ = 0x000052C0; + param->madj_max = 88; + param->dll2_finetune_step = 4; + break; + case 504: + ast_moutdwm(ast, 0x1E6E2020, 0x0270); + param->wodt = 1; + param->reg_AC1 = 0x33302926; + param->reg_AC2 = 0xDE44A61D; + param->reg_DQSIC = 0x00000117; + param->reg_MRS = 0x00081A30; + param->reg_EMRS = 0x00000000; + param->reg_IOZ = 0x070000BB; + param->reg_DQIDLY = 0x000000A0; + param->reg_FREQ = 0x000054C0; + param->madj_max = 79; + param->dll2_finetune_step = 4; + break; + case 528: + ast_moutdwm(ast, 0x1E6E2020, 0x0290); + param->wodt = 1; + param->rodt = 1; + param->reg_AC1 = 0x33302926; + param->reg_AC2 = 0xEF44B61E; + param->reg_DQSIC = 0x00000125; + param->reg_MRS = 0x00081A30; + param->reg_EMRS = 0x00000040; + param->reg_DRV = 0x000000F5; + param->reg_IOZ = 0x00000023; + param->reg_DQIDLY = 0x00000088; + param->reg_FREQ = 0x000055C0; + param->madj_max = 76; + param->dll2_finetune_step = 3; + break; + case 576: + ast_moutdwm(ast, 0x1E6E2020, 0x0140); + param->reg_MADJ = 0x00136868; + param->reg_SADJ = 0x00004534; + param->wodt = 1; + param->rodt = 1; + param->reg_AC1 = 0x33302A37; + param->reg_AC2 = 0xEF56B61E; + param->reg_DQSIC = 0x0000013F; + param->reg_MRS = 0x00101A50; + param->reg_EMRS = 0x00000040; + param->reg_DRV = 0x000000FA; + param->reg_IOZ = 0x00000023; + param->reg_DQIDLY = 0x00000078; + param->reg_FREQ = 0x000057C0; + param->madj_max = 136; + param->dll2_finetune_step = 3; + break; + case 600: + ast_moutdwm(ast, 0x1E6E2020, 0x02E1); + param->reg_MADJ = 0x00136868; + param->reg_SADJ = 0x00004534; + param->wodt = 1; + param->rodt = 1; + param->reg_AC1 = 0x32302A37; + param->reg_AC2 = 0xDF56B61F; + param->reg_DQSIC = 0x0000014D; + param->reg_MRS = 0x00101A50; + param->reg_EMRS = 0x00000004; + param->reg_DRV = 0x000000F5; + param->reg_IOZ = 0x00000023; + param->reg_DQIDLY = 0x00000078; + param->reg_FREQ = 0x000058C0; + param->madj_max = 132; + param->dll2_finetune_step = 3; + break; + case 624: + ast_moutdwm(ast, 0x1E6E2020, 0x0160); + param->reg_MADJ = 0x00136868; + param->reg_SADJ = 0x00004534; + param->wodt = 1; + param->rodt = 1; + param->reg_AC1 = 0x32302A37; + param->reg_AC2 = 0xEF56B621; + param->reg_DQSIC = 0x0000015A; + param->reg_MRS = 0x02101A50; + param->reg_EMRS = 0x00000004; + param->reg_DRV = 0x000000F5; + param->reg_IOZ = 0x00000034; + param->reg_DQIDLY = 0x00000078; + param->reg_FREQ = 0x000059C0; + param->madj_max = 128; + param->dll2_finetune_step = 3; + break; + } /* switch freq */ + + switch (param->dram_chipid) { + case AST_DRAM_512Mx16: + param->dram_config = 0x130; + break; + default: + case AST_DRAM_1Gx16: + param->dram_config = 0x131; + break; + case AST_DRAM_2Gx16: + param->dram_config = 0x132; + break; + case AST_DRAM_4Gx16: + param->dram_config = 0x133; + break; + } /* switch size */ + + switch (param->vram_size) { + default: + case SZ_8M: + param->dram_config |= 0x00; + break; + case SZ_16M: + param->dram_config |= 0x04; + break; + case SZ_32M: + param->dram_config |= 0x08; + break; + case SZ_64M: + param->dram_config |= 0x0c; + break; + } +} + +static void ddr3_init(struct ast_device *ast, struct ast2300_dram_param *param) +{ + u32 data, data2, retry = 0; + +ddr3_init_start: + ast_moutdwm(ast, 0x1E6E0000, 0xFC600309); + ast_moutdwm(ast, 0x1E6E0018, 0x00000100); + ast_moutdwm(ast, 0x1E6E0024, 0x00000000); + ast_moutdwm(ast, 0x1E6E0034, 0x00000000); + udelay(10); + ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ); + ast_moutdwm(ast, 0x1E6E0068, param->reg_SADJ); + udelay(10); + ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000); + udelay(10); + + ast_moutdwm(ast, 0x1E6E0004, param->dram_config); + ast_moutdwm(ast, 0x1E6E0008, 0x90040f); + ast_moutdwm(ast, 0x1E6E0010, param->reg_AC1); + ast_moutdwm(ast, 0x1E6E0014, param->reg_AC2); + ast_moutdwm(ast, 0x1E6E0020, param->reg_DQSIC); + ast_moutdwm(ast, 0x1E6E0080, 0x00000000); + ast_moutdwm(ast, 0x1E6E0084, 0x00000000); + ast_moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY); + ast_moutdwm(ast, 0x1E6E0018, 0x4000A170); + ast_moutdwm(ast, 0x1E6E0018, 0x00002370); + ast_moutdwm(ast, 0x1E6E0038, 0x00000000); + ast_moutdwm(ast, 0x1E6E0040, 0xFF444444); + ast_moutdwm(ast, 0x1E6E0044, 0x22222222); + ast_moutdwm(ast, 0x1E6E0048, 0x22222222); + ast_moutdwm(ast, 0x1E6E004C, 0x00000002); + ast_moutdwm(ast, 0x1E6E0050, 0x80000000); + ast_moutdwm(ast, 0x1E6E0050, 0x00000000); + ast_moutdwm(ast, 0x1E6E0054, 0); + ast_moutdwm(ast, 0x1E6E0060, param->reg_DRV); + ast_moutdwm(ast, 0x1E6E006C, param->reg_IOZ); + ast_moutdwm(ast, 0x1E6E0070, 0x00000000); + ast_moutdwm(ast, 0x1E6E0074, 0x00000000); + ast_moutdwm(ast, 0x1E6E0078, 0x00000000); + ast_moutdwm(ast, 0x1E6E007C, 0x00000000); + /* Wait MCLK2X lock to MCLK */ + do { + data = ast_mindwm(ast, 0x1E6E001C); + } while (!(data & 0x08000000)); + data = ast_mindwm(ast, 0x1E6E001C); + data = (data >> 8) & 0xff; + while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) { + data2 = (ast_mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4; + if ((data2 & 0xff) > param->madj_max) + break; + ast_moutdwm(ast, 0x1E6E0064, data2); + if (data2 & 0x00100000) + data2 = ((data2 & 0xff) >> 3) + 3; + else + data2 = ((data2 & 0xff) >> 2) + 5; + data = ast_mindwm(ast, 0x1E6E0068) & 0xffff00ff; + data2 += data & 0xff; + data = data | (data2 << 8); + ast_moutdwm(ast, 0x1E6E0068, data); + udelay(10); + ast_moutdwm(ast, 0x1E6E0064, ast_mindwm(ast, 0x1E6E0064) | 0xC0000); + udelay(10); + data = ast_mindwm(ast, 0x1E6E0018) & 0xfffff1ff; + ast_moutdwm(ast, 0x1E6E0018, data); + data = data | 0x200; + ast_moutdwm(ast, 0x1E6E0018, data); + do { + data = ast_mindwm(ast, 0x1E6E001C); + } while (!(data & 0x08000000)); + + data = ast_mindwm(ast, 0x1E6E001C); + data = (data >> 8) & 0xff; + } + ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, 0x1E6E0068) & 0xffff); + data = ast_mindwm(ast, 0x1E6E0018) | 0xC00; + ast_moutdwm(ast, 0x1E6E0018, data); + + ast_moutdwm(ast, 0x1E6E0034, 0x00000001); + ast_moutdwm(ast, 0x1E6E000C, 0x00000040); + udelay(50); + /* Mode Register Setting */ + ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100); + ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS); + ast_moutdwm(ast, 0x1E6E0028, 0x00000005); + ast_moutdwm(ast, 0x1E6E0028, 0x00000007); + ast_moutdwm(ast, 0x1E6E0028, 0x00000003); + ast_moutdwm(ast, 0x1E6E0028, 0x00000001); + ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS); + ast_moutdwm(ast, 0x1E6E000C, 0x00005C08); + ast_moutdwm(ast, 0x1E6E0028, 0x00000001); + + ast_moutdwm(ast, 0x1E6E000C, 0x00005C01); + data = 0; + if (param->wodt) + data = 0x300; + if (param->rodt) + data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3); + ast_moutdwm(ast, 0x1E6E0034, data | 0x3); + + /* Calibrate the DQSI delay */ + if ((cbr_dll2(ast, param) == false) && (retry++ < 10)) + goto ddr3_init_start; + + ast_moutdwm(ast, 0x1E6E0120, param->reg_FREQ); + /* ECC Memory Initialization */ +#ifdef ECC + ast_moutdwm(ast, 0x1E6E007C, 0x00000000); + ast_moutdwm(ast, 0x1E6E0070, 0x221); + do { + data = ast_mindwm(ast, 0x1E6E0070); + } while (!(data & 0x00001000)); + ast_moutdwm(ast, 0x1E6E0070, 0x00000000); + ast_moutdwm(ast, 0x1E6E0050, 0x80000000); + ast_moutdwm(ast, 0x1E6E0050, 0x00000000); +#endif +} + +static void get_ddr2_info(struct ast_device *ast, struct ast2300_dram_param *param) +{ + u32 trap, trap_AC2, trap_MRS; + + ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8); + + /* Ger trap info */ + trap = (ast_mindwm(ast, 0x1E6E2070) >> 25) & 0x3; + trap_AC2 = (trap << 20) | (trap << 16); + trap_AC2 += 0x00110000; + trap_MRS = 0x00000040 | (trap << 4); + + param->reg_MADJ = 0x00034C4C; + param->reg_SADJ = 0x00001800; + param->reg_DRV = 0x000000F0; + param->reg_PERIOD = param->dram_freq; + param->rodt = 0; + + switch (param->dram_freq) { + case 264: + ast_moutdwm(ast, 0x1E6E2020, 0x0130); + param->wodt = 0; + param->reg_AC1 = 0x11101513; + param->reg_AC2 = 0x78117011; + param->reg_DQSIC = 0x00000092; + param->reg_MRS = 0x00000842; + param->reg_EMRS = 0x00000000; + param->reg_DRV = 0x000000F0; + param->reg_IOZ = 0x00000034; + param->reg_DQIDLY = 0x0000005A; + param->reg_FREQ = 0x00004AC0; + param->madj_max = 138; + param->dll2_finetune_step = 3; + break; + case 336: + ast_moutdwm(ast, 0x1E6E2020, 0x0190); + param->wodt = 1; + param->reg_AC1 = 0x22202613; + param->reg_AC2 = 0xAA009016 | trap_AC2; + param->reg_DQSIC = 0x000000BA; + param->reg_MRS = 0x00000A02 | trap_MRS; + param->reg_EMRS = 0x00000040; + param->reg_DRV = 0x000000FA; + param->reg_IOZ = 0x00000034; + param->reg_DQIDLY = 0x00000074; + param->reg_FREQ = 0x00004DC0; + param->madj_max = 96; + param->dll2_finetune_step = 3; + switch (param->dram_chipid) { + default: + case AST_DRAM_512Mx16: + param->reg_AC2 = 0xAA009012 | trap_AC2; + break; + case AST_DRAM_1Gx16: + param->reg_AC2 = 0xAA009016 | trap_AC2; + break; + case AST_DRAM_2Gx16: + param->reg_AC2 = 0xAA009023 | trap_AC2; + break; + case AST_DRAM_4Gx16: + param->reg_AC2 = 0xAA00903B | trap_AC2; + break; + } + break; + default: + case 396: + ast_moutdwm(ast, 0x1E6E2020, 0x03F1); + param->wodt = 1; + param->rodt = 0; + param->reg_AC1 = 0x33302714; + param->reg_AC2 = 0xCC00B01B | trap_AC2; + param->reg_DQSIC = 0x000000E2; + param->reg_MRS = 0x00000C02 | trap_MRS; + param->reg_EMRS = 0x00000040; + param->reg_DRV = 0x000000FA; + param->reg_IOZ = 0x00000034; + param->reg_DQIDLY = 0x00000089; + param->reg_FREQ = 0x00005040; + param->madj_max = 96; + param->dll2_finetune_step = 4; + + switch (param->dram_chipid) { + case AST_DRAM_512Mx16: + param->reg_AC2 = 0xCC00B016 | trap_AC2; + break; + default: + case AST_DRAM_1Gx16: + param->reg_AC2 = 0xCC00B01B | trap_AC2; + break; + case AST_DRAM_2Gx16: + param->reg_AC2 = 0xCC00B02B | trap_AC2; + break; + case AST_DRAM_4Gx16: + param->reg_AC2 = 0xCC00B03F | trap_AC2; + break; + } + + break; + + case 408: + ast_moutdwm(ast, 0x1E6E2020, 0x01F0); + param->wodt = 1; + param->rodt = 0; + param->reg_AC1 = 0x33302714; + param->reg_AC2 = 0xCC00B01B | trap_AC2; + param->reg_DQSIC = 0x000000E2; + param->reg_MRS = 0x00000C02 | trap_MRS; + param->reg_EMRS = 0x00000040; + param->reg_DRV = 0x000000FA; + param->reg_IOZ = 0x00000034; + param->reg_DQIDLY = 0x00000089; + param->reg_FREQ = 0x000050C0; + param->madj_max = 96; + param->dll2_finetune_step = 4; + + switch (param->dram_chipid) { + case AST_DRAM_512Mx16: + param->reg_AC2 = 0xCC00B016 | trap_AC2; + break; + default: + case AST_DRAM_1Gx16: + param->reg_AC2 = 0xCC00B01B | trap_AC2; + break; + case AST_DRAM_2Gx16: + param->reg_AC2 = 0xCC00B02B | trap_AC2; + break; + case AST_DRAM_4Gx16: + param->reg_AC2 = 0xCC00B03F | trap_AC2; + break; + } + + break; + case 456: + ast_moutdwm(ast, 0x1E6E2020, 0x0230); + param->wodt = 0; + param->reg_AC1 = 0x33302815; + param->reg_AC2 = 0xCD44B01E; + param->reg_DQSIC = 0x000000FC; + param->reg_MRS = 0x00000E72; + param->reg_EMRS = 0x00000000; + param->reg_DRV = 0x00000000; + param->reg_IOZ = 0x00000034; + param->reg_DQIDLY = 0x00000097; + param->reg_FREQ = 0x000052C0; + param->madj_max = 88; + param->dll2_finetune_step = 3; + break; + case 504: + ast_moutdwm(ast, 0x1E6E2020, 0x0261); + param->wodt = 1; + param->rodt = 1; + param->reg_AC1 = 0x33302815; + param->reg_AC2 = 0xDE44C022; + param->reg_DQSIC = 0x00000117; + param->reg_MRS = 0x00000E72; + param->reg_EMRS = 0x00000040; + param->reg_DRV = 0x0000000A; + param->reg_IOZ = 0x00000045; + param->reg_DQIDLY = 0x000000A0; + param->reg_FREQ = 0x000054C0; + param->madj_max = 79; + param->dll2_finetune_step = 3; + break; + case 528: + ast_moutdwm(ast, 0x1E6E2020, 0x0120); + param->wodt = 1; + param->rodt = 1; + param->reg_AC1 = 0x33302815; + param->reg_AC2 = 0xEF44D024; + param->reg_DQSIC = 0x00000125; + param->reg_MRS = 0x00000E72; + param->reg_EMRS = 0x00000004; + param->reg_DRV = 0x000000F9; + param->reg_IOZ = 0x00000045; + param->reg_DQIDLY = 0x000000A7; + param->reg_FREQ = 0x000055C0; + param->madj_max = 76; + param->dll2_finetune_step = 3; + break; + case 552: + ast_moutdwm(ast, 0x1E6E2020, 0x02A1); + param->wodt = 1; + param->rodt = 1; + param->reg_AC1 = 0x43402915; + param->reg_AC2 = 0xFF44E025; + param->reg_DQSIC = 0x00000132; + param->reg_MRS = 0x00000E72; + param->reg_EMRS = 0x00000040; + param->reg_DRV = 0x0000000A; + param->reg_IOZ = 0x00000045; + param->reg_DQIDLY = 0x000000AD; + param->reg_FREQ = 0x000056C0; + param->madj_max = 76; + param->dll2_finetune_step = 3; + break; + case 576: + ast_moutdwm(ast, 0x1E6E2020, 0x0140); + param->wodt = 1; + param->rodt = 1; + param->reg_AC1 = 0x43402915; + param->reg_AC2 = 0xFF44E027; + param->reg_DQSIC = 0x0000013F; + param->reg_MRS = 0x00000E72; + param->reg_EMRS = 0x00000004; + param->reg_DRV = 0x000000F5; + param->reg_IOZ = 0x00000045; + param->reg_DQIDLY = 0x000000B3; + param->reg_FREQ = 0x000057C0; + param->madj_max = 76; + param->dll2_finetune_step = 3; + break; + } + + switch (param->dram_chipid) { + case AST_DRAM_512Mx16: + param->dram_config = 0x100; + break; + default: + case AST_DRAM_1Gx16: + param->dram_config = 0x121; + break; + case AST_DRAM_2Gx16: + param->dram_config = 0x122; + break; + case AST_DRAM_4Gx16: + param->dram_config = 0x123; + break; + } /* switch size */ + + switch (param->vram_size) { + default: + case SZ_8M: + param->dram_config |= 0x00; + break; + case SZ_16M: + param->dram_config |= 0x04; + break; + case SZ_32M: + param->dram_config |= 0x08; + break; + case SZ_64M: + param->dram_config |= 0x0c; + break; + } +} + +static void ddr2_init(struct ast_device *ast, struct ast2300_dram_param *param) +{ + u32 data, data2, retry = 0; + +ddr2_init_start: + ast_moutdwm(ast, 0x1E6E0000, 0xFC600309); + ast_moutdwm(ast, 0x1E6E0018, 0x00000100); + ast_moutdwm(ast, 0x1E6E0024, 0x00000000); + ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ); + ast_moutdwm(ast, 0x1E6E0068, param->reg_SADJ); + udelay(10); + ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000); + udelay(10); + + ast_moutdwm(ast, 0x1E6E0004, param->dram_config); + ast_moutdwm(ast, 0x1E6E0008, 0x90040f); + ast_moutdwm(ast, 0x1E6E0010, param->reg_AC1); + ast_moutdwm(ast, 0x1E6E0014, param->reg_AC2); + ast_moutdwm(ast, 0x1E6E0020, param->reg_DQSIC); + ast_moutdwm(ast, 0x1E6E0080, 0x00000000); + ast_moutdwm(ast, 0x1E6E0084, 0x00000000); + ast_moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY); + ast_moutdwm(ast, 0x1E6E0018, 0x4000A130); + ast_moutdwm(ast, 0x1E6E0018, 0x00002330); + ast_moutdwm(ast, 0x1E6E0038, 0x00000000); + ast_moutdwm(ast, 0x1E6E0040, 0xFF808000); + ast_moutdwm(ast, 0x1E6E0044, 0x88848466); + ast_moutdwm(ast, 0x1E6E0048, 0x44440008); + ast_moutdwm(ast, 0x1E6E004C, 0x00000000); + ast_moutdwm(ast, 0x1E6E0050, 0x80000000); + ast_moutdwm(ast, 0x1E6E0050, 0x00000000); + ast_moutdwm(ast, 0x1E6E0054, 0); + ast_moutdwm(ast, 0x1E6E0060, param->reg_DRV); + ast_moutdwm(ast, 0x1E6E006C, param->reg_IOZ); + ast_moutdwm(ast, 0x1E6E0070, 0x00000000); + ast_moutdwm(ast, 0x1E6E0074, 0x00000000); + ast_moutdwm(ast, 0x1E6E0078, 0x00000000); + ast_moutdwm(ast, 0x1E6E007C, 0x00000000); + + /* Wait MCLK2X lock to MCLK */ + do { + data = ast_mindwm(ast, 0x1E6E001C); + } while (!(data & 0x08000000)); + data = ast_mindwm(ast, 0x1E6E001C); + data = (data >> 8) & 0xff; + while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) { + data2 = (ast_mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4; + if ((data2 & 0xff) > param->madj_max) + break; + ast_moutdwm(ast, 0x1E6E0064, data2); + if (data2 & 0x00100000) + data2 = ((data2 & 0xff) >> 3) + 3; + else + data2 = ((data2 & 0xff) >> 2) + 5; + data = ast_mindwm(ast, 0x1E6E0068) & 0xffff00ff; + data2 += data & 0xff; + data = data | (data2 << 8); + ast_moutdwm(ast, 0x1E6E0068, data); + udelay(10); + ast_moutdwm(ast, 0x1E6E0064, ast_mindwm(ast, 0x1E6E0064) | 0xC0000); + udelay(10); + data = ast_mindwm(ast, 0x1E6E0018) & 0xfffff1ff; + ast_moutdwm(ast, 0x1E6E0018, data); + data = data | 0x200; + ast_moutdwm(ast, 0x1E6E0018, data); + do { + data = ast_mindwm(ast, 0x1E6E001C); + } while (!(data & 0x08000000)); + + data = ast_mindwm(ast, 0x1E6E001C); + data = (data >> 8) & 0xff; + } + ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, 0x1E6E0008) & 0xffff); + data = ast_mindwm(ast, 0x1E6E0018) | 0xC00; + ast_moutdwm(ast, 0x1E6E0018, data); + + ast_moutdwm(ast, 0x1E6E0034, 0x00000001); + ast_moutdwm(ast, 0x1E6E000C, 0x00000000); + udelay(50); + /* Mode Register Setting */ + ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100); + ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS); + ast_moutdwm(ast, 0x1E6E0028, 0x00000005); + ast_moutdwm(ast, 0x1E6E0028, 0x00000007); + ast_moutdwm(ast, 0x1E6E0028, 0x00000003); + ast_moutdwm(ast, 0x1E6E0028, 0x00000001); + + ast_moutdwm(ast, 0x1E6E000C, 0x00005C08); + ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS); + ast_moutdwm(ast, 0x1E6E0028, 0x00000001); + ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS | 0x380); + ast_moutdwm(ast, 0x1E6E0028, 0x00000003); + ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS); + ast_moutdwm(ast, 0x1E6E0028, 0x00000003); + + ast_moutdwm(ast, 0x1E6E000C, 0x7FFF5C01); + data = 0; + if (param->wodt) + data = 0x500; + if (param->rodt) + data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3); + ast_moutdwm(ast, 0x1E6E0034, data | 0x3); + ast_moutdwm(ast, 0x1E6E0120, param->reg_FREQ); + + /* Calibrate the DQSI delay */ + if ((cbr_dll2(ast, param) == false) && (retry++ < 10)) + goto ddr2_init_start; + + /* ECC Memory Initialization */ +#ifdef ECC + ast_moutdwm(ast, 0x1E6E007C, 0x00000000); + ast_moutdwm(ast, 0x1E6E0070, 0x221); + do { + data = ast_mindwm(ast, 0x1E6E0070); + } while (!(data & 0x00001000)); + ast_moutdwm(ast, 0x1E6E0070, 0x00000000); + ast_moutdwm(ast, 0x1E6E0050, 0x80000000); + ast_moutdwm(ast, 0x1E6E0050, 0x00000000); +#endif +} + +static void ast_post_chip_2300(struct ast_device *ast) +{ + struct ast2300_dram_param param; + u32 temp; + u8 reg; + + reg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); + if ((reg & 0x80) == 0) {/* vga only */ + ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf000, 0x1); + ast_write32(ast, 0x12000, 0x1688a8a8); + do { + ; + } while (ast_read32(ast, 0x12000) != 0x1); + + ast_write32(ast, 0x10000, 0xfc600309); + do { + ; + } while (ast_read32(ast, 0x10000) != 0x1); + + /* Slow down CPU/AHB CLK in VGA only mode */ + temp = ast_read32(ast, 0x12008); + temp |= 0x73; + ast_write32(ast, 0x12008, temp); + + param.dram_freq = 396; + param.dram_type = AST_DDR3; + temp = ast_mindwm(ast, 0x1e6e2070); + if (temp & 0x01000000) + param.dram_type = AST_DDR2; + switch (temp & 0x18000000) { + case 0: + param.dram_chipid = AST_DRAM_512Mx16; + break; + default: + case 0x08000000: + param.dram_chipid = AST_DRAM_1Gx16; + break; + case 0x10000000: + param.dram_chipid = AST_DRAM_2Gx16; + break; + case 0x18000000: + param.dram_chipid = AST_DRAM_4Gx16; + break; + } + switch (temp & 0x0c) { + default: + case 0x00: + param.vram_size = SZ_8M; + break; + case 0x04: + param.vram_size = SZ_16M; + break; + case 0x08: + param.vram_size = SZ_32M; + break; + case 0x0c: + param.vram_size = SZ_64M; + break; + } + + if (param.dram_type == AST_DDR3) { + get_ddr3_info(ast, ¶m); + ddr3_init(ast, ¶m); + } else { + get_ddr2_info(ast, ¶m); + ddr2_init(ast, ¶m); + } + + 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_2300_post(struct ast_device *ast) +{ + ast_2300_set_def_ext_reg(ast); + + if (ast->config_mode == ast_use_p2a) { + ast_post_chip_2300(ast); + ast_init_3rdtx(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; +} diff --git a/drivers/gpu/drm/ast/ast_2500.c b/drivers/gpu/drm/ast/ast_2500.c new file mode 100644 index 000000000000..1e541498ea67 --- /dev/null +++ b/drivers/gpu/drm/ast/ast_2500.c @@ -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; +} diff --git a/drivers/gpu/drm/ast/ast_2600.c b/drivers/gpu/drm/ast/ast_2600.c new file mode 100644 index 000000000000..8d75a47444f5 --- /dev/null +++ b/drivers/gpu/drm/ast/ast_2600.c @@ -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; +} diff --git a/drivers/gpu/drm/ast/ast_dram_tables.h b/drivers/gpu/drm/ast/ast_dram_tables.h deleted file mode 100644 index 1e9ac9d6d26c..000000000000 --- a/drivers/gpu/drm/ast/ast_dram_tables.h +++ /dev/null @@ -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 diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 054acda41909..473faa92d08c 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -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 */ diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 2ee402096cd9..e37a55295ed7 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -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); diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index 37568cf3822c..b72914dbed38 100644 --- a/drivers/gpu/drm/ast/ast_post.c +++ b/drivers/gpu/drm/ast/ast_post.c @@ -31,51 +31,10 @@ #include <drm/drm_print.h> -#include "ast_dram_tables.h" #include "ast_drv.h" +#include "ast_post.h" -static void ast_post_chip_2300(struct ast_device *ast); -static void ast_post_chip_2500(struct ast_device *ast); - -static const u8 extreginfo[] = { 0x0f, 0x04, 0x1c, 0xff }; -static const u8 extreginfo_ast2300[] = { 0x0f, 0x04, 0x1f, 0xff }; - -static void ast_set_def_ext_reg(struct ast_device *ast) -{ - 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); - - if (IS_AST_GEN4(ast) || IS_AST_GEN5(ast) || IS_AST_GEN6(ast)) - ext_reg_info = extreginfo_ast2300; - else - 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; - if (IS_AST_GEN4(ast) || IS_AST_GEN5(ast) || IS_AST_GEN6(ast)) - reg |= 0x20; - ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0xff, reg); -} - -static u32 __ast_mindwm(void __iomem *regs, u32 r) +u32 __ast_mindwm(void __iomem *regs, u32 r) { u32 data; @@ -89,7 +48,7 @@ static u32 __ast_mindwm(void __iomem *regs, u32 r) return __ast_read32(regs, 0x10000 + (r & 0x0000ffff)); } -static void __ast_moutdwm(void __iomem *regs, u32 r, u32 v) +void __ast_moutdwm(void __iomem *regs, u32 r, u32 v) { u32 data; @@ -113,332 +72,38 @@ void ast_moutdwm(struct ast_device *ast, u32 r, u32 v) __ast_moutdwm(ast->regs, r, v); } -/* - * 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; -} - -#if 0 /* unused in DDX driver - here for completeness */ -static u32 mmctestsingle2_ast2150(struct ast_device *ast, u32 datagen) -{ - u32 data, timeout; - - ast_moutdwm(ast, 0x1e6e0070, 0x00000000); - ast_moutdwm(ast, 0x1e6e0070, 0x00000005 | (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; -} -#endif - -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] = dll_min[1] = dll_min[2] = dll_min[3] = 0xff; - dll_max[0] = dll_max[1] = dll_max[2] = dll_max[3] = 0x0; - 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_init_dram_reg(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 (IS_AST_GEN1(ast)) { - 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); - } else { /* GEN2/GEN3 */ - 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 (dram_reg_info->index != 0xffff) { - if (dram_reg_info->index == 0xff00) {/* delay fn */ - for (i = 0; i < 15; i++) - udelay(dram_reg_info->data); - } else if (dram_reg_info->index == 0x4 && !IS_AST_GEN1(ast)) { - 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 */ - } - - switch (AST_GEN(ast)) { - case 1: - temp = ast_read32(ast, 0x10140); - ast_write32(ast, 0x10140, temp | 0x40); - break; - case 2: - case 3: - temp = ast_read32(ast, 0x1200c); - ast_write32(ast, 0x1200c, temp & 0xfffffffd); - temp = ast_read32(ast, 0x12040); - ast_write32(ast, 0x12040, temp | 0x40); - break; - default: - break; - } - } - - /* wait ready */ - do { - j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); - } while ((j & 0x40) == 0); -} - int ast_post_gpu(struct ast_device *ast) { int ret; - ast_set_def_ext_reg(ast); - if (AST_GEN(ast) >= 7) { - if (ast->tx_chip == AST_TX_ASTDP) { - ret = ast_dp_launch(ast); - if (ret) - return ret; - } + ret = ast_2600_post(ast); + if (ret) + return ret; } else if (AST_GEN(ast) >= 6) { - 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); - } - } + ret = ast_2500_post(ast); + if (ret) + return ret; } else if (AST_GEN(ast) >= 4) { - if (ast->config_mode == ast_use_p2a) { - ast_post_chip_2300(ast); - ast_init_3rdtx(ast); - } else { - if (ast->tx_chip == AST_TX_SIL164) { - /* Enable DVO */ - ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x80); - } - } + ret = ast_2300_post(ast); + if (ret) + return ret; + } else if (AST_GEN(ast) >= 2) { + ret = ast_2100_post(ast); + if (ret) + return ret; } else { - if (ast->config_mode == ast_use_p2a) { - ast_init_dram_reg(ast); - } else { - if (ast->tx_chip == AST_TX_SIL164) { - /* Enable DVO */ - ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x80); - } - } + ret = ast_2000_post(ast); + if (ret) + return ret; } return 0; } -/* AST 2300 DRAM settings */ -#define AST_DDR3 0 -#define AST_DDR2 1 - -struct ast2300_dram_param { - u32 dram_type; - u32 dram_chipid; - u32 dram_freq; - u32 vram_size; - u32 odt; - u32 wodt; - u32 rodt; - u32 dram_config; - u32 reg_PERIOD; - u32 reg_MADJ; - u32 reg_SADJ; - u32 reg_MRS; - u32 reg_EMRS; - u32 reg_AC1; - u32 reg_AC2; - u32 reg_DQSIC; - u32 reg_DRV; - u32 reg_IOZ; - u32 reg_DQIDLY; - u32 reg_FREQ; - u32 madj_max; - u32 dll2_finetune_step; -}; - -/* - * DQSI DLL CBR Setting - */ -#define CBR_SIZE0 ((1 << 10) - 1) -#define CBR_SIZE1 ((4 << 10) - 1) -#define CBR_SIZE2 ((64 << 10) - 1) -#define CBR_PASSNUM 5 -#define CBR_PASSNUM2 5 -#define CBR_THRESHOLD 10 -#define CBR_THRESHOLD2 10 #define TIMEOUT 5000000 -#define CBR_PATNUM 8 -static const u32 pattern[8] = { - 0xFF00FF00, - 0xCC33CC33, - 0xAA55AA55, - 0x88778877, - 0x92CC4D6E, - 0x543D3CDE, - 0xF1E843C7, - 0x7C61D253 -}; - -static bool mmc_test(struct ast_device *ast, u32 datagen, u8 test_ctl) +bool mmc_test(struct ast_device *ast, u32 datagen, u8 test_ctl) { u32 data, timeout; @@ -458,1657 +123,7 @@ static bool mmc_test(struct ast_device *ast, u32 datagen, u8 test_ctl) return true; } -static u32 mmc_test2(struct ast_device *ast, u32 datagen, u8 test_ctl) -{ - u32 data, timeout; - - ast_moutdwm(ast, 0x1e6e0070, 0x00000000); - ast_moutdwm(ast, 0x1e6e0070, (datagen << 3) | test_ctl); - timeout = 0; - do { - data = ast_mindwm(ast, 0x1e6e0070) & 0x1000; - if (++timeout > TIMEOUT) { - ast_moutdwm(ast, 0x1e6e0070, 0x0); - return 0xffffffff; - } - } while (!data); - data = ast_mindwm(ast, 0x1e6e0078); - data = (data | (data >> 16)) & 0xffff; - ast_moutdwm(ast, 0x1e6e0070, 0x00000000); - return data; -} - - -static bool mmc_test_burst(struct ast_device *ast, u32 datagen) +bool mmc_test_burst(struct ast_device *ast, u32 datagen) { return mmc_test(ast, datagen, 0xc1); } - -static u32 mmc_test_burst2(struct ast_device *ast, u32 datagen) -{ - return mmc_test2(ast, datagen, 0x41); -} - -static bool mmc_test_single(struct ast_device *ast, u32 datagen) -{ - return mmc_test(ast, datagen, 0xc5); -} - -static u32 mmc_test_single2(struct ast_device *ast, u32 datagen) -{ - return mmc_test2(ast, datagen, 0x05); -} - -static bool mmc_test_single_2500(struct ast_device *ast, u32 datagen) -{ - return mmc_test(ast, datagen, 0x85); -} - -static int cbr_test(struct ast_device *ast) -{ - u32 data; - int i; - data = mmc_test_single2(ast, 0); - if ((data & 0xff) && (data & 0xff00)) - return 0; - for (i = 0; i < 8; i++) { - data = mmc_test_burst2(ast, i); - if ((data & 0xff) && (data & 0xff00)) - return 0; - } - if (!data) - return 3; - else if (data & 0xff) - return 2; - return 1; -} - -static int cbr_scan(struct ast_device *ast) -{ - u32 data, data2, patcnt, loop; - - data2 = 3; - for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) { - ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]); - for (loop = 0; loop < CBR_PASSNUM2; loop++) { - if ((data = cbr_test(ast)) != 0) { - data2 &= data; - if (!data2) - return 0; - break; - } - } - if (loop == CBR_PASSNUM2) - return 0; - } - return data2; -} - -static u32 cbr_test2(struct ast_device *ast) -{ - u32 data; - - data = mmc_test_burst2(ast, 0); - if (data == 0xffff) - return 0; - data |= mmc_test_single2(ast, 0); - if (data == 0xffff) - return 0; - - return ~data & 0xffff; -} - -static u32 cbr_scan2(struct ast_device *ast) -{ - u32 data, data2, patcnt, loop; - - data2 = 0xffff; - for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) { - ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]); - for (loop = 0; loop < CBR_PASSNUM2; loop++) { - if ((data = cbr_test2(ast)) != 0) { - data2 &= data; - if (!data2) - return 0; - break; - } - } - if (loop == CBR_PASSNUM2) - return 0; - } - return data2; -} - -static bool cbr_test3(struct ast_device *ast) -{ - if (!mmc_test_burst(ast, 0)) - return false; - if (!mmc_test_single(ast, 0)) - return false; - return true; -} - -static bool cbr_scan3(struct ast_device *ast) -{ - u32 patcnt, loop; - - for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) { - ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]); - for (loop = 0; loop < 2; loop++) { - if (cbr_test3(ast)) - break; - } - if (loop == 2) - return false; - } - return true; -} - -static bool finetuneDQI_L(struct ast_device *ast, struct ast2300_dram_param *param) -{ - u32 gold_sadj[2], dllmin[16], dllmax[16], dlli, data, cnt, mask, passcnt, retry = 0; - bool status = false; -FINETUNE_START: - for (cnt = 0; cnt < 16; cnt++) { - dllmin[cnt] = 0xff; - dllmax[cnt] = 0x0; - } - passcnt = 0; - for (dlli = 0; dlli < 76; dlli++) { - ast_moutdwm(ast, 0x1E6E0068, 0x00001400 | (dlli << 16) | (dlli << 24)); - ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE1); - data = cbr_scan2(ast); - if (data != 0) { - mask = 0x00010001; - for (cnt = 0; cnt < 16; cnt++) { - if (data & mask) { - if (dllmin[cnt] > dlli) { - dllmin[cnt] = dlli; - } - if (dllmax[cnt] < dlli) { - dllmax[cnt] = dlli; - } - } - mask <<= 1; - } - passcnt++; - } else if (passcnt >= CBR_THRESHOLD2) { - break; - } - } - gold_sadj[0] = 0x0; - passcnt = 0; - for (cnt = 0; cnt < 16; cnt++) { - if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { - gold_sadj[0] += dllmin[cnt]; - passcnt++; - } - } - if (retry++ > 10) - goto FINETUNE_DONE; - if (passcnt != 16) { - goto FINETUNE_START; - } - status = true; -FINETUNE_DONE: - gold_sadj[0] = gold_sadj[0] >> 4; - gold_sadj[1] = gold_sadj[0]; - - data = 0; - for (cnt = 0; cnt < 8; cnt++) { - data >>= 3; - if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { - dlli = dllmin[cnt]; - if (gold_sadj[0] >= dlli) { - dlli = ((gold_sadj[0] - dlli) * 19) >> 5; - if (dlli > 3) { - dlli = 3; - } - } else { - dlli = ((dlli - gold_sadj[0]) * 19) >> 5; - if (dlli > 4) { - dlli = 4; - } - dlli = (8 - dlli) & 0x7; - } - data |= dlli << 21; - } - } - ast_moutdwm(ast, 0x1E6E0080, data); - - data = 0; - for (cnt = 8; cnt < 16; cnt++) { - data >>= 3; - if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { - dlli = dllmin[cnt]; - if (gold_sadj[1] >= dlli) { - dlli = ((gold_sadj[1] - dlli) * 19) >> 5; - if (dlli > 3) { - dlli = 3; - } else { - dlli = (dlli - 1) & 0x7; - } - } else { - dlli = ((dlli - gold_sadj[1]) * 19) >> 5; - dlli += 1; - if (dlli > 4) { - dlli = 4; - } - dlli = (8 - dlli) & 0x7; - } - data |= dlli << 21; - } - } - ast_moutdwm(ast, 0x1E6E0084, data); - return status; -} /* finetuneDQI_L */ - -static void finetuneDQSI(struct ast_device *ast) -{ - u32 dlli, dqsip, dqidly; - u32 reg_mcr18, reg_mcr0c, passcnt[2], diff; - u32 g_dqidly, g_dqsip, g_margin, g_side; - u16 pass[32][2][2]; - char tag[2][76]; - - /* Disable DQI CBR */ - reg_mcr0c = ast_mindwm(ast, 0x1E6E000C); - reg_mcr18 = ast_mindwm(ast, 0x1E6E0018); - reg_mcr18 &= 0x0000ffff; - ast_moutdwm(ast, 0x1E6E0018, reg_mcr18); - - for (dlli = 0; dlli < 76; dlli++) { - tag[0][dlli] = 0x0; - tag[1][dlli] = 0x0; - } - for (dqidly = 0; dqidly < 32; dqidly++) { - pass[dqidly][0][0] = 0xff; - pass[dqidly][0][1] = 0x0; - pass[dqidly][1][0] = 0xff; - pass[dqidly][1][1] = 0x0; - } - for (dqidly = 0; dqidly < 32; dqidly++) { - passcnt[0] = passcnt[1] = 0; - for (dqsip = 0; dqsip < 2; dqsip++) { - ast_moutdwm(ast, 0x1E6E000C, 0); - ast_moutdwm(ast, 0x1E6E0018, reg_mcr18 | (dqidly << 16) | (dqsip << 23)); - ast_moutdwm(ast, 0x1E6E000C, reg_mcr0c); - for (dlli = 0; dlli < 76; dlli++) { - ast_moutdwm(ast, 0x1E6E0068, 0x00001300 | (dlli << 16) | (dlli << 24)); - ast_moutdwm(ast, 0x1E6E0070, 0); - ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE0); - if (cbr_scan3(ast)) { - if (dlli == 0) - break; - passcnt[dqsip]++; - tag[dqsip][dlli] = 'P'; - if (dlli < pass[dqidly][dqsip][0]) - pass[dqidly][dqsip][0] = (u16) dlli; - if (dlli > pass[dqidly][dqsip][1]) - pass[dqidly][dqsip][1] = (u16) dlli; - } else if (passcnt[dqsip] >= 5) - break; - else { - pass[dqidly][dqsip][0] = 0xff; - pass[dqidly][dqsip][1] = 0x0; - } - } - } - if (passcnt[0] == 0 && passcnt[1] == 0) - dqidly++; - } - /* Search margin */ - g_dqidly = g_dqsip = g_margin = g_side = 0; - - for (dqidly = 0; dqidly < 32; dqidly++) { - for (dqsip = 0; dqsip < 2; dqsip++) { - if (pass[dqidly][dqsip][0] > pass[dqidly][dqsip][1]) - continue; - diff = pass[dqidly][dqsip][1] - pass[dqidly][dqsip][0]; - if ((diff+2) < g_margin) - continue; - passcnt[0] = passcnt[1] = 0; - for (dlli = pass[dqidly][dqsip][0]; dlli > 0 && tag[dqsip][dlli] != 0; dlli--, passcnt[0]++); - for (dlli = pass[dqidly][dqsip][1]; dlli < 76 && tag[dqsip][dlli] != 0; dlli++, passcnt[1]++); - if (passcnt[0] > passcnt[1]) - passcnt[0] = passcnt[1]; - passcnt[1] = 0; - if (passcnt[0] > g_side) - passcnt[1] = passcnt[0] - g_side; - if (diff > (g_margin+1) && (passcnt[1] > 0 || passcnt[0] > 8)) { - g_margin = diff; - g_dqidly = dqidly; - g_dqsip = dqsip; - g_side = passcnt[0]; - } else if (passcnt[1] > 1 && g_side < 8) { - if (diff > g_margin) - g_margin = diff; - g_dqidly = dqidly; - g_dqsip = dqsip; - g_side = passcnt[0]; - } - } - } - reg_mcr18 = reg_mcr18 | (g_dqidly << 16) | (g_dqsip << 23); - ast_moutdwm(ast, 0x1E6E0018, reg_mcr18); - -} -static bool cbr_dll2(struct ast_device *ast, struct ast2300_dram_param *param) -{ - u32 dllmin[2], dllmax[2], dlli, data, passcnt, retry = 0; - bool status = false; - - finetuneDQSI(ast); - if (finetuneDQI_L(ast, param) == false) - return status; - -CBR_START2: - dllmin[0] = dllmin[1] = 0xff; - dllmax[0] = dllmax[1] = 0x0; - passcnt = 0; - for (dlli = 0; dlli < 76; dlli++) { - ast_moutdwm(ast, 0x1E6E0068, 0x00001300 | (dlli << 16) | (dlli << 24)); - ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE2); - data = cbr_scan(ast); - if (data != 0) { - if (data & 0x1) { - if (dllmin[0] > dlli) { - dllmin[0] = dlli; - } - if (dllmax[0] < dlli) { - dllmax[0] = dlli; - } - } - if (data & 0x2) { - if (dllmin[1] > dlli) { - dllmin[1] = dlli; - } - if (dllmax[1] < dlli) { - dllmax[1] = dlli; - } - } - passcnt++; - } else if (passcnt >= CBR_THRESHOLD) { - break; - } - } - if (retry++ > 10) - goto CBR_DONE2; - if (dllmax[0] == 0 || (dllmax[0]-dllmin[0]) < CBR_THRESHOLD) { - goto CBR_START2; - } - if (dllmax[1] == 0 || (dllmax[1]-dllmin[1]) < CBR_THRESHOLD) { - goto CBR_START2; - } - status = true; -CBR_DONE2: - dlli = (dllmin[1] + dllmax[1]) >> 1; - dlli <<= 8; - dlli += (dllmin[0] + dllmax[0]) >> 1; - ast_moutdwm(ast, 0x1E6E0068, ast_mindwm(ast, 0x1E720058) | (dlli << 16)); - return status; -} /* CBRDLL2 */ - -static void get_ddr3_info(struct ast_device *ast, struct ast2300_dram_param *param) -{ - u32 trap, trap_AC2, trap_MRS; - - ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8); - - /* Ger trap info */ - trap = (ast_mindwm(ast, 0x1E6E2070) >> 25) & 0x3; - trap_AC2 = 0x00020000 + (trap << 16); - trap_AC2 |= 0x00300000 + ((trap & 0x2) << 19); - trap_MRS = 0x00000010 + (trap << 4); - trap_MRS |= ((trap & 0x2) << 18); - - param->reg_MADJ = 0x00034C4C; - param->reg_SADJ = 0x00001800; - param->reg_DRV = 0x000000F0; - param->reg_PERIOD = param->dram_freq; - param->rodt = 0; - - switch (param->dram_freq) { - case 336: - ast_moutdwm(ast, 0x1E6E2020, 0x0190); - param->wodt = 0; - param->reg_AC1 = 0x22202725; - param->reg_AC2 = 0xAA007613 | trap_AC2; - param->reg_DQSIC = 0x000000BA; - param->reg_MRS = 0x04001400 | trap_MRS; - param->reg_EMRS = 0x00000000; - param->reg_IOZ = 0x00000023; - param->reg_DQIDLY = 0x00000074; - param->reg_FREQ = 0x00004DC0; - param->madj_max = 96; - param->dll2_finetune_step = 3; - switch (param->dram_chipid) { - default: - case AST_DRAM_512Mx16: - case AST_DRAM_1Gx16: - param->reg_AC2 = 0xAA007613 | trap_AC2; - break; - case AST_DRAM_2Gx16: - param->reg_AC2 = 0xAA00761C | trap_AC2; - break; - case AST_DRAM_4Gx16: - param->reg_AC2 = 0xAA007636 | trap_AC2; - break; - } - break; - default: - case 396: - ast_moutdwm(ast, 0x1E6E2020, 0x03F1); - param->wodt = 1; - param->reg_AC1 = 0x33302825; - param->reg_AC2 = 0xCC009617 | trap_AC2; - param->reg_DQSIC = 0x000000E2; - param->reg_MRS = 0x04001600 | trap_MRS; - param->reg_EMRS = 0x00000000; - param->reg_IOZ = 0x00000034; - param->reg_DRV = 0x000000FA; - param->reg_DQIDLY = 0x00000089; - param->reg_FREQ = 0x00005040; - param->madj_max = 96; - param->dll2_finetune_step = 4; - - switch (param->dram_chipid) { - default: - case AST_DRAM_512Mx16: - case AST_DRAM_1Gx16: - param->reg_AC2 = 0xCC009617 | trap_AC2; - break; - case AST_DRAM_2Gx16: - param->reg_AC2 = 0xCC009622 | trap_AC2; - break; - case AST_DRAM_4Gx16: - param->reg_AC2 = 0xCC00963F | trap_AC2; - break; - } - break; - - case 408: - ast_moutdwm(ast, 0x1E6E2020, 0x01F0); - param->wodt = 1; - param->reg_AC1 = 0x33302825; - param->reg_AC2 = 0xCC009617 | trap_AC2; - param->reg_DQSIC = 0x000000E2; - param->reg_MRS = 0x04001600 | trap_MRS; - param->reg_EMRS = 0x00000000; - param->reg_IOZ = 0x00000023; - param->reg_DRV = 0x000000FA; - param->reg_DQIDLY = 0x00000089; - param->reg_FREQ = 0x000050C0; - param->madj_max = 96; - param->dll2_finetune_step = 4; - - switch (param->dram_chipid) { - default: - case AST_DRAM_512Mx16: - case AST_DRAM_1Gx16: - param->reg_AC2 = 0xCC009617 | trap_AC2; - break; - case AST_DRAM_2Gx16: - param->reg_AC2 = 0xCC009622 | trap_AC2; - break; - case AST_DRAM_4Gx16: - param->reg_AC2 = 0xCC00963F | trap_AC2; - break; - } - - break; - case 456: - ast_moutdwm(ast, 0x1E6E2020, 0x0230); - param->wodt = 0; - param->reg_AC1 = 0x33302926; - param->reg_AC2 = 0xCD44961A; - param->reg_DQSIC = 0x000000FC; - param->reg_MRS = 0x00081830; - param->reg_EMRS = 0x00000000; - param->reg_IOZ = 0x00000045; - param->reg_DQIDLY = 0x00000097; - param->reg_FREQ = 0x000052C0; - param->madj_max = 88; - param->dll2_finetune_step = 4; - break; - case 504: - ast_moutdwm(ast, 0x1E6E2020, 0x0270); - param->wodt = 1; - param->reg_AC1 = 0x33302926; - param->reg_AC2 = 0xDE44A61D; - param->reg_DQSIC = 0x00000117; - param->reg_MRS = 0x00081A30; - param->reg_EMRS = 0x00000000; - param->reg_IOZ = 0x070000BB; - param->reg_DQIDLY = 0x000000A0; - param->reg_FREQ = 0x000054C0; - param->madj_max = 79; - param->dll2_finetune_step = 4; - break; - case 528: - ast_moutdwm(ast, 0x1E6E2020, 0x0290); - param->wodt = 1; - param->rodt = 1; - param->reg_AC1 = 0x33302926; - param->reg_AC2 = 0xEF44B61E; - param->reg_DQSIC = 0x00000125; - param->reg_MRS = 0x00081A30; - param->reg_EMRS = 0x00000040; - param->reg_DRV = 0x000000F5; - param->reg_IOZ = 0x00000023; - param->reg_DQIDLY = 0x00000088; - param->reg_FREQ = 0x000055C0; - param->madj_max = 76; - param->dll2_finetune_step = 3; - break; - case 576: - ast_moutdwm(ast, 0x1E6E2020, 0x0140); - param->reg_MADJ = 0x00136868; - param->reg_SADJ = 0x00004534; - param->wodt = 1; - param->rodt = 1; - param->reg_AC1 = 0x33302A37; - param->reg_AC2 = 0xEF56B61E; - param->reg_DQSIC = 0x0000013F; - param->reg_MRS = 0x00101A50; - param->reg_EMRS = 0x00000040; - param->reg_DRV = 0x000000FA; - param->reg_IOZ = 0x00000023; - param->reg_DQIDLY = 0x00000078; - param->reg_FREQ = 0x000057C0; - param->madj_max = 136; - param->dll2_finetune_step = 3; - break; - case 600: - ast_moutdwm(ast, 0x1E6E2020, 0x02E1); - param->reg_MADJ = 0x00136868; - param->reg_SADJ = 0x00004534; - param->wodt = 1; - param->rodt = 1; - param->reg_AC1 = 0x32302A37; - param->reg_AC2 = 0xDF56B61F; - param->reg_DQSIC = 0x0000014D; - param->reg_MRS = 0x00101A50; - param->reg_EMRS = 0x00000004; - param->reg_DRV = 0x000000F5; - param->reg_IOZ = 0x00000023; - param->reg_DQIDLY = 0x00000078; - param->reg_FREQ = 0x000058C0; - param->madj_max = 132; - param->dll2_finetune_step = 3; - break; - case 624: - ast_moutdwm(ast, 0x1E6E2020, 0x0160); - param->reg_MADJ = 0x00136868; - param->reg_SADJ = 0x00004534; - param->wodt = 1; - param->rodt = 1; - param->reg_AC1 = 0x32302A37; - param->reg_AC2 = 0xEF56B621; - param->reg_DQSIC = 0x0000015A; - param->reg_MRS = 0x02101A50; - param->reg_EMRS = 0x00000004; - param->reg_DRV = 0x000000F5; - param->reg_IOZ = 0x00000034; - param->reg_DQIDLY = 0x00000078; - param->reg_FREQ = 0x000059C0; - param->madj_max = 128; - param->dll2_finetune_step = 3; - break; - } /* switch freq */ - - switch (param->dram_chipid) { - case AST_DRAM_512Mx16: - param->dram_config = 0x130; - break; - default: - case AST_DRAM_1Gx16: - param->dram_config = 0x131; - break; - case AST_DRAM_2Gx16: - param->dram_config = 0x132; - break; - case AST_DRAM_4Gx16: - param->dram_config = 0x133; - break; - } /* switch size */ - - switch (param->vram_size) { - default: - case SZ_8M: - param->dram_config |= 0x00; - break; - case SZ_16M: - param->dram_config |= 0x04; - break; - case SZ_32M: - param->dram_config |= 0x08; - break; - case SZ_64M: - param->dram_config |= 0x0c; - break; - } - -} - -static void ddr3_init(struct ast_device *ast, struct ast2300_dram_param *param) -{ - u32 data, data2, retry = 0; - -ddr3_init_start: - ast_moutdwm(ast, 0x1E6E0000, 0xFC600309); - ast_moutdwm(ast, 0x1E6E0018, 0x00000100); - ast_moutdwm(ast, 0x1E6E0024, 0x00000000); - ast_moutdwm(ast, 0x1E6E0034, 0x00000000); - udelay(10); - ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ); - ast_moutdwm(ast, 0x1E6E0068, param->reg_SADJ); - udelay(10); - ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000); - udelay(10); - - ast_moutdwm(ast, 0x1E6E0004, param->dram_config); - ast_moutdwm(ast, 0x1E6E0008, 0x90040f); - ast_moutdwm(ast, 0x1E6E0010, param->reg_AC1); - ast_moutdwm(ast, 0x1E6E0014, param->reg_AC2); - ast_moutdwm(ast, 0x1E6E0020, param->reg_DQSIC); - ast_moutdwm(ast, 0x1E6E0080, 0x00000000); - ast_moutdwm(ast, 0x1E6E0084, 0x00000000); - ast_moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY); - ast_moutdwm(ast, 0x1E6E0018, 0x4000A170); - ast_moutdwm(ast, 0x1E6E0018, 0x00002370); - ast_moutdwm(ast, 0x1E6E0038, 0x00000000); - ast_moutdwm(ast, 0x1E6E0040, 0xFF444444); - ast_moutdwm(ast, 0x1E6E0044, 0x22222222); - ast_moutdwm(ast, 0x1E6E0048, 0x22222222); - ast_moutdwm(ast, 0x1E6E004C, 0x00000002); - ast_moutdwm(ast, 0x1E6E0050, 0x80000000); - ast_moutdwm(ast, 0x1E6E0050, 0x00000000); - ast_moutdwm(ast, 0x1E6E0054, 0); - ast_moutdwm(ast, 0x1E6E0060, param->reg_DRV); - ast_moutdwm(ast, 0x1E6E006C, param->reg_IOZ); - ast_moutdwm(ast, 0x1E6E0070, 0x00000000); - ast_moutdwm(ast, 0x1E6E0074, 0x00000000); - ast_moutdwm(ast, 0x1E6E0078, 0x00000000); - ast_moutdwm(ast, 0x1E6E007C, 0x00000000); - /* Wait MCLK2X lock to MCLK */ - do { - data = ast_mindwm(ast, 0x1E6E001C); - } while (!(data & 0x08000000)); - data = ast_mindwm(ast, 0x1E6E001C); - data = (data >> 8) & 0xff; - while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) { - data2 = (ast_mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4; - if ((data2 & 0xff) > param->madj_max) { - break; - } - ast_moutdwm(ast, 0x1E6E0064, data2); - if (data2 & 0x00100000) { - data2 = ((data2 & 0xff) >> 3) + 3; - } else { - data2 = ((data2 & 0xff) >> 2) + 5; - } - data = ast_mindwm(ast, 0x1E6E0068) & 0xffff00ff; - data2 += data & 0xff; - data = data | (data2 << 8); - ast_moutdwm(ast, 0x1E6E0068, data); - udelay(10); - ast_moutdwm(ast, 0x1E6E0064, ast_mindwm(ast, 0x1E6E0064) | 0xC0000); - udelay(10); - data = ast_mindwm(ast, 0x1E6E0018) & 0xfffff1ff; - ast_moutdwm(ast, 0x1E6E0018, data); - data = data | 0x200; - ast_moutdwm(ast, 0x1E6E0018, data); - do { - data = ast_mindwm(ast, 0x1E6E001C); - } while (!(data & 0x08000000)); - - data = ast_mindwm(ast, 0x1E6E001C); - data = (data >> 8) & 0xff; - } - ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, 0x1E6E0068) & 0xffff); - data = ast_mindwm(ast, 0x1E6E0018) | 0xC00; - ast_moutdwm(ast, 0x1E6E0018, data); - - ast_moutdwm(ast, 0x1E6E0034, 0x00000001); - ast_moutdwm(ast, 0x1E6E000C, 0x00000040); - udelay(50); - /* Mode Register Setting */ - ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100); - ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS); - ast_moutdwm(ast, 0x1E6E0028, 0x00000005); - ast_moutdwm(ast, 0x1E6E0028, 0x00000007); - ast_moutdwm(ast, 0x1E6E0028, 0x00000003); - ast_moutdwm(ast, 0x1E6E0028, 0x00000001); - ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS); - ast_moutdwm(ast, 0x1E6E000C, 0x00005C08); - ast_moutdwm(ast, 0x1E6E0028, 0x00000001); - - ast_moutdwm(ast, 0x1E6E000C, 0x00005C01); - data = 0; - if (param->wodt) { - data = 0x300; - } - if (param->rodt) { - data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3); - } - ast_moutdwm(ast, 0x1E6E0034, data | 0x3); - - /* Calibrate the DQSI delay */ - if ((cbr_dll2(ast, param) == false) && (retry++ < 10)) - goto ddr3_init_start; - - ast_moutdwm(ast, 0x1E6E0120, param->reg_FREQ); - /* ECC Memory Initialization */ -#ifdef ECC - ast_moutdwm(ast, 0x1E6E007C, 0x00000000); - ast_moutdwm(ast, 0x1E6E0070, 0x221); - do { - data = ast_mindwm(ast, 0x1E6E0070); - } while (!(data & 0x00001000)); - ast_moutdwm(ast, 0x1E6E0070, 0x00000000); - ast_moutdwm(ast, 0x1E6E0050, 0x80000000); - ast_moutdwm(ast, 0x1E6E0050, 0x00000000); -#endif - - -} - -static void get_ddr2_info(struct ast_device *ast, struct ast2300_dram_param *param) -{ - u32 trap, trap_AC2, trap_MRS; - - ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8); - - /* Ger trap info */ - trap = (ast_mindwm(ast, 0x1E6E2070) >> 25) & 0x3; - trap_AC2 = (trap << 20) | (trap << 16); - trap_AC2 += 0x00110000; - trap_MRS = 0x00000040 | (trap << 4); - - - param->reg_MADJ = 0x00034C4C; - param->reg_SADJ = 0x00001800; - param->reg_DRV = 0x000000F0; - param->reg_PERIOD = param->dram_freq; - param->rodt = 0; - - switch (param->dram_freq) { - case 264: - ast_moutdwm(ast, 0x1E6E2020, 0x0130); - param->wodt = 0; - param->reg_AC1 = 0x11101513; - param->reg_AC2 = 0x78117011; - param->reg_DQSIC = 0x00000092; - param->reg_MRS = 0x00000842; - param->reg_EMRS = 0x00000000; - param->reg_DRV = 0x000000F0; - param->reg_IOZ = 0x00000034; - param->reg_DQIDLY = 0x0000005A; - param->reg_FREQ = 0x00004AC0; - param->madj_max = 138; - param->dll2_finetune_step = 3; - break; - case 336: - ast_moutdwm(ast, 0x1E6E2020, 0x0190); - param->wodt = 1; - param->reg_AC1 = 0x22202613; - param->reg_AC2 = 0xAA009016 | trap_AC2; - param->reg_DQSIC = 0x000000BA; - param->reg_MRS = 0x00000A02 | trap_MRS; - param->reg_EMRS = 0x00000040; - param->reg_DRV = 0x000000FA; - param->reg_IOZ = 0x00000034; - param->reg_DQIDLY = 0x00000074; - param->reg_FREQ = 0x00004DC0; - param->madj_max = 96; - param->dll2_finetune_step = 3; - switch (param->dram_chipid) { - default: - case AST_DRAM_512Mx16: - param->reg_AC2 = 0xAA009012 | trap_AC2; - break; - case AST_DRAM_1Gx16: - param->reg_AC2 = 0xAA009016 | trap_AC2; - break; - case AST_DRAM_2Gx16: - param->reg_AC2 = 0xAA009023 | trap_AC2; - break; - case AST_DRAM_4Gx16: - param->reg_AC2 = 0xAA00903B | trap_AC2; - break; - } - break; - default: - case 396: - ast_moutdwm(ast, 0x1E6E2020, 0x03F1); - param->wodt = 1; - param->rodt = 0; - param->reg_AC1 = 0x33302714; - param->reg_AC2 = 0xCC00B01B | trap_AC2; - param->reg_DQSIC = 0x000000E2; - param->reg_MRS = 0x00000C02 | trap_MRS; - param->reg_EMRS = 0x00000040; - param->reg_DRV = 0x000000FA; - param->reg_IOZ = 0x00000034; - param->reg_DQIDLY = 0x00000089; - param->reg_FREQ = 0x00005040; - param->madj_max = 96; - param->dll2_finetune_step = 4; - - switch (param->dram_chipid) { - case AST_DRAM_512Mx16: - param->reg_AC2 = 0xCC00B016 | trap_AC2; - break; - default: - case AST_DRAM_1Gx16: - param->reg_AC2 = 0xCC00B01B | trap_AC2; - break; - case AST_DRAM_2Gx16: - param->reg_AC2 = 0xCC00B02B | trap_AC2; - break; - case AST_DRAM_4Gx16: - param->reg_AC2 = 0xCC00B03F | trap_AC2; - break; - } - - break; - - case 408: - ast_moutdwm(ast, 0x1E6E2020, 0x01F0); - param->wodt = 1; - param->rodt = 0; - param->reg_AC1 = 0x33302714; - param->reg_AC2 = 0xCC00B01B | trap_AC2; - param->reg_DQSIC = 0x000000E2; - param->reg_MRS = 0x00000C02 | trap_MRS; - param->reg_EMRS = 0x00000040; - param->reg_DRV = 0x000000FA; - param->reg_IOZ = 0x00000034; - param->reg_DQIDLY = 0x00000089; - param->reg_FREQ = 0x000050C0; - param->madj_max = 96; - param->dll2_finetune_step = 4; - - switch (param->dram_chipid) { - case AST_DRAM_512Mx16: - param->reg_AC2 = 0xCC00B016 | trap_AC2; - break; - default: - case AST_DRAM_1Gx16: - param->reg_AC2 = 0xCC00B01B | trap_AC2; - break; - case AST_DRAM_2Gx16: - param->reg_AC2 = 0xCC00B02B | trap_AC2; - break; - case AST_DRAM_4Gx16: - param->reg_AC2 = 0xCC00B03F | trap_AC2; - break; - } - - break; - case 456: - ast_moutdwm(ast, 0x1E6E2020, 0x0230); - param->wodt = 0; - param->reg_AC1 = 0x33302815; - param->reg_AC2 = 0xCD44B01E; - param->reg_DQSIC = 0x000000FC; - param->reg_MRS = 0x00000E72; - param->reg_EMRS = 0x00000000; - param->reg_DRV = 0x00000000; - param->reg_IOZ = 0x00000034; - param->reg_DQIDLY = 0x00000097; - param->reg_FREQ = 0x000052C0; - param->madj_max = 88; - param->dll2_finetune_step = 3; - break; - case 504: - ast_moutdwm(ast, 0x1E6E2020, 0x0261); - param->wodt = 1; - param->rodt = 1; - param->reg_AC1 = 0x33302815; - param->reg_AC2 = 0xDE44C022; - param->reg_DQSIC = 0x00000117; - param->reg_MRS = 0x00000E72; - param->reg_EMRS = 0x00000040; - param->reg_DRV = 0x0000000A; - param->reg_IOZ = 0x00000045; - param->reg_DQIDLY = 0x000000A0; - param->reg_FREQ = 0x000054C0; - param->madj_max = 79; - param->dll2_finetune_step = 3; - break; - case 528: - ast_moutdwm(ast, 0x1E6E2020, 0x0120); - param->wodt = 1; - param->rodt = 1; - param->reg_AC1 = 0x33302815; - param->reg_AC2 = 0xEF44D024; - param->reg_DQSIC = 0x00000125; - param->reg_MRS = 0x00000E72; - param->reg_EMRS = 0x00000004; - param->reg_DRV = 0x000000F9; - param->reg_IOZ = 0x00000045; - param->reg_DQIDLY = 0x000000A7; - param->reg_FREQ = 0x000055C0; - param->madj_max = 76; - param->dll2_finetune_step = 3; - break; - case 552: - ast_moutdwm(ast, 0x1E6E2020, 0x02A1); - param->wodt = 1; - param->rodt = 1; - param->reg_AC1 = 0x43402915; - param->reg_AC2 = 0xFF44E025; - param->reg_DQSIC = 0x00000132; - param->reg_MRS = 0x00000E72; - param->reg_EMRS = 0x00000040; - param->reg_DRV = 0x0000000A; - param->reg_IOZ = 0x00000045; - param->reg_DQIDLY = 0x000000AD; - param->reg_FREQ = 0x000056C0; - param->madj_max = 76; - param->dll2_finetune_step = 3; - break; - case 576: - ast_moutdwm(ast, 0x1E6E2020, 0x0140); - param->wodt = 1; - param->rodt = 1; - param->reg_AC1 = 0x43402915; - param->reg_AC2 = 0xFF44E027; - param->reg_DQSIC = 0x0000013F; - param->reg_MRS = 0x00000E72; - param->reg_EMRS = 0x00000004; - param->reg_DRV = 0x000000F5; - param->reg_IOZ = 0x00000045; - param->reg_DQIDLY = 0x000000B3; - param->reg_FREQ = 0x000057C0; - param->madj_max = 76; - param->dll2_finetune_step = 3; - break; - } - - switch (param->dram_chipid) { - case AST_DRAM_512Mx16: - param->dram_config = 0x100; - break; - default: - case AST_DRAM_1Gx16: - param->dram_config = 0x121; - break; - case AST_DRAM_2Gx16: - param->dram_config = 0x122; - break; - case AST_DRAM_4Gx16: - param->dram_config = 0x123; - break; - } /* switch size */ - - switch (param->vram_size) { - default: - case SZ_8M: - param->dram_config |= 0x00; - break; - case SZ_16M: - param->dram_config |= 0x04; - break; - case SZ_32M: - param->dram_config |= 0x08; - break; - case SZ_64M: - param->dram_config |= 0x0c; - break; - } -} - -static void ddr2_init(struct ast_device *ast, struct ast2300_dram_param *param) -{ - u32 data, data2, retry = 0; - -ddr2_init_start: - ast_moutdwm(ast, 0x1E6E0000, 0xFC600309); - ast_moutdwm(ast, 0x1E6E0018, 0x00000100); - ast_moutdwm(ast, 0x1E6E0024, 0x00000000); - ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ); - ast_moutdwm(ast, 0x1E6E0068, param->reg_SADJ); - udelay(10); - ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000); - udelay(10); - - ast_moutdwm(ast, 0x1E6E0004, param->dram_config); - ast_moutdwm(ast, 0x1E6E0008, 0x90040f); - ast_moutdwm(ast, 0x1E6E0010, param->reg_AC1); - ast_moutdwm(ast, 0x1E6E0014, param->reg_AC2); - ast_moutdwm(ast, 0x1E6E0020, param->reg_DQSIC); - ast_moutdwm(ast, 0x1E6E0080, 0x00000000); - ast_moutdwm(ast, 0x1E6E0084, 0x00000000); - ast_moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY); - ast_moutdwm(ast, 0x1E6E0018, 0x4000A130); - ast_moutdwm(ast, 0x1E6E0018, 0x00002330); - ast_moutdwm(ast, 0x1E6E0038, 0x00000000); - ast_moutdwm(ast, 0x1E6E0040, 0xFF808000); - ast_moutdwm(ast, 0x1E6E0044, 0x88848466); - ast_moutdwm(ast, 0x1E6E0048, 0x44440008); - ast_moutdwm(ast, 0x1E6E004C, 0x00000000); - ast_moutdwm(ast, 0x1E6E0050, 0x80000000); - ast_moutdwm(ast, 0x1E6E0050, 0x00000000); - ast_moutdwm(ast, 0x1E6E0054, 0); - ast_moutdwm(ast, 0x1E6E0060, param->reg_DRV); - ast_moutdwm(ast, 0x1E6E006C, param->reg_IOZ); - ast_moutdwm(ast, 0x1E6E0070, 0x00000000); - ast_moutdwm(ast, 0x1E6E0074, 0x00000000); - ast_moutdwm(ast, 0x1E6E0078, 0x00000000); - ast_moutdwm(ast, 0x1E6E007C, 0x00000000); - - /* Wait MCLK2X lock to MCLK */ - do { - data = ast_mindwm(ast, 0x1E6E001C); - } while (!(data & 0x08000000)); - data = ast_mindwm(ast, 0x1E6E001C); - data = (data >> 8) & 0xff; - while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) { - data2 = (ast_mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4; - if ((data2 & 0xff) > param->madj_max) { - break; - } - ast_moutdwm(ast, 0x1E6E0064, data2); - if (data2 & 0x00100000) { - data2 = ((data2 & 0xff) >> 3) + 3; - } else { - data2 = ((data2 & 0xff) >> 2) + 5; - } - data = ast_mindwm(ast, 0x1E6E0068) & 0xffff00ff; - data2 += data & 0xff; - data = data | (data2 << 8); - ast_moutdwm(ast, 0x1E6E0068, data); - udelay(10); - ast_moutdwm(ast, 0x1E6E0064, ast_mindwm(ast, 0x1E6E0064) | 0xC0000); - udelay(10); - data = ast_mindwm(ast, 0x1E6E0018) & 0xfffff1ff; - ast_moutdwm(ast, 0x1E6E0018, data); - data = data | 0x200; - ast_moutdwm(ast, 0x1E6E0018, data); - do { - data = ast_mindwm(ast, 0x1E6E001C); - } while (!(data & 0x08000000)); - - data = ast_mindwm(ast, 0x1E6E001C); - data = (data >> 8) & 0xff; - } - ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, 0x1E6E0008) & 0xffff); - data = ast_mindwm(ast, 0x1E6E0018) | 0xC00; - ast_moutdwm(ast, 0x1E6E0018, data); - - ast_moutdwm(ast, 0x1E6E0034, 0x00000001); - ast_moutdwm(ast, 0x1E6E000C, 0x00000000); - udelay(50); - /* Mode Register Setting */ - ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100); - ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS); - ast_moutdwm(ast, 0x1E6E0028, 0x00000005); - ast_moutdwm(ast, 0x1E6E0028, 0x00000007); - ast_moutdwm(ast, 0x1E6E0028, 0x00000003); - ast_moutdwm(ast, 0x1E6E0028, 0x00000001); - - ast_moutdwm(ast, 0x1E6E000C, 0x00005C08); - ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS); - ast_moutdwm(ast, 0x1E6E0028, 0x00000001); - ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS | 0x380); - ast_moutdwm(ast, 0x1E6E0028, 0x00000003); - ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS); - ast_moutdwm(ast, 0x1E6E0028, 0x00000003); - - ast_moutdwm(ast, 0x1E6E000C, 0x7FFF5C01); - data = 0; - if (param->wodt) { - data = 0x500; - } - if (param->rodt) { - data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3); - } - ast_moutdwm(ast, 0x1E6E0034, data | 0x3); - ast_moutdwm(ast, 0x1E6E0120, param->reg_FREQ); - - /* Calibrate the DQSI delay */ - if ((cbr_dll2(ast, param) == false) && (retry++ < 10)) - goto ddr2_init_start; - - /* ECC Memory Initialization */ -#ifdef ECC - ast_moutdwm(ast, 0x1E6E007C, 0x00000000); - ast_moutdwm(ast, 0x1E6E0070, 0x221); - do { - data = ast_mindwm(ast, 0x1E6E0070); - } while (!(data & 0x00001000)); - ast_moutdwm(ast, 0x1E6E0070, 0x00000000); - ast_moutdwm(ast, 0x1E6E0050, 0x80000000); - ast_moutdwm(ast, 0x1E6E0050, 0x00000000); -#endif - -} - -static void ast_post_chip_2300(struct ast_device *ast) -{ - struct ast2300_dram_param param; - u32 temp; - u8 reg; - - reg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); - if ((reg & 0x80) == 0) {/* vga only */ - ast_write32(ast, 0xf004, 0x1e6e0000); - ast_write32(ast, 0xf000, 0x1); - ast_write32(ast, 0x12000, 0x1688a8a8); - do { - ; - } while (ast_read32(ast, 0x12000) != 0x1); - - ast_write32(ast, 0x10000, 0xfc600309); - do { - ; - } while (ast_read32(ast, 0x10000) != 0x1); - - /* Slow down CPU/AHB CLK in VGA only mode */ - temp = ast_read32(ast, 0x12008); - temp |= 0x73; - ast_write32(ast, 0x12008, temp); - - param.dram_freq = 396; - param.dram_type = AST_DDR3; - temp = ast_mindwm(ast, 0x1e6e2070); - if (temp & 0x01000000) - param.dram_type = AST_DDR2; - switch (temp & 0x18000000) { - case 0: - param.dram_chipid = AST_DRAM_512Mx16; - break; - default: - case 0x08000000: - param.dram_chipid = AST_DRAM_1Gx16; - break; - case 0x10000000: - param.dram_chipid = AST_DRAM_2Gx16; - break; - case 0x18000000: - param.dram_chipid = AST_DRAM_4Gx16; - break; - } - switch (temp & 0x0c) { - default: - case 0x00: - param.vram_size = SZ_8M; - break; - - case 0x04: - param.vram_size = SZ_16M; - break; - - case 0x08: - param.vram_size = SZ_32M; - break; - - case 0x0c: - param.vram_size = SZ_64M; - break; - } - - if (param.dram_type == AST_DDR3) { - get_ddr3_info(ast, ¶m); - ddr3_init(ast, ¶m); - } else { - get_ddr2_info(ast, ¶m); - ddr2_init(ast, ¶m); - } - - 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); -} - -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; -} - -void ast_patch_ahb_2500(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 */ -} - -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_patch_ahb_2500(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); -} diff --git a/drivers/gpu/drm/ast/ast_post.h b/drivers/gpu/drm/ast/ast_post.h new file mode 100644 index 000000000000..aa5d247bebe8 --- /dev/null +++ b/drivers/gpu/drm/ast/ast_post.h @@ -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 diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 9df18a8f2e37..f59d19b4b81a 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -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; diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index a1bc3e96dd35..ed35e567d117 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -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 @@ out_dp_init: 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 @@ out: 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); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 2b54120ba4a3..b86e93f30ed6 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -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; diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 61559467e2d2..562fea47b3ec 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -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, diff --git a/drivers/gpu/drm/clients/drm_client_setup.c b/drivers/gpu/drm/clients/drm_client_setup.c index aec2fab6d2bf..72480db1f00d 100644 --- a/drivers/gpu/drm/clients/drm_client_setup.c +++ b/drivers/gpu/drm/clients/drm_client_setup.c @@ -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")) { diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index db7896c7edb8..1c3920297906 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -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); diff --git a/drivers/gpu/drm/display/drm_hdmi_cec_helper.c b/drivers/gpu/drm/display/drm_hdmi_cec_helper.c index b4273c3522fa..3651ad0f76e0 100644 --- a/drivers/gpu/drm/display/drm_hdmi_cec_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_cec_helper.c @@ -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); diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index abceb28b23fc..365cf337529f 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -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 */ diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 02556363e918..cdd591b11488 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -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) diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 3952e27447ee..eebd1a05ee97 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -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 @@ out_prime_destroy: 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)) { diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 442eb31351dd..9078504e789c 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -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; } diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs index dd55b1cb764d..18492daae4b3 100644 --- a/drivers/gpu/drm/drm_panic_qr.rs +++ b/drivers/gpu/drm/drm_panic_qr.rs @@ -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); diff --git a/drivers/gpu/drm/imagination/pvr_power.c b/drivers/gpu/drm/imagination/pvr_power.c index 41f5d89e78b8..65642ded051d 100644 --- a/drivers/gpu/drm/imagination/pvr_power.c +++ b/drivers/gpu/drm/imagination/pvr_power.c @@ -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); diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index 7c00fd77758b..a123bc740ba1 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -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); } } diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h index 4dd732dcd59f..8fc7215e9b90 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.h +++ b/drivers/gpu/drm/panthor/panthor_gem.h @@ -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), }; /** diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index 292c31de18f1..24f6b3879f4b 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -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 @@ err_clk_disable: 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 @@ out: 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 @@ out: 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 @@ out: 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); - - 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, +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, + + .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,26 +996,35 @@ 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; - - 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; - } + 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 = devm_drm_bridge_add(dev, &dp->bridge); + if (ret) + return ret; - drm_connector_helper_add(connector, &cdn_dp_connector_helper_funcs); + ret = drm_bridge_attach(encoder, &dp->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret) + return ret; - ret = drm_connector_attach_encoder(connector, encoder); - if (ret) { - DRM_ERROR("failed to attach connector and encoder\n"); - goto err_free_connector; + 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_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); - if (ret) - return ret; - ret = component_add(dev, &cdn_dp_component_ops); if (ret) - goto err_audio_deinit; + return ret; return 0; - -err_audio_deinit: - platform_device_unregister(dp->audio_pdev); - return ret; } static void cdn_dp_remove(struct platform_device *pdev) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 17498f576ce7..e9c30b9fd543 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -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 */ diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index f737e7d46e66..acb59b25d928 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -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) { diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index db4b4038e51d..1ab3ad4bde9e 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -29,11 +29,360 @@ #include "rockchip_drm_drv.h" -#include "inno_hdmi.h" +#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U -#define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16) +#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 INNO_HDMI_MIN_TMDS_CLOCK 25000000U +#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 RK3036_GRF_SOC_CON2 0x148 #define RK3036_HDMI_PHSYNC BIT(4) @@ -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 = { diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.h b/drivers/gpu/drm/rockchip/inno_hdmi.h deleted file mode 100644 index 8b7ef3fac485..000000000000 --- a/drivers/gpu/drm/rockchip/inno_hdmi.h +++ /dev/null @@ -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__ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index d0f5fea15e21..186f6452a7d3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -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) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h index fc3ecb9fcd95..fa5c56f16047 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -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 */ diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index a673779de3d2..2411260db51d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -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 = { diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 32c4ed685739..45c5e3987813 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -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) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index c63543132f9d..81ad40d9582b 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -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; diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index d202b6c1eb8f..2c015f563de9 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -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"); diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 37b8d619066e..4e7c3d78b2b9 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -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) { diff --git a/drivers/gpu/drm/sti/sti_hdmi.h b/drivers/gpu/drm/sti/sti_hdmi.h index 6d4c3f57bc46..91d43dd46f13 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.h +++ b/drivers/gpu/drm/sti/sti_hdmi.h @@ -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); diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index dbc1394f96b8..41a285ec889f 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -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); } } diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c index ce5ae7cacb90..1922988625eb 100644 --- a/drivers/gpu/drm/udl/udl_drv.c +++ b/drivers/gpu/drm/udl/udl_drv.c @@ -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, diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c index 2752ab4f1c97..260c64733972 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.c +++ b/drivers/gpu/drm/vgem/vgem_drv.c @@ -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); diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c index 8c9898b9055d..e60573e0f3e9 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -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; } diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index a24d1655f7b8..e8472d9b6e3b 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -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; } diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index 68b5e3fce455..8013c31efe3b 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -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; }; diff --git a/drivers/gpu/trace/Kconfig b/drivers/gpu/trace/Kconfig index c24e9edd022e..cd3d19c4a201 100644 --- a/drivers/gpu/trace/Kconfig +++ b/drivers/gpu/trace/Kconfig @@ -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". diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index c3da6c0bfca6..d51777df12d1 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -87,4 +87,6 @@ if FB_CORE || SGI_NEWPORT_CONSOLE endif +source "drivers/gpu/trace/Kconfig" + endmenu diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 25684f5d6523..d8eab4859fd4 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -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]; diff --git a/include/drm/drm_accel.h b/include/drm/drm_accel.h index 038ccb02f9a3..20a665ec6f16 100644 --- a/include/drm/drm_accel.h +++ b/include/drm/drm_accel.h @@ -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) { } diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 7f66f9018c10..d2454ba83db3 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -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), diff --git a/include/drm/drm_debugfs.h b/include/drm/drm_debugfs.h index cf06cee4343f..ea8cba94208a 100644 --- a/include/drm/drm_debugfs.h +++ b/include/drm/drm_debugfs.h @@ -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_ */ diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 3f76a32d6b84..42fc085f986d 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -572,9 +572,24 @@ static inline bool drm_firmware_drivers_only(void) } #if defined(CONFIG_DEBUG_FS) -void drm_debugfs_dev_init(struct drm_device *dev, struct dentry *root); +void drm_debugfs_dev_init(struct drm_device *dev); +void drm_debugfs_init_root(void); +void drm_debugfs_remove_root(void); +void drm_debugfs_bridge_params(void); #else -static inline void drm_debugfs_dev_init(struct drm_device *dev, struct dentry *root) +static inline void drm_debugfs_dev_init(struct drm_device *dev) +{ +} + +static inline void drm_debugfs_init_root(void) +{ +} + +static inline void drm_debugfs_remove_root(void) +{ +} + +static inline void drm_debugfs_bridge_params(void) { } #endif diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h index 5c3b2aa3e69d..eab7546aad79 100644 --- a/include/drm/drm_file.h +++ b/include/drm/drm_file.h @@ -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; }; /** diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h index 35f7466dca84..92f5db84b9c2 100644 --- a/include/drm/drm_gem_shmem_helper.h +++ b/include/drm/drm_gem_shmem_helper.h @@ -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 diff --git a/include/drm/drm_managed.h b/include/drm/drm_managed.h index 53017cc609ac..72bfac002c06 100644 --- a/include/drm/drm_managed.h +++ b/include/drm/drm_managed.h @@ -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 diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs index acb638086131..af93d46d03d3 100644 --- a/rust/kernel/drm/driver.rs +++ b/rust/kernel/drm/driver.rs @@ -10,7 +10,6 @@ use crate::{ drm, error::{to_result, Result}, prelude::*, - str::CStr, types::ARef, }; use macros::vtable; |