drm-misc-next for v7.2-rc1:

UAPI Changes:
 - amdxdna: Revert read-only user-pointer BO mappings.
 - panthor: Add eviction and reclaim info to fdinfo.
 
 Cross-subsystem Changes:
 - Convert DMA-buf system and cma heap allocators to module.
 
 Core Changes:
 - Cleanup driver misuses of drm/exec.
 
 Driver Changes:
 - Add LG LP129WT232166, AM-1280800W8TZQW-T00H, NEC NL6448BC33-70C,
   Riverdi RVT70HSLNWCA0 and RVT101HVLNWC00 panels.
 - Add support for RZ/T2H SoC to renesas.
 - Add cursor plane support to verisilicon.
 - Support DVI outputs in ite-it66121 bridge.
 - Assorted bugfixes, docbook updates and improvements to ivpu, tegra,
   host1x, nouveau.
 - Add DSC quirk for ASUS DC301 USB-C dock.
 - Use drm client buffer for tegra framebuffer.
 - Add support for GA100 to nouveau.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAmoYjNIACgkQ/lWMcqZw
 E8MtBhAAkNrVkJcjZY+i6bl7IF4QyByDf+3Yo3momVM7mYaaLDkmhlX3KDL/a9xI
 5by1hm2D8+K4t7AsoWDk3oMhVD/kVU7UzuwYlFx/r3F2NUG/EF+oLJCIvL+a+kwH
 FH76iL9cGdqi5X76iHuZ7lbSvQv7dJbOL8EhZsbJxoKN6DHYeFDueRKckJtO1cfZ
 qWLLzkHQ9DsjkvDRzMN81VpXWhBRvAcFw9ZV2A+cgy8ZoOzjlQx+ytFHJt9iYWD7
 FYJPMwmUR1vhYVeO1JXwRijcnYM16qkj76CoXfpOpJkIzyKgR6BrTRosDntH3xAj
 PHY1yKgJ8ulXsw8rmPguIPtKtRRTLYkcJh9/dYpAMjVNPPuA7HJ5+F+7TCGii8wb
 JSP2P0X7OZKWqko5BBX5HStTxEUmpLfFYGfRauvr5sycfEyO850rJMBaEcW16w6Y
 sBfDcKcgV0icU95HFEuzrT50UWb6YhYguFdRrPTa+owtubNWqa7zpRtIDolyECHh
 Vbg0Tzwa2iPHbempmBply9xt6PbP0Kg2yS3JZh2uGNNjS+AqvijqhzXE3qZ0eDy8
 xmgNcHqeRIQkaUs3y+arCWIfQuBtXkmTkBOztwqYeDhroeqZMGsKGO9XWThC89Sc
 ujroH5TjQnX0KcRgFCWNuFyEUBj+ifkI/e4KaZmKTgeXe1e18oU=
 =9KcG
 -----END PGP SIGNATURE-----

Merge tag 'drm-misc-next-2026-05-28' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for v7.2-rc1:

UAPI Changes:
- amdxdna: Revert read-only user-pointer BO mappings.
- panthor: Add eviction and reclaim info to fdinfo.

Cross-subsystem Changes:
- Convert DMA-buf system and cma heap allocators to module.

Core Changes:
- Cleanup driver misuses of drm/exec.

Driver Changes:
- Add LG LP129WT232166, AM-1280800W8TZQW-T00H, NEC NL6448BC33-70C,
  Riverdi RVT70HSLNWCA0 and RVT101HVLNWC00 panels.
- Add support for RZ/T2H SoC to renesas.
- Add cursor plane support to verisilicon.
- Support DVI outputs in ite-it66121 bridge.
- Assorted bugfixes, docbook updates and improvements to ivpu, tegra,
  host1x, nouveau.
- Add DSC quirk for ASUS DC301 USB-C dock.
- Use drm client buffer for tegra framebuffer.
- Add support for GA100 to nouveau.

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patch.msgid.link/ef65f43c-becf-473c-a5cc-203fdfecd491@linux.intel.com
This commit is contained in:
Dave Airlie 2026-06-03 14:31:52 +10:00
commit 61cd9291ca
76 changed files with 1393 additions and 392 deletions

View File

@ -58,6 +58,10 @@ properties:
- hydis,hv070wx2-1e0
# Jenson Display BL-JT60050-01A 7" WSVGA (1024x600) color TFT LCD LVDS panel
- jenson,bl-jt60050-01a
# Riverdi RVT101HVLNWC00 10.1" WXGA (1280x800) TFT LCD LVDS panel
- riverdi,rvt101hvlnwc00
# Riverdi RVT70HSLNWCA0 7.0" WSVGA (1024x600) TFT LCD LVDS panel
- riverdi,rvt70hslnwca0
# Samsung LTN070NL01 7.0" WSVGA (1024x600) TFT LCD LVDS panel
- samsung,ltn070nl01
# Samsung LTN101AL03 10.1" WXGA (800x1280) TFT LCD LVDS panel

View File

@ -31,6 +31,8 @@ properties:
# Ampire AM-1280800N3TZQW-T00H 10.1" WQVGA TFT LCD panel
- ampire,am-1280800n3tzqw-t00h
# Ampire AM-1280800W8TZQW-T00H 10.1" WXGA TFT LCD panel
- ampire,am-1280800w8tzqw-t00h
# Ampire AM-480272H3TMQW-T01H 4.3" WQVGA TFT LCD panel
- ampire,am-480272h3tmqw-t01h
# Ampire AM-800480L1TMQW-T00H 5" WVGA TFT LCD panel
@ -234,6 +236,8 @@ properties:
- nec,nl12880bc20-05
# NEC LCD Technologies,Ltd. WQVGA TFT LCD panel
- nec,nl4827hc19-05b
# NEC LCD Technologies,Ltd. VGA TFT LCD panel
- nec,nl6448bc33-70c
# Netron-DY E231732 7.0" WSVGA TFT LCD panel
- netron-dy,e231732
# Newhaven Display International 480 x 272 TFT LCD panel

View File

@ -21,6 +21,7 @@ properties:
- renesas,r9a07g043u-du # RZ/G2UL
- renesas,r9a07g044-du # RZ/G2{L,LC}
- renesas,r9a09g057-du # RZ/V2H(P)
- renesas,r9a09g077-du # RZ/T2H
- items:
- enum:
- renesas,r9a07g054-du # RZ/V2L
@ -28,6 +29,9 @@ properties:
- items:
- const: renesas,r9a09g056-du # RZ/V2N
- const: renesas,r9a09g057-du # RZ/V2H(P) fallback
- items:
- const: renesas,r9a09g087-du # RZ/N2H
- const: renesas,r9a09g077-du # RZ/T2H fallback
reg:
maxItems: 1
@ -83,7 +87,6 @@ required:
- interrupts
- clocks
- clock-names
- resets
- power-domains
- ports
- renesas,vsps
@ -95,13 +98,16 @@ allOf:
properties:
compatible:
contains:
const: renesas,r9a07g043u-du
enum:
- renesas,r9a07g043u-du
- renesas,r9a09g077-du
then:
properties:
ports:
properties:
port@0:
description: DPI
port@1: false
required:
- port@0
@ -137,6 +143,17 @@ allOf:
required:
- port@0
- if:
properties:
compatible:
contains:
const: renesas,r9a09g077-du
then:
properties:
resets: false
else:
required:
- resets
examples:
# RZ/G2L DU

View File

@ -1411,6 +1411,9 @@ CONFIG_RZ_DMAC=y
CONFIG_TI_K3_UDMA=y
CONFIG_TI_K3_UDMA_GLUE_LAYER=y
CONFIG_STM32_DMA3=m
CONFIG_DMABUF_HEAPS=y
CONFIG_DMABUF_HEAPS_SYSTEM=m
CONFIG_DMABUF_HEAPS_CMA=m
CONFIG_VFIO=y
CONFIG_VFIO_PCI=y
CONFIG_VIRTIO_PCI=y

View File

@ -75,26 +75,6 @@ static const struct dma_buf_ops amdxdna_ubuf_dmabuf_ops = {
.release = amdxdna_ubuf_release,
};
static int readonly_va_entry(struct amdxdna_drm_va_entry *va_ent)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
int ret;
mmap_read_lock(mm);
vma = find_vma(mm, va_ent->vaddr);
if (!vma ||
vma->vm_start > va_ent->vaddr ||
vma->vm_end - va_ent->vaddr < va_ent->len)
ret = -ENOENT;
else
ret = vma->vm_flags & VM_WRITE ? 0 : 1;
mmap_read_unlock(mm);
return ret;
}
struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
u32 num_entries, void __user *va_entries)
{
@ -104,7 +84,6 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
struct amdxdna_ubuf_priv *ubuf;
u32 npages, start = 0;
struct dma_buf *dbuf;
bool readonly = true;
int i, ret;
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
@ -143,10 +122,6 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
ret = -EINVAL;
goto free_ent;
}
/* Pin pages as writable as long as not all entries are read-only. */
if (readonly && readonly_va_entry(&va_ent[i]) != 1)
readonly = false;
}
ubuf->nr_pages = exp_info.size >> PAGE_SHIFT;
@ -169,7 +144,7 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
npages = va_ent[i].len >> PAGE_SHIFT;
ret = pin_user_pages_fast(va_ent[i].vaddr, npages,
(readonly ? 0 : FOLL_WRITE) | FOLL_LONGTERM,
FOLL_WRITE | FOLL_LONGTERM,
&ubuf->pages[start]);
if (ret >= 0) {
start += ret;
@ -186,7 +161,7 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
exp_info.ops = &amdxdna_ubuf_dmabuf_ops;
exp_info.priv = ubuf;
exp_info.flags = (readonly ? O_RDONLY : O_RDWR) | O_CLOEXEC;
exp_info.flags = O_RDWR | O_CLOEXEC;
dbuf = dma_buf_export(&exp_info);
if (IS_ERR(dbuf)) {

View File

@ -111,7 +111,6 @@ struct ivpu_wa_table {
bool clear_runtime_mem;
bool interrupt_clear_with_0;
bool disable_clock_relinquish;
bool disable_d0i3_msg;
bool wp0_during_power_up;
bool disable_d0i2;
};
@ -220,8 +219,6 @@ extern bool ivpu_force_snoop;
#define IVPU_TEST_MODE_FW_TEST BIT(0)
#define IVPU_TEST_MODE_NULL_HW BIT(1)
#define IVPU_TEST_MODE_NULL_SUBMISSION BIT(2)
#define IVPU_TEST_MODE_D0I3_MSG_DISABLE BIT(4)
#define IVPU_TEST_MODE_D0I3_MSG_ENABLE BIT(5)
#define IVPU_TEST_MODE_MIP_DISABLE BIT(6)
#define IVPU_TEST_MODE_DISABLE_TIMEOUTS BIT(8)
#define IVPU_TEST_MODE_TURBO_ENABLE BIT(9)

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020-2025 Intel Corporation
* Copyright (C) 2020-2026 Intel Corporation
*/
#include <linux/firmware.h>
@ -347,22 +347,6 @@ static void ivpu_fw_release(struct ivpu_device *vdev)
release_firmware(vdev->fw->file);
}
/* Initialize workarounds that depend on FW version */
static void
ivpu_fw_init_wa(struct ivpu_device *vdev)
{
const struct vpu_firmware_header *fw_hdr = (const void *)vdev->fw->file->data;
if (IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, BOOT, 3, 17) ||
(ivpu_test_mode & IVPU_TEST_MODE_D0I3_MSG_DISABLE))
vdev->wa.disable_d0i3_msg = true;
/* Force enable the feature for testing purposes */
if (ivpu_test_mode & IVPU_TEST_MODE_D0I3_MSG_ENABLE)
vdev->wa.disable_d0i3_msg = false;
IVPU_PRINT_WA(disable_d0i3_msg);
}
static int ivpu_fw_mem_init(struct ivpu_device *vdev)
{
@ -480,8 +464,6 @@ int ivpu_fw_init(struct ivpu_device *vdev)
if (ret)
goto err_fw_release;
ivpu_fw_init_wa(vdev);
ret = ivpu_fw_mem_init(vdev);
if (ret)
goto err_fw_release;
@ -711,8 +693,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params
if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW)
boot_params->vpu_focus_present_timer_ms = IVPU_FOCUS_PRESENT_TIMER_MS;
boot_params->dvfs_mode = vdev->fw->dvfs_mode;
if (!IVPU_WA(disable_d0i3_msg))
boot_params->d0i3_delayed_entry = 1;
boot_params->d0i3_delayed_entry = 1;
boot_params->d0i3_residency_time_us = 0;
boot_params->d0i3_entry_vpu_ts = 0;
if (IVPU_WA(disable_d0i2))

View File

@ -97,7 +97,11 @@ ivpu_ipc_tx_prepare(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
memset(tx_buf, 0, sizeof(*tx_buf));
tx_buf->ipc.data_addr = jsm_vpu_addr;
/* TODO: Set data_size to actual JSM message size, not union of all messages */
/*
* Firmware expects full JSM message size regardless of the payload size.
* Unused fields must be zeroed to allow future extensions of existing
* commands without breaking compatibility.
*/
tx_buf->ipc.data_size = sizeof(*req);
tx_buf->ipc.channel = cons->channel;
tx_buf->ipc.src_node = 0;

View File

@ -275,9 +275,6 @@ int ivpu_jsm_pwr_d0i3_enter(struct ivpu_device *vdev)
struct vpu_jsm_msg resp;
int ret;
if (IVPU_WA(disable_d0i3_msg))
return 0;
req.payload.pwr_d0i3_enter.send_response = 1;
ret = ivpu_ipc_send_receive_internal(vdev, &req, VPU_JSM_MSG_PWR_D0I3_ENTER_DONE, &resp,

View File

@ -41,7 +41,7 @@
/**
* API header changed (field names, documentation, formatting) but API itself has not been changed
*/
#define VPU_BOOT_API_VER_PATCH 4
#define VPU_BOOT_API_VER_PATCH 5
/**
* Index in the API version table
@ -320,9 +320,11 @@ struct vpu_boot_params {
u64 dvfs_param;
/**
* D0i3 delayed entry
* Bit0: Disable CPU state save on D0i2 entry flow.
* Bit 0: Disable CPU state save on D0i2 entry flow.
* 0: Every D0i2 entry saves state. Save state IPC message ignored.
* 1: IPC message required to save state on D0i3 entry flow.
* NOTE: This parameter is deprecated starting NPU50xx+. Bit 0 is now hardcoded to 1,
* meaning CPU state save always requires IPC message on D0i3 entry flow.
*/
u32 d0i3_delayed_entry;
/** Time spent by VPU in D0i3 state */

View File

@ -53,6 +53,7 @@ bool __read_mostly mem_accounting;
module_param(mem_accounting, bool, 0444);
MODULE_PARM_DESC(mem_accounting,
"Enable cgroup-based memory accounting for dma-buf heap allocations (default=false).");
EXPORT_SYMBOL_NS_GPL(mem_accounting, "DMA_BUF_HEAP");
static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
u32 fd_flags,

View File

@ -1,12 +1,12 @@
config DMABUF_HEAPS_SYSTEM
bool "DMA-BUF System Heap"
tristate "DMA-BUF System Heap"
depends on DMABUF_HEAPS
help
Choose this option to enable the system dmabuf heap. The system heap
is backed by pages from the buddy allocator. If in doubt, say Y.
config DMABUF_HEAPS_CMA
bool "DMA-BUF CMA Heap"
tristate "DMA-BUF CMA Heap"
depends on DMABUF_HEAPS && DMA_CMA
help
Choose this option to enable dma-buf CMA heap. This heap is backed

View File

@ -420,3 +420,6 @@ static int __init add_cma_heaps(void)
}
module_init(add_cma_heaps);
MODULE_DESCRIPTION("DMA-BUF CMA Heap");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("DMA_BUF");
MODULE_IMPORT_NS("DMA_BUF_HEAP");

View File

@ -537,3 +537,8 @@ static int __init system_heap_create(void)
return 0;
}
module_init(system_heap_create);
MODULE_DESCRIPTION("DMA-BUF System Heap");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("DMA_BUF");
MODULE_IMPORT_NS("DMA_BUF_HEAP");

View File

@ -2999,7 +2999,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence __rcu *
/* Validate PDs, PTs and evicted DMABuf imports last. Otherwise BO
* validations above would invalidate DMABuf imports again.
*/
ret = process_validate_vms(process_info, &exec.ticket);
ret = process_validate_vms(process_info, drm_exec_ticket(&exec));
if (ret) {
pr_debug("Validating VMs failed, ret: %d\n", ret);
goto validate_map_fail;
@ -3040,7 +3040,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence __rcu *
goto validate_map_fail;
}
ret = amdgpu_vm_handle_moved(adev, peer_vm, &exec.ticket);
ret = amdgpu_vm_handle_moved(adev, peer_vm, drm_exec_ticket(&exec));
if (ret) {
dev_dbg(adev->dev,
"Memory eviction: handle moved failed, pid %8d. Try again.\n",

View File

@ -850,7 +850,6 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
struct amdgpu_vm *vm = &fpriv->vm;
struct amdgpu_bo_list_entry *e;
struct drm_gem_object *obj;
unsigned long index;
unsigned int i;
int r;
@ -961,7 +960,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
goto out_free_user_pages;
}
drm_exec_for_each_locked_object(&p->exec, index, obj) {
drm_exec_for_each_locked_object(&p->exec, obj) {
r = amdgpu_cs_bo_validate(p, gem_to_amdgpu_bo(obj));
if (unlikely(r))
goto out_free_user_pages;
@ -1158,7 +1157,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
return r;
}
r = amdgpu_vm_handle_moved(adev, vm, &p->exec.ticket);
r = amdgpu_vm_handle_moved(adev, vm, drm_exec_ticket(&p->exec));
if (r)
return r;
@ -1201,7 +1200,6 @@ static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p)
struct drm_gpu_scheduler *sched;
struct drm_gem_object *obj;
struct dma_fence *fence;
unsigned long index;
unsigned int i;
int r;
@ -1212,7 +1210,7 @@ static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p)
return r;
}
drm_exec_for_each_locked_object(&p->exec, index, obj) {
drm_exec_for_each_locked_object(&p->exec, obj) {
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
struct dma_resv *resv = bo->tbo.base.resv;
@ -1281,7 +1279,6 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
struct amdgpu_job *leader = p->gang_leader;
struct amdgpu_bo_list_entry *e;
struct drm_gem_object *gobj;
unsigned long index;
unsigned int i;
uint64_t seq;
int r;
@ -1331,7 +1328,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
}
p->fence = dma_fence_get(&leader->base.s_fence->finished);
drm_exec_for_each_locked_object(&p->exec, index, gobj) {
drm_exec_for_each_locked_object(&p->exec, gobj) {
ttm_bo_move_to_lru_tail_unlocked(&gem_to_amdgpu_bo(gobj)->tbo);
@ -1362,7 +1359,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
cs->out.handle = seq;
leader->uf_sequence = seq;
amdgpu_vm_bo_trace_cs(&fpriv->vm, &p->exec.ticket);
amdgpu_vm_bo_trace_cs(&fpriv->vm, drm_exec_ticket(&p->exec));
for (i = 0; i < p->gang_size; ++i) {
amdgpu_job_free_resources(p->jobs[i]);
trace_amdgpu_cs_ioctl(p->jobs[i]);
@ -1797,7 +1794,7 @@ int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
*map = mapping;
/* Double check that the BO is reserved by this CS */
if (dma_resv_locking_ctx((*bo)->tbo.base.resv) != &parser->exec.ticket)
if (dma_resv_locking_ctx((*bo)->tbo.base.resv) != drm_exec_ticket(&parser->exec))
return -EINVAL;
/* Make sure VRAM is allocated contigiously */

View File

@ -121,7 +121,6 @@ int amdgpu_evf_mgr_rearm(struct amdgpu_eviction_fence_mgr *evf_mgr,
{
struct amdgpu_eviction_fence *ev_fence;
struct drm_gem_object *obj;
unsigned long index;
/* Create and initialize a new eviction fence */
ev_fence = kzalloc_obj(*ev_fence);
@ -140,7 +139,7 @@ int amdgpu_evf_mgr_rearm(struct amdgpu_eviction_fence_mgr *evf_mgr,
evf_mgr->ev_fence = &ev_fence->base;
/* And add it to all existing BOs */
drm_exec_for_each_locked_object(exec, index, obj) {
drm_exec_for_each_locked_object(exec, obj) {
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
amdgpu_evf_mgr_attach_fence(evf_mgr, bo);

View File

@ -205,6 +205,8 @@ config DRM_LONTIUM_LT8713SX
config DRM_ITE_IT66121
tristate "ITE IT66121 HDMI bridge"
depends on OF
select DRM_DISPLAY_HDMI_STATE_HELPER
select DRM_DISPLAY_HELPER
select DRM_KMS_HELPER
select REGMAP_I2C
help

View File

@ -20,6 +20,8 @@
#include <linux/pinctrl/consumer.h>
#include <linux/regulator/consumer.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_edid.h>
@ -161,6 +163,14 @@
#define IT66121_PKT_GEN_CTRL_ON BIT(0)
#define IT66121_PKT_GEN_CTRL_RPT BIT(1)
#define IT66121_PKT_NULL_CTRL_REG 0xC9
#define IT66121_PKT_NULL_CTRL_ON BIT(0)
#define IT66121_PKT_NULL_CTRL_RPT BIT(1)
/* Null packet data registers (used for HDMI Vendor Specific InfoFrame) */
#define IT66121_PKT_NULL_HB(n) (0x138 + (n))
#define IT66121_PKT_NULL_PB(n) (0x13B + (n))
#define IT66121_AVIINFO_DB1_REG 0x158
#define IT66121_AVIINFO_DB2_REG 0x159
#define IT66121_AVIINFO_DB3_REG 0x15A
@ -180,8 +190,16 @@
#define IT66121_AVI_INFO_PKT_ON BIT(0)
#define IT66121_AVI_INFO_PKT_RPT BIT(1)
#define IT66121_AUD_INFO_PKT_REG 0xCE
#define IT66121_AUD_INFO_PKT_ON BIT(0)
#define IT66121_AUD_INFO_PKT_RPT BIT(1)
#define IT66121_AUD_INFO_DB1_REG 0x168
#define IT66121_AUD_INFO_CSUM_REG 0x16D
#define IT66121_HDMI_MODE_REG 0xC0
#define IT66121_HDMI_MODE_HDMI BIT(0)
#define IT66121_HDMI_MODE_DVI 0
#define IT66121_SYS_STATUS_REG 0x0E
#define IT66121_SYS_STATUS_ACTIVE_IRQ BIT(7)
@ -298,13 +316,11 @@ struct it66121_chip_info {
struct it66121_ctx {
struct regmap *regmap;
struct drm_bridge bridge;
struct drm_connector *connector;
struct device *dev;
struct gpio_desc *gpio_reset;
struct i2c_client *client;
u32 bus_width;
struct mutex lock; /* Protects fields below and device registers */
struct hdmi_avi_infoframe hdmi_avi_infoframe;
struct {
u8 ch_enable;
u8 fs;
@ -652,6 +668,60 @@ static int it66121_bridge_attach(struct drm_bridge *bridge,
return 0;
}
static void it66121_set_mode(struct it66121_ctx *ctx,
struct drm_connector *connector,
struct drm_atomic_commit *state)
{
const struct drm_connector_state *conn_state;
const struct drm_crtc_state *crtc_state;
const struct drm_display_mode *mode;
struct drm_crtc *crtc;
conn_state = drm_atomic_get_new_connector_state(state, connector);
if (WARN_ON(!conn_state))
return;
crtc = conn_state->crtc;
if (WARN_ON(!crtc))
return;
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
if (WARN_ON(!crtc_state))
return;
mode = &crtc_state->adjusted_mode;
mutex_lock(&ctx->lock);
/* Set TX mode to HDMI or DVI */
if (regmap_write(ctx->regmap, IT66121_HDMI_MODE_REG,
connector->display_info.is_hdmi ?
IT66121_HDMI_MODE_HDMI : IT66121_HDMI_MODE_DVI))
goto unlock;
if ((ctx->id == ID_IT66121 || ctx->id == ID_IT66122) &&
regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
IT66121_CLK_BANK_PWROFF_TXCLK,
IT66121_CLK_BANK_PWROFF_TXCLK)) {
goto unlock;
}
if (it66121_configure_input(ctx))
goto unlock;
if (it66121_configure_afe(ctx, mode))
goto unlock;
if ((ctx->id == ID_IT66121 || ctx->id == ID_IT66122) &&
regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
IT66121_CLK_BANK_PWROFF_TXCLK, 0)) {
goto unlock;
}
unlock:
mutex_unlock(&ctx->lock);
}
static int it66121_set_mute(struct it66121_ctx *ctx, bool mute)
{
int ret;
@ -724,9 +794,15 @@ static void it66121_bridge_enable(struct drm_bridge *bridge,
struct drm_atomic_commit *state)
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
struct drm_connector *connector;
ctx->connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
if (WARN_ON(!connector))
return;
drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
it66121_set_mode(ctx, connector, state);
it66121_set_mute(ctx, false);
}
@ -736,8 +812,6 @@ static void it66121_bridge_disable(struct drm_bridge *bridge,
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
it66121_set_mute(ctx, true);
ctx->connector = NULL;
}
static int it66121_bridge_check(struct drm_bridge *bridge,
@ -758,90 +832,6 @@ static int it66121_bridge_check(struct drm_bridge *bridge,
return 0;
}
static
void it66121_bridge_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
const struct drm_display_mode *adjusted_mode)
{
u8 buf[HDMI_INFOFRAME_SIZE(AVI)];
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
int ret;
mutex_lock(&ctx->lock);
ret = drm_hdmi_avi_infoframe_from_display_mode(&ctx->hdmi_avi_infoframe, ctx->connector,
adjusted_mode);
if (ret) {
DRM_ERROR("Failed to setup AVI infoframe: %d\n", ret);
goto unlock;
}
ret = hdmi_avi_infoframe_pack(&ctx->hdmi_avi_infoframe, buf, sizeof(buf));
if (ret < 0) {
DRM_ERROR("Failed to pack infoframe: %d\n", ret);
goto unlock;
}
/* Write new AVI infoframe packet */
ret = regmap_bulk_write(ctx->regmap, IT66121_AVIINFO_DB1_REG,
&buf[HDMI_INFOFRAME_HEADER_SIZE],
HDMI_AVI_INFOFRAME_SIZE);
if (ret)
goto unlock;
if (regmap_write(ctx->regmap, IT66121_AVIINFO_CSUM_REG, buf[3]))
goto unlock;
/* Enable AVI infoframe */
if (regmap_write(ctx->regmap, IT66121_AVI_INFO_PKT_REG,
IT66121_AVI_INFO_PKT_ON | IT66121_AVI_INFO_PKT_RPT))
goto unlock;
/* Set TX mode to HDMI */
if (regmap_write(ctx->regmap, IT66121_HDMI_MODE_REG, IT66121_HDMI_MODE_HDMI))
goto unlock;
if ((ctx->id == ID_IT66121 || ctx->id == ID_IT66122) &&
regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
IT66121_CLK_BANK_PWROFF_TXCLK,
IT66121_CLK_BANK_PWROFF_TXCLK)) {
goto unlock;
}
if (it66121_configure_input(ctx))
goto unlock;
if (it66121_configure_afe(ctx, adjusted_mode))
goto unlock;
if ((ctx->id == ID_IT66121 || ctx->id == ID_IT66122) &&
regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
IT66121_CLK_BANK_PWROFF_TXCLK, 0)) {
goto unlock;
}
unlock:
mutex_unlock(&ctx->lock);
}
static enum drm_mode_status it66121_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
unsigned long max_clock;
max_clock = (ctx->bus_width == 12) ? 74250 : 148500;
if (mode->clock > max_clock)
return MODE_CLOCK_HIGH;
if (mode->clock < 25000)
return MODE_CLOCK_LOW;
return MODE_OK;
}
static enum drm_connector_status
it66121_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector)
{
@ -872,6 +862,128 @@ static void it66121_bridge_hpd_disable(struct drm_bridge *bridge)
dev_err(ctx->dev, "failed to disable HPD IRQ\n");
}
static enum drm_mode_status
it66121_bridge_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
const struct drm_display_mode *mode,
unsigned long long tmds_rate)
{
const struct it66121_ctx *ctx =
container_of(bridge, const struct it66121_ctx, bridge);
unsigned long long max_rate;
max_rate = (ctx->bus_width == 12) ? 74250000ULL : 148500000ULL;
if (tmds_rate > max_rate)
return MODE_CLOCK_HIGH;
if (tmds_rate < HDMI_TMDS_CHAR_RATE_MIN_HZ)
return MODE_CLOCK_LOW;
return MODE_OK;
}
static int it66121_bridge_hdmi_clear_avi_infoframe(struct drm_bridge *bridge)
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
/* Clear both IT66121_AVI_INFO_PKT_ON and IT66121_AVI_INFO_PKT_RPT */
return regmap_write(ctx->regmap, IT66121_AVI_INFO_PKT_REG, 0);
}
static int it66121_bridge_hdmi_write_avi_infoframe(struct drm_bridge *bridge,
const u8 *buffer, size_t len)
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
int ret;
mutex_lock(&ctx->lock);
/* Write new AVI infoframe packet */
ret = regmap_bulk_write(ctx->regmap, IT66121_AVIINFO_DB1_REG,
&buffer[HDMI_INFOFRAME_HEADER_SIZE],
HDMI_AVI_INFOFRAME_SIZE);
if (ret)
goto unlock;
ret = regmap_write(ctx->regmap, IT66121_AVIINFO_CSUM_REG, buffer[3]);
if (ret)
goto unlock;
/* Enable AVI infoframe */
ret = regmap_write(ctx->regmap, IT66121_AVI_INFO_PKT_REG,
IT66121_AVI_INFO_PKT_ON | IT66121_AVI_INFO_PKT_RPT);
unlock:
mutex_unlock(&ctx->lock);
return ret;
}
static int it66121_bridge_hdmi_clear_hdmi_infoframe(struct drm_bridge *bridge)
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
/* Clear both IT66121_PKT_NULL_CTRL_ON and IT66121_PKT_NULL_CTRL_RPT */
return regmap_write(ctx->regmap, IT66121_PKT_NULL_CTRL_REG, 0);
}
static int it66121_bridge_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge,
const u8 *buffer, size_t len)
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
int ret;
mutex_lock(&ctx->lock);
/* Write new HDMI Vendor Specific Infoframe packet */
ret = regmap_bulk_write(ctx->regmap, IT66121_PKT_NULL_HB(0), buffer, len);
if (ret)
goto unlock;
/* Enable HDMI Vendor Specific Infoframe */
ret = regmap_write(ctx->regmap, IT66121_PKT_NULL_CTRL_REG,
IT66121_PKT_NULL_CTRL_ON | IT66121_PKT_NULL_CTRL_RPT);
unlock:
mutex_unlock(&ctx->lock);
return ret;
}
static int it66121_bridge_hdmi_clear_audio_infoframe(struct drm_bridge *bridge)
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
/* Clear both IT66121_AUD_INFO_PKT_ON and IT66121_AUD_INFO_PKT_RPT */
return regmap_write(ctx->regmap, IT66121_AUD_INFO_PKT_REG, 0);
}
static int it66121_bridge_hdmi_write_audio_infoframe(struct drm_bridge *bridge,
const u8 *buffer, size_t len)
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
int ret;
mutex_lock(&ctx->lock);
/* Write new Audio infoframe packet */
ret = regmap_bulk_write(ctx->regmap, IT66121_AUD_INFO_DB1_REG,
&buffer[HDMI_INFOFRAME_HEADER_SIZE],
min_t(size_t, len - HDMI_INFOFRAME_HEADER_SIZE, 5));
if (ret)
goto unlock;
ret = regmap_write(ctx->regmap, IT66121_AUD_INFO_CSUM_REG, buffer[3]);
if (ret)
goto unlock;
/* Enable Audio infoframe */
ret = regmap_write(ctx->regmap, IT66121_AUD_INFO_PKT_REG,
IT66121_AUD_INFO_PKT_ON | IT66121_AUD_INFO_PKT_RPT);
unlock:
mutex_unlock(&ctx->lock);
return ret;
}
static const struct drm_edid *it66121_bridge_edid_read(struct drm_bridge *bridge,
struct drm_connector *connector)
{
@ -1359,6 +1471,10 @@ static int it66121_hdmi_audio_prepare(struct drm_bridge *bridge,
out:
mutex_unlock(&ctx->lock);
if (!ret)
ret = drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector,
&params->cea);
return ret;
}
@ -1384,6 +1500,8 @@ static void it66121_hdmi_audio_shutdown(struct drm_bridge *bridge,
int ret;
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector);
mutex_lock(&ctx->lock);
ret = it661221_audio_output_enable(ctx, false);
if (ret)
@ -1432,12 +1550,17 @@ static const struct drm_bridge_funcs it66121_bridge_funcs = {
.atomic_enable = it66121_bridge_enable,
.atomic_disable = it66121_bridge_disable,
.atomic_check = it66121_bridge_check,
.mode_set = it66121_bridge_mode_set,
.mode_valid = it66121_bridge_mode_valid,
.detect = it66121_bridge_detect,
.edid_read = it66121_bridge_edid_read,
.hpd_enable = it66121_bridge_hpd_enable,
.hpd_disable = it66121_bridge_hpd_disable,
.hdmi_tmds_char_rate_valid = it66121_bridge_hdmi_tmds_char_rate_valid,
.hdmi_clear_avi_infoframe = it66121_bridge_hdmi_clear_avi_infoframe,
.hdmi_write_avi_infoframe = it66121_bridge_hdmi_write_avi_infoframe,
.hdmi_clear_hdmi_infoframe = it66121_bridge_hdmi_clear_hdmi_infoframe,
.hdmi_write_hdmi_infoframe = it66121_bridge_hdmi_write_hdmi_infoframe,
.hdmi_clear_audio_infoframe = it66121_bridge_hdmi_clear_audio_infoframe,
.hdmi_write_audio_infoframe = it66121_bridge_hdmi_write_audio_infoframe,
.hdmi_audio_startup = it66121_hdmi_audio_startup,
.hdmi_audio_prepare = it66121_hdmi_audio_prepare,
.hdmi_audio_shutdown = it66121_hdmi_audio_shutdown,
@ -1543,7 +1666,10 @@ static int it66121_probe(struct i2c_client *client)
ctx->bridge.of_node = dev->of_node;
ctx->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
ctx->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID;
ctx->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |
DRM_BRIDGE_OP_HDMI;
ctx->bridge.vendor = "ITE";
ctx->bridge.product = "IT66121";
if (client->irq > 0) {
ctx->bridge.ops |= DRM_BRIDGE_OP_HPD;

View File

@ -2546,6 +2546,8 @@ static const struct dpcd_quirk dpcd_quirk_list[] = {
{ OUI(0x00, 0x00, 0x00), DEVICE_ID('C', 'H', '7', '5', '1', '1'), false, BIT(DP_DPCD_QUIRK_NO_SINK_COUNT) },
/* Synaptics DP1.4 MST hubs can support DSC without virtual DPCD */
{ OUI(0x90, 0xCC, 0x24), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) },
/* Realtek DP1.4 MST hubs can support DSC without virtual DPCD */
{ OUI(0x00, 0xe0, 0x4c), DEVICE_ID('D', 'p', '1', '.', '4', 0), true, BIT(DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) },
/* Synaptics DP1.4 MST hubs require DSC for some modes on which it applies HBLANK expansion. */
{ OUI(0x90, 0xCC, 0x24), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_HBLANK_EXPANSION_REQUIRES_DSC) },
/* MediaTek panels (at least in U3224KBA) require DSC for modes with a short HBLANK on UHBR links. */

View File

@ -24,7 +24,6 @@
*
* struct drm_gem_object *obj;
* struct drm_exec exec;
* unsigned long index;
* int ret;
*
* drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
@ -40,7 +39,7 @@
* goto error;
* }
*
* drm_exec_for_each_locked_object(&exec, index, obj) {
* drm_exec_for_each_locked_object(&exec, obj) {
* dma_resv_add_fence(obj->resv, fence, DMA_RESV_USAGE_READ);
* ...
* }
@ -49,16 +48,12 @@
* See struct dma_exec for more details.
*/
/* Dummy value used to initially enter the retry loop */
#define DRM_EXEC_DUMMY ((void *)~0)
/* Unlock all objects and drop references */
static void drm_exec_unlock_all(struct drm_exec *exec)
{
struct drm_gem_object *obj;
unsigned long index;
drm_exec_for_each_locked_object_reverse(exec, index, obj) {
drm_exec_for_each_locked_object_reverse(exec, obj) {
dma_resv_unlock(obj->resv);
drm_gem_object_put(obj);
}

View File

@ -1553,9 +1553,8 @@ drm_gpuvm_resv_add_fence(struct drm_gpuvm *gpuvm,
enum dma_resv_usage extobj_usage)
{
struct drm_gem_object *obj;
unsigned long index;
drm_exec_for_each_locked_object(exec, index, obj) {
drm_exec_for_each_locked_object(exec, obj) {
dma_resv_assert_held(obj->resv);
dma_resv_add_fence(obj->resv, fence,
drm_gpuvm_is_extobj(gpuvm, obj) ?

View File

@ -108,6 +108,7 @@ static void drm_panel_add_release(void *data)
/**
* devm_drm_panel_add - add a panel to the global registry using devres
* @dev: device to which the panel is attached
* @panel: panel to add
*
* Add a panel to the global registry so that it can be looked

View File

@ -293,7 +293,7 @@ nvkm_gsp_rpc_rd(struct nvkm_gsp *gsp, u32 fn, u32 argc)
{
void *argv = nvkm_gsp_rpc_get(gsp, fn, argc);
if (IS_ERR_OR_NULL(argv))
if (IS_ERR(argv))
return argv;
return nvkm_gsp_rpc_push(gsp, argv, NVKM_GSP_RPC_REPLY_RECV, argc);
@ -373,7 +373,7 @@ nvkm_gsp_rm_alloc_get(struct nvkm_gsp_object *parent, u32 handle, u32 oclass, u3
object->handle = handle;
argv = gsp->rm->api->alloc->get(object, oclass, argc);
if (IS_ERR_OR_NULL(argv)) {
if (IS_ERR(argv)) {
object->client = NULL;
return argv;
}
@ -415,8 +415,8 @@ nvkm_gsp_rm_alloc(struct nvkm_gsp_object *parent, u32 handle, u32 oclass, u32 ar
{
void *argv = nvkm_gsp_rm_alloc_get(parent, handle, oclass, argc, object);
if (IS_ERR_OR_NULL(argv))
return argv ? PTR_ERR(argv) : -EIO;
if (IS_ERR(argv))
return PTR_ERR(argv);
return nvkm_gsp_rm_alloc_wr(object, argv);
}

View File

@ -2530,6 +2530,7 @@ nv170_chipset = {
.vfn = { 0x00000001, ga100_vfn_new },
.ce = { 0x000003ff, ga100_ce_new },
.fifo = { 0x00000001, ga100_fifo_new },
.sec2 = { 0x00000001, tu102_sec2_new },
};
static const struct nvkm_device_chip
@ -3341,6 +3342,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
case 0x166: device->chip = &nv166_chipset; break;
case 0x167: device->chip = &nv167_chipset; break;
case 0x168: device->chip = &nv168_chipset; break;
case 0x170: device->chip = &nv170_chipset; break;
case 0x172: device->chip = &nv172_chipset; break;
case 0x173: device->chip = &nv173_chipset; break;
case 0x174: device->chip = &nv174_chipset; break;
@ -3360,14 +3362,6 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
case 0x1b6: device->chip = &nv1b6_chipset; break;
case 0x1b7: device->chip = &nv1b7_chipset; break;
default:
if (nvkm_boolopt(device->cfgopt, "NvEnableUnsupportedChipsets", false)) {
switch (device->chipset) {
case 0x170: device->chip = &nv170_chipset; break;
default:
break;
}
}
if (!device->chip) {
nvdev_error(device, "unknown chipset (%08x)\n", boot0);
ret = -ENODEV;

View File

@ -65,13 +65,14 @@ pramin_init(struct nvkm_bios *bios, const char *name)
/* we can't get the bios image pointer without PDISP */
if (device->card_type >= GA100)
addr = device->chipset == 0x170; /*XXX: find the fuse reg for this */
addr = nvkm_rd32(device, 0x820c04);
else
if (device->card_type >= GM100)
addr = nvkm_rd32(device, 0x021c04);
else
if (device->card_type >= NV_C0)
addr = nvkm_rd32(device, 0x022500);
if (addr & 0x00000001) {
nvkm_debug(subdev, "... display disabled\n");
return ERR_PTR(-ENODEV);

View File

@ -24,34 +24,126 @@
#include <subdev/pci.h>
#define NV_PBUS_IFR_FMT_FIXED0_SIGNATURE_VALUE 0x4947564E /* "NVGI" */
#define NV_ROM_DIRECTORY_IDENTIFIER 0x44524652 /* "RFRD" */
struct priv {
struct nvkm_device *device;
u32 pci_rom_offset;
};
static u32
nvbios_prom_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
{
struct nvkm_device *device = data;
struct priv *priv = data;
struct nvkm_device *device = priv->device;
u32 i;
if (offset + length <= 0x00100000) {
for (i = offset; i < offset + length; i += 4)
*(u32 *)&bios->data[i] = nvkm_rd32(device, 0x300000 + i);
return length;
}
return 0;
/* Make sure we don't try to read past the end of data[] */
if (offset + length > bios->size)
return 0;
/* Make sure the read falls within the 1MB PROM window */
if (offset + priv->pci_rom_offset + length > 0x00100000)
return 0;
for (i = offset; i < offset + length; i += 4)
*(u32 *)&bios->data[i] = nvkm_rd32(device, 0x300000 + priv->pci_rom_offset + i);
return length;
}
static void
nvbios_prom_fini(void *data)
{
struct nvkm_device *device = data;
struct priv *priv = data;
struct nvkm_device *device = priv->device;
nvkm_pci_rom_shadow(device->pci, true);
kfree(data);
}
static void *
nvbios_prom_init(struct nvkm_bios *bios, const char *name)
{
struct nvkm_device *device = bios->subdev.device;
struct priv *priv;
u32 fixed0;
/* There is no PROM on NV4x iGPUs */
if (device->card_type == NV_40 && device->chipset >= 0x4c)
return ERR_PTR(-ENODEV);
priv = kzalloc_obj(*priv);
if (!priv)
return ERR_PTR(-ENOMEM);
/* Disable the PCI ROM shadow so that we can read PROM. */
nvkm_pci_rom_shadow(device->pci, false);
return device;
/*
* Check for an IFR header. If present, parse it to find the actual PCI ROM header.
*
* The IFR header is documented in Documentation/gpu/nova/core/vbios.rst
*/
fixed0 = nvkm_rd32(device, 0x300000);
if (fixed0 == NV_PBUS_IFR_FMT_FIXED0_SIGNATURE_VALUE) {
u32 fixed1 = nvkm_rd32(device, 0x300004);
u8 version = (fixed1 >> 8) & 0xff;
u32 fixed2, data_size, offset, signature;
switch (version) {
case 1:
case 2:
data_size = (fixed1 >> 16) & 0x7fff;
priv->pci_rom_offset = nvkm_rd32(device, 0x300000 + data_size + 4);
break;
case 3:
fixed2 = nvkm_rd32(device, 0x300008);
data_size = fixed2 & 0x000fffff;
/* ROM directory offset */
offset = nvkm_rd32(device, 0x300000 + data_size) + 4096;
signature = nvkm_rd32(device, 0x300000 + offset);
if (signature != NV_ROM_DIRECTORY_IDENTIFIER) {
nvkm_error(&bios->subdev, "could not find IFR ROM directory\n");
goto fail;
}
priv->pci_rom_offset = nvkm_rd32(device, 0x300000 + offset + 8);
break;
default:
nvkm_error(&bios->subdev, "unsupported IFR header version %u\n",
version);
goto fail;
}
/* Double-check that the offset is valid */
if (priv->pci_rom_offset >= 0x00100000) {
nvkm_error(&bios->subdev,
"PCI ROM offset of 0x%x is too large\n", priv->pci_rom_offset);
goto fail;
}
/* If there is an IFR header, there must also be a PCI ROM header. */
signature = nvkm_rd32(device, 0x300000 + priv->pci_rom_offset) & 0xffff;
if (signature != 0xaa55) {
nvkm_error(&bios->subdev,
"could not find PCI ROM signature at offset 0x%x\n",
priv->pci_rom_offset);
goto fail;
}
}
priv->device = device;
return priv;
fail:
nvkm_pci_rom_shadow(device->pci, true);
kfree(priv);
return ERR_PTR(-ENODEV);
}
const struct nvbios_source

View File

@ -63,7 +63,6 @@ static struct nvkm_gsp_fwif
ga100_gsps[] = {
{ 1, tu102_gsp_load, &ga100_gsp, &r570_rm_tu102, "570.144" },
{ 0, tu102_gsp_load, &ga100_gsp, &r535_rm_tu102, "535.113.01" },
{ -1, gv100_gsp_nofw, &gv100_gsp },
{}
};

View File

@ -35,7 +35,7 @@ r535_gsp_rpc_rm_free(struct nvkm_gsp_object *object)
client->object.handle, object->handle);
rpc = nvkm_gsp_rpc_get(gsp, NV_VGPU_MSG_FUNCTION_FREE, sizeof(*rpc));
if (WARN_ON(IS_ERR_OR_NULL(rpc)))
if (WARN_ON(IS_ERR(rpc)))
return -EIO;
rpc->params.hRoot = client->object.handle;
@ -60,7 +60,7 @@ r535_gsp_rpc_rm_alloc_push(struct nvkm_gsp_object *object, void *params)
void *ret = NULL;
rpc = nvkm_gsp_rpc_push(gsp, rpc, NVKM_GSP_RPC_REPLY_RECV, sizeof(*rpc));
if (IS_ERR_OR_NULL(rpc))
if (IS_ERR(rpc))
return rpc;
if (rpc->status) {

View File

@ -55,7 +55,7 @@ r535_bar_bar2_update_pde(struct nvkm_gsp *gsp, u8 page_shift, u64 pdbe)
rpc_update_bar_pde_v15_00 *rpc;
rpc = nvkm_gsp_rpc_get(gsp, NV_VGPU_MSG_FUNCTION_UPDATE_BAR_PDE, sizeof(*rpc));
if (WARN_ON(IS_ERR_OR_NULL(rpc)))
if (WARN_ON(IS_ERR(rpc)))
return -EIO;
rpc->info.barType = NV_RPC_UPDATE_PDE_BAR_2;

View File

@ -42,7 +42,7 @@ r535_gsp_rpc_rm_ctrl_push(struct nvkm_gsp_object *object, void **params, u32 rep
int ret = 0;
rpc = nvkm_gsp_rpc_push(gsp, rpc, NVKM_GSP_RPC_REPLY_RECV, repc);
if (IS_ERR_OR_NULL(rpc)) {
if (IS_ERR(rpc)) {
*params = NULL;
return PTR_ERR(rpc);
}

View File

@ -324,7 +324,7 @@ r535_gsp_msgq_recv(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *retries)
u32 size;
rpc = r535_gsp_msgq_peek(gsp, sizeof(*rpc), info.retries);
if (IS_ERR_OR_NULL(rpc)) {
if (IS_ERR(rpc)) {
kvfree(buf);
return rpc;
}
@ -333,7 +333,7 @@ r535_gsp_msgq_recv(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *retries)
info.continuation = true;
rpc = r535_gsp_msgq_recv_one_elem(gsp, &info);
if (IS_ERR_OR_NULL(rpc)) {
if (IS_ERR(rpc)) {
kvfree(buf);
return rpc;
}
@ -459,11 +459,11 @@ r535_gsp_msg_recv(struct nvkm_gsp *gsp, int fn, u32 gsp_rpc_len)
retry:
rpc = r535_gsp_msgq_peek(gsp, sizeof(*rpc), &retries);
if (IS_ERR_OR_NULL(rpc))
if (IS_ERR(rpc))
return rpc;
rpc = r535_gsp_msgq_recv(gsp, gsp_rpc_len, &retries);
if (IS_ERR_OR_NULL(rpc))
if (IS_ERR(rpc))
return rpc;
if (rpc->rpc_result) {
@ -561,7 +561,7 @@ r535_gsp_rpc_handle_reply(struct nvkm_gsp *gsp, u32 fn,
break;
case NVKM_GSP_RPC_REPLY_RECV:
reply = r535_gsp_msg_recv(gsp, fn, gsp_rpc_len);
if (!IS_ERR_OR_NULL(reply))
if (!IS_ERR(reply))
repv = reply->data;
else
repv = reply;

View File

@ -246,7 +246,7 @@ tu102_gsp_wpr_meta_init(struct nvkm_gsp *gsp)
meta->bootBinOffset = gsp->fb.wpr2.boot.addr;
meta->frtsOffset = gsp->fb.wpr2.frts.addr;
meta->frtsSize = gsp->fb.wpr2.frts.size;
meta->gspFwWprEnd = ALIGN_DOWN(gsp->fb.bios.vga_workspace.addr, 0x20000);
meta->gspFwWprEnd = ALIGN_DOWN(gsp->fb.bios.addr, 0x20000);
meta->fbSize = gsp->fb.size;
meta->vgaWorkspaceOffset = gsp->fb.bios.vga_workspace.addr;
meta->vgaWorkspaceSize = gsp->fb.bios.vga_workspace.size;
@ -291,6 +291,42 @@ tu102_gsp_vga_workspace_addr(struct nvkm_gsp *gsp, u64 fb_size)
return addr;
}
/*
* Read the MMU_LOCK range programmed by VBIOS.
*
* The row remapper reserves a small amount of DRAM at the end of FB for
* spare rows used to repair memory errors. The register used to report
* FB size rounds to 1GB boundaries, and VBIOS rounds up rather than
* down -- reporting a larger size than is actually usable. To
* compensate, VBIOS programs MMU_LOCK to fence off the unusable region
* at the top. We must read this and keep WPR below it.
*
* Returns the low address of the locked region, or 0 if not set.
*/
static u64
ga100_gsp_mmu_lock_lo(struct nvkm_gsp *gsp)
{
struct nvkm_device *device = gsp->subdev.device;
u32 lo, hi;
u64 addr_lo, addr_hi;
/* NV_PFB_PRI_MMU_LOCK_CFG_PRIV_LEVEL_MASK */
if (!(nvkm_rd32(device, 0x1fa7c8) & 0x00000001))
return 0;
lo = nvkm_rd32(device, 0x1fa82c); /* NV_PFB_PRI_MMU_LOCK_ADDR_LO */
hi = nvkm_rd32(device, 0x1fa830); /* NV_PFB_PRI_MMU_LOCK_ADDR_HI */
addr_lo = (u64)(lo >> 4) << 12;
addr_hi = (u64)(hi >> 4) << 12;
if (addr_hi < addr_lo)
return 0;
nvkm_debug(&gsp->subdev, "MMU_LOCK range: 0x%llx - 0x%llx\n", addr_lo, addr_hi);
return addr_lo;
}
int
tu102_gsp_oneinit(struct nvkm_gsp *gsp)
{
@ -304,6 +340,19 @@ tu102_gsp_oneinit(struct nvkm_gsp *gsp)
gsp->fb.bios.addr = gsp->fb.bios.vga_workspace.addr;
gsp->fb.bios.size = gsp->fb.bios.vga_workspace.size;
/*
* On GA100, VBIOS may lock the top of FB via MMU_LOCK to reserve
* space for the row remapper. Mirror OpenRM's kgspCalculateFbLayout
* by clamping bios.addr to min(mmuLockLo, vgaWorkspace) so that the
* entire WPR2 layout and gspFwWprEnd stay within usable FB.
*/
if (device->chipset == 0x170) {
u64 lock_lo = ga100_gsp_mmu_lock_lo(gsp);
if (lock_lo)
gsp->fb.bios.addr = min(gsp->fb.bios.addr, lock_lo);
}
ret = gsp->func->booter.ctor(gsp, "booter-load", gsp->fws.booter.load,
&device->sec2->falcon, &gsp->booter.load);
if (ret)
@ -318,8 +367,13 @@ tu102_gsp_oneinit(struct nvkm_gsp *gsp)
if (ret)
return ret;
/* Calculate FB layout. */
gsp->fb.wpr2.frts.size = 0x100000;
/*
* Calculate FB layout. FRTS is a memory region created by running the FWSEC-FRTS
* command, which writes power management data into WPR2. On GA100, the booter
* firmware handles WPR2 setup directly and FRTS data is not needed, so no FRTS
* region is reserved.
*/
gsp->fb.wpr2.frts.size = device->chipset == 0x170 ? 0 : 0x100000;
gsp->fb.wpr2.frts.addr = ALIGN_DOWN(gsp->fb.bios.addr, 0x20000) - gsp->fb.wpr2.frts.size;
gsp->fb.wpr2.boot.size = gsp->boot.fw.size;
@ -343,9 +397,12 @@ tu102_gsp_oneinit(struct nvkm_gsp *gsp)
if (ret)
return ret;
ret = nvkm_gsp_fwsec_frts(gsp);
if (WARN_ON(ret))
return ret;
/* Only boot FWSEC-FRTS if it actually exists */
if (gsp->fb.wpr2.frts.size) {
ret = nvkm_gsp_fwsec_frts(gsp);
if (WARN_ON(ret))
return ret;
}
/* Reset GSP into RISC-V mode. */
ret = gsp->func->reset(gsp);

View File

@ -2134,6 +2134,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('L', 'G', 'D', 0x0567, &delay_200_500_e200_d200, "Unknown"),
EDP_PANEL_ENTRY('L', 'G', 'D', 0x05af, &delay_200_500_e200_d200, "Unknown"),
EDP_PANEL_ENTRY('L', 'G', 'D', 0x05f1, &delay_200_500_e200_d200, "Unknown"),
EDP_PANEL_ENTRY('L', 'G', 'D', 0x06b2, &delay_200_500_e200_d200, "LP129WT232166"),
EDP_PANEL_ENTRY('L', 'G', 'D', 0x0778, &delay_200_500_e200_d200, "134WT1"),
EDP_PANEL_ENTRY('L', 'G', 'D', 0x07fe, &delay_200_500_e200_d200, "LP116WHA-SPB1"),

View File

@ -820,6 +820,31 @@ static const struct panel_desc ampire_am_1280800n3tzqw_t00h = {
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct drm_display_mode ampire_am_1280800w8tzqw_t00h_mode = {
.clock = 72400,
.hdisplay = 1280,
.hsync_start = 1280 + 40,
.hsync_end = 1280 + 40 + 80,
.htotal = 1280 + 40 + 80 + 40,
.vdisplay = 800,
.vsync_start = 800 + 10,
.vsync_end = 800 + 10 + 18,
.vtotal = 800 + 10 + 18 + 10,
};
static const struct panel_desc ampire_am_1280800w8tzqw_t00h = {
.modes = &ampire_am_1280800w8tzqw_t00h_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 217,
.height = 136,
},
.bus_flags = DRM_BUS_FLAG_DE_HIGH,
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct drm_display_mode ampire_am_480272h3tmqw_t01h_mode = {
.clock = 9000,
.hdisplay = 480,
@ -3692,6 +3717,32 @@ static const struct panel_desc nec_nl4827hc19_05b = {
.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
};
static const struct drm_display_mode nec_nl6448bc33_70c_mode = {
.clock = 25175,
.hdisplay = 640,
.hsync_start = 640 + 16,
.hsync_end = 640 + 16 + 48,
.htotal = 640 + 16 + 48 + 96,
.vdisplay = 480,
.vsync_start = 480 + 2,
.vsync_end = 480 + 2 + 31,
.vtotal = 480 + 2 + 31 + 31,
.flags = DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_PHSYNC,
};
static const struct panel_desc nec_nl6448bc33_70c = {
.modes = &nec_nl6448bc33_70c_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 211,
.height = 158,
},
.bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
.bus_flags = DRM_BUS_FLAG_DE_HIGH,
.connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct drm_display_mode netron_dy_e231732_mode = {
.clock = 66000,
.hdisplay = 1024,
@ -5588,6 +5639,9 @@ static const struct of_device_id platform_of_match[] = {
{
.compatible = "ampire,am-1280800n3tzqw-t00h",
.data = &ampire_am_1280800n3tzqw_t00h,
}, {
.compatible = "ampire,am-1280800w8tzqw-t00h",
.data = &ampire_am_1280800w8tzqw_t00h,
}, {
.compatible = "ampire,am-480272h3tmqw-t01h",
.data = &ampire_am_480272h3tmqw_t01h,
@ -5918,6 +5972,9 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "nec,nl4827hc19-05b",
.data = &nec_nl4827hc19_05b,
}, {
.compatible = "nec,nl6448bc33-70c",
.data = &nec_nl6448bc33_70c,
}, {
.compatible = "netron-dy,e231732",
.data = &netron_dy_e231732,

View File

@ -687,6 +687,8 @@ static void panthor_gem_evict_locked(struct panthor_gem_object *bo)
if (drm_WARN_ON_ONCE(bo->base.dev, !bo->backing.pages))
return;
atomic_add_unless(&bo->reclaimed_count, 1, INT_MAX);
panthor_gem_dev_map_cleanup_locked(bo);
panthor_gem_backing_cleanup_locked(bo);
panthor_gem_update_reclaim_state_locked(bo, NULL);
@ -1590,6 +1592,7 @@ static void panthor_gem_debugfs_print_flag_names(struct seq_file *m)
static const char * const gem_state_flags_names[] = {
[PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT] = "imported",
[PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT] = "exported",
[PANTHOR_DEBUGFS_GEM_STATE_EVICTED_BIT] = "evicted",
};
static const char * const gem_usage_flags_names[] = {
@ -1620,6 +1623,7 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo,
{
enum panthor_gem_reclaim_state reclaim_state = bo->reclaim_state;
unsigned int refcount = kref_read(&bo->base.refcount);
int reclaimed_count = atomic_read(&bo->reclaimed_count);
char creator_info[32] = {};
size_t resident_size;
u32 gem_usage_flags = bo->debugfs.flags;
@ -1633,16 +1637,20 @@ static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo,
snprintf(creator_info, sizeof(creator_info),
"%s/%d", bo->debugfs.creator.process_name, bo->debugfs.creator.tgid);
seq_printf(m, "%-32s%-16d%-16d%-16zd%-16zd0x%-16lx",
seq_printf(m, "%-32s%-16d%-11d%-11d%-16zd%-16zd0x%-16lx",
creator_info,
bo->base.name,
refcount,
reclaimed_count,
bo->base.size,
resident_size,
drm_vma_node_start(&bo->base.vma_node));
if (drm_gem_is_imported(&bo->base))
gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED;
else if (!resident_size && reclaimed_count)
gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_EVICTED;
if (bo->base.dma_buf)
gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED;
@ -1666,8 +1674,8 @@ static void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev,
panthor_gem_debugfs_print_flag_names(m);
seq_puts(m, "created-by global-name refcount size resident-size file-offset state usage label\n");
seq_puts(m, "----------------------------------------------------------------------------------------------------------------------------------------------\n");
seq_puts(m, "created-by global-name refcount evictions size resident-size file-offset state usage label\n");
seq_puts(m, "----------------------------------------------------------------------------------------------------------------------------------------------------\n");
scoped_guard(mutex, &ptdev->gems.lock) {
list_for_each_entry(bo, &ptdev->gems.node, debugfs.node) {
@ -1675,7 +1683,7 @@ static void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev,
}
}
seq_puts(m, "==============================================================================================================================================\n");
seq_puts(m, "====================================================================================================================================================\n");
seq_printf(m, "Total size: %zd, Total resident: %zd, Total reclaimable: %zd\n",
totals.size, totals.resident, totals.reclaimable);
}

View File

@ -19,12 +19,16 @@ struct panthor_vm;
enum panthor_debugfs_gem_state_flags {
PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT = 0,
PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT = 1,
PANTHOR_DEBUGFS_GEM_STATE_EVICTED_BIT = 2,
/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED: GEM BO is PRIME imported. */
PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT),
/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED: GEM BO is PRIME exported. */
PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT),
/** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_EVICTED: GEM BO is evicted to swap. */
PANTHOR_DEBUGFS_GEM_STATE_FLAG_EVICTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_EVICTED_BIT),
};
enum panthor_debugfs_gem_usage_flags {
@ -172,6 +176,12 @@ struct panthor_gem_object {
/** @reclaim_state: Cached reclaim state */
enum panthor_gem_reclaim_state reclaim_state;
/**
* @reclaimed_count: How many times object has been evicted to swap.
* The count saturates at %INT_MAX and will never wrap around to 0.
*/
atomic_t reclaimed_count;
/**
* @exclusive_vm_root_gem: Root GEM of the exclusive VM this GEM object
* is attached to.

View File

@ -28,6 +28,7 @@
#include "rzg2l_du_vsp.h"
#define DU_MCR0 0x00
#define DU_MCR0_DPI_EN BIT(0)
#define DU_MCR0_DI_EN BIT(8)
#define DU_DITR0 0x10
@ -217,8 +218,12 @@ static void rzg2l_du_crtc_put(struct rzg2l_du_crtc *rcrtc)
static void rzg2l_du_start_stop(struct rzg2l_du_crtc *rcrtc, bool start)
{
struct rzg2l_du_device *rcdu = rcrtc->dev;
u32 val = DU_MCR0_DI_EN;
writel(start ? DU_MCR0_DI_EN : 0, rcdu->mmio + DU_MCR0);
if (start && rzg2l_du_has(rcdu, RZG2L_DU_FEATURE_DPIO_OE))
val |= DU_MCR0_DPI_EN;
writel(start ? val : 0, rcdu->mmio + DU_MCR0);
}
static void rzg2l_du_crtc_start(struct rzg2l_du_crtc *rcrtc)
@ -380,7 +385,7 @@ int rzg2l_du_crtc_create(struct rzg2l_du_device *rcdu)
struct drm_plane *primary;
int ret;
rcrtc->rstc = devm_reset_control_get_shared(rcdu->dev, NULL);
rcrtc->rstc = devm_reset_control_get_optional_shared(rcdu->dev, NULL);
if (IS_ERR(rcrtc->rstc)) {
dev_err(rcdu->dev, "can't get cpg reset\n");
return PTR_ERR(rcrtc->rstc);

View File

@ -35,6 +35,8 @@ static const struct rzg2l_du_device_info rzg2l_du_r9a07g043u_info = {
.port = 0,
},
},
.mode_clock_min = 20875,
.mode_clock_max = 83500,
};
static const struct rzg2l_du_device_info rzg2l_du_r9a07g044_info = {
@ -48,7 +50,9 @@ static const struct rzg2l_du_device_info rzg2l_du_r9a07g044_info = {
.possible_outputs = BIT(0),
.port = 1,
}
}
},
.mode_clock_min = 20875,
.mode_clock_max = 83500,
};
static const struct rzg2l_du_device_info rzg2l_du_r9a09g057_info = {
@ -61,10 +65,24 @@ static const struct rzg2l_du_device_info rzg2l_du_r9a09g057_info = {
},
};
static const struct rzg2l_du_device_info rzg2l_du_r9a09g077_info = {
.channels_mask = BIT(0),
.routes = {
[RZG2L_DU_OUTPUT_DPAD0] = {
.possible_outputs = BIT(0),
.port = 0,
},
},
.features = RZG2L_DU_FEATURE_DPIO_OE,
.mode_clock_min = 5000,
.mode_clock_max = 100000,
};
static const struct of_device_id rzg2l_du_of_table[] = {
{ .compatible = "renesas,r9a07g043u-du", .data = &rzg2l_du_r9a07g043u_info },
{ .compatible = "renesas,r9a07g044-du", .data = &rzg2l_du_r9a07g044_info },
{ .compatible = "renesas,r9a09g057-du", .data = &rzg2l_du_r9a09g057_info },
{ .compatible = "renesas,r9a09g077-du", .data = &rzg2l_du_r9a09g077_info },
{ /* sentinel */ }
};

View File

@ -20,6 +20,8 @@
struct device;
struct drm_property;
#define RZG2L_DU_FEATURE_DPIO_OE BIT(0) /* Has DPIO output enable control */
enum rzg2l_du_output {
RZG2L_DU_OUTPUT_DSI0,
RZG2L_DU_OUTPUT_DPAD0,
@ -44,10 +46,16 @@ struct rzg2l_du_output_routing {
* struct rzg2l_du_device_info - DU model-specific information
* @channels_mask: bit mask of available DU channels
* @routes: array of CRTC to output routes, indexed by output (RZG2L_DU_OUTPUT_*)
* @mode_clock_min: minimum pixel clock in kHz
* @mode_clock_max: maximum pixel clock in kHz
* @features: device features (RZG2L_DU_FEATURE_*)
*/
struct rzg2l_du_device_info {
unsigned int channels_mask;
struct rzg2l_du_output_routing routes[RZG2L_DU_OUTPUT_MAX];
u32 mode_clock_min;
u32 mode_clock_max;
unsigned int features;
};
#define RZG2L_DU_MAX_CRTCS 1
@ -73,6 +81,12 @@ static inline struct rzg2l_du_device *to_rzg2l_du_device(struct drm_device *dev)
return container_of(dev, struct rzg2l_du_device, ddev);
}
static inline bool rzg2l_du_has(struct rzg2l_du_device *rcdu,
unsigned int feature)
{
return rcdu->info->features & feature;
}
const char *rzg2l_du_output_name(enum rzg2l_du_output output);
#endif /* __RZG2L_DU_DRV_H__ */

View File

@ -50,8 +50,15 @@ rzg2l_du_encoder_mode_valid(struct drm_encoder *encoder,
const struct drm_display_mode *mode)
{
struct rzg2l_du_encoder *renc = to_rzg2l_encoder(encoder);
struct rzg2l_du_device *rcdu = to_rzg2l_du_device(renc->base.dev);
const struct rzg2l_du_device_info *info = rcdu->info;
if (renc->output == RZG2L_DU_OUTPUT_DPAD0 && mode->clock > 83500)
if (renc->output != RZG2L_DU_OUTPUT_DPAD0)
return MODE_OK;
if (mode->clock < info->mode_clock_min)
return MODE_CLOCK_LOW;
if (mode->clock > info->mode_clock_max)
return MODE_CLOCK_HIGH;
return MODE_OK;

View File

@ -36,6 +36,103 @@
#include "hub.h"
#include "plane.h"
static const u16 default_srgb_lut[] = {
0x6000, 0x60CE, 0x619D, 0x626C, 0x632D, 0x63D4, 0x6469, 0x64F0, 0x656B, 0x65DF, 0x664A,
0x66B0, 0x6711, 0x676D, 0x67C4, 0x6819, 0x686A, 0x68B8, 0x6904, 0x694D, 0x6994, 0x69D8,
0x6A1B, 0x6A5D, 0x6A9C, 0x6ADA, 0x6B17, 0x6B52, 0x6B8C, 0x6BC5, 0x6BFD, 0x6C33, 0x6C69,
0x6C9E, 0x6CD1, 0x6D04, 0x6D36, 0x6D67, 0x6D98, 0x6DC7, 0x6DF6, 0x6E25, 0x6E52, 0x6E7F,
0x6EAC, 0x6ED7, 0x6F03, 0x6F2D, 0x6F58, 0x6F81, 0x6FAA, 0x6FD3, 0x6FFB, 0x7023, 0x704B,
0x7071, 0x7098, 0x70BE, 0x70E4, 0x7109, 0x712E, 0x7153, 0x7177, 0x719B, 0x71BF, 0x71E2,
0x7205, 0x7227, 0x724A, 0x726C, 0x728E, 0x72AF, 0x72D0, 0x72F1, 0x7312, 0x7333, 0x7353,
0x7373, 0x7392, 0x73B2, 0x73D1, 0x73F0, 0x740F, 0x742D, 0x744C, 0x746A, 0x7488, 0x74A6,
0x74C3, 0x74E0, 0x74FE, 0x751B, 0x7537, 0x7554, 0x7570, 0x758D, 0x75A9, 0x75C4, 0x75E0,
0x75FC, 0x7617, 0x7632, 0x764D, 0x7668, 0x7683, 0x769E, 0x76B8, 0x76D3, 0x76ED, 0x7707,
0x7721, 0x773B, 0x7754, 0x776E, 0x7787, 0x77A0, 0x77B9, 0x77D2, 0x77EB, 0x7804, 0x781D,
0x7835, 0x784E, 0x7866, 0x787E, 0x7896, 0x78AE, 0x78C6, 0x78DD, 0x78F5, 0x790D, 0x7924,
0x793B, 0x7952, 0x796A, 0x7981, 0x7997, 0x79AE, 0x79C5, 0x79DB, 0x79F2, 0x7A08, 0x7A1F,
0x7A35, 0x7A4B, 0x7A61, 0x7A77, 0x7A8D, 0x7AA3, 0x7AB8, 0x7ACE, 0x7AE3, 0x7AF9, 0x7B0E,
0x7B24, 0x7B39, 0x7B4E, 0x7B63, 0x7B78, 0x7B8D, 0x7BA2, 0x7BB6, 0x7BCB, 0x7BE0, 0x7BF4,
0x7C08, 0x7C1D, 0x7C31, 0x7C45, 0x7C59, 0x7C6E, 0x7C82, 0x7C96, 0x7CA9, 0x7CBD, 0x7CD1,
0x7CE5, 0x7CF8, 0x7D0C, 0x7D1F, 0x7D33, 0x7D46, 0x7D59, 0x7D6D, 0x7D80, 0x7D93, 0x7DA6,
0x7DB9, 0x7DCC, 0x7DDF, 0x7DF2, 0x7E04, 0x7E17, 0x7E2A, 0x7E3C, 0x7E4F, 0x7E61, 0x7E74,
0x7E86, 0x7E98, 0x7EAB, 0x7EBD, 0x7ECF, 0x7EE1, 0x7EF3, 0x7F05, 0x7F17, 0x7F29, 0x7F3B,
0x7F4D, 0x7F5E, 0x7F70, 0x7F82, 0x7F93, 0x7FA5, 0x7FB6, 0x7FC8, 0x7FD9, 0x7FEB, 0x7FFC,
0x800D, 0x801E, 0x8030, 0x8041, 0x8052, 0x8063, 0x8074, 0x8085, 0x8096, 0x80A7, 0x80B7,
0x80C8, 0x80D9, 0x80EA, 0x80FA, 0x810B, 0x811C, 0x812C, 0x813D, 0x814D, 0x815D, 0x816E,
0x817E, 0x818E, 0x819F, 0x81AF, 0x81BF, 0x81CF, 0x81DF, 0x81EF, 0x81FF, 0x820F, 0x821F,
0x822F, 0x823F, 0x824F, 0x825F, 0x826F, 0x827E, 0x828E, 0x829E, 0x82AD, 0x82BD, 0x82CC,
0x82DC, 0x82EB, 0x82FB, 0x830A, 0x831A, 0x8329, 0x8338, 0x8348, 0x8357, 0x8366, 0x8375,
0x8385, 0x8394, 0x83A3, 0x83B2, 0x83C1, 0x83D0, 0x83DF, 0x83EE, 0x83FD, 0x840C, 0x841A,
0x8429, 0x8438, 0x8447, 0x8455, 0x8464, 0x8473, 0x8481, 0x8490, 0x849F, 0x84AD, 0x84BC,
0x84CA, 0x84D9, 0x84E7, 0x84F5, 0x8504, 0x8512, 0x8521, 0x852F, 0x853D, 0x854B, 0x855A,
0x8568, 0x8576, 0x8584, 0x8592, 0x85A0, 0x85AE, 0x85BC, 0x85CA, 0x85D8, 0x85E6, 0x85F4,
0x8602, 0x8610, 0x861E, 0x862C, 0x8639, 0x8647, 0x8655, 0x8663, 0x8670, 0x867E, 0x868C,
0x8699, 0x86A7, 0x86B5, 0x86C2, 0x86D0, 0x86DD, 0x86EB, 0x86F8, 0x8705, 0x8713, 0x8720,
0x872E, 0x873B, 0x8748, 0x8756, 0x8763, 0x8770, 0x877D, 0x878B, 0x8798, 0x87A5, 0x87B2,
0x87BF, 0x87CC, 0x87D9, 0x87E6, 0x87F3, 0x8801, 0x880E, 0x881A, 0x8827, 0x8834, 0x8841,
0x884E, 0x885B, 0x8868, 0x8875, 0x8882, 0x888E, 0x889B, 0x88A8, 0x88B5, 0x88C1, 0x88CE,
0x88DB, 0x88E7, 0x88F4, 0x8900, 0x890D, 0x891A, 0x8926, 0x8933, 0x893F, 0x894C, 0x8958,
0x8965, 0x8971, 0x897D, 0x898A, 0x8996, 0x89A3, 0x89AF, 0x89BB, 0x89C8, 0x89D4, 0x89E0,
0x89EC, 0x89F9, 0x8A05, 0x8A11, 0x8A1D, 0x8A29, 0x8A36, 0x8A42, 0x8A4E, 0x8A5A, 0x8A66,
0x8A72, 0x8A7E, 0x8A8A, 0x8A96, 0x8AA2, 0x8AAE, 0x8ABA, 0x8AC6, 0x8AD2, 0x8ADE, 0x8AEA,
0x8AF5, 0x8B01, 0x8B0D, 0x8B19, 0x8B25, 0x8B31, 0x8B3C, 0x8B48, 0x8B54, 0x8B60, 0x8B6B,
0x8B77, 0x8B83, 0x8B8E, 0x8B9A, 0x8BA6, 0x8BB1, 0x8BBD, 0x8BC8, 0x8BD4, 0x8BDF, 0x8BEB,
0x8BF6, 0x8C02, 0x8C0D, 0x8C19, 0x8C24, 0x8C30, 0x8C3B, 0x8C47, 0x8C52, 0x8C5D, 0x8C69,
0x8C74, 0x8C80, 0x8C8B, 0x8C96, 0x8CA1, 0x8CAD, 0x8CB8, 0x8CC3, 0x8CCF, 0x8CDA, 0x8CE5,
0x8CF0, 0x8CFB, 0x8D06, 0x8D12, 0x8D1D, 0x8D28, 0x8D33, 0x8D3E, 0x8D49, 0x8D54, 0x8D5F,
0x8D6A, 0x8D75, 0x8D80, 0x8D8B, 0x8D96, 0x8DA1, 0x8DAC, 0x8DB7, 0x8DC2, 0x8DCD, 0x8DD8,
0x8DE3, 0x8DEE, 0x8DF9, 0x8E04, 0x8E0E, 0x8E19, 0x8E24, 0x8E2F, 0x8E3A, 0x8E44, 0x8E4F,
0x8E5A, 0x8E65, 0x8E6F, 0x8E7A, 0x8E85, 0x8E90, 0x8E9A, 0x8EA5, 0x8EB0, 0x8EBA, 0x8EC5,
0x8ECF, 0x8EDA, 0x8EE5, 0x8EEF, 0x8EFA, 0x8F04, 0x8F0F, 0x8F19, 0x8F24, 0x8F2E, 0x8F39,
0x8F43, 0x8F4E, 0x8F58, 0x8F63, 0x8F6D, 0x8F78, 0x8F82, 0x8F8C, 0x8F97, 0x8FA1, 0x8FAC,
0x8FB6, 0x8FC0, 0x8FCB, 0x8FD5, 0x8FDF, 0x8FEA, 0x8FF4, 0x8FFE, 0x9008, 0x9013, 0x901D,
0x9027, 0x9031, 0x903C, 0x9046, 0x9050, 0x905A, 0x9064, 0x906E, 0x9079, 0x9083, 0x908D,
0x9097, 0x90A1, 0x90AB, 0x90B5, 0x90BF, 0x90C9, 0x90D3, 0x90DD, 0x90E7, 0x90F1, 0x90FB,
0x9105, 0x910F, 0x9119, 0x9123, 0x912D, 0x9137, 0x9141, 0x914B, 0x9155, 0x915F, 0x9169,
0x9173, 0x917D, 0x9186, 0x9190, 0x919A, 0x91A4, 0x91AE, 0x91B8, 0x91C1, 0x91CB, 0x91D5,
0x91DF, 0x91E9, 0x91F2, 0x91FC, 0x9206, 0x9210, 0x9219, 0x9223, 0x922D, 0x9236, 0x9240,
0x924A, 0x9253, 0x925D, 0x9267, 0x9270, 0x927A, 0x9283, 0x928D, 0x9297, 0x92A0, 0x92AA,
0x92B3, 0x92BD, 0x92C6, 0x92D0, 0x92DA, 0x92E3, 0x92ED, 0x92F6, 0x9300, 0x9309, 0x9313,
0x931C, 0x9325, 0x932F, 0x9338, 0x9342, 0x934B, 0x9355, 0x935E, 0x9367, 0x9371, 0x937A,
0x9384, 0x938D, 0x9396, 0x93A0, 0x93A9, 0x93B2, 0x93BC, 0x93C5, 0x93CE, 0x93D7, 0x93E1,
0x93EA, 0x93F3, 0x93FC, 0x9406, 0x940F, 0x9418, 0x9421, 0x942B, 0x9434, 0x943D, 0x9446,
0x944F, 0x9459, 0x9462, 0x946B, 0x9474, 0x947D, 0x9486, 0x948F, 0x9499, 0x94A2, 0x94AB,
0x94B4, 0x94BD, 0x94C6, 0x94CF, 0x94D8, 0x94E1, 0x94EA, 0x94F3, 0x94FC, 0x9505, 0x950E,
0x9517, 0x9520, 0x9529, 0x9532, 0x953B, 0x9544, 0x954D, 0x9556, 0x955F, 0x9568, 0x9571,
0x957A, 0x9583, 0x958C, 0x9595, 0x959D, 0x95A6, 0x95AF, 0x95B8, 0x95C1, 0x95CA, 0x95D3,
0x95DB, 0x95E4, 0x95ED, 0x95F6, 0x95FF, 0x9608, 0x9610, 0x9619, 0x9622, 0x962B, 0x9633,
0x963C, 0x9645, 0x964E, 0x9656, 0x965F, 0x9668, 0x9671, 0x9679, 0x9682, 0x968B, 0x9693,
0x969C, 0x96A5, 0x96AD, 0x96B6, 0x96BF, 0x96C7, 0x96D0, 0x96D9, 0x96E1, 0x96EA, 0x96F2,
0x96FB, 0x9704, 0x970C, 0x9715, 0x971D, 0x9726, 0x972E, 0x9737, 0x9740, 0x9748, 0x9751,
0x9759, 0x9762, 0x976A, 0x9773, 0x977B, 0x9784, 0x978C, 0x9795, 0x979D, 0x97A6, 0x97AE,
0x97B6, 0x97BF, 0x97C7, 0x97D0, 0x97D8, 0x97E1, 0x97E9, 0x97F1, 0x97FA, 0x9802, 0x980B,
0x9813, 0x981B, 0x9824, 0x982C, 0x9834, 0x983D, 0x9845, 0x984D, 0x9856, 0x985E, 0x9866,
0x986F, 0x9877, 0x987F, 0x9888, 0x9890, 0x9898, 0x98A0, 0x98A9, 0x98B1, 0x98B9, 0x98C1,
0x98CA, 0x98D2, 0x98DA, 0x98E2, 0x98EB, 0x98F3, 0x98FB, 0x9903, 0x990B, 0x9914, 0x991C,
0x9924, 0x992C, 0x9934, 0x993C, 0x9945, 0x994D, 0x9955, 0x995D, 0x9965, 0x996D, 0x9975,
0x997D, 0x9986, 0x998E, 0x9996, 0x999E, 0x99A6, 0x99AE, 0x99B6, 0x99BE, 0x99C6, 0x99CE,
0x99D6, 0x99DE, 0x99E6, 0x99EE, 0x99F6, 0x99FE, 0x9A06, 0x9A0E, 0x9A16, 0x9A1E, 0x9A26,
0x9A2E, 0x9A36, 0x9A3E, 0x9A46, 0x9A4E, 0x9A56, 0x9A5E, 0x9A66, 0x9A6E, 0x9A76, 0x9A7E,
0x9A86, 0x9A8E, 0x9A96, 0x9A9D, 0x9AA5, 0x9AAD, 0x9AB5, 0x9ABD, 0x9AC5, 0x9ACD, 0x9AD5,
0x9ADC, 0x9AE4, 0x9AEC, 0x9AF4, 0x9AFC, 0x9B04, 0x9B0C, 0x9B13, 0x9B1B, 0x9B23, 0x9B2B,
0x9B33, 0x9B3A, 0x9B42, 0x9B4A, 0x9B52, 0x9B59, 0x9B61, 0x9B69, 0x9B71, 0x9B79, 0x9B80,
0x9B88, 0x9B90, 0x9B97, 0x9B9F, 0x9BA7, 0x9BAF, 0x9BB6, 0x9BBE, 0x9BC6, 0x9BCD, 0x9BD5,
0x9BDD, 0x9BE5, 0x9BEC, 0x9BF4, 0x9BFC, 0x9C03, 0x9C0B, 0x9C12, 0x9C1A, 0x9C22, 0x9C29,
0x9C31, 0x9C39, 0x9C40, 0x9C48, 0x9C50, 0x9C57, 0x9C5F, 0x9C66, 0x9C6E, 0x9C75, 0x9C7D,
0x9C85, 0x9C8C, 0x9C94, 0x9C9B, 0x9CA3, 0x9CAA, 0x9CB2, 0x9CBA, 0x9CC1, 0x9CC9, 0x9CD0,
0x9CD8, 0x9CDF, 0x9CE7, 0x9CEE, 0x9CF6, 0x9CFD, 0x9D05, 0x9D0C, 0x9D14, 0x9D1B, 0x9D23,
0x9D2A, 0x9D32, 0x9D39, 0x9D40, 0x9D48, 0x9D4F, 0x9D57, 0x9D5E, 0x9D66, 0x9D6D, 0x9D75,
0x9D7C, 0x9D83, 0x9D8B, 0x9D92, 0x9D9A, 0x9DA1, 0x9DA8, 0x9DB0, 0x9DB7, 0x9DBE, 0x9DC6,
0x9DCD, 0x9DD5, 0x9DDC, 0x9DE3, 0x9DEB, 0x9DF2, 0x9DF9, 0x9E01, 0x9E08, 0x9E0F, 0x9E17,
0x9E1E, 0x9E25, 0x9E2D, 0x9E34, 0x9E3B, 0x9E43, 0x9E4A, 0x9E51, 0x9E58, 0x9E60, 0x9E67,
0x9E6E, 0x9E75, 0x9E7D, 0x9E84, 0x9E8B, 0x9E92, 0x9E9A, 0x9EA1, 0x9EA8, 0x9EAF, 0x9EB7,
0x9EBE, 0x9EC5, 0x9ECC, 0x9ED4, 0x9EDB, 0x9EE2, 0x9EE9, 0x9EF0, 0x9EF7, 0x9EFF, 0x9F06,
0x9F0D, 0x9F14, 0x9F1B, 0x9F23, 0x9F2A, 0x9F31, 0x9F38, 0x9F3F, 0x9F46, 0x9F4D, 0x9F55,
0x9F5C, 0x9F63, 0x9F6A, 0x9F71, 0x9F78, 0x9F7F, 0x9F86, 0x9F8D, 0x9F95, 0x9F9C, 0x9FA3,
0x9FAA, 0x9FB1, 0x9FB8, 0x9FBF, 0x9FC6, 0x9FCD, 0x9FD4, 0x9FDB, 0x9FE2, 0x9FE9, 0x9FF0,
0x9FF7, 0x9FFF,
};
static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state);
@ -101,8 +198,10 @@ bool tegra_dc_has_output(struct tegra_dc *dc, struct device *dev)
int err;
of_for_each_phandle(&it, err, np, "nvidia,outputs", NULL, 0)
if (it.node == dev->of_node)
if (it.node == dev->of_node) {
of_node_put(it.node);
return true;
}
return false;
}
@ -3251,6 +3350,25 @@ static int tegra_dc_probe(struct platform_device *pdev)
if (dc->irq < 0)
return -ENXIO;
if (dc->soc->has_nvdisplay) {
unsigned int i;
u64 r;
dc->cmu_output_lut =
dmam_alloc_coherent(dc->dev, ARRAY_SIZE(default_srgb_lut) * sizeof(u64),
&dc->cmu_output_lut_phys, GFP_KERNEL);
if (!dc->cmu_output_lut) {
dev_err(dc->dev, "failed to allocate lut for cmu\n");
return -ENOMEM;
}
for (i = 0; i < ARRAY_SIZE(default_srgb_lut); i++) {
r = default_srgb_lut[i];
dc->cmu_output_lut[i] = (r << 32) | (r << 16) | r;
}
}
err = tegra_dc_rgb_probe(dc);
if (err < 0 && err != -ENODEV)
return dev_err_probe(&pdev->dev, err,

View File

@ -103,6 +103,9 @@ struct tegra_dc {
const struct tegra_dc_soc_info *soc;
bool has_opp_table;
u64 *cmu_output_lut;
dma_addr_t cmu_output_lut_phys;
};
static inline struct tegra_dc *
@ -447,6 +450,7 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define BASE_COLOR_SIZE_888 ( 8 << 0)
#define BASE_COLOR_SIZE_101010 ( 10 << 0)
#define BASE_COLOR_SIZE_121212 ( 12 << 0)
#define CMU_ENABLE_ENABLE (1 << 20)
#define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431
#define SC1_H_QUALIFIER_NONE (1 << 16)
@ -732,6 +736,15 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define PROTOCOL_MASK (0xf << 8)
#define PROTOCOL_SINGLE_TMDS_A (0x1 << 8)
#define DC_DISP_CORE_HEAD_SET_CONTROL_OUTPUT_LUT 0x431
#define OUTPUT_LUT_MODE_MASK (3 << 5)
#define OUTPUT_LUT_MODE_INTERPOLATE (1 << 5)
#define OUTPUT_LUT_SIZE_MASK (3 << 1)
#define OUTPUT_LUT_SIZE_SIZE_1025 (2 << 1)
#define DC_DISP_COREPVT_HEAD_SET_OUTPUT_LUT_BASE 0x432
#define DC_DISP_COREPVT_HEAD_SET_OUTPUT_LUT_BASE_HI 0x433
#define DC_DISP_PCALC_HEAD_SET_CROPPED_POINT_IN_CURSOR 0x442
#define DC_DISP_PCALC_HEAD_SET_CROPPED_SIZE_IN_CURSOR 0x446

View File

@ -4,6 +4,8 @@
* Copyright (C) 2015 Rob Clark
*/
#include <linux/string_choices.h>
#include <drm/display/drm_dp_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_print.h>
@ -668,7 +670,7 @@ static int drm_dp_link_train_full(struct drm_dp_link *link)
retry:
DRM_DEBUG_KMS("full-training link: %u lane%s at %u MHz\n",
link->lanes, (link->lanes > 1) ? "s" : "",
link->lanes, str_plural(link->lanes),
link->rate / 100);
err = drm_dp_link_configure(link->aux, link);
@ -724,7 +726,7 @@ static int drm_dp_link_train_fast(struct drm_dp_link *link)
int err;
DRM_DEBUG_KMS("fast-training link: %u lane%s at %u MHz\n",
link->lanes, (link->lanes > 1) ? "s" : "",
link->lanes, str_plural(link->lanes),
link->rate / 100);
err = drm_dp_link_configure(link->aux, link);

View File

@ -26,7 +26,7 @@ struct drm_dp_link_caps {
bool enhanced_framing;
/**
* tps3_supported:
* @tps3_supported:
*
* training pattern sequence 3 supported for equalization
*/
@ -62,12 +62,12 @@ void drm_dp_link_caps_copy(struct drm_dp_link_caps *dest,
*/
struct drm_dp_link_ops {
/**
* @apply_training:
* @apply_training: apply the link training
*/
int (*apply_training)(struct drm_dp_link *link);
/**
* @configure:
* @configure: configure the DP link
*/
int (*configure)(struct drm_dp_link *link);
};
@ -113,6 +113,8 @@ struct drm_dp_link_train {
* @max_lanes: maximum number of lanes supported on the link
* @caps: capabilities supported on the link (see &drm_dp_link_caps)
* @aux_rd_interval: AUX read interval to use for training (in microseconds)
* @aux_rd_interval.cr: clock recovery read interval
* @aux_rd_interval.ce: channel equalization read interval
* @edp: eDP revision (0x11: eDP 1.1, 0x12: eDP 1.2, ...)
* @rate: currently configured link rate
* @lanes: currently configured number of lanes
@ -126,10 +128,6 @@ struct drm_dp_link {
struct drm_dp_link_caps caps;
/**
* @cr: clock recovery read interval
* @ce: channel equalization read interval
*/
struct {
unsigned int cr;
unsigned int ce;

View File

@ -184,11 +184,6 @@ struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer,
bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer);
int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
struct tegra_bo_tiling *tiling);
struct drm_framebuffer *tegra_fb_alloc(struct drm_device *drm,
const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd,
struct tegra_bo **planes,
unsigned int num_planes);
struct drm_framebuffer *tegra_fb_create(struct drm_device *drm,
struct drm_file *file,
const struct drm_format_info *info,

View File

@ -102,6 +102,7 @@ static const struct drm_framebuffer_funcs tegra_fb_funcs = {
.create_handle = drm_gem_fb_create_handle,
};
static
struct drm_framebuffer *tegra_fb_alloc(struct drm_device *drm,
const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd,

View File

@ -40,8 +40,7 @@ static int tegra_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
static void tegra_fbdev_fb_destroy(struct fb_info *info)
{
struct drm_fb_helper *helper = info->par;
struct drm_framebuffer *fb = helper->fb;
struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
struct tegra_bo *bo = tegra_fb_get_plane(helper->fb, 0);
drm_fb_helper_fini(helper);
@ -50,8 +49,8 @@ static void tegra_fbdev_fb_destroy(struct fb_info *info)
vunmap(bo->vaddr);
bo->vaddr = NULL;
}
drm_framebuffer_remove(fb);
drm_client_buffer_delete(helper->buffer);
drm_client_release(&helper->client);
}
@ -70,74 +69,79 @@ static const struct drm_fb_helper_funcs tegra_fbdev_helper_funcs = {
int tegra_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
struct tegra_drm *tegra = helper->dev->dev_private;
struct drm_device *drm = helper->dev;
struct drm_mode_fb_cmd2 cmd = { 0 };
struct drm_client_dev *client = &helper->client;
struct drm_device *drm = client->dev;
struct drm_file *file = client->file;
struct tegra_drm *tegra = drm->dev_private;
struct fb_info *info = helper->info;
unsigned int bytes_per_pixel;
struct drm_framebuffer *fb;
unsigned long offset;
u32 fourcc, pitch;
u64 size;
const struct drm_format_info *format;
struct tegra_bo *bo;
size_t size;
struct drm_gem_object *gem;
u32 handle;
struct drm_client_buffer *buffer;
int err;
bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
cmd.width = sizes->surface_width;
cmd.height = sizes->surface_height;
cmd.pitches[0] = round_up(sizes->surface_width * bytes_per_pixel,
tegra->pitch_align);
cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
sizes->surface_depth);
size = cmd.pitches[0] * cmd.height;
fourcc = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
format = drm_get_format_info(drm, fourcc, DRM_FORMAT_MOD_LINEAR);
pitch = round_up(drm_format_info_min_pitch(format, 0, sizes->surface_width),
tegra->pitch_align);
size = ALIGN(pitch * sizes->surface_height, PAGE_SIZE);
bo = tegra_bo_create(drm, size, 0);
if (IS_ERR(bo))
return PTR_ERR(bo);
gem = &bo->gem;
fb = tegra_fb_alloc(drm,
drm_get_format_info(drm, cmd.pixel_format, cmd.modifier[0]),
&cmd, &bo, 1);
if (IS_ERR(fb)) {
err = PTR_ERR(fb);
dev_err(drm->dev, "failed to allocate DRM framebuffer: %d\n",
err);
drm_gem_object_put(&bo->gem);
return PTR_ERR(fb);
err = drm_gem_handle_create(file, gem, &handle);
if (err)
goto err_drm_gem_object_put;
buffer = drm_client_buffer_create(client, sizes->surface_width, sizes->surface_height,
fourcc, handle, pitch);
if (IS_ERR(buffer)) {
err = PTR_ERR(buffer);
goto err_drm_gem_handle_delete;
}
helper->funcs = &tegra_fbdev_helper_funcs;
helper->fb = fb;
helper->info = info;
helper->buffer = buffer;
helper->fb = buffer->fb;
info->fbops = &tegra_fb_ops;
drm_fb_helper_fill_info(info, helper, sizes);
offset = info->var.xoffset * bytes_per_pixel +
info->var.yoffset * fb->pitches[0];
if (bo->pages) {
bo->vaddr = vmap(bo->pages, bo->num_pages, VM_MAP,
pgprot_writecombine(PAGE_KERNEL));
if (!bo->vaddr) {
dev_err(drm->dev, "failed to vmap() framebuffer\n");
err = -ENOMEM;
goto destroy;
goto err_drm_client_buffer_delete;
}
}
info->flags |= FBINFO_VIRTFB;
info->screen_buffer = bo->vaddr + offset;
info->screen_size = size;
info->fix.smem_start = (unsigned long)(bo->iova + offset);
info->fix.smem_len = size;
info->screen_buffer = bo->vaddr;
info->screen_size = gem->size;
info->fix.smem_start = (unsigned long)(bo->iova);
info->fix.smem_len = gem->size;
/* The handle is only needed for creating the framebuffer. */
drm_gem_handle_delete(file, handle);
/* The framebuffer still holds a reference on the GEM object. */
drm_gem_object_put(gem);
return 0;
destroy:
drm_framebuffer_remove(fb);
err_drm_client_buffer_delete:
drm_client_buffer_delete(buffer);
err_drm_gem_handle_delete:
drm_gem_handle_delete(file, handle);
err_drm_gem_object_put:
drm_gem_object_put(gem);
return err;
}

View File

@ -69,7 +69,7 @@ static struct host1x_bo_mapping *tegra_bo_pin(struct device *dev, struct host1x_
return ERR_PTR(-ENOMEM);
kref_init(&map->ref);
map->bo = host1x_bo_get(bo);
map->bo = bo;
map->direction = direction;
map->dev = dev;
@ -170,7 +170,6 @@ static void tegra_bo_unpin(struct host1x_bo_mapping *map)
kfree(map->sgt);
}
host1x_bo_put(map->bo);
kfree(map);
}
@ -235,6 +234,7 @@ static const struct host1x_bo_ops tegra_bo_ops = {
static int tegra_bo_iommu_map(struct tegra_drm *tegra, struct tegra_bo *bo)
{
int prot = IOMMU_READ | IOMMU_WRITE;
ssize_t size;
int err;
if (bo->mm)
@ -256,13 +256,15 @@ static int tegra_bo_iommu_map(struct tegra_drm *tegra, struct tegra_bo *bo)
bo->iova = bo->mm->start;
bo->size = iommu_map_sgtable(tegra->domain, bo->iova, bo->sgt, prot);
if (!bo->size) {
size = iommu_map_sgtable(tegra->domain, bo->iova, bo->sgt, prot);
if (size < 0) {
dev_err(tegra->drm->dev, "failed to map buffer\n");
err = -ENOMEM;
err = size;
goto remove;
}
bo->size = size;
mutex_unlock(&tegra->mm_lock);
return 0;
@ -509,17 +511,9 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm,
void tegra_bo_free_object(struct drm_gem_object *gem)
{
struct tegra_drm *tegra = gem->dev->dev_private;
struct host1x_bo_mapping *mapping, *tmp;
struct tegra_bo *bo = to_tegra_bo(gem);
/* remove all mappings of this buffer object from any caches */
list_for_each_entry_safe(mapping, tmp, &bo->base.mappings, list) {
if (mapping->cache)
host1x_bo_unpin(mapping);
else
dev_err(gem->dev->dev, "mapping %p stale for device %s\n", mapping,
dev_name(mapping->dev));
}
host1x_bo_clear_cached_mappings(&bo->base);
if (tegra->domain) {
tegra_bo_iommu_unmap(tegra, bo);

View File

@ -100,9 +100,6 @@ static int gr2d_exit(struct host1x_client *client)
if (err < 0)
return err;
pm_runtime_dont_use_autosuspend(client->dev);
pm_runtime_force_suspend(client->dev);
host1x_client_iommu_detach(client);
host1x_syncpt_put(client->syncpts[0]);
host1x_channel_put(gr2d->channel);
@ -276,15 +273,21 @@ static int gr2d_probe(struct platform_device *pdev)
if (err)
return err;
/* initialize address register map */
for (i = 0; i < ARRAY_SIZE(gr2d_addr_regs); i++)
set_bit(gr2d_addr_regs[i], gr2d->addr_regs);
pm_runtime_enable(dev);
err = host1x_client_register(&gr2d->client.base);
if (err < 0) {
pm_runtime_disable(dev);
dev_err(dev, "failed to register host1x client: %d\n", err);
return err;
}
/* initialize address register map */
for (i = 0; i < ARRAY_SIZE(gr2d_addr_regs); i++)
set_bit(gr2d_addr_regs[i], gr2d->addr_regs);
pm_runtime_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, 500);
return 0;
}
@ -367,10 +370,6 @@ static int __maybe_unused gr2d_runtime_resume(struct device *dev)
goto disable_clk;
}
pm_runtime_enable(dev);
pm_runtime_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, 500);
return 0;
disable_clk:

View File

@ -109,9 +109,6 @@ static int gr3d_exit(struct host1x_client *client)
if (err < 0)
return err;
pm_runtime_dont_use_autosuspend(client->dev);
pm_runtime_force_suspend(client->dev);
host1x_client_iommu_detach(client);
host1x_syncpt_put(client->syncpts[0]);
host1x_channel_put(gr3d->channel);
@ -506,16 +503,22 @@ static int gr3d_probe(struct platform_device *pdev)
if (err)
return err;
/* initialize address register map */
for (i = 0; i < ARRAY_SIZE(gr3d_addr_regs); i++)
set_bit(gr3d_addr_regs[i], gr3d->addr_regs);
pm_runtime_enable(&pdev->dev);
err = host1x_client_register(&gr3d->client.base);
if (err < 0) {
pm_runtime_disable(&pdev->dev);
dev_err(&pdev->dev, "failed to register host1x client: %d\n",
err);
return err;
}
/* initialize address register map */
for (i = 0; i < ARRAY_SIZE(gr3d_addr_regs); i++)
set_bit(gr3d_addr_regs[i], gr3d->addr_regs);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
return 0;
}
@ -578,10 +581,6 @@ static int __maybe_unused gr3d_runtime_resume(struct device *dev)
goto disable_clk;
}
pm_runtime_enable(dev);
pm_runtime_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, 500);
return 0;
disable_clk:

View File

@ -25,12 +25,12 @@
#include <drm/drm_crtc.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
#include <drm/drm_eld.h>
#include <drm/drm_file.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include "hda.h"
#include "hdmi.h"
@ -372,6 +372,10 @@ static const struct tmds_config tegra124_tmds_config[] = {
},
};
static const struct drm_encoder_funcs tegra_hdmi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
static void tegra_hdmi_audio_lock(struct tegra_hdmi *hdmi)
{
mutex_lock(&hdmi->audio_lock);
@ -1555,8 +1559,8 @@ static int tegra_hdmi_init(struct host1x_client *client)
hdmi->output.dev = client->dev;
drm_simple_encoder_init(drm, &hdmi->output.encoder,
DRM_MODE_ENCODER_TMDS);
drm_encoder_init(drm, &hdmi->output.encoder, &tegra_hdmi_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
drm_encoder_helper_add(&hdmi->output.encoder,
&tegra_hdmi_encoder_helper_funcs);

View File

@ -13,6 +13,7 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/string_choices.h>
#include <soc/tegra/pmc.h>
@ -22,10 +23,10 @@
#include <drm/drm_debugfs.h>
#include <drm/drm_edid.h>
#include <drm/drm_eld.h>
#include <drm/drm_encoder.h>
#include <drm/drm_file.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_simple_kms_helper.h>
#include "dc.h"
#include "dp.h"
@ -940,7 +941,7 @@ static int tegra_sor_dp_link_configure(struct drm_dp_link *link)
err = tegra_sor_power_up_lanes(sor, lanes);
if (err < 0) {
dev_err(sor->dev, "failed to power up %u lane%s: %d\n",
lanes, (lanes != 1) ? "s" : "", err);
lanes, str_plural(lanes), err);
return err;
}
@ -2557,6 +2558,17 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder)
value = tegra_dc_readl(dc, DC_DISP_DISP_COLOR_CONTROL);
value &= ~DITHER_CONTROL_MASK;
value &= ~BASE_COLOR_SIZE_MASK;
if (dc->soc->has_nvdisplay) {
tegra_dc_writel(dc, lower_32_bits(dc->cmu_output_lut_phys),
DC_DISP_COREPVT_HEAD_SET_OUTPUT_LUT_BASE);
tegra_dc_writel(dc, upper_32_bits(dc->cmu_output_lut_phys),
DC_DISP_COREPVT_HEAD_SET_OUTPUT_LUT_BASE_HI);
tegra_dc_writel(dc, OUTPUT_LUT_MODE_INTERPOLATE | OUTPUT_LUT_SIZE_SIZE_1025,
DC_DISP_CORE_HEAD_SET_CONTROL_OUTPUT_LUT);
value |= CMU_ENABLE_ENABLE;
}
switch (state->bpc) {
case 6:
@ -2921,6 +2933,20 @@ static void tegra_sor_dp_enable(struct drm_encoder *encoder)
if (err < 0)
dev_err(sor->dev, "failed to attach SOR: %d\n", err);
if (dc->soc->has_nvdisplay) {
value = tegra_dc_readl(dc, DC_DISP_DISP_COLOR_CONTROL);
tegra_dc_writel(dc, lower_32_bits(dc->cmu_output_lut_phys),
DC_DISP_COREPVT_HEAD_SET_OUTPUT_LUT_BASE);
tegra_dc_writel(dc, upper_32_bits(dc->cmu_output_lut_phys),
DC_DISP_COREPVT_HEAD_SET_OUTPUT_LUT_BASE_HI);
tegra_dc_writel(dc, OUTPUT_LUT_MODE_INTERPOLATE | OUTPUT_LUT_SIZE_SIZE_1025,
DC_DISP_CORE_HEAD_SET_CONTROL_OUTPUT_LUT);
value |= CMU_ENABLE_ENABLE;
tegra_dc_writel(dc, value, DC_DISP_DISP_COLOR_CONTROL);
}
value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
value |= SOR_ENABLE(sor->index);
tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
@ -3038,6 +3064,10 @@ static const struct tegra_sor_ops tegra_sor_dp_ops = {
.probe = tegra_sor_dp_probe,
};
static const struct drm_encoder_funcs tegra_sor_encoder_funcs_cleanup = {
.destroy = drm_encoder_cleanup,
};
static int tegra_sor_init(struct host1x_client *client)
{
struct drm_device *drm = dev_get_drvdata(client->host);
@ -3081,7 +3111,8 @@ static int tegra_sor_init(struct host1x_client *client)
&tegra_sor_connector_helper_funcs);
sor->output.connector.dpms = DRM_MODE_DPMS_OFF;
drm_simple_encoder_init(drm, &sor->output.encoder, encoder);
drm_encoder_init(drm, &sor->output.encoder,
&tegra_sor_encoder_funcs_cleanup, encoder, NULL);
drm_encoder_helper_add(&sor->output.encoder, helpers);
drm_connector_attach_encoder(&sor->output.connector,

View File

@ -76,7 +76,7 @@ gather_bo_pin(struct device *dev, struct host1x_bo *bo, enum dma_data_direction
return ERR_PTR(-ENOMEM);
kref_init(&map->ref);
map->bo = host1x_bo_get(bo);
map->bo = bo;
map->direction = direction;
map->dev = dev;
@ -117,7 +117,6 @@ static void gather_bo_unpin(struct host1x_bo_mapping *map)
dma_unmap_sgtable(map->dev, map->sgt, map->direction, 0);
sg_free_table(map->sgt);
kfree(map->sgt);
host1x_bo_put(map->bo);
kfree(map);
}

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
verisilicon-dc-objs := vs_bridge.o vs_crtc.o vs_dc.o vs_drm.o vs_hwdb.o vs_plane.o vs_primary_plane.o
verisilicon-dc-objs := vs_bridge.o vs_crtc.o vs_dc.o vs_drm.o vs_hwdb.o \
vs_plane.o vs_primary_plane.o vs_cursor_plane.o
obj-$(CONFIG_DRM_VERISILICON_DC) += verisilicon-dc.o

View File

@ -159,7 +159,7 @@ struct vs_crtc *vs_crtc_init(struct drm_device *drm_dev, struct vs_dc *dc,
unsigned int output)
{
struct vs_crtc *vcrtc;
struct drm_plane *primary;
struct drm_plane *primary, *cursor;
int ret;
vcrtc = drmm_kzalloc(drm_dev, sizeof(*vcrtc), GFP_KERNEL);
@ -175,9 +175,16 @@ struct vs_crtc *vs_crtc_init(struct drm_device *drm_dev, struct vs_dc *dc,
return ERR_PTR(PTR_ERR(primary));
}
/* Create our cursor plane */
cursor = vs_cursor_plane_init(drm_dev, dc);
if (IS_ERR(cursor)) {
drm_err(drm_dev, "Couldn't create the cursor plane\n");
return ERR_CAST(cursor);
}
ret = drmm_crtc_init_with_planes(drm_dev, &vcrtc->base,
primary,
NULL,
cursor,
&vs_crtc_funcs,
NULL);
if (ret) {

View File

@ -0,0 +1,272 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2026 Institute of Software, Chinese Academy of Sciences (ISCAS)
*
* Authors:
* Icenowy Zheng <zhengxingda@iscas.ac.cn>
*/
#include <linux/log2.h>
#include <linux/regmap.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_plane.h>
#include <drm/drm_print.h>
#include "vs_crtc.h"
#include "vs_plane.h"
#include "vs_dc.h"
#include "vs_hwdb.h"
#include "vs_cursor_plane_regs.h"
#define VSDC_MIN_CURSOR_SIZE 32
#define VSDC_MAX_CURSOR_SIZE 256
#define VSDC_CURSOR_LOCATION_MAX_POSITIVE BIT_MASK(15)
#define VSDC_CURSOR_LOCATION_MAX_NEGATIVE BIT_MASK(5)
static bool vs_cursor_plane_check_coord(int32_t coord)
{
if (coord >= 0)
return coord <= VSDC_CURSOR_LOCATION_MAX_POSITIVE;
else
return (-coord) <= VSDC_CURSOR_LOCATION_MAX_NEGATIVE;
}
static int vs_cursor_plane_atomic_check(struct drm_plane *plane,
struct drm_atomic_commit *state)
{
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
plane);
struct drm_crtc *crtc = new_plane_state->crtc;
struct drm_framebuffer *fb = new_plane_state->fb;
struct drm_crtc_state *crtc_state = NULL;
struct vs_crtc *vcrtc;
struct vs_dc *dc;
int ret;
if (crtc)
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
ret = drm_atomic_helper_check_plane_state(new_plane_state,
crtc_state,
DRM_PLANE_NO_SCALING,
DRM_PLANE_NO_SCALING,
true, true);
if (ret)
return ret;
if (!new_plane_state->visible)
return 0; /* Skip validity check */
vcrtc = drm_crtc_to_vs_crtc(crtc);
dc = vcrtc->dc;
/* Only certain PoT square sizes is supported. */
if (!is_power_of_2(new_plane_state->crtc_w) ||
new_plane_state->crtc_w < VSDC_MIN_CURSOR_SIZE ||
new_plane_state->crtc_w > dc->identity.max_cursor_size)
return -EINVAL;
if (new_plane_state->crtc_w != new_plane_state->crtc_h)
return -EINVAL;
/* Check if the cursor is inside the register fields' range */
if (!vs_cursor_plane_check_coord(new_plane_state->crtc_x) ||
!vs_cursor_plane_check_coord(new_plane_state->crtc_y))
return -EINVAL;
/* Extra line padding isn't supported */
if (fb->pitches[0] !=
drm_format_info_min_pitch(fb->format, 0, new_plane_state->crtc_w))
return -EINVAL;
return 0;
}
static void vs_cursor_plane_commit(struct vs_dc *dc, unsigned int output)
{
regmap_set_bits(dc->regs, VSDC_CURSOR_CONFIG(output),
VSDC_CURSOR_CONFIG_COMMIT |
VSDC_CURSOR_CONFIG_IMG_UPDATE);
}
static void vs_cursor_plane_atomic_enable(struct drm_plane *plane,
struct drm_atomic_commit *atomic_state)
{
struct drm_plane_state *state = drm_atomic_get_new_plane_state(atomic_state,
plane);
struct drm_crtc *crtc = state->crtc;
struct vs_crtc *vcrtc = drm_crtc_to_vs_crtc(crtc);
unsigned int output = vcrtc->id;
struct vs_dc *dc = vcrtc->dc;
regmap_update_bits(dc->regs, VSDC_CURSOR_CONFIG(output),
VSDC_CURSOR_CONFIG_FMT_MASK,
VSDC_CURSOR_CONFIG_FMT_ARGB8888);
vs_cursor_plane_commit(dc, output);
}
static void vs_cursor_plane_atomic_disable(struct drm_plane *plane,
struct drm_atomic_commit *atomic_state)
{
struct drm_plane_state *state = drm_atomic_get_old_plane_state(atomic_state,
plane);
struct drm_crtc *crtc = state->crtc;
struct vs_crtc *vcrtc = drm_crtc_to_vs_crtc(crtc);
unsigned int output = vcrtc->id;
struct vs_dc *dc = vcrtc->dc;
regmap_update_bits(dc->regs, VSDC_CURSOR_CONFIG(output),
VSDC_CURSOR_CONFIG_FMT_MASK,
VSDC_CURSOR_CONFIG_FMT_OFF);
vs_cursor_plane_commit(dc, output);
}
static void vs_cursor_plane_atomic_update(struct drm_plane *plane,
struct drm_atomic_commit *atomic_state)
{
struct drm_plane_state *state = drm_atomic_get_new_plane_state(atomic_state,
plane);
struct drm_framebuffer *fb = state->fb;
struct drm_crtc *crtc = state->crtc;
struct vs_dc *dc;
struct vs_crtc *vcrtc;
unsigned int output;
dma_addr_t dma_addr;
if (!state->visible) {
vs_cursor_plane_atomic_disable(plane, atomic_state);
return;
}
vcrtc = drm_crtc_to_vs_crtc(crtc);
output = vcrtc->id;
dc = vcrtc->dc;
/* Other sizes should be rejected by atomic_check */
switch (state->crtc_w) {
case 32:
regmap_update_bits(dc->regs, VSDC_CURSOR_CONFIG(output),
VSDC_CURSOR_CONFIG_SIZE_MASK,
VSDC_CURSOR_CONFIG_SIZE_32);
break;
case 64:
regmap_update_bits(dc->regs, VSDC_CURSOR_CONFIG(output),
VSDC_CURSOR_CONFIG_SIZE_MASK,
VSDC_CURSOR_CONFIG_SIZE_64);
break;
case 128:
regmap_update_bits(dc->regs, VSDC_CURSOR_CONFIG(output),
VSDC_CURSOR_CONFIG_SIZE_MASK,
VSDC_CURSOR_CONFIG_SIZE_128);
break;
case 256:
regmap_update_bits(dc->regs, VSDC_CURSOR_CONFIG(output),
VSDC_CURSOR_CONFIG_SIZE_MASK,
VSDC_CURSOR_CONFIG_SIZE_256);
break;
}
dma_addr = vs_fb_get_dma_addr(fb, &state->src);
regmap_write(dc->regs, VSDC_CURSOR_ADDRESS(output),
lower_32_bits(dma_addr));
/*
* The X_OFF and Y_OFF fields define which point does the LOCATION
* register represent in the cursor image, and LOCATION register
* values are unsigned. To for positive left-top coordinates the
* offset is set to 0 and the location is set to the coordinate, for
* negative coordinates the location is set to 0 and the offset
* is set to the opposite number of the coordinate to offset the
* cursor image partly off-screen.
*/
if (state->crtc_x >= 0) {
regmap_update_bits(dc->regs, VSDC_CURSOR_CONFIG(output),
VSDC_CURSOR_CONFIG_X_OFF_MASK, 0);
regmap_update_bits(dc->regs, VSDC_CURSOR_LOCATION(output),
VSDC_CURSOR_LOCATION_X_MASK,
VSDC_CURSOR_LOCATION_X(state->crtc_x));
} else {
regmap_update_bits(dc->regs, VSDC_CURSOR_CONFIG(output),
VSDC_CURSOR_CONFIG_X_OFF_MASK,
-state->crtc_x);
regmap_update_bits(dc->regs, VSDC_CURSOR_LOCATION(output),
VSDC_CURSOR_LOCATION_X_MASK, 0);
}
if (state->crtc_y >= 0) {
regmap_update_bits(dc->regs, VSDC_CURSOR_CONFIG(output),
VSDC_CURSOR_CONFIG_Y_OFF_MASK, 0);
regmap_update_bits(dc->regs, VSDC_CURSOR_LOCATION(output),
VSDC_CURSOR_LOCATION_Y_MASK,
VSDC_CURSOR_LOCATION_Y(state->crtc_y));
} else {
regmap_update_bits(dc->regs, VSDC_CURSOR_CONFIG(output),
VSDC_CURSOR_CONFIG_Y_OFF_MASK,
-state->crtc_y);
regmap_update_bits(dc->regs, VSDC_CURSOR_LOCATION(output),
VSDC_CURSOR_LOCATION_Y_MASK, 0);
}
vs_cursor_plane_commit(dc, output);
}
static const struct drm_plane_helper_funcs vs_cursor_plane_helper_funcs = {
.atomic_check = vs_cursor_plane_atomic_check,
.atomic_update = vs_cursor_plane_atomic_update,
.atomic_enable = vs_cursor_plane_atomic_enable,
.atomic_disable = vs_cursor_plane_atomic_disable,
};
static const struct drm_plane_funcs vs_cursor_plane_funcs = {
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.disable_plane = drm_atomic_helper_disable_plane,
.reset = drm_atomic_helper_plane_reset,
.update_plane = drm_atomic_helper_update_plane,
};
static const u32 vs_cursor_plane_formats[] = {
DRM_FORMAT_ARGB8888,
};
static const u64 vs_cursor_plane_modifiers[] = {
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID, /* sentinel */
};
struct drm_plane *vs_cursor_plane_init(struct drm_device *drm_dev,
struct vs_dc *dc)
{
int32_t max_cursor_size = dc->identity.max_cursor_size;
struct drm_plane *plane;
if (drm_WARN_ON_ONCE(drm_dev, max_cursor_size < VSDC_MIN_CURSOR_SIZE ||
max_cursor_size > VSDC_MAX_CURSOR_SIZE))
return ERR_PTR(-EINVAL);
plane = drmm_universal_plane_alloc(drm_dev, struct drm_plane, dev, 0,
&vs_cursor_plane_funcs,
vs_cursor_plane_formats,
ARRAY_SIZE(vs_cursor_plane_formats),
vs_cursor_plane_modifiers,
DRM_PLANE_TYPE_CURSOR,
NULL);
if (IS_ERR(plane))
return plane;
drm_plane_helper_add(plane, &vs_cursor_plane_helper_funcs);
return plane;
}

View File

@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2025 Icenowy Zheng <uwu@icenowy.me>
*
* Based on vs_dc_hw.h, which is:
* Copyright (C) 2023 VeriSilicon Holdings Co., Ltd.
*/
#ifndef _VS_CURSOR_PLANE_REGS_H_
#define _VS_CURSOR_PLANE_REGS_H_
#include <linux/bits.h>
#define VSDC_CURSOR_CONFIG(n) (0x1468 + 0x1080 * (n))
#define VSDC_CURSOR_CONFIG_FMT_MASK GENMASK(1, 0)
#define VSDC_CURSOR_CONFIG_FMT_ARGB8888 (0x2 << 0)
#define VSDC_CURSOR_CONFIG_FMT_OFF (0x0 << 0)
#define VSDC_CURSOR_CONFIG_IMG_UPDATE BIT(2)
#define VSDC_CURSOR_CONFIG_COMMIT BIT(3)
#define VSDC_CURSOR_CONFIG_SIZE_MASK GENMASK(7, 5)
#define VSDC_CURSOR_CONFIG_SIZE_32 (0x0 << 5)
#define VSDC_CURSOR_CONFIG_SIZE_64 (0x1 << 5)
#define VSDC_CURSOR_CONFIG_SIZE_128 (0x2 << 5)
#define VSDC_CURSOR_CONFIG_SIZE_256 (0x3 << 5)
#define VSDC_CURSOR_CONFIG_Y_OFF_MASK GENMASK(12, 8)
#define VSDC_CURSOR_CONFIG_Y_OFF(v) ((v) << 8)
#define VSDC_CURSOR_CONFIG_X_OFF_MASK GENMASK(20, 16)
#define VSDC_CURSOR_CONFIG_X_OFF(v) ((v) << 16)
#define VSDC_CURSOR_ADDRESS(n) (0x146C + 0x1080 * (n))
#define VSDC_CURSOR_LOCATION(n) (0x1470 + 0x1080 * (n))
#define VSDC_CURSOR_LOCATION_X_MASK GENMASK(14, 0)
#define VSDC_CURSOR_LOCATION_X(v) ((v) << 0)
#define VSDC_CURSOR_LOCATION_Y_MASK GENMASK(30, 16)
#define VSDC_CURSOR_LOCATION_Y(v) ((v) << 16)
#define VSDC_CURSOR_BACKGROUND(n) (0x1474 + 0x1080 * (n))
#define VSDC_CURSOR_BACKGRUOND_DEFAULT 0x00FFFFFF
#define VSDC_CURSOR_FOREGROUND(n) (0x1478 + 0x1080 * (n))
#define VSDC_CURSOR_FOREGRUOND_DEFAULT 0x00AAAAAA
#endif /* _VS_CURSOR_PLANE_REGS_H_ */

View File

@ -95,6 +95,7 @@ static struct vs_chip_identity vs_chip_identities[] = {
.customer_id = ~0U,
.display_count = 2,
.max_cursor_size = 64,
.formats = &vs_formats_no_yuv444,
},
{
@ -103,6 +104,7 @@ static struct vs_chip_identity vs_chip_identities[] = {
.customer_id = 0x30B,
.display_count = 2,
.max_cursor_size = 64,
.formats = &vs_formats_no_yuv444,
},
{
@ -111,6 +113,7 @@ static struct vs_chip_identity vs_chip_identities[] = {
.customer_id = 0x310,
.display_count = 2,
.max_cursor_size = 64,
.formats = &vs_formats_with_yuv444,
},
{
@ -119,6 +122,7 @@ static struct vs_chip_identity vs_chip_identities[] = {
.customer_id = 0x311,
.display_count = 2,
.max_cursor_size = 64,
.formats = &vs_formats_no_yuv444,
},
};

View File

@ -20,6 +20,11 @@ struct vs_chip_identity {
u32 customer_id;
u32 display_count;
/*
* The hardware only supports square cursor planes, so this field
* is both the maximum width and height in pixels.
*/
int32_t max_cursor_size;
const struct vs_formats *formats;
};

View File

@ -84,5 +84,6 @@ void vs_plane_destroy_state(struct drm_plane *plane,
void vs_plane_reset(struct drm_plane *plane);
struct drm_plane *vs_primary_plane_init(struct drm_device *dev, struct vs_dc *dc);
struct drm_plane *vs_cursor_plane_init(struct drm_device *dev, struct vs_dc *dc);
#endif /* _VS_PLANE_H_ */

View File

@ -156,7 +156,7 @@ int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_d
#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
/*
* This abuses both drm_exec and ww_mutex internals and should be
* This abuses ww_mutex internals and should be
* replaced by checking for -EDEADLK when we can make TTM
* stop converting -EDEADLK to -ENOMEM.
* An alternative is to not have exhaustive eviction with
@ -164,7 +164,7 @@ int xe_validation_ctx_init(struct xe_validation_ctx *ctx, struct xe_validation_d
*/
static bool xe_validation_contention_injected(struct drm_exec *exec)
{
return !!exec->ticket.contending_lock;
return !!drm_exec_ticket(exec)->contending_lock;
}
#else

View File

@ -146,7 +146,7 @@ bool xe_validation_should_retry(struct xe_validation_ctx *ctx, int *ret);
#define xe_validation_retry_on_oom(_ctx, _ret) \
do { \
if (xe_validation_should_retry(_ctx, _ret)) \
goto *__drm_exec_retry_ptr; \
drm_exec_retry((_ctx)->exec); \
} while (0)
/**

View File

@ -373,7 +373,6 @@ int xe_vm_validate_rebind(struct xe_vm *vm, struct drm_exec *exec,
unsigned int num_fences)
{
struct drm_gem_object *obj;
unsigned long index;
int ret;
do {
@ -386,7 +385,7 @@ int xe_vm_validate_rebind(struct xe_vm *vm, struct drm_exec *exec,
return ret;
} while (!list_empty(&vm->gpuvm.evict.list));
drm_exec_for_each_locked_object(exec, index, obj) {
drm_exec_for_each_locked_object(exec, obj) {
ret = dma_resv_reserve_fences(obj->resv, num_fences);
if (ret)
return ret;

View File

@ -221,7 +221,7 @@ int host1x_device_init(struct host1x_device *device)
teardown:
list_for_each_entry_continue_reverse(client, &device->clients, list)
if (client->ops->exit)
if (client->ops && client->ops->exit)
client->ops->exit(client);
/* reset client to end of list for late teardown */
@ -229,7 +229,7 @@ int host1x_device_init(struct host1x_device *device)
teardown_late:
list_for_each_entry_continue_reverse(client, &device->clients, list)
if (client->ops->late_exit)
if (client->ops && client->ops->late_exit)
client->ops->late_exit(client);
mutex_unlock(&device->clients_lock);
@ -485,7 +485,7 @@ static int host1x_device_add(struct host1x *host1x,
err = host1x_device_parse_dt(device, driver);
if (err < 0) {
kfree(device);
put_device(&device->dev);
return err;
}
@ -887,6 +887,20 @@ int host1x_client_resume(struct host1x_client *client)
}
EXPORT_SYMBOL(host1x_client_resume);
/**
* host1x_bo_pin() - Create a DMA mapping for the buffer object
* @dev: Device onto which DMA map to
* @bo: Buffer object to map
* @dir: DMA direction
* @cache: Cache in which to store mapping, or NULL
*
* Creates a DMA mapping pointing to @bo for @dev. The refcount of @bo is incremented
* until host1x_bo_unpin is called.
*
* If @cache is specified, the mapping is also stored in the cache and not released
* until @bo is freed (refcount drops to zero). This improves performance when a buffer
* is pinned and unpinned frequently as in the case of display use.
*/
struct host1x_bo_mapping *host1x_bo_pin(struct device *dev, struct host1x_bo *bo,
enum dma_data_direction dir,
struct host1x_bo_cache *cache)
@ -899,6 +913,7 @@ struct host1x_bo_mapping *host1x_bo_pin(struct device *dev, struct host1x_bo *bo
list_for_each_entry(mapping, &cache->mappings, entry) {
if (mapping->bo == bo && mapping->direction == dir) {
kref_get(&mapping->ref);
host1x_bo_get(bo);
goto unlock;
}
}
@ -908,6 +923,8 @@ struct host1x_bo_mapping *host1x_bo_pin(struct device *dev, struct host1x_bo *bo
if (IS_ERR(mapping))
goto unlock;
host1x_bo_get(bo);
spin_lock(&mapping->bo->lock);
list_add_tail(&mapping->list, &bo->mappings);
spin_unlock(&mapping->bo->lock);
@ -918,7 +935,12 @@ struct host1x_bo_mapping *host1x_bo_pin(struct device *dev, struct host1x_bo *bo
list_add_tail(&mapping->entry, &cache->mappings);
/* bump reference count to track the copy in the cache */
/*
* Bump the mapping reference count to track the mapping in the cache,
* but do not bump the BO's refcount. This allows the BO to still get freed,
* triggering the release of the cache mapping through
* host1x_bo_clear_cached_mappings.
*/
kref_get(&mapping->ref);
}
@ -948,9 +970,17 @@ static void __host1x_bo_unpin(struct kref *ref)
mapping->bo->ops->unpin(mapping);
}
/**
* host1x_bo_unpin() - Release an established DMA mapping of a buffer object
* @mapping: Mapping to release
*
* Unmaps the given @mapping, unless it is cached. Decreases the refcount on
* the underlying buffer object.
*/
void host1x_bo_unpin(struct host1x_bo_mapping *mapping)
{
struct host1x_bo_cache *cache = mapping->cache;
struct host1x_bo *bo = mapping->bo;
if (cache)
mutex_lock(&cache->lock);
@ -959,5 +989,33 @@ void host1x_bo_unpin(struct host1x_bo_mapping *mapping)
if (cache)
mutex_unlock(&cache->lock);
host1x_bo_put(bo);
}
EXPORT_SYMBOL(host1x_bo_unpin);
/**
* host1x_bo_clear_cached_mappings() - Remove all cached mappings pointing at a bo
* @bo: Buffer object to release mappings of
*
* Drops references to any mappings pointing to @bo left in any caches. This must
* be called by any host1x_bo implementers that may be pinned with caching enabled
* before freeing the bo.
*/
void host1x_bo_clear_cached_mappings(struct host1x_bo *bo)
{
struct host1x_bo_mapping *mapping, *tmp;
struct host1x_bo_cache *cache;
list_for_each_entry_safe(mapping, tmp, &bo->mappings, list) {
cache = mapping->cache;
if (WARN_ON(!cache))
continue;
mutex_lock(&mapping->cache->lock);
WARN_ON(kref_read(&mapping->ref) != 1);
__host1x_bo_unpin(&mapping->ref);
mutex_unlock(&mapping->cache->lock);
}
}
EXPORT_SYMBOL(host1x_bo_clear_cached_mappings);

View File

@ -4,6 +4,7 @@
*/
#include <linux/device.h>
#include <linux/host1x_context_bus.h>
#include <linux/kref.h>
#include <linux/of.h>
#include <linux/of_device.h>

View File

@ -12,8 +12,7 @@
#include <linux/refcount.h>
struct host1x;
extern struct bus_type host1x_context_device_bus_type;
struct host1x_memory_context;
struct host1x_memory_context_list {
struct mutex lock;

View File

@ -4,6 +4,7 @@
*/
#include <linux/device.h>
#include <linux/host1x_context_bus.h>
#include <linux/of.h>
const struct bus_type host1x_context_device_bus_type = {

View File

@ -92,8 +92,12 @@ void host1x_intr_handle_interrupt(struct host1x *host, unsigned int id)
host1x_fence_signal(fence);
}
/* Re-enable interrupt if necessary */
host1x_intr_update_hw_state(host, sp);
/*
* Re-enable interrupt if necessary. The ISR already disabled the interrupt,
* so if no fences remain, no update is needed.
*/
if (!list_empty(&sp->fences.list))
host1x_intr_update_hw_state(host, sp);
spin_unlock(&sp->fences.lock);
}

View File

@ -235,6 +235,8 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job)
}
if (host->domain) {
ssize_t map_err;
for_each_sgtable_sg(map->sgt, sg, j)
gather_size += sg->length;
@ -248,11 +250,11 @@ static unsigned int pin_job(struct host1x *host, struct host1x_job *job)
goto put;
}
err = iommu_map_sgtable(host->domain, iova_dma_addr(&host->iova, alloc),
map->sgt, IOMMU_READ);
if (err == 0) {
map_err = iommu_map_sgtable(host->domain, iova_dma_addr(&host->iova, alloc),
map->sgt, IOMMU_READ);
if (map_err < 0) {
__free_iova(&host->iova, alloc);
err = -EINVAL;
err = map_err;
goto put;
}

View File

@ -114,8 +114,10 @@ struct tegra_mipi_device *tegra_mipi_request(struct device *device,
if (err < 0)
return ERR_PTR(err);
if (provider.np != args.np)
return ERR_PTR(-ENODEV);
if (provider.np != args.np) {
err = -ENODEV;
goto out;
}
mipidev = kzalloc_obj(*mipidev);
if (!mipidev) {

View File

@ -222,11 +222,12 @@ int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
{
struct dma_fence *fence;
long wait_err;
u32 curr;
host1x_hw_syncpt_load(sp->host, sp);
curr = host1x_syncpt_load(sp);
if (value)
*value = host1x_syncpt_load(sp);
*value = curr;
if (host1x_syncpt_is_expired(sp, thresh))
return 0;
@ -245,21 +246,25 @@ int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
host1x_fence_cancel(fence);
dma_fence_put(fence);
if (value)
*value = host1x_syncpt_load(sp);
/*
* Don't rely on dma_fence_wait_timeout return value,
* since it returns zero both on timeout and if the
* wait completed with 0 jiffies left.
*/
host1x_hw_syncpt_load(sp->host, sp);
if (wait_err == 0 && !host1x_syncpt_is_expired(sp, thresh))
if (wait_err == 0 && !host1x_syncpt_is_expired(sp, thresh)) {
if (value)
*value = host1x_syncpt_load(sp);
return -EAGAIN;
else if (wait_err < 0)
} else if (wait_err < 0) {
return wait_err;
else
} else {
/* Success, read the value cached by ISR */
if (value)
*value = host1x_syncpt_read_min(sp);
return 0;
}
}
EXPORT_SYMBOL(host1x_syncpt_wait);

View File

@ -9,6 +9,12 @@
#define DRM_EXEC_INTERRUPTIBLE_WAIT BIT(0)
#define DRM_EXEC_IGNORE_DUPLICATES BIT(1)
/*
* Dummy value used to initially enter the retry loop.
* internal use only.
*/
#define DRM_EXEC_DUMMY ((void *)~0)
struct drm_gem_object;
/**
@ -65,31 +71,46 @@ drm_exec_obj(struct drm_exec *exec, unsigned long index)
return index < exec->num_objects ? exec->objects[index] : NULL;
}
/* Helper for drm_exec_for_each_locked_object(). Internal use only. */
#define __drm_exec_for_each_locked_object(exec, obj, __index) \
for (unsigned long __index = 0; ((obj) = drm_exec_obj(exec, __index)); ++__index)
/**
* drm_exec_for_each_locked_object - iterate over all the locked objects
* @exec: drm_exec object
* @index: unsigned long index for the iteration
* @obj: the current GEM object
*
* Iterate over all the locked GEM objects inside the drm_exec object.
*/
#define drm_exec_for_each_locked_object(exec, index, obj) \
for ((index) = 0; ((obj) = drm_exec_obj(exec, index)); ++(index))
#define drm_exec_for_each_locked_object(exec, obj) \
__drm_exec_for_each_locked_object(exec, obj, __UNIQUE_ID(drm_exec))
/* Helper for drm_exec_for_each_locked_object_reverse(). Internal use only. */
#define __drm_exec_for_each_locked_object_reverse(exec, obj, __index) \
for (unsigned long __index = (exec)->num_objects - 1; \
((obj) = drm_exec_obj(exec, __index)); --__index)
/**
* drm_exec_for_each_locked_object_reverse - iterate over all the locked
* objects in reverse locking order
* @exec: drm_exec object
* @index: unsigned long index for the iteration
* @obj: the current GEM object
*
* Iterate over all the locked GEM objects inside the drm_exec object in
* reverse locking order. Note that @index may go below zero and wrap,
* reverse locking order. Note that the internal index may wrap around,
* but that will be caught by drm_exec_obj(), returning a NULL object.
*/
#define drm_exec_for_each_locked_object_reverse(exec, index, obj) \
for ((index) = (exec)->num_objects - 1; \
((obj) = drm_exec_obj(exec, index)); --(index))
#define drm_exec_for_each_locked_object_reverse(exec, obj) \
__drm_exec_for_each_locked_object_reverse(exec, obj, __UNIQUE_ID(drm_exec))
/*
* Helper to drm_exec_until_all_locked(). Don't use directly.
*
* Since labels can't be defined local to the loop's body we use a jump pointer
* to make sure that the retry is only used from within the loop's body.
*/
#define __drm_exec_until_all_locked(exec, _label) \
_label: \
for (void *const __maybe_unused __drm_exec_retry_ptr = &&_label; \
drm_exec_cleanup(exec);)
/**
* drm_exec_until_all_locked - loop until all GEM objects are locked
@ -98,17 +119,9 @@ drm_exec_obj(struct drm_exec *exec, unsigned long index)
* Core functionality of the drm_exec object. Loops until all GEM objects are
* locked and no more contention exists. At the beginning of the loop it is
* guaranteed that no GEM object is locked.
*
* Since labels can't be defined local to the loops body we use a jump pointer
* to make sure that the retry is only used from within the loops body.
*/
#define drm_exec_until_all_locked(exec) \
__PASTE(__drm_exec_, __LINE__): \
for (void *__drm_exec_retry_ptr; ({ \
__drm_exec_retry_ptr = &&__PASTE(__drm_exec_, __LINE__);\
(void)__drm_exec_retry_ptr; \
drm_exec_cleanup(exec); \
});)
__drm_exec_until_all_locked(exec, __UNIQUE_ID(drm_exec))
/**
* drm_exec_retry_on_contention - restart the loop to grap all locks
@ -135,6 +148,30 @@ static inline bool drm_exec_is_contended(struct drm_exec *exec)
return !!exec->contended;
}
/**
* drm_exec_retry() - Unconditionally restart the loop to grab all locks.
* @exec: drm_exec object
*
* Unconditionally retry the loop to lock all objects. For consistency,
* the exec object needs to be newly initialized.
*/
#define drm_exec_retry(_exec) \
do { \
WARN_ON((_exec)->contended != DRM_EXEC_DUMMY); \
goto *__drm_exec_retry_ptr; \
} while (0)
/**
* drm_exec_ticket - return the ww_acquire_ctx for this exec context
* @exec: drm_exec object
*
* Return: Pointer to the ww_acquire_ctx embedded in @exec.
*/
static inline struct ww_acquire_ctx *drm_exec_ticket(struct drm_exec *exec)
{
return &exec->ticket;
}
void drm_exec_init(struct drm_exec *exec, u32 flags, unsigned nr);
void drm_exec_fini(struct drm_exec *exec);
bool drm_exec_cleanup(struct drm_exec *exec);

View File

@ -143,6 +143,12 @@ static inline struct host1x_bo_mapping *to_host1x_bo_mapping(struct kref *ref)
return container_of(ref, struct host1x_bo_mapping, ref);
}
/**
* struct host1x_bo_ops - operations implemented by a host1x_bo provider
*
* @pin: create a DMA mapping. Implementation must not touch the bo's refcount.
* @unpin: destroy a DMA mapping. Implementation must not touch the bo's refcount.
*/
struct host1x_bo_ops {
struct host1x_bo *(*get)(struct host1x_bo *bo);
void (*put)(struct host1x_bo *bo);
@ -181,6 +187,7 @@ struct host1x_bo_mapping *host1x_bo_pin(struct device *dev, struct host1x_bo *bo
enum dma_data_direction dir,
struct host1x_bo_cache *cache);
void host1x_bo_unpin(struct host1x_bo_mapping *map);
void host1x_bo_clear_cached_mappings(struct host1x_bo *bo);
static inline void *host1x_bo_mmap(struct host1x_bo *bo)
{

View File

@ -21,9 +21,11 @@ struct host1x_bo;
DECLARE_EVENT_CLASS(host1x,
TP_PROTO(const char *name),
TP_ARGS(name),
TP_STRUCT__entry(__field(const char *, name)),
TP_fast_assign(__entry->name = name;),
TP_printk("name=%s", __entry->name)
TP_STRUCT__entry(__string(name, name)),
TP_fast_assign(
__assign_str(name);
),
TP_printk("name=%s", __get_str(name))
);
DEFINE_EVENT(host1x, host1x_channel_open,
@ -52,19 +54,19 @@ TRACE_EVENT(host1x_cdma_push,
TP_ARGS(name, op1, op2),
TP_STRUCT__entry(
__field(const char *, name)
__string(name, name)
__field(u32, op1)
__field(u32, op2)
),
TP_fast_assign(
__entry->name = name;
__assign_str(name);
__entry->op1 = op1;
__entry->op2 = op2;
),
TP_printk("name=%s, op1=%08x, op2=%08x",
__entry->name, __entry->op1, __entry->op2)
__get_str(name), __entry->op1, __entry->op2)
);
TRACE_EVENT(host1x_cdma_push_wide,
@ -73,7 +75,7 @@ TRACE_EVENT(host1x_cdma_push_wide,
TP_ARGS(name, op1, op2, op3, op4),
TP_STRUCT__entry(
__field(const char *, name)
__string(name, name)
__field(u32, op1)
__field(u32, op2)
__field(u32, op3)
@ -81,7 +83,7 @@ TRACE_EVENT(host1x_cdma_push_wide,
),
TP_fast_assign(
__entry->name = name;
__assign_str(name);
__entry->op1 = op1;
__entry->op2 = op2;
__entry->op3 = op3;
@ -89,7 +91,7 @@ TRACE_EVENT(host1x_cdma_push_wide,
),
TP_printk("name=%s, op1=%08x, op2=%08x, op3=%08x op4=%08x",
__entry->name, __entry->op1, __entry->op2, __entry->op3,
__get_str(name), __entry->op1, __entry->op2, __entry->op3,
__entry->op4)
);
@ -100,7 +102,7 @@ TRACE_EVENT(host1x_cdma_push_gather,
TP_ARGS(name, bo, words, offset, cmdbuf),
TP_STRUCT__entry(
__field(const char *, name)
__string(name, name)
__field(struct host1x_bo *, bo)
__field(u32, words)
__field(u32, offset)
@ -114,14 +116,14 @@ TRACE_EVENT(host1x_cdma_push_gather,
words * sizeof(u32));
}
__entry->cmdbuf = cmdbuf;
__entry->name = name;
__assign_str(name);
__entry->bo = bo;
__entry->words = words;
__entry->offset = offset;
),
TP_printk("name=%s, bo=%p, words=%u, offset=%d, contents=[%s]",
__entry->name, __entry->bo,
__get_str(name), __entry->bo,
__entry->words, __entry->offset,
__print_hex(__get_dynamic_array(cmdbuf),
__entry->cmdbuf ? __entry->words * 4 : 0))
@ -134,7 +136,7 @@ TRACE_EVENT(host1x_channel_submit,
TP_ARGS(name, cmdbufs, relocs, syncpt_id, syncpt_incrs),
TP_STRUCT__entry(
__field(const char *, name)
__string(name, name)
__field(u32, cmdbufs)
__field(u32, relocs)
__field(u32, syncpt_id)
@ -142,7 +144,7 @@ TRACE_EVENT(host1x_channel_submit,
),
TP_fast_assign(
__entry->name = name;
__assign_str(name);
__entry->cmdbufs = cmdbufs;
__entry->relocs = relocs;
__entry->syncpt_id = syncpt_id;
@ -151,7 +153,7 @@ TRACE_EVENT(host1x_channel_submit,
TP_printk("name=%s, cmdbufs=%u, relocs=%u, syncpt_id=%u, "
"syncpt_incrs=%u",
__entry->name, __entry->cmdbufs, __entry->relocs,
__get_str(name), __entry->cmdbufs, __entry->relocs,
__entry->syncpt_id, __entry->syncpt_incrs)
);
@ -161,19 +163,19 @@ TRACE_EVENT(host1x_channel_submitted,
TP_ARGS(name, syncpt_base, syncpt_max),
TP_STRUCT__entry(
__field(const char *, name)
__string(name, name)
__field(u32, syncpt_base)
__field(u32, syncpt_max)
),
TP_fast_assign(
__entry->name = name;
__assign_str(name);
__entry->syncpt_base = syncpt_base;
__entry->syncpt_max = syncpt_max;
),
TP_printk("name=%s, syncpt_base=%d, syncpt_max=%d",
__entry->name, __entry->syncpt_base, __entry->syncpt_max)
__get_str(name), __entry->syncpt_base, __entry->syncpt_max)
);
TRACE_EVENT(host1x_channel_submit_complete,
@ -182,19 +184,19 @@ TRACE_EVENT(host1x_channel_submit_complete,
TP_ARGS(name, count, thresh),
TP_STRUCT__entry(
__field(const char *, name)
__string(name, name)
__field(int, count)
__field(u32, thresh)
),
TP_fast_assign(
__entry->name = name;
__assign_str(name);
__entry->count = count;
__entry->thresh = thresh;
),
TP_printk("name=%s, count=%d, thresh=%d",
__entry->name, __entry->count, __entry->thresh)
__get_str(name), __entry->count, __entry->thresh)
);
TRACE_EVENT(host1x_wait_cdma,
@ -203,16 +205,16 @@ TRACE_EVENT(host1x_wait_cdma,
TP_ARGS(name, eventid),
TP_STRUCT__entry(
__field(const char *, name)
__string(name, name)
__field(u32, eventid)
),
TP_fast_assign(
__entry->name = name;
__assign_str(name);
__entry->eventid = eventid;
),
TP_printk("name=%s, event=%d", __entry->name, __entry->eventid)
TP_printk("name=%s, event=%d", __get_str(name), __entry->eventid)
);
TRACE_EVENT(host1x_syncpt_load_min,

View File

@ -304,6 +304,7 @@ struct drm_tegra_cmdbuf {
* struct drm_tegra_reloc - GEM object relocation structure
*/
struct drm_tegra_reloc {
/** @cmdbuf: cmd information */
struct {
/**
* @cmdbuf.handle:
@ -321,6 +322,7 @@ struct drm_tegra_reloc {
*/
__u32 offset;
} cmdbuf;
/** @target: relocate target information */
struct {
/**
* @target.handle:
@ -778,6 +780,9 @@ struct drm_tegra_channel_unmap {
/* Submission */
/**
* define DRM_TEGRA_SUBMIT_RELOC_SECTOR_LAYOUT - \
* Select sector layout swizzling for in-memory buffers.
*
* Specify that bit 39 of the patched-in address should be set to switch
* swizzling between Tegra and non-Tegra sector layout on systems that store
* surfaces in system memory in non-Tegra sector layout.
@ -830,16 +835,27 @@ struct drm_tegra_submit_buf {
};
/**
* define DRM_TEGRA_SUBMIT_CMD_GATHER_UPTR - \
* Execute Host1x opcodes from user pointer.
*
* Execute `words` words of Host1x opcodes specified in the `gather_data_ptr`
* buffer. Each GATHER_UPTR command uses successive words from the buffer.
*/
#define DRM_TEGRA_SUBMIT_CMD_GATHER_UPTR 0
/**
* define DRM_TEGRA_SUBMIT_CMD_WAIT_SYNCPT - \
* Wait for syncpoint (absolute).
*
* Wait for a syncpoint to reach a value before continuing with further
* commands.
*/
#define DRM_TEGRA_SUBMIT_CMD_WAIT_SYNCPT 1
/**
* define DRM_TEGRA_SUBMIT_CMD_WAIT_SYNCPT_RELATIVE - \
* Wait for syncpoint (relative).
*
* Wait for a syncpoint to reach a value before continuing with further
* commands. The threshold is calculated relative to the start of the job.
*/