drm-misc-next for v7.4:

UAPI Changes:
 
 colorop:
 - provide DRM_COLOR_OP_FIXED_MATRIX
 
 Cross-subsystem Changes:
 
 cgroups:
 - fix typos
 
 dma-buf:
 - fix typos
 
 sound:
 - adapt to changes in omapdrm
 
 Core Changes:
 
 atomic:
 - convert most of DRM from state reset callbacks to atomic_create_state
 - remove drm_simple_encoder_init(); update drivers
 
 buddy:
 - improve dirty-page tracking
 
 clients:
 - log: Improve vmap handling
 
 display:
 - export HDMI SCDC status data via debugfs
 
 edid:
 - parse AMD VSDB entries
 - parse ALLM/VRR capabilities
 
 log:
 - add drm_warn_ratelimited()
 
 sched:
 - add missing locking
 
 Driver Changes:
 
 amd:
 - display: Use AMD VSDB for FreeSync
 - display: Implement YUV-to-RGB with fixed-matrix colorop
 
 amdxdma:
 - various fixes
 
 ast:
 - support 256-byte EDID data
 
 bridge:
 - clean up redundant error reporting
 - ti-sn65dsi83: Simplify error condition logic
 
 hyperv_drm:
 - remove support for pre-Win10 hosts
 
 komeda:
 - fix usage of GLB_CORE_ID
 
 nouveau:
 - improve runtime PM on R570 GSP firmware
 - various fixes throughout the driver
 - dispnv50: Support 2.147 GHz pixel clock in GB20x
 
 omap:
 - report HDMI hotplug events to ASoC HDMI codec
 
 panel:
 - panel-edp: Support MNE007QS3-F, TM140VDXP15, and KD116N36-30NB-A001
 - samsung-s6d16d0: Use mipi_dsi_*_multi() functions
 - support Ilitek ILI7836A OLED plus DT bindings
 - support Novatek NT36532 plus DT bindings
 - convert several drivers to managed cleanup
 - fix Kconfig selections
 
 panthor:
 - provide gpu_cache_flush tracepoint
 - improve dma_fence signalling latency
 - improve locking
 
 qaic:
 - reject BOs that exceed maximum page count
 - add missing include statements
 
 verisilicon:
 - fix hardware cursor offsets
 
 vkms:
 - implement YUV-to-RGB with fixed-matrix colorop
 -----BEGIN PGP SIGNATURE-----
 
 iQFPBAABCgA5FiEEchf7rIzpz2NEoWjlaA3BHVMLeiMFAmqZbyAbFIAAAAAABAAO
 bWFudTIsMi41KzEuMTIsMiwyAAoJEGgNwR1TC3oj0KwIAKhga8cMi+oqZ+WIRq7i
 MsCI4Tdl3jukry9Yho8BIsaFpknVcYV+v3qNsR1Za0Hcu3Znd4nqL2TOv5piGESB
 ErUsMkn3OJoMZUuHsCxBUPtxYUhVgWYIFvFx5CXLdKhESeqLtmWsqEDu8QcikiNB
 Wn6eyYOyuCG5ZD9ZRrWXM7WTIVrsPVar62t8FHdtoVgms9bMxtQadSrFwpmWnESQ
 +a+O+K7mI6NC2oh/znvVFYmZa9INoKAJf16lPDfL7UC9GTHg52Gu+yZDj2rYkqQK
 p4k1zpZHU0WyyjKoQxIY9rBQ4BLuzy/JP8ZZQakLOA98mHMM9ZwvftvudH4I5PPK
 JMg=
 =4Nm4
 -----END PGP SIGNATURE-----

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

drm-misc-next for v7.4:

UAPI Changes:

colorop:
- provide DRM_COLOR_OP_FIXED_MATRIX

Cross-subsystem Changes:

cgroups:
- fix typos

dma-buf:
- fix typos

sound:
- adapt to changes in omapdrm

Core Changes:

atomic:
- convert most of DRM from state reset callbacks to atomic_create_state
- remove drm_simple_encoder_init(); update drivers

buddy:
- improve dirty-page tracking

clients:
- log: Improve vmap handling

display:
- export HDMI SCDC status data via debugfs

edid:
- parse AMD VSDB entries
- parse ALLM/VRR capabilities

log:
- add drm_warn_ratelimited()

sched:
- add missing locking

Driver Changes:

amd:
- display: Use AMD VSDB for FreeSync
- display: Implement YUV-to-RGB with fixed-matrix colorop

amdxdma:
- various fixes

ast:
- support 256-byte EDID data

bridge:
- clean up redundant error reporting
- ti-sn65dsi83: Simplify error condition logic

hyperv_drm:
- remove support for pre-Win10 hosts

komeda:
- fix usage of GLB_CORE_ID

nouveau:
- improve runtime PM on R570 GSP firmware
- various fixes throughout the driver
- dispnv50: Support 2.147 GHz pixel clock in GB20x

omap:
- report HDMI hotplug events to ASoC HDMI codec

panel:
- panel-edp: Support MNE007QS3-F, TM140VDXP15, and KD116N36-30NB-A001
- samsung-s6d16d0: Use mipi_dsi_*_multi() functions
- support Ilitek ILI7836A OLED plus DT bindings
- support Novatek NT36532 plus DT bindings
- convert several drivers to managed cleanup
- fix Kconfig selections

panthor:
- provide gpu_cache_flush tracepoint
- improve dma_fence signalling latency
- improve locking

qaic:
- reject BOs that exceed maximum page count
- add missing include statements

verisilicon:
- fix hardware cursor offsets

vkms:
- implement YUV-to-RGB with fixed-matrix colorop

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

From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patch.msgid.link/20260903130548.GA91506@2a02-2455-9062-2500-3419-2212-e55c-8a45.dyn6.pyur.net
This commit is contained in:
Dave Airlie 2026-09-08 16:51:58 +10:00
commit 483ece619b
272 changed files with 5652 additions and 3319 deletions

View File

@ -0,0 +1,58 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/ilitek,ili7836a.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Ilitek ILI7836A-based OLED panels
maintainers:
- Neil Armstrong <neil.armstrong@linaro.org>
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
items:
- const: retroidpocket,nova-panel
- const: ilitek,ili7836a
reg:
maxItems: 1
description: DSI virtual channel
vddio-supply: true
avdd-supply: true
backlight: true
port: true
reset-gpios: true
rotation: true
required:
- compatible
- reg
- vddio-supply
- avdd-supply
- reset-gpios
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
dsi {
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "retroidpocket,nova-panel", "ilitek,ili7836a";
reg = <0>;
vddio-supply = <&vdd_disp_1v8>;
avdd-supply = <&vdd_disp2_2v8>;
reset-gpios = <&tlmm 133 GPIO_ACTIVE_HIGH>;
};
};
...

View File

@ -0,0 +1,83 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/novatek,nt36532.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Novatek NT36532 based DSI display Panels
maintainers:
- Junjie Cao <junjie.cao@linux.dev>
description: |
The NT36532 IC from Novatek is a Driver IC used to drive MIPI-DSI panels.
allOf:
- $ref: panel-common-dual.yaml#
properties:
compatible:
items:
- enum:
- csot,ppc100hb1-1
- const: novatek,nt36532
reg:
maxItems: 1
reset-gpios:
maxItems: 1
description: phandle of gpio for reset line - This should be 8mA
vddio-supply:
description: regulator that supplies the I/O voltage
ports: true
required:
- compatible
- reg
- vddio-supply
- reset-gpios
- ports
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
dsi {
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "csot,ppc100hb1-1", "novatek,nt36532";
reg = <0>;
reset-gpios = <&tlmm 133 GPIO_ACTIVE_LOW>;
vddio-supply = <&vreg_l12b_1p8>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
panel_in_0: endpoint {
remote-endpoint = <&dsi0_out>;
};
};
port@1 {
reg = <1>;
panel_in_1: endpoint {
remote-endpoint = <&dsi1_out>;
};
};
};
};
};
...

View File

@ -34,7 +34,7 @@ required:
- compatible
- reg
additionalProperties: false
unevaluatedProperties: false
examples:
- |

View File

@ -29,21 +29,6 @@ refactorings already and are an expert in the specific area
Subsystem-wide refactorings
===========================
Open-code drm_simple_encoder_init()
-----------------------------------
The helper drm_simple_encoder_init() was supposed to simplify encoder
initialization. Instead it only added an intermediate layer between atomic
modesetting and the DRM driver.
The task here is to remove drm_simple_encoder_init(). Search for a driver
that calls drm_simple_encoder_init() and inline the helper. The driver will
also need its own instance of drm_encoder_funcs.
Contact: Thomas Zimmermann, respective driver maintainer
Level: Easy
Replace struct drm_simple_display_pipe with regular atomic helpers
------------------------------------------------------------------

View File

@ -8340,6 +8340,13 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: Documentation/devicetree/bindings/display/panel/novatek,nt36523.yaml
F: drivers/gpu/drm/panel/panel-novatek-nt36523.c
DRM DRIVER FOR NOVATEK NT36532 PANELS
M: Junjie Cao <junjie.cao@linux.dev>
S: Maintained
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: Documentation/devicetree/bindings/display/panel/novatek,nt36532.yaml
F: drivers/gpu/drm/panel/panel-novatek-nt36532.c
DRM DRIVER FOR NOVATEK NT36672A PANELS
M: Sumit Semwal <sumit.semwal@linaro.org>
S: Maintained
@ -9069,6 +9076,21 @@ F: include/drm/drm_gpuvm.h
F: rust/helpers/drm_gpuvm.c
F: rust/kernel/drm/gpuvm/
DRM GPUSVM
M: Matthew Brost <matthew.brost@intel.com>
R: Thomas Hellström <thomas.hellstrom@linux.intel.com>
R: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
R: Honglei Huang <honghuan@amd.com>
L: dri-devel@lists.freedesktop.org
S: Supported
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: drivers/gpu/drm/drm_gpusvm.c
F: drivers/gpu/drm/drm_pagemap.c
F: drivers/gpu/drm/drm_pagemap_util.c
F: include/drm/drm_gpusvm.h
F: include/drm/drm_pagemap.h
F: include/drm/drm_pagemap_util.h
DRM LOG
M: Jocelyn Falempe <jfalempe@redhat.com>
M: Javier Martinez Canillas <javierm@redhat.com>

View File

@ -799,6 +799,7 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
for (i = 0; i < ARRAY_SIZE(priv->cmd_buf); i++) {
if (!priv->cmd_buf[i])
continue;
amdxdna_gem_heap_free(client, priv->cmd_buf[i]);
drm_gem_object_put(to_gobj(priv->cmd_buf[i]));
}
amdxdna_gem_unpin(heap);
@ -836,8 +837,14 @@ void aie2_hwctx_fini(struct amdxdna_hwctx *hwctx)
drm_sched_fini(&hwctx->priv->sched);
aie2_ctx_syncobj_destroy(hwctx);
for (idx = 0; idx < ARRAY_SIZE(hwctx->priv->cmd_buf); idx++)
for (idx = 0; idx < ARRAY_SIZE(hwctx->priv->cmd_buf); idx++) {
/*
* The open/close will never be called for driver allocated
* dev bo. Call amdxdna_gem_heap_free explicitly.
*/
amdxdna_gem_heap_free(hwctx->client, hwctx->priv->cmd_buf[idx]);
drm_gem_object_put(to_gobj(hwctx->priv->cmd_buf[idx]));
}
amdxdna_gem_unpin(hwctx->priv->heap);
drm_gem_object_put(to_gobj(hwctx->priv->heap));

View File

@ -37,6 +37,7 @@ amdxdna_init_dev_bo(struct amdxdna_gem_obj *dev_bo)
struct amdxdna_gem_obj *heap;
u64 heap_addr, exp_heap_uva;
u32 heap_id;
int ret;
if (xa_empty(&client->dev_heap_xa)) {
XDNA_DBG(xdna, "Empty heap xa");
@ -58,24 +59,32 @@ amdxdna_init_dev_bo(struct amdxdna_gem_obj *dev_bo)
heap = xa_load(&client->dev_heap_xa, heap_id);
exp_heap_uva = amdxdna_gem_uva(heap);
heap_addr = amdxdna_gem_dev_addr(heap);
dev_bo->heap_start_id = heap_id;
dev_bo->mem.uva = dev_bo->mm_node.start - heap_addr + exp_heap_uva;
for (; heap_id < client->dev_heap_nid; heap_id++) {
heap = xa_load(&client->dev_heap_xa, heap_id);
if (!heap) {
XDNA_ERR(xdna, "Failed to load heap %d", heap_id);
return -EINVAL;
ret = -EINVAL;
goto cleanup_heap_xa;
}
heap_addr = amdxdna_gem_uva(heap);
if (heap_addr == AMDXDNA_INVALID_ADDR) {
XDNA_ERR(xdna, "Heap %d is not mapped", heap_id);
return -EAGAIN;
ret = -EAGAIN;
goto cleanup_heap_xa;
}
if (heap_addr != exp_heap_uva) {
XDNA_ERR(xdna, "Heap %d uva is not contiguous", heap_id);
return -EINVAL;
ret = -EINVAL;
goto cleanup_heap_xa;
}
ret = xa_insert(&dev_bo->heap_xa, heap_id, heap, GFP_KERNEL);
if (ret) {
ret = -ENOMEM;
goto cleanup_heap_xa;
}
if (heap->dev_addr + heap->mem.size >=
@ -87,12 +96,15 @@ amdxdna_init_dev_bo(struct amdxdna_gem_obj *dev_bo)
if (heap_id == client->dev_heap_nid) {
XDNA_DBG(xdna, "Can not find heap end");
return -EAGAIN;
ret = -EAGAIN;
goto cleanup_heap_xa;
}
dev_bo->heap_end_id = heap_id;
return 0;
cleanup_heap_xa:
xa_destroy(&dev_bo->heap_xa);
return ret;
}
static int
@ -132,8 +144,7 @@ amdxdna_gem_heap_alloc(struct amdxdna_gem_obj *abo)
}
client->heap_usage += mem->size;
xa_for_each_range(&client->dev_heap_xa, heap_id, heap,
abo->heap_start_id, abo->heap_end_id)
xa_for_each(&abo->heap_xa, heap_id, heap)
drm_gem_object_get(to_gobj(heap));
unlock_out:
@ -142,22 +153,13 @@ amdxdna_gem_heap_alloc(struct amdxdna_gem_obj *abo)
return ret;
}
static void
amdxdna_gem_heap_free(struct amdxdna_gem_obj *abo)
void amdxdna_gem_heap_free(struct amdxdna_client *client, struct amdxdna_gem_obj *abo)
{
struct amdxdna_client *client = abo->client;
struct amdxdna_gem_obj *heap;
unsigned long heap_id;
mutex_lock(&client->mm_lock);
drm_mm_remove_node(&abo->mm_node);
client->heap_usage -= abo->mem.size;
xa_for_each_range(&client->dev_heap_xa, heap_id, heap,
abo->heap_start_id, abo->heap_end_id)
drm_gem_object_put(to_gobj(heap));
mutex_unlock(&client->mm_lock);
}
@ -180,6 +182,7 @@ amdxdna_gem_create_obj(struct drm_device *dev, size_t size)
abo->open_ref = 0;
abo->internal = false;
INIT_LIST_HEAD(&abo->mem.umap_list);
xa_init_flags(&abo->heap_xa, XA_FLAGS_ALLOC);
return abo;
}
@ -253,13 +256,16 @@ static bool amdxdna_hmm_invalidate(struct mmu_interval_notifier *mni,
struct amdxdna_gem_obj *abo = mapp->abo;
struct amdxdna_dev *xdna;
if (!mmu_notifier_range_blockable(range))
return false;
if (mapp->unmapped)
return true;
xdna = to_xdna_dev(to_gobj(abo)->dev);
XDNA_DBG(xdna, "Invalidating range 0x%lx, 0x%lx, type %d",
mapp->range.start, mapp->range.end, abo->type);
if (!mmu_notifier_range_blockable(range))
return false;
down_write(&xdna->notifier_lock);
abo->mem.map_invalid = true;
mapp->invalid = true;
@ -301,33 +307,40 @@ static void amdxdna_hmm_unregister(struct amdxdna_gem_obj *abo,
down_write(&xdna->notifier_lock);
list_for_each_entry(mapp, &abo->mem.umap_list, node) {
if (!vma || compare_range(mapp, vma->vm_mm, vma->vm_start, vma->vm_end)) {
if (!mapp->unmapped) {
queue_work(xdna->notifier_wq, &mapp->hmm_unreg_work);
mapp->unmapped = true;
}
if (vma)
break;
}
if (!compare_range(mapp, vma->vm_mm, vma->vm_start, vma->vm_end))
continue;
queue_work(xdna->notifier_wq, &mapp->hmm_unreg_work);
mapp->unmapped = true;
}
up_write(&xdna->notifier_lock);
}
static void amdxdna_hmm_unregister_all(struct amdxdna_gem_obj *abo)
{
struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev);
struct amdxdna_umap *mapp, *tmp;
LIST_HEAD(dead);
down_write(&xdna->notifier_lock);
list_for_each_entry_safe(mapp, tmp, &abo->mem.umap_list, node) {
mapp->unmapped = true;
mapp->cleanup = true;
list_move(&mapp->node, &dead);
}
up_write(&xdna->notifier_lock);
list_for_each_entry_safe(mapp, tmp, &dead, node) {
cancel_work_sync(&mapp->hmm_unreg_work);
amdxdna_umap_put(mapp);
}
}
static void amdxdna_umap_release(struct kref *ref)
{
struct amdxdna_umap *mapp = container_of(ref, struct amdxdna_umap, refcnt);
struct amdxdna_gem_obj *abo = mapp->abo;
struct amdxdna_dev *xdna;
mmu_interval_notifier_remove(&mapp->notifier);
xdna = to_xdna_dev(to_gobj(mapp->abo)->dev);
down_write(&xdna->notifier_lock);
list_del(&mapp->node);
if (list_empty(&abo->mem.umap_list))
abo->mem.uva = AMDXDNA_INVALID_ADDR;
up_write(&xdna->notifier_lock);
kvfree(mapp->range.hmm_pfns);
kfree(mapp);
}
@ -341,6 +354,20 @@ static void amdxdna_hmm_unreg_work(struct work_struct *work)
{
struct amdxdna_umap *mapp = container_of(work, struct amdxdna_umap,
hmm_unreg_work);
struct amdxdna_gem_obj *abo = mapp->abo;
struct amdxdna_dev *xdna;
xdna = to_xdna_dev(to_gobj(mapp->abo)->dev);
down_write(&xdna->notifier_lock);
if (mapp->cleanup) {
up_write(&xdna->notifier_lock);
return;
}
list_del(&mapp->node);
if (list_empty(&abo->mem.umap_list))
abo->mem.uva = AMDXDNA_INVALID_ADDR;
up_write(&xdna->notifier_lock);
amdxdna_umap_put(mapp);
}
@ -425,13 +452,18 @@ static void amdxdna_gem_dev_obj_free(struct drm_gem_object *gobj)
{
struct amdxdna_dev *xdna = to_xdna_dev(gobj->dev);
struct amdxdna_gem_obj *abo = to_xdna_obj(gobj);
struct amdxdna_gem_obj *heap;
unsigned long heap_id;
XDNA_DBG(xdna, "BO type %d xdna_addr 0x%llx", abo->type, amdxdna_gem_dev_addr(abo));
if (abo->pinned)
amdxdna_gem_unpin(abo);
amdxdna_gem_vunmap(abo);
amdxdna_gem_heap_free(abo);
xa_for_each(&abo->heap_xa, heap_id, heap)
drm_gem_object_put(to_gobj(heap));
xa_destroy(&abo->heap_xa);
drm_gem_object_release(gobj);
amdxdna_gem_destroy_obj(abo);
}
@ -643,8 +675,7 @@ static void amdxdna_gem_obj_free(struct drm_gem_object *gobj)
struct amdxdna_dev *xdna = to_xdna_dev(gobj->dev);
struct amdxdna_gem_obj *abo = to_xdna_obj(gobj);
amdxdna_hmm_unregister(abo, NULL);
flush_workqueue(xdna->notifier_wq);
amdxdna_hmm_unregister_all(abo);
if (abo->pinned)
amdxdna_gem_unpin(abo);
@ -734,19 +765,72 @@ static void amdxdna_gem_obj_vunmap(struct drm_gem_object *obj, struct iosys_map
drm_gem_shmem_object_vunmap(obj, map);
}
static int amdxdna_gem_dev_obj_open(struct drm_gem_object *gobj, struct drm_file *filp)
{
struct amdxdna_gem_obj *abo = to_xdna_obj(gobj);
guard(mutex)(&abo->lock);
if (filp->driver_priv != abo->client)
return -EPERM;
abo->open_ref++;
return 0;
}
static void amdxdna_gem_dev_obj_close(struct drm_gem_object *gobj, struct drm_file *filp)
{
struct amdxdna_gem_obj *abo = to_xdna_obj(gobj);
struct amdxdna_client *client = NULL;
mutex_lock(&abo->lock);
abo->open_ref--;
/*
* Freeing the heap allocation here, when the handle is closed, is
* intentional. DEV BOs are carved out of a per-client drm_mm heap;
* any subsequent allocation that lands on the same device address will
* also belong to the same client. If the user closes the handle while
* a job is still in flight the only consequence is self-inflicted
* corruption within their own context -- it cannot affect other
* processes. The GEM reference held by the in-flight job keeps the
* amdxdna_gem_obj struct alive until the job completes; it does not
* prevent the device address from being reclaimed by the allocator.
*
* Cross-process handle creation for DEV BOs is rejected in
* amdxdna_gem_dev_obj_open(), which prevents the following UAF:
* if a second process shared the handle via GEM flink and the
* original creator exited (freeing client), the importer would later
* reach open_ref == 0 here and call amdxdna_gem_heap_free() with a
* dangling abo->client pointer. Because cross-process opens are
* rejected, the process arriving here is always the owning client,
* which is still alive. abo->client is nulled out afterwards so that
* any code path running on a lingering GEM reference (e.g. an
* in-flight job) cannot silently dereference a stale pointer.
*/
if (abo->open_ref == 0) {
client = abo->client;
abo->client = NULL;
}
mutex_unlock(&abo->lock);
if (client)
amdxdna_gem_heap_free(client, abo);
}
static int amdxdna_gem_dev_obj_vmap(struct drm_gem_object *obj, struct iosys_map *map)
{
struct amdxdna_gem_obj *abo = to_xdna_obj(obj);
struct amdxdna_gem_obj *heap;
unsigned long index = 0;
void *base;
u64 offset;
/* vmap dev bo which is across more than 1 heap is not allowed */
if (abo->heap_start_id != abo->heap_end_id)
heap = xa_find(&abo->heap_xa, &index, ULONG_MAX, XA_PRESENT);
if (!heap)
return -ENOMEM;
heap = xa_load(&abo->client->dev_heap_xa, abo->heap_start_id);
if (!heap)
/* vmap dev bo which is across more than 1 heap is not allowed */
if (xa_find_after(&abo->heap_xa, &index, ULONG_MAX, XA_PRESENT))
return -ENOMEM;
base = amdxdna_gem_vmap(heap);
@ -765,6 +849,8 @@ static struct dma_buf *amdxdna_gem_dev_obj_export(struct drm_gem_object *gobj, i
static const struct drm_gem_object_funcs amdxdna_gem_dev_obj_funcs = {
.free = amdxdna_gem_dev_obj_free,
.open = amdxdna_gem_dev_obj_open,
.close = amdxdna_gem_dev_obj_close,
.vmap = amdxdna_gem_dev_obj_vmap,
.export = amdxdna_gem_dev_obj_export,
};
@ -1103,6 +1189,8 @@ int amdxdna_drm_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_f
args->handle, args->type, amdxdna_gem_uva(abo),
amdxdna_gem_dev_addr(abo), abo->mem.size);
put_obj:
if (ret && abo->type == AMDXDNA_BO_DEV)
amdxdna_gem_heap_free(client, abo);
/* Dereference object reference. Handle holds it now. */
drm_gem_object_put(to_gobj(abo));
return ret;
@ -1136,7 +1224,6 @@ static void amdxdna_bo_unpin(struct amdxdna_gem_obj *abo)
int amdxdna_gem_pin_nolock(struct amdxdna_gem_obj *abo)
{
struct amdxdna_client *client = abo->client;
struct amdxdna_gem_obj *heap;
unsigned long heap_id, last = ULONG_MAX;
int ret = 0;
@ -1144,17 +1231,15 @@ int amdxdna_gem_pin_nolock(struct amdxdna_gem_obj *abo)
if (abo->type != AMDXDNA_BO_DEV)
return amdxdna_bo_pin(abo);
xa_for_each_range(&client->dev_heap_xa, heap_id, heap,
abo->heap_start_id, abo->heap_end_id) {
xa_for_each(&abo->heap_xa, heap_id, heap) {
ret = amdxdna_bo_pin(heap);
if (ret)
break;
last = heap_id;
}
if (ret && last <= abo->heap_end_id) {
xa_for_each_range(&client->dev_heap_xa, heap_id, heap,
abo->heap_start_id, last)
if (ret && last != ULONG_MAX) {
xa_for_each_range(&abo->heap_xa, heap_id, heap, 0, last)
amdxdna_bo_unpin(heap);
}
@ -1179,8 +1264,7 @@ void amdxdna_gem_unpin(struct amdxdna_gem_obj *abo)
struct amdxdna_gem_obj *heap;
unsigned long heap_id;
xa_for_each_range(&abo->client->dev_heap_xa, heap_id, heap,
abo->heap_start_id, abo->heap_end_id)
xa_for_each(&abo->heap_xa, heap_id, heap)
amdxdna_bo_unpin(heap);
} else {
amdxdna_bo_unpin(abo);
@ -1300,8 +1384,7 @@ int amdxdna_drm_sync_bo_ioctl(struct drm_device *dev,
u64 flush_start = bo_start + args->offset;
u64 flush_end = flush_start + args->size;
xa_for_each_range(&client->dev_heap_xa, heap_id, heap,
abo->heap_start_id, abo->heap_end_id) {
xa_for_each(&abo->heap_xa, heap_id, heap) {
u64 heap_start = amdxdna_gem_dev_addr(heap);
u64 heap_end = heap_start + heap->mem.size;
u64 start = max(flush_start, heap_start);

View File

@ -20,6 +20,7 @@ struct amdxdna_umap {
struct kref refcnt;
bool invalid;
bool unmapped;
bool cleanup;
};
struct amdxdna_mem {
@ -46,8 +47,7 @@ struct amdxdna_gem_obj {
/* Below members are initialized when needed */
struct drm_mm_node mm_node; /* For AMDXDNA_BO_DEV */
u32 heap_start_id;
u32 heap_end_id;
struct xarray heap_xa;
u64 dev_addr; /* For heap bo */
u32 assigned_hwctx;
struct dma_buf *dma_buf;
@ -104,6 +104,7 @@ static inline u64 amdxdna_obj_dma_addr(struct amdxdna_gem_obj *abo)
}
void amdxdna_umap_put(struct amdxdna_umap *mapp);
void amdxdna_gem_heap_free(struct amdxdna_client *client, struct amdxdna_gem_obj *abo);
struct drm_gem_object *
amdxdna_gem_create_shmem_object_cb(struct drm_device *dev, size_t size);

View File

@ -345,10 +345,8 @@ int ethosu_job_init(struct ethosu_device *edev)
ethosu_job_irq_handler_thread,
IRQF_SHARED, KBUILD_MODNAME,
edev);
if (ret) {
dev_err(dev, "failed to request irq\n");
if (ret)
return ret;
}
edev->fence_context = dma_fence_context_alloc(1);

View File

@ -91,7 +91,7 @@
drm_warn(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__)
#define ivpu_warn_ratelimited(vdev, fmt, ...) \
drm_err_ratelimited(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__)
drm_warn_ratelimited(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__)
#define ivpu_info(vdev, fmt, ...) drm_info(&(vdev)->drm, fmt, ##__VA_ARGS__)

View File

@ -15,6 +15,7 @@
#include <linux/math64.h>
#include <linux/mm.h>
#include <linux/moduleparam.h>
#include <linux/overflow.h>
#include <linux/scatterlist.h>
#include <linux/spinlock.h>
#include <linux/srcu.h>
@ -455,7 +456,12 @@ static int create_sgt(struct qaic_device *qdev, struct sg_table **sgt_out, u64 s
int order;
if (size) {
nr_pages = DIV_ROUND_UP(size, PAGE_SIZE);
u64 nr_pages_u64 = DIV_ROUND_UP_ULL(size, PAGE_SIZE);
if (overflows_type(nr_pages_u64, int))
return -E2BIG;
nr_pages = nr_pages_u64;
/*
* calculate how much extra we are going to allocate, to remove
* later

View File

@ -5,6 +5,7 @@
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/device-id/mhi.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/mhi.h>

View File

@ -4,6 +4,7 @@
/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */
#include <linux/delay.h>
#include <linux/device-id/mhi.h>
#include <linux/dma-mapping.h>
#include <linux/idr.h>
#include <linux/interrupt.h>

View File

@ -5,6 +5,7 @@
#include <asm/byteorder.h>
#include <linux/device.h>
#include <linux/device-id/mhi.h>
#include <linux/kernel.h>
#include <linux/mhi.h>

View File

@ -8,6 +8,7 @@
#include <drm/drm_managed.h>
#include <linux/devcoredump.h>
#include <linux/device.h>
#include <linux/device-id/mhi.h>
#include <linux/kernel.h>
#include <linux/mhi.h>
#include <linux/workqueue.h>

View File

@ -2,6 +2,7 @@
/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */
#include <linux/device-id/mhi.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/math64.h>

View File

@ -3,6 +3,7 @@
/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */
#include <linux/devcoredump.h>
#include <linux/device-id/mhi.h>
#include <linux/firmware.h>
#include <linux/limits.h>
#include <linux/mhi.h>

View File

@ -260,7 +260,7 @@ static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence)
/* only support discovering the end of the buffer,
* but also allow SEEK_SET to maintain the idiomatic
* SEEK_END(0), SEEK_CUR(0) pattern.
* SEEK_END(0), SEEK_SET(0) pattern.
*/
if (whence == SEEK_END)
base = dmabuf->size;

View File

@ -633,7 +633,7 @@ int dma_resv_get_singleton(struct dma_resv *obj, enum dma_resv_usage usage,
int r;
r = dma_resv_get_fences(obj, usage, &count, &fences);
if (r)
if (r)
return r;
if (count == 0) {

File diff suppressed because it is too large Load Diff

View File

@ -351,7 +351,7 @@ static const struct drm_crtc_funcs adp_crtc_funcs = {
.destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.reset = drm_atomic_helper_crtc_reset,
.atomic_create_state = drm_atomic_helper_crtc_create_state,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.enable_vblank = adp_crtc_enable_vblank,

View File

@ -36,7 +36,6 @@
#include "dc/inc/hw/dmcu.h"
#include "dc/inc/hw/abm.h"
#include "dc/dc_dmub_srv.h"
#include "dc/dc_edid_parser.h"
#include "dc/dc_stat.h"
#include "dc/dc_state.h"
#include "amdgpu_dm_trace.h"
@ -2883,7 +2882,8 @@ STATIC_IFN_KUNIT bool modereset_required(struct drm_crtc_state *crtc_state)
EXPORT_IF_KUNIT(modereset_required);
STATIC_IFN_KUNIT int
fill_plane_color_attributes(const struct drm_plane_state *plane_state,
fill_plane_color_attributes(struct drm_atomic_commit *state,
const struct drm_plane_state *plane_state,
const enum surface_pixel_format format,
enum dc_color_space *color_space)
{
@ -2892,7 +2892,7 @@ fill_plane_color_attributes(const struct drm_plane_state *plane_state,
*color_space = COLOR_SPACE_SRGB;
/* Ignore properties when DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE is set */
if (plane_state->state && plane_state->state->plane_color_pipeline)
if (state && state->plane_color_pipeline)
return 0;
/* DRM color properties only affect non-RGB formats. */
@ -2933,6 +2933,7 @@ EXPORT_IF_KUNIT(fill_plane_color_attributes);
static int
fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
struct drm_atomic_commit *state,
const struct drm_plane_state *plane_state,
struct dc_plane_info *plane_info,
struct dc_plane_address *address,
@ -3025,7 +3026,7 @@ fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
plane_info->layer_index = plane_state->normalized_zpos;
ret = fill_plane_color_attributes(plane_state, plane_info->format,
ret = fill_plane_color_attributes(state, plane_state, plane_info->format,
&plane_info->color_space);
if (ret)
return ret;
@ -3066,7 +3067,7 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev,
dc_plane_state->clip_rect = scaling_info.clip_rect;
dc_plane_state->scaling_quality = scaling_info.scaling_quality;
ret = fill_dc_plane_info_and_addr(adev, plane_state,
ret = fill_dc_plane_info_and_addr(adev, plane_state->state, plane_state,
&plane_info,
&dc_plane_state->address,
afb->tmz_surface);
@ -3903,11 +3904,13 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
}
fill_dc_plane_info_and_addr(
dm->adev, new_plane_state,
dm->adev, state, new_plane_state,
&bundle->plane_infos[planes_count],
&bundle->flip_addrs[planes_count].address,
afb->tmz_surface);
bundle->plane_infos[planes_count].color_space = dc_plane->color_space;
drm_dbg_state(state->dev, "plane: id=%d dcc_en=%d\n",
new_plane_state->plane->index,
bundle->plane_infos[planes_count].dcc.enable);
@ -5897,6 +5900,19 @@ static int dm_update_plane_state(struct dc *dc,
if (ret)
goto out;
/*
* Recreating the plane re-derives its DC color pipeline from the
* colorop states in this commit. Pull the plane's colorops in so
* the derivation sees the current pipeline; otherwise every stage
* silently defaults to bypass (dropping YUV->RGB, shaper, 3D LUT
* and regamma) when userspace didn't touch color in this commit.
*/
if (new_plane_state->color_pipeline) {
ret = drm_atomic_add_affected_colorops(state, plane);
if (ret)
goto out;
}
WARN_ON(dm_new_plane_state->dc_state);
dc_new_plane_state = dc_create_plane_state(dc);

View File

@ -1172,9 +1172,10 @@ struct dm_atomic_state *dm_atomic_get_new_state(struct drm_atomic_commit *state)
void dm_atomic_destroy_state(struct drm_private_obj *obj,
struct drm_private_state *state);
int dm_plane_layer_index_cmp(const void *a, const void *b);
int fill_plane_color_attributes(const struct drm_plane_state *plane_state,
const enum surface_pixel_format format,
enum dc_color_space *color_space);
int fill_plane_color_attributes(struct drm_atomic_commit *state,
const struct drm_plane_state *plane_state,
const enum surface_pixel_format format,
enum dc_color_space *color_space);
bool modereset_required(struct drm_crtc_state *crtc_state);
bool is_scaling_state_different(const struct dm_connector_state *dm_state,
const struct dm_connector_state *old_dm_state);

View File

@ -1551,6 +1551,8 @@ __set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state,
struct dc_transfer_func *tf = &dc_plane_state->in_transfer_func;
struct drm_colorop *colorop = colorop_state->colorop;
struct drm_device *drm = colorop->dev;
struct dc_color_caps *color_caps = NULL;
bool is_subsampled_format;
if (colorop->type != DRM_COLOROP_1D_CURVE)
return -EINVAL;
@ -1564,14 +1566,82 @@ __set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state,
}
drm_dbg(drm, "Degamma colorop with ID: %d\n", colorop->base.id);
tf->type = TF_TYPE_PREDEFINED;
/* Check if format requires post-scale color processing (subsampled formats) */
is_subsampled_format = (dc_plane_state->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN &&
dc_plane_state->format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END);
tf->tf = amdgpu_colorop_tf_to_dc_tf(colorop_state->curve_1d_type);
if (dc_plane_state->ctx && dc_plane_state->ctx->dc)
color_caps = &dc_plane_state->ctx->dc->caps.color;
if (!mod_color_calculate_degamma_params(color_caps, tf, NULL,
is_subsampled_format)) {
drm_err(drm, "Failed to calculate degamma params\n");
return -EINVAL;
}
return 0;
}
EXPORT_IF_KUNIT(__set_colorop_in_tf_1d_curve);
static int
__set_dm_plane_colorop_fixed_matrix(struct drm_plane_state *plane_state,
struct dc_plane_state *dc_plane_state,
struct drm_colorop *colorop)
{
struct drm_colorop *old_colorop;
struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
struct drm_atomic_commit *state = plane_state->state;
int i = 0;
old_colorop = colorop;
for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
if (new_colorop_state->colorop == old_colorop) {
colorop_state = new_colorop_state;
break;
}
}
if (!colorop_state)
return -EINVAL;
if (colorop_state->bypass) {
dc_plane_state->color_space = COLOR_SPACE_SRGB;
return 0;
}
switch (colorop_state->fixed_matrix_type) {
case DRM_COLOROP_FM_YCBCR601_FULL_RGB:
dc_plane_state->color_space = COLOR_SPACE_YCBCR601;
break;
case DRM_COLOROP_FM_YCBCR601_LIMITED_RGB:
dc_plane_state->color_space = COLOR_SPACE_YCBCR601_LIMITED;
break;
case DRM_COLOROP_FM_YCBCR709_FULL_RGB:
dc_plane_state->color_space = COLOR_SPACE_YCBCR709;
break;
case DRM_COLOROP_FM_YCBCR709_LIMITED_RGB:
dc_plane_state->color_space = COLOR_SPACE_YCBCR709_LIMITED;
break;
case DRM_COLOROP_FM_YCBCR2020_NC_FULL_RGB:
dc_plane_state->color_space = COLOR_SPACE_2020_YCBCR_FULL;
break;
case DRM_COLOROP_FM_YCBCR2020_NC_LIMITED_RGB:
dc_plane_state->color_space = COLOR_SPACE_2020_YCBCR_LIMITED;
break;
default:
return -EINVAL;
}
dc_plane_state->update_bits.full_update = 1;
return 0;
}
STATIC_IFN_KUNIT int
__set_dm_plane_colorop_degamma(struct drm_plane_state *plane_state,
struct dc_plane_state *dc_plane_state,
@ -1976,10 +2046,21 @@ amdgpu_dm_plane_set_colorop_properties(struct drm_plane_state *plane_state,
bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut || adev->dm.dc->caps.color.mpc.preblend;
int ret;
/* 1D Curve - DEGAM TF */
/* Fixed Matrix (YUV to RGB) */
if (!colorop)
return -EINVAL;
ret = __set_dm_plane_colorop_fixed_matrix(plane_state, dc_plane_state, colorop);
if (ret)
return ret;
/* 1D Curve - DEGAM TF */
colorop = colorop->next;
if (!colorop) {
drm_dbg(dev, "no degamma colorop found\n");
return -EINVAL;
}
ret = __set_dm_plane_colorop_degamma(plane_state, dc_plane_state, colorop);
if (ret)
return ret;

View File

@ -55,6 +55,14 @@ const u64 amdgpu_dm_supported_blnd_tfs =
BIT(DRM_COLOROP_1D_CURVE_GAMMA22);
EXPORT_IF_KUNIT(amdgpu_dm_supported_blnd_tfs);
const u64 amdgpu_dm_supported_fm =
BIT(DRM_COLOROP_FM_YCBCR601_FULL_RGB) |
BIT(DRM_COLOROP_FM_YCBCR601_LIMITED_RGB) |
BIT(DRM_COLOROP_FM_YCBCR709_FULL_RGB) |
BIT(DRM_COLOROP_FM_YCBCR709_LIMITED_RGB) |
BIT(DRM_COLOROP_FM_YCBCR2020_NC_FULL_RGB) |
BIT(DRM_COLOROP_FM_YCBCR2020_NC_LIMITED_RGB);
#define MAX_COLOR_PIPELINE_OPS 10
#define LUT3D_SIZE 17
@ -73,6 +81,23 @@ amdgpu_dm_build_default_pipeline(struct drm_device *dev, struct drm_plane *plane
memset(ops, 0, sizeof(ops));
/* Fixed Matrix (YUV to RGB) */
ops[i] = kzalloc_obj(*ops[0]);
if (!ops[i]) {
ret = -ENOMEM;
goto cleanup;
}
ret = drm_plane_colorop_fixed_matrix_init(dev, ops[i], plane, &dm_colorop_funcs,
amdgpu_dm_supported_fm,
DRM_COLOROP_FLAG_ALLOW_BYPASS);
if (ret)
goto cleanup;
list->type = ops[i]->base.id;
i++;
/* 1D curve - DEGAM TF */
ops[i] = kzalloc_obj(*ops[0]);
if (!ops[i]) {
@ -86,7 +111,7 @@ amdgpu_dm_build_default_pipeline(struct drm_device *dev, struct drm_plane *plane
if (ret)
goto cleanup;
list->type = ops[i]->base.id;
drm_colorop_set_next_property(ops[i - 1], ops[i]);
i++;

View File

@ -30,6 +30,7 @@
extern const u64 amdgpu_dm_supported_degam_tfs;
extern const u64 amdgpu_dm_supported_shaper_tfs;
extern const u64 amdgpu_dm_supported_blnd_tfs;
extern const u64 amdgpu_dm_supported_fm;
int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct drm_prop_enum_list *list);

View File

@ -27,7 +27,6 @@
#include "dm_services_types.h"
#include "dc.h"
#include "dc/dc_dmub_srv.h"
#include "dc/dc_edid_parser.h"
#include "dc/dc_stat.h"
#include "dc/dc_state.h"
#include "dc/dc_stream.h"
@ -3591,139 +3590,6 @@ void dm_restore_drm_connector_state(struct drm_device *dev,
dm_force_atomic_commit(&aconnector->base);
}
static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
unsigned int offset,
unsigned int total_length,
u8 *data,
unsigned int length,
struct amdgpu_hdmi_vsdb_info *vsdb)
{
bool res;
union dmub_rb_cmd cmd;
struct dmub_cmd_send_edid_cea *input;
struct dmub_cmd_edid_cea_output *output;
if (length > DMUB_EDID_CEA_DATA_CHUNK_BYTES)
return false;
memset(&cmd, 0, sizeof(cmd));
input = &cmd.edid_cea.data.input;
cmd.edid_cea.header.type = DMUB_CMD__EDID_CEA;
cmd.edid_cea.header.sub_type = 0;
cmd.edid_cea.header.payload_bytes =
sizeof(cmd.edid_cea) - sizeof(cmd.edid_cea.header);
input->offset = offset;
input->length = length;
input->cea_total_length = total_length;
memcpy(input->payload, data, length);
res = dc_wake_and_execute_dmub_cmd(dm->dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY);
if (!res) {
drm_err(adev_to_drm(dm->adev), "EDID CEA parser failed\n");
return false;
}
output = &cmd.edid_cea.data.output;
if (output->type == DMUB_CMD__EDID_CEA_ACK) {
if (!output->ack.success) {
drm_err(adev_to_drm(dm->adev), "EDID CEA ack failed at offset %d\n",
output->ack.offset);
}
} else if (output->type == DMUB_CMD__EDID_CEA_AMD_VSDB) {
if (!output->amd_vsdb.vsdb_found)
return false;
vsdb->freesync_supported = output->amd_vsdb.freesync_supported;
vsdb->amd_vsdb_version = output->amd_vsdb.amd_vsdb_version;
vsdb->min_refresh_rate_hz = output->amd_vsdb.min_frame_rate;
vsdb->max_refresh_rate_hz = output->amd_vsdb.max_frame_rate;
vsdb->freesync_mccs_vcp_code = output->amd_vsdb.freesync_mccs_vcp_code;
} else {
drm_warn(adev_to_drm(dm->adev), "Unknown EDID CEA parser results\n");
return false;
}
return true;
}
static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm,
u8 *edid_ext, int len,
struct amdgpu_hdmi_vsdb_info *vsdb_info)
{
int i;
/* send extension block to DMCU for parsing */
for (i = 0; i < len; i += 8) {
bool res;
int offset;
/* send 8 bytes a time */
if (!dc_edid_parser_send_cea(dm->dc, i, len, &edid_ext[i], 8))
return false;
if (i+8 == len) {
/* EDID block sent completed, expect result */
int version, min_rate, max_rate;
res = dc_edid_parser_recv_amd_vsdb(dm->dc, &version, &min_rate, &max_rate);
if (res) {
/* amd vsdb found */
vsdb_info->freesync_supported = 1;
vsdb_info->amd_vsdb_version = version;
vsdb_info->min_refresh_rate_hz = min_rate;
vsdb_info->max_refresh_rate_hz = max_rate;
/* Not enabled on DMCU*/
vsdb_info->freesync_mccs_vcp_code = 0;
return true;
}
/* not amd vsdb */
return false;
}
/* check for ack*/
res = dc_edid_parser_recv_cea_ack(dm->dc, &offset);
if (!res)
return false;
}
return false;
}
static bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm,
u8 *edid_ext, int len,
struct amdgpu_hdmi_vsdb_info *vsdb_info)
{
int i;
/* send extension block to DMCU for parsing */
for (i = 0; i < len; i += 8) {
/* send 8 bytes a time */
if (!dm_edid_parser_send_cea(dm, i, len, &edid_ext[i], 8, vsdb_info))
return false;
}
return vsdb_info->freesync_supported;
}
static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
u8 *edid_ext, int len,
struct amdgpu_hdmi_vsdb_info *vsdb_info)
{
struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev);
bool ret;
mutex_lock(&adev->dm.dc_lock);
if (adev->dm.dmub_srv)
ret = parse_edid_cea_dmub(&adev->dm, edid_ext, len, vsdb_info);
else
ret = parse_edid_cea_dmcu(&adev->dm, edid_ext, len, vsdb_info);
mutex_unlock(&adev->dm.dc_lock);
return ret;
}
STATIC_IFN_KUNIT void parse_edid_displayid_vrr(struct drm_connector *connector,
const struct edid *edid)
{
@ -3775,44 +3641,15 @@ STATIC_IFN_KUNIT int get_amd_vsdb(struct amdgpu_dm_connector *aconnector,
vsdb_info->replay_mode = connector->display_info.amd_vsdb.replay_mode;
vsdb_info->amd_vsdb_version = connector->display_info.amd_vsdb.version;
vsdb_info->freesync_supported = connector->display_info.amd_vsdb.freesync_supported;
vsdb_info->min_refresh_rate_hz = connector->display_info.amd_vsdb.min_frame_rate;
vsdb_info->max_refresh_rate_hz = connector->display_info.amd_vsdb.max_frame_rate;
vsdb_info->freesync_mccs_vcp_code = connector->display_info.amd_vsdb.freesync_vcp_code;
return connector->display_info.amd_vsdb.version != 0;
}
EXPORT_IF_KUNIT(get_amd_vsdb);
STATIC_IFN_KUNIT int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
const struct edid *edid,
struct amdgpu_hdmi_vsdb_info *vsdb_info)
{
u8 *edid_ext = NULL;
int i;
bool valid_vsdb_found = false;
/*----- drm_find_cea_extension() -----*/
/* No EDID or EDID extensions */
if (edid == NULL || edid->extensions == 0)
return -ENODEV;
/* Find CEA extension */
for (i = 0; i < edid->extensions; i++) {
edid_ext = (uint8_t *)edid + EDID_LENGTH * (i + 1);
if (edid_ext[0] == CEA_EXT)
break;
}
if (i == edid->extensions)
return -ENODEV;
/*----- cea_db_offsets() -----*/
if (edid_ext[0] != CEA_EXT)
return -ENODEV;
valid_vsdb_found = parse_edid_cea(aconnector, edid_ext, EDID_LENGTH, vsdb_info);
return valid_vsdb_found ? i : -ENODEV;
}
EXPORT_IF_KUNIT(parse_hdmi_amd_vsdb);
/**
* amdgpu_dm_update_freesync_caps - Update Freesync capabilities
*
@ -3831,7 +3668,7 @@ EXPORT_IF_KUNIT(parse_hdmi_amd_vsdb);
void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
const struct drm_edid *drm_edid, bool do_mccs)
{
int i = 0;
bool has_vsdb = 0;
struct amdgpu_dm_connector *amdgpu_dm_connector =
to_amdgpu_dm_connector(connector);
struct dm_connector_state *dm_con_state = NULL;
@ -3876,63 +3713,57 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
connector->display_info.monitor_range.max_vfreq == 0))
parse_edid_displayid_vrr(connector, edid);
if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
sink->sink_signal == SIGNAL_TYPE_EDP)) {
if (amdgpu_dm_connector->dc_link &&
amdgpu_dm_connector->dc_link->dpcd_caps.allow_invalid_MSA_timing_param) {
amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq;
amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq;
if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
freesync_capable = true;
}
has_vsdb = get_amd_vsdb(amdgpu_dm_connector, &vsdb_info) != 0;
get_amd_vsdb(amdgpu_dm_connector, &vsdb_info);
if (has_vsdb) {
amdgpu_dm_connector->vsdb_info = vsdb_info;
/* copy refresh rate info as long as VSDB advertises FreeSync */
if (vsdb_info.freesync_supported) {
amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
connector->display_info.monitor_range.min_vfreq =
vsdb_info.min_refresh_rate_hz;
connector->display_info.monitor_range.max_vfreq =
vsdb_info.max_refresh_rate_hz;
}
} else {
/* fall back to the base EDID range when there is no VSDB */
amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq;
amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq;
}
if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
sink->sink_signal == SIGNAL_TYPE_EDP) {
if (amdgpu_dm_connector->dc_link &&
amdgpu_dm_connector->dc_link->dpcd_caps.allow_invalid_MSA_timing_param &&
amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
freesync_capable = true;
if (vsdb_info.replay_mode) {
amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_info.replay_mode;
amdgpu_dm_connector->vsdb_info.amd_vsdb_version = vsdb_info.amd_vsdb_version;
amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
}
} else if (has_vsdb && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code;
} else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
if (i >= 0) {
amdgpu_dm_connector->vsdb_info = vsdb_info;
sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code;
if (vsdb_info.freesync_supported) {
amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
freesync_capable = true;
connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
}
}
if (vsdb_info.freesync_supported &&
amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
freesync_capable = true;
}
if (amdgpu_dm_connector->dc_link)
as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link);
if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) {
i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
if (i >= 0) {
amdgpu_dm_connector->vsdb_info = vsdb_info;
sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code;
if (has_vsdb && as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) {
sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code;
if (vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) {
amdgpu_dm_connector->pack_sdp_v1_3 = true;
amdgpu_dm_connector->as_type = as_type;
if (vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) {
amdgpu_dm_connector->pack_sdp_v1_3 = true;
amdgpu_dm_connector->as_type = as_type;
amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
freesync_capable = true;
connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
}
if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
freesync_capable = true;
}
}

View File

@ -335,7 +335,7 @@ static void dm_test_fill_color_attr_rgb_format(struct kunit *test)
plane_state.color_encoding = DRM_COLOR_YCBCR_BT709;
plane_state.color_range = DRM_COLOR_YCBCR_FULL_RANGE;
ret = fill_plane_color_attributes(&plane_state,
ret = fill_plane_color_attributes(NULL, &plane_state,
SURFACE_PIXEL_FORMAT_GRPH_ARGB8888,
&color_space);
KUNIT_EXPECT_EQ(test, ret, 0);
@ -355,7 +355,7 @@ static void dm_test_fill_color_attr_bt601_full(struct kunit *test)
plane_state.color_encoding = DRM_COLOR_YCBCR_BT601;
plane_state.color_range = DRM_COLOR_YCBCR_FULL_RANGE;
ret = fill_plane_color_attributes(&plane_state,
ret = fill_plane_color_attributes(NULL, &plane_state,
SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr,
&color_space);
KUNIT_EXPECT_EQ(test, ret, 0);
@ -375,7 +375,7 @@ static void dm_test_fill_color_attr_bt601_limited(struct kunit *test)
plane_state.color_encoding = DRM_COLOR_YCBCR_BT601;
plane_state.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
ret = fill_plane_color_attributes(&plane_state,
ret = fill_plane_color_attributes(NULL, &plane_state,
SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr,
&color_space);
KUNIT_EXPECT_EQ(test, ret, 0);
@ -396,7 +396,7 @@ static void dm_test_fill_color_attr_bt709_full(struct kunit *test)
plane_state.color_encoding = DRM_COLOR_YCBCR_BT709;
plane_state.color_range = DRM_COLOR_YCBCR_FULL_RANGE;
ret = fill_plane_color_attributes(&plane_state,
ret = fill_plane_color_attributes(NULL, &plane_state,
SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr,
&color_space);
KUNIT_EXPECT_EQ(test, ret, 0);
@ -416,7 +416,7 @@ static void dm_test_fill_color_attr_bt709_limited(struct kunit *test)
plane_state.color_encoding = DRM_COLOR_YCBCR_BT709;
plane_state.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
ret = fill_plane_color_attributes(&plane_state,
ret = fill_plane_color_attributes(NULL, &plane_state,
SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr,
&color_space);
KUNIT_EXPECT_EQ(test, ret, 0);
@ -437,7 +437,7 @@ static void dm_test_fill_color_attr_bt2020_full(struct kunit *test)
plane_state.color_encoding = DRM_COLOR_YCBCR_BT2020;
plane_state.color_range = DRM_COLOR_YCBCR_FULL_RANGE;
ret = fill_plane_color_attributes(&plane_state,
ret = fill_plane_color_attributes(NULL, &plane_state,
SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr,
&color_space);
KUNIT_EXPECT_EQ(test, ret, 0);
@ -458,7 +458,7 @@ static void dm_test_fill_color_attr_bt2020_limited(struct kunit *test)
plane_state.color_encoding = DRM_COLOR_YCBCR_BT2020;
plane_state.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
ret = fill_plane_color_attributes(&plane_state,
ret = fill_plane_color_attributes(NULL, &plane_state,
SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr,
&color_space);
KUNIT_EXPECT_EQ(test, ret, 0);
@ -479,7 +479,7 @@ static void dm_test_fill_color_attr_invalid_encoding(struct kunit *test)
plane_state.color_encoding = 99;
plane_state.color_range = DRM_COLOR_YCBCR_FULL_RANGE;
ret = fill_plane_color_attributes(&plane_state,
ret = fill_plane_color_attributes(NULL, &plane_state,
SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr,
&color_space);
KUNIT_EXPECT_EQ(test, ret, -EINVAL);

View File

@ -63,7 +63,6 @@ include $(AMD_DC)
FILES =
FILES += dc_dmub_srv.o
FILES += dc_edid_parser.o
FILES += dc_fused_io.o
FILES += dc_helper.o
FILES += core/dc.o

View File

@ -1,80 +0,0 @@
/*
* Copyright 2021 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#include "dce/dce_dmcu.h"
#include "dc_edid_parser.h"
bool dc_edid_parser_send_cea(struct dc *dc,
int offset,
int total_length,
uint8_t *data,
int length)
{
struct dmcu *dmcu = dc->res_pool->dmcu;
if (dmcu &&
dmcu->funcs->is_dmcu_initialized(dmcu) &&
dmcu->funcs->send_edid_cea) {
return dmcu->funcs->send_edid_cea(dmcu,
offset,
total_length,
data,
length);
}
return false;
}
bool dc_edid_parser_recv_cea_ack(struct dc *dc, int *offset)
{
struct dmcu *dmcu = dc->res_pool->dmcu;
if (dmcu &&
dmcu->funcs->is_dmcu_initialized(dmcu) &&
dmcu->funcs->recv_edid_cea_ack) {
return dmcu->funcs->recv_edid_cea_ack(dmcu, offset);
}
return false;
}
bool dc_edid_parser_recv_amd_vsdb(struct dc *dc,
int *version,
int *min_frame_rate,
int *max_frame_rate)
{
struct dmcu *dmcu = dc->res_pool->dmcu;
if (dmcu &&
dmcu->funcs->is_dmcu_initialized(dmcu) &&
dmcu->funcs->recv_amd_vsdb) {
return dmcu->funcs->recv_amd_vsdb(dmcu,
version,
min_frame_rate,
max_frame_rate);
}
return false;
}

View File

@ -1,44 +0,0 @@
/*
* Copyright 2021 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#ifndef _DC_EDID_PARSER_H_
#define _DC_EDID_PARSER_H_
#include "core_types.h"
bool dc_edid_parser_send_cea(struct dc *dc,
int offset,
int total_length,
uint8_t *data,
int length);
bool dc_edid_parser_recv_cea_ack(struct dc *dc, int *offset);
bool dc_edid_parser_recv_amd_vsdb(struct dc *dc,
int *version,
int *min_frame_rate,
int *max_frame_rate);
#endif /* _DC_EDID_PARSER_H_ */

View File

@ -56,9 +56,6 @@
#define MCP_BL_SET_PWM_FRAC 0x6A /* Enable or disable Fractional PWM */
#define CRC_WIN_NOTIFY 0x92
#define CRC_STOP_UPDATE 0x93
#define MCP_SEND_EDID_CEA 0xA0
#define EDID_CEA_CMD_ACK 1
#define EDID_CEA_CMD_NACK 2
#define MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK 0x00000001L
// PSP FW version
@ -812,121 +809,6 @@ static bool dcn20_unlock_phy(struct dmcu *dmcu)
return true;
}
static bool dcn10_send_edid_cea(struct dmcu *dmcu,
int offset,
int total_length,
uint8_t *data,
int length)
{
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
uint32_t header, data1, data2;
/* If microcontroller is not running, do nothing */
if (dmcu->dmcu_state != DMCU_RUNNING)
return false;
if (length > 8 || length <= 0)
return false;
header = ((uint32_t)offset & 0xFFFF) << 16 | (total_length & 0xFFFF);
data1 = (((uint32_t)data[0]) << 24) | (((uint32_t)data[1]) << 16) |
(((uint32_t)data[2]) << 8) | ((uint32_t)data[3]);
data2 = (((uint32_t)data[4]) << 24) | (((uint32_t)data[5]) << 16) |
(((uint32_t)data[6]) << 8) | ((uint32_t)data[7]);
/* waitDMCUReadyForCmd */
REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
/* setDMCUParam_Cmd */
REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, MCP_SEND_EDID_CEA);
REG_WRITE(MASTER_COMM_DATA_REG1, header);
REG_WRITE(MASTER_COMM_DATA_REG2, data1);
REG_WRITE(MASTER_COMM_DATA_REG3, data2);
/* notifyDMCUMsg */
REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
/* waitDMCUReadyForCmd */
REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
return true;
}
static bool dcn10_get_scp_results(struct dmcu *dmcu,
uint32_t *cmd,
uint32_t *data1,
uint32_t *data2,
uint32_t *data3)
{
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
/* If microcontroller is not running, do nothing */
if (dmcu->dmcu_state != DMCU_RUNNING)
return false;
*cmd = REG_READ(SLAVE_COMM_CMD_REG);
*data1 = REG_READ(SLAVE_COMM_DATA_REG1);
*data2 = REG_READ(SLAVE_COMM_DATA_REG2);
*data3 = REG_READ(SLAVE_COMM_DATA_REG3);
/* clear SCP interrupt */
REG_UPDATE(SLAVE_COMM_CNTL_REG, SLAVE_COMM_INTERRUPT, 0);
return true;
}
static bool dcn10_recv_amd_vsdb(struct dmcu *dmcu,
int *version,
int *min_frame_rate,
int *max_frame_rate)
{
uint32_t data[4];
int cmd, ack, len;
if (!dcn10_get_scp_results(dmcu, &data[0], &data[1], &data[2], &data[3]))
return false;
cmd = data[0] & 0x3FF;
len = (data[0] >> 10) & 0x3F;
ack = data[1];
if (cmd != MCP_SEND_EDID_CEA || ack != EDID_CEA_CMD_ACK || len != 12)
return false;
if ((data[2] & 0xFF)) {
*version = (data[2] >> 8) & 0xFF;
*min_frame_rate = (data[3] >> 16) & 0xFFFF;
*max_frame_rate = data[3] & 0xFFFF;
return true;
}
return false;
}
static bool dcn10_recv_edid_cea_ack(struct dmcu *dmcu, int *offset)
{
uint32_t data[4];
int cmd, ack;
if (!dcn10_get_scp_results(dmcu,
&data[0], &data[1], &data[2], &data[3]))
return false;
cmd = data[0] & 0x3FF;
ack = data[1];
if (cmd != MCP_SEND_EDID_CEA)
return false;
if (ack == EDID_CEA_CMD_ACK)
return true;
*offset = data[2]; /* nack */
return false;
}
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
static void dcn10_forward_crc_window(struct dmcu *dmcu,
struct rect *rect,
@ -1030,9 +912,6 @@ static const struct dmcu_funcs dcn10_funcs = {
.get_psr_state = dcn10_get_dmcu_psr_state,
.set_psr_wait_loop = dcn10_psr_wait_loop,
.get_psr_wait_loop = dcn10_get_psr_wait_loop,
.send_edid_cea = dcn10_send_edid_cea,
.recv_amd_vsdb = dcn10_recv_amd_vsdb,
.recv_edid_cea_ack = dcn10_recv_edid_cea_ack,
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
.forward_crc_window = dcn10_forward_crc_window,
.stop_crc_win_update = dcn10_stop_crc_win_update,

View File

@ -74,16 +74,6 @@ struct dmcu_funcs {
bool (*is_dmcu_initialized)(struct dmcu *dmcu);
bool (*lock_phy)(struct dmcu *dmcu);
bool (*unlock_phy)(struct dmcu *dmcu);
bool (*send_edid_cea)(struct dmcu *dmcu,
int offset,
int total_length,
uint8_t *data,
int length);
bool (*recv_amd_vsdb)(struct dmcu *dmcu,
int *version,
int *min_frame_rate,
int *max_frame_rate);
bool (*recv_edid_cea_ack)(struct dmcu *dmcu, int *offset);
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
void (*forward_crc_window)(struct dmcu *dmcu,
struct rect *rect,

View File

@ -1923,10 +1923,6 @@ enum dmub_cmd_type {
* Command type used for interfacing with DPIA.
*/
DMUB_CMD__DPIA = 77,
/**
* Command type used for EDID CEA parsing
*/
DMUB_CMD__EDID_CEA = 79,
/**
* Command type used for getting usbc cable ID
*/
@ -6886,69 +6882,6 @@ struct dmub_rb_cmd_transmitter_set_phy_fsm {
struct dmub_rb_cmd_transmitter_set_phy_fsm_data data; /**< payload */
};
/**
* Maximum number of bytes a chunk sent to DMUB for parsing
*/
#define DMUB_EDID_CEA_DATA_CHUNK_BYTES 8
/**
* Represent a chunk of CEA blocks sent to DMUB for parsing
*/
struct dmub_cmd_send_edid_cea {
uint16_t offset; /**< offset into the CEA block */
uint8_t length; /**< number of bytes in payload to copy as part of CEA block */
uint16_t cea_total_length; /**< total length of the CEA block */
uint8_t payload[DMUB_EDID_CEA_DATA_CHUNK_BYTES]; /**< data chunk of the CEA block */
uint8_t pad[3]; /**< padding and for future expansion */
};
/**
* Result of VSDB parsing from CEA block
*/
struct dmub_cmd_edid_cea_amd_vsdb {
uint8_t vsdb_found; /**< 1 if parsing has found valid AMD VSDB */
uint8_t freesync_supported; /**< 1 if Freesync is supported */
uint16_t amd_vsdb_version; /**< AMD VSDB version */
uint16_t min_frame_rate; /**< Maximum frame rate */
uint16_t max_frame_rate; /**< Minimum frame rate */
uint8_t freesync_mccs_vcp_code; /**< Freesync MCCS VCP code */
};
/**
* Result of sending a CEA chunk
*/
struct dmub_cmd_edid_cea_ack {
uint16_t offset; /**< offset of the chunk into the CEA block */
uint8_t success; /**< 1 if this sending of chunk succeeded */
uint8_t pad; /**< padding and for future expansion */
};
/**
* Specify whether the result is an ACK/NACK or the parsing has finished
*/
enum dmub_cmd_edid_cea_reply_type {
DMUB_CMD__EDID_CEA_AMD_VSDB = 1, /**< VSDB parsing has finished */
DMUB_CMD__EDID_CEA_ACK = 2, /**< acknowledges the CEA sending is OK or failing */
};
/**
* Definition of a DMUB_CMD__EDID_CEA command.
*/
struct dmub_rb_cmd_edid_cea {
struct dmub_cmd_header header; /**< Command header */
union dmub_cmd_edid_cea_data {
struct dmub_cmd_send_edid_cea input; /**< input to send CEA chunks */
struct dmub_cmd_edid_cea_output { /**< output with results */
uint8_t type; /**< dmub_cmd_edid_cea_reply_type */
union {
struct dmub_cmd_edid_cea_amd_vsdb amd_vsdb;
struct dmub_cmd_edid_cea_ack ack;
};
} output; /**< output to retrieve ACK/NACK or VSDB parsing results */
} data; /**< Command data */
};
/**
* struct dmub_cmd_cable_id_input - Defines the input of DMUB_CMD_GET_USBC_CABLE_ID command.
*/
@ -7801,10 +7734,6 @@ union dmub_rb_cmd {
* Definition of a DMUB_CMD__DPIA_SET_TPS_NOTIFICATION command.
*/
struct dmub_rb_cmd_set_tps_notification set_tps_notification;
/**
* Definition of a DMUB_CMD__EDID_CEA command.
*/
struct dmub_rb_cmd_edid_cea edid_cea;
/**
* Definition of a DMUB_CMD_GET_USBC_CABLE_ID command.
*/

View File

@ -1696,7 +1696,8 @@ bool mod_color_calculate_degamma_params(struct dc_color_caps *dc_caps,
return true;
if (dc_caps != NULL &&
dc_caps->dpp.dcn_arch == 1) {
dc_caps->dpp.dcn_arch == 1 &&
!map_user_ramp) {
if (input_tf->tf == TRANSFER_FUNCTION_PQ &&
dc_caps->dpp.dgam_rom_caps.pq == 1)

View File

@ -8,14 +8,18 @@
#define _MALIDP_PRODUCT_H_
/* Product identification */
/* GLB_CORE_ID fields as per HW specification:
* MINOR is 8 bits ([11:4]) and STATUS is 4 bits ([3:0]).
* Update masks/shifts accordingly.
*/
#define MALIDP_CORE_ID(__product, __major, __minor, __status) \
((((__product) & 0xFFFF) << 16) | (((__major) & 0xF) << 12) | \
(((__minor) & 0xF) << 8) | ((__status) & 0xFF))
(((__minor) & 0xFF) << 4) | ((__status) & 0xF))
#define MALIDP_CORE_ID_PRODUCT_ID(__core_id) ((__u32)(__core_id) >> 16)
#define MALIDP_CORE_ID_MAJOR(__core_id) (((__u32)(__core_id) >> 12) & 0xF)
#define MALIDP_CORE_ID_MINOR(__core_id) (((__u32)(__core_id) >> 8) & 0xF)
#define MALIDP_CORE_ID_STATUS(__core_id) (((__u32)(__core_id)) & 0xFF)
#define MALIDP_CORE_ID_MINOR(__core_id) (((__u32)(__core_id) >> 4) & 0xFF)
#define MALIDP_CORE_ID_STATUS(__core_id) ((__u32)(__core_id) & 0xF)
/* Mali-display product IDs */
#define MALIDP_D71_PRODUCT_ID 0x0071

View File

@ -11,9 +11,9 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_encoder.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <drm/drm_simple_kms_helper.h>
#include <drm/drm_bridge.h>
#include "komeda_dev.h"
@ -493,19 +493,17 @@ static const struct drm_crtc_helper_funcs komeda_crtc_helper_funcs = {
.mode_fixup = komeda_crtc_mode_fixup,
};
static void komeda_crtc_reset(struct drm_crtc *crtc)
static struct drm_crtc_state *komeda_crtc_create_state(struct drm_crtc *crtc)
{
struct komeda_crtc_state *state;
if (crtc->state)
__drm_atomic_helper_crtc_destroy_state(crtc->state);
kfree(to_kcrtc_st(crtc->state));
crtc->state = NULL;
state = kzalloc_obj(*state);
if (state)
__drm_atomic_helper_crtc_reset(crtc, &state->base);
if (!state)
return ERR_PTR(-ENOMEM);
__drm_atomic_helper_crtc_state_init(&state->base, crtc);
return &state->base;
}
static struct drm_crtc_state *
@ -555,7 +553,7 @@ static const struct drm_crtc_funcs komeda_crtc_funcs = {
.destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.reset = komeda_crtc_reset,
.atomic_create_state = komeda_crtc_create_state,
.atomic_duplicate_state = komeda_crtc_atomic_duplicate_state,
.atomic_destroy_state = komeda_crtc_atomic_destroy_state,
.enable_vblank = komeda_crtc_vblank_enable,
@ -635,6 +633,10 @@ static int komeda_attach_bridge(struct device *dev,
return err;
}
static const struct drm_encoder_funcs komeda_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
static int komeda_crtc_add(struct komeda_kms_dev *kms,
struct komeda_crtc *kcrtc)
{
@ -658,7 +660,8 @@ static int komeda_crtc_add(struct komeda_kms_dev *kms,
* bridge
*/
kcrtc->encoder.possible_crtcs = drm_crtc_mask(crtc);
err = drm_simple_encoder_init(base, encoder, DRM_MODE_ENCODER_TMDS);
err = drm_encoder_init(base, encoder, &komeda_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
if (err)
return err;

View File

@ -132,19 +132,17 @@ static void komeda_plane_destroy(struct drm_plane *plane)
kfree(to_kplane(plane));
}
static void komeda_plane_reset(struct drm_plane *plane)
static struct drm_plane_state *komeda_plane_create_state(struct drm_plane *plane)
{
struct komeda_plane_state *state;
if (plane->state)
__drm_atomic_helper_plane_destroy_state(plane->state);
kfree(plane->state);
plane->state = NULL;
state = kzalloc_obj(*state);
if (state)
__drm_atomic_helper_plane_reset(plane, &state->base);
if (!state)
return ERR_PTR(-ENOMEM);
__drm_atomic_helper_plane_state_init(&state->base, plane);
return &state->base;
}
static struct drm_plane_state *
@ -188,7 +186,7 @@ static const struct drm_plane_funcs komeda_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = komeda_plane_destroy,
.reset = komeda_plane_reset,
.atomic_create_state = komeda_plane_create_state,
.atomic_duplicate_state = komeda_plane_atomic_duplicate_state,
.atomic_destroy_state = komeda_plane_atomic_destroy_state,
.format_mod_supported = komeda_plane_format_mod_supported,

View File

@ -143,12 +143,17 @@ static int komeda_wb_connector_add(struct komeda_kms_dev *kms,
struct komeda_wb_connector *kwb_conn;
struct drm_writeback_connector *wb_conn;
struct drm_display_info *info;
struct drm_encoder *encoder;
struct drm_encoder *wb_encoder;
u32 *formats, n_formats = 0;
u32 crtc_mask;
int err;
if (!kcrtc->master->wb_layer)
return 0;
crtc_mask = drm_crtc_mask(&kcrtc->base);
kwb_conn = kzalloc_obj(*kwb_conn);
if (!kwb_conn)
return -ENOMEM;
@ -176,6 +181,34 @@ static int komeda_wb_connector_add(struct komeda_kms_dev *kms,
return err;
}
wb_encoder = &wb_conn->encoder;
/*
* The writeback connector is associated with a single CRTC. Make its
* encoder clone-compatible only with encoders that can drive that CRTC.
*
* possible_clones must contain the encoder's own bit whenever it is
* non-zero. Add both the encoder itself and the writeback encoder when
* updating the reciprocal clone relationship.
*/
wb_encoder->possible_clones = drm_encoder_mask(wb_encoder);
drm_for_each_encoder(encoder, &kms->base) {
u32 encoder_mask;
if (encoder == wb_encoder)
continue;
if (!(encoder->possible_crtcs & crtc_mask))
continue;
encoder_mask = drm_encoder_mask(encoder);
wb_encoder->possible_clones |= encoder_mask;
encoder->possible_clones |= encoder_mask |
drm_encoder_mask(wb_encoder);
}
drm_connector_helper_add(&wb_conn->base, &komeda_wb_conn_helper_funcs);
info = &kwb_conn->base.base.display_info;

View File

@ -67,7 +67,7 @@ static const struct drm_crtc_funcs hdlcd_crtc_funcs = {
.destroy = hdlcd_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.reset = drm_atomic_helper_crtc_reset,
.atomic_create_state = drm_atomic_helper_crtc_create_state,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.enable_vblank = hdlcd_crtc_enable_vblank,
@ -297,7 +297,7 @@ static const struct drm_plane_helper_funcs hdlcd_plane_helper_funcs = {
static const struct drm_plane_funcs hdlcd_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.reset = drm_atomic_helper_plane_reset,
.atomic_create_state = drm_atomic_helper_plane_create_state,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
};

View File

@ -476,17 +476,17 @@ static void malidp_crtc_destroy_state(struct drm_crtc *crtc,
kfree(mali_state);
}
static void malidp_crtc_reset(struct drm_crtc *crtc)
static struct drm_crtc_state *malidp_crtc_create_state(struct drm_crtc *crtc)
{
struct malidp_crtc_state *state = kzalloc_obj(*state);
struct malidp_crtc_state *state;
if (crtc->state)
malidp_crtc_destroy_state(crtc, crtc->state);
state = kzalloc_obj(*state);
if (!state)
return ERR_PTR(-ENOMEM);
if (state)
__drm_atomic_helper_crtc_reset(crtc, &state->base);
else
__drm_atomic_helper_crtc_reset(crtc, NULL);
__drm_atomic_helper_crtc_state_init(&state->base, crtc);
return &state->base;
}
static int malidp_crtc_enable_vblank(struct drm_crtc *crtc)
@ -511,7 +511,7 @@ static void malidp_crtc_disable_vblank(struct drm_crtc *crtc)
static const struct drm_crtc_funcs malidp_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.reset = malidp_crtc_reset,
.atomic_create_state = malidp_crtc_create_state,
.atomic_duplicate_state = malidp_crtc_duplicate_state,
.atomic_destroy_state = malidp_crtc_destroy_state,
.enable_vblank = malidp_crtc_enable_vblank,

View File

@ -73,17 +73,17 @@
* allocate a new empty object. We just need enough space to store
* a malidp_plane_state instead of a drm_plane_state.
*/
static void malidp_plane_reset(struct drm_plane *plane)
static struct drm_plane_state *malidp_plane_create_state(struct drm_plane *plane)
{
struct malidp_plane_state *state = to_malidp_plane_state(plane->state);
struct malidp_plane_state *state;
if (state)
__drm_atomic_helper_plane_destroy_state(&state->base);
kfree(state);
plane->state = NULL;
state = kzalloc_obj(*state);
if (state)
__drm_atomic_helper_plane_reset(plane, &state->base);
if (!state)
return ERR_PTR(-ENOMEM);
__drm_atomic_helper_plane_state_init(&state->base, plane);
return &state->base;
}
static struct
@ -252,7 +252,7 @@ static bool malidp_format_mod_supported_per_plane(struct drm_plane *plane,
static const struct drm_plane_funcs malidp_de_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.reset = malidp_plane_reset,
.atomic_create_state = malidp_plane_create_state,
.atomic_duplicate_state = malidp_duplicate_plane_state,
.atomic_destroy_state = malidp_destroy_plane_state,
.atomic_print_state = malidp_plane_atomic_print_state,

View File

@ -817,7 +817,7 @@ static void armada_drm_crtc_disable_vblank(struct drm_crtc *crtc)
}
static const struct drm_crtc_funcs armada_crtc_funcs = {
.reset = drm_atomic_helper_crtc_reset,
.atomic_create_state = drm_atomic_helper_crtc_create_state,
.cursor_set = armada_drm_crtc_cursor_set,
.cursor_move = armada_drm_crtc_cursor_move,
.destroy = armada_drm_crtc_destroy,

View File

@ -88,8 +88,14 @@ static int ast_astdp_read_edid_block(void *data, u8 *buf, unsigned int block, si
int ret = 0;
unsigned int i;
if (block > 0)
return -EIO; /* extension headers not supported */
if (block > 1) {
/* ASPEED DP's EDID buffer holds blocks 0 and 1 only (256
* bytes). Report anything beyond that as an all-zero block
* rather than a read failure.
*/
memset(buf, 0, len);
return 0;
}
/*
* Protect access to I/O registers from concurrent modesetting
@ -154,20 +160,6 @@ static int ast_astdp_read_edid_block(void *data, u8 *buf, unsigned int block, si
ediddata[2] = ast_get_index_reg(ast, AST_IO_VGACRI, 0xda);
ediddata[3] = ast_get_index_reg(ast, AST_IO_VGACRI, 0xdb);
if (i == 31) {
/*
* For 128-bytes EDID_1.3,
* 1. Add the value of Bytes-126 to Bytes-127.
* The Bytes-127 is Checksum. Sum of all 128bytes should
* equal 0 (mod 256).
* 2. Modify Bytes-126 to be 0.
* The Bytes-126 indicates the Number of extensions to
* follow. 0 represents noextensions.
*/
ediddata[3] = ediddata[3] + ediddata[2];
ediddata[2] = 0;
}
memcpy(buf, ediddata, min((len - i), 4));
buf += 4;
}

View File

@ -888,17 +888,17 @@ static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = {
.atomic_disable = ast_crtc_helper_atomic_disable,
};
static void ast_crtc_reset(struct drm_crtc *crtc)
static struct drm_crtc_state *ast_crtc_create_state(struct drm_crtc *crtc)
{
struct ast_crtc_state *ast_state = kzalloc_obj(*ast_state);
struct ast_crtc_state *ast_state;
if (crtc->state)
crtc->funcs->atomic_destroy_state(crtc, crtc->state);
ast_state = kzalloc_obj(*ast_state);
if (!ast_state)
return ERR_PTR(-ENOMEM);
if (ast_state)
__drm_atomic_helper_crtc_reset(crtc, &ast_state->base);
else
__drm_atomic_helper_crtc_reset(crtc, NULL);
__drm_atomic_helper_crtc_state_init(&ast_state->base, crtc);
return &ast_state->base;
}
static struct drm_crtc_state *
@ -934,7 +934,7 @@ static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc,
}
static const struct drm_crtc_funcs ast_crtc_funcs = {
.reset = ast_crtc_reset,
.atomic_create_state = ast_crtc_create_state,
.destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,

View File

@ -529,20 +529,17 @@ void atmel_hlcdc_crtc_irq(struct drm_crtc *c)
atmel_hlcdc_crtc_finish_page_flip(drm_crtc_to_atmel_hlcdc_crtc(c));
}
static void atmel_hlcdc_crtc_reset(struct drm_crtc *crtc)
static struct drm_crtc_state *atmel_hlcdc_crtc_create_state(struct drm_crtc *crtc)
{
struct atmel_hlcdc_crtc_state *state;
if (crtc->state) {
__drm_atomic_helper_crtc_destroy_state(crtc->state);
state = drm_crtc_state_to_atmel_hlcdc_crtc_state(crtc->state);
kfree(state);
crtc->state = NULL;
}
state = kzalloc_obj(*state);
if (state)
__drm_atomic_helper_crtc_reset(crtc, &state->base);
if (!state)
return ERR_PTR(-ENOMEM);
__drm_atomic_helper_crtc_state_init(&state->base, crtc);
return &state->base;
}
static struct drm_crtc_state *
@ -599,7 +596,7 @@ static void atmel_hlcdc_crtc_disable_vblank(struct drm_crtc *c)
static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
.page_flip = drm_atomic_helper_page_flip,
.set_config = drm_atomic_helper_set_config,
.reset = atmel_hlcdc_crtc_reset,
.atomic_create_state = atmel_hlcdc_crtc_create_state,
.atomic_duplicate_state = atmel_hlcdc_crtc_duplicate_state,
.atomic_destroy_state = atmel_hlcdc_crtc_destroy_state,
.enable_vblank = atmel_hlcdc_crtc_enable_vblank,

View File

@ -225,7 +225,6 @@ config DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW
tristate "MegaChips stdp4028-ge-b850v3-fw and stdp2690-ge-b850v3-fw"
depends on OF
select DRM_KMS_HELPER
select DRM_PANEL
help
This is a driver for the display bridges of
GE B850v3 that convert dual channel LVDS
@ -291,7 +290,7 @@ config DRM_PARADE_PS8640
select DRM_DISPLAY_DP_AUX_BUS
select DRM_KMS_HELPER
select DRM_MIPI_DSI
select DRM_PANEL
select DRM_PANEL_BRIDGE
help
Choose this option if you have PS8640 for display
The PS8640 is a high-performance and low-power
@ -463,7 +462,7 @@ config DRM_TI_SN65DSI83
depends on OF
select DRM_KMS_HELPER
select REGMAP_I2C
select DRM_PANEL
select DRM_PANEL_BRIDGE
select DRM_MIPI_DSI
help
Texas Instruments SN65DSI83 and SN65DSI84 DSI to LVDS Bridge driver
@ -476,10 +475,10 @@ config DRM_TI_SN65DSI86
select DRM_BRIDGE_CONNECTOR
select DRM_KMS_HELPER
select REGMAP_I2C
select DRM_PANEL
select DRM_MIPI_DSI
select AUXILIARY_BUS
select DRM_DISPLAY_DP_AUX_BUS
select DRM_PANEL_BRIDGE
help
Texas Instruments SN65DSI86 DSI to eDP Bridge driver

View File

@ -1414,10 +1414,8 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
analogix_dp_hardirq,
analogix_dp_irq_thread,
irq_flags, "analogix-dp", dp);
if (ret) {
dev_err(&pdev->dev, "failed to request irq\n");
if (ret)
return ERR_PTR(ret);
}
dp->aux.name = "DP-AUX";
dp->aux.transfer = analogix_dpaux_transfer;

View File

@ -2343,7 +2343,6 @@ static int cdns_mhdp_probe(struct platform_device *pdev)
cdns_mhdp_irq_handler, IRQF_ONESHOT,
"mhdp8546", mhdp);
if (ret) {
dev_err(dev, "cannot install IRQ %d\n", irq);
ret = -EIO;
goto plat_fini;
}

View File

@ -531,7 +531,7 @@ static int chipone_dsi_attach(struct chipone *icn)
dsi->hs_rate = 500000000;
dsi->lp_rate = 16000000;
ret = mipi_dsi_attach(dsi);
ret = devm_mipi_dsi_attach(dev, dsi);
if (ret < 0)
dev_err(icn->dev, "failed to attach dsi\n");
@ -763,11 +763,6 @@ static int chipone_i2c_probe(struct i2c_client *client)
return chipone_dsi_host_attach(icn);
}
static void chipone_dsi_remove(struct mipi_dsi_device *dsi)
{
mipi_dsi_detach(dsi);
}
static const struct of_device_id chipone_of_match[] = {
{ .compatible = "chipone,icn6211", },
{ /* sentinel */ }
@ -776,7 +771,6 @@ MODULE_DEVICE_TABLE(of, chipone_of_match);
static struct mipi_dsi_driver chipone_dsi_driver = {
.probe = chipone_dsi_probe,
.remove = chipone_dsi_remove,
.driver = {
.name = "chipone-icn6211",
.of_match_table = chipone_of_match,

View File

@ -3607,10 +3607,8 @@ static int it6505_i2c_probe(struct i2c_client *client)
IRQF_TRIGGER_LOW | IRQF_ONESHOT |
IRQF_NO_AUTOEN,
"it6505-intp", it6505);
if (err) {
dev_err(dev, "Failed to request INTP threaded IRQ: %d", err);
if (err)
return err;
}
INIT_WORK(&it6505->link_works, it6505_link_training_work);
INIT_WORK(&it6505->hdcp_wait_ksv_list, it6505_hdcp_wait_ksv_list);

View File

@ -1156,10 +1156,8 @@ static int lt9611_probe(struct i2c_client *client)
ret = devm_request_threaded_irq(dev, client->irq, NULL,
lt9611_irq_thread_handler,
IRQF_ONESHOT, "lt9611", lt9611);
if (ret) {
dev_err(dev, "failed to request irq\n");
if (ret)
goto err_disable_regulators;
}
i2c_set_clientdata(client, lt9611);

View File

@ -2184,10 +2184,8 @@ int samsung_dsim_probe(struct platform_device *pdev)
samsung_dsim_irq,
IRQF_ONESHOT | IRQF_NO_AUTOEN,
dev_name(dev), dsi);
if (ret) {
dev_err(dev, "failed to request dsi irq\n");
if (ret)
return ret;
}
ret = samsung_dsim_parse_dt(dsi);
if (ret)

View File

@ -2320,8 +2320,7 @@ static int sii8620_probe(struct i2c_client *client)
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"sii8620", ctx);
if (ret < 0)
return dev_err_probe(dev, ret,
"failed to install IRQ handler\n");
return ret;
ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ctx->gpio_reset))

View File

@ -2079,10 +2079,8 @@ struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
ret = devm_request_threaded_irq(dev, dp->irq, NULL, dw_dp_irq,
IRQF_ONESHOT, dev_name(dev), dp);
if (ret) {
dev_err_probe(dev, ret, "failed to request irq\n");
if (ret)
goto unregister_aux;
}
return dp;

View File

@ -3353,7 +3353,7 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
hdmi->channels = 2;
hdmi->disabled = true;
hdmi->rxsense = true;
hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
hdmi->phy_mask = ~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE) & 0xff;
hdmi->mc_clkdis = 0x7f;
hdmi->last_connector_result = connector_status_disconnected;

View File

@ -2530,10 +2530,8 @@ static int tc_probe(struct i2c_client *client)
NULL, tc_irq_handler,
IRQF_ONESHOT,
"tc358767-irq", tc);
if (ret) {
dev_err(dev, "failed to register dp interrupt\n");
if (ret)
return ret;
}
tc->have_irq = true;
}

View File

@ -825,48 +825,35 @@ static int sn65dsi83_select_lvds_vod_swing(struct device *dev,
static int sn65dsi83_parse_lvds_endpoint(struct sn65dsi83 *ctx, int channel)
{
struct device *dev = ctx->dev;
struct device_node *endpoint;
int endpoint_reg;
int endpoint_reg = (channel == CHANNEL_A) ? 2 : 3;
struct device_node *endpoint __free(device_node) =
of_graph_get_endpoint_by_regs(dev->of_node, endpoint_reg, -1);
/* Set so the property can be freely selected if not defined */
u32 lvds_vod_swing_data[2] = { 0, 1000000 };
u32 lvds_vod_swing_clk[2] = { 0, 1000000 };
/* Set default near end terminataion to 200 Ohm */
u32 lvds_term = 200;
int lvds_vod_swing_conf;
int ret = 0;
int ret_data;
int ret_clock;
if (channel == CHANNEL_A)
endpoint_reg = 2;
else
endpoint_reg = 3;
endpoint = of_graph_get_endpoint_by_regs(dev->of_node, endpoint_reg, -1);
of_property_read_u32(endpoint, "ti,lvds-termination-ohms", &lvds_term);
if (lvds_term == 100)
ctx->lvds_term_conf[channel] = OHM_100;
else if (lvds_term == 200)
ctx->lvds_term_conf[channel] = OHM_200;
else {
ret = -EINVAL;
goto exit;
}
else
return -EINVAL;
ret_data = of_property_read_u32_array(endpoint, "ti,lvds-vod-swing-data-microvolt",
lvds_vod_swing_data, ARRAY_SIZE(lvds_vod_swing_data));
if (ret_data != 0 && ret_data != -EINVAL) {
ret = ret_data;
goto exit;
}
if (ret_data != 0 && ret_data != -EINVAL)
return ret_data;
ret_clock = of_property_read_u32_array(endpoint, "ti,lvds-vod-swing-clock-microvolt",
lvds_vod_swing_clk, ARRAY_SIZE(lvds_vod_swing_clk));
if (ret_clock != 0 && ret_clock != -EINVAL) {
ret = ret_clock;
goto exit;
}
if (ret_clock != 0 && ret_clock != -EINVAL)
return ret_clock;
/* Use default value if both properties are NOT defined. */
if (ret_data == -EINVAL && ret_clock == -EINVAL)
@ -876,17 +863,13 @@ static int sn65dsi83_parse_lvds_endpoint(struct sn65dsi83 *ctx, int channel)
if (!ret_data || !ret_clock) {
lvds_vod_swing_conf = sn65dsi83_select_lvds_vod_swing(dev, lvds_vod_swing_data,
lvds_vod_swing_clk, ctx->lvds_term_conf[channel]);
if (lvds_vod_swing_conf < 0) {
ret = lvds_vod_swing_conf;
goto exit;
}
if (lvds_vod_swing_conf < 0)
return lvds_vod_swing_conf;
}
ctx->lvds_vod_swing_conf[channel] = lvds_vod_swing_conf;
ret = 0;
exit:
of_node_put(endpoint);
return ret;
return 0;
}
static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model)
@ -1040,7 +1023,7 @@ static int sn65dsi83_probe(struct i2c_client *client)
ret = devm_request_threaded_irq(ctx->dev, ctx->irq, NULL, sn65dsi83_irq,
IRQF_ONESHOT, dev_name(ctx->dev), ctx);
if (ret)
return dev_err_probe(dev, ret, "failed to request irq\n");
return ret;
}
dev_set_drvdata(dev, ctx);

View File

@ -89,25 +89,21 @@ static void drm_log_blit(struct iosys_map *dst, unsigned int dst_pitch,
}
}
static void drm_log_clear_line(struct drm_log_scanout *scanout, u32 line)
static void drm_log_clear_line(struct drm_log_scanout *scanout, u32 line,
struct iosys_map map)
{
struct drm_framebuffer *fb = scanout->buffer->fb;
unsigned long height = scanout->scaled_font_h;
struct iosys_map map;
struct drm_rect r = DRM_RECT_INIT(0, line * height, fb->width, height);
if (drm_client_buffer_vmap_local(scanout->buffer, &map))
return;
iosys_map_memset(&map, r.y1 * fb->pitches[0], 0, height * fb->pitches[0]);
drm_client_buffer_vunmap_local(scanout->buffer);
drm_client_buffer_flush(scanout->buffer, &r);
}
static void drm_log_draw_line(struct drm_log_scanout *scanout, const char *s,
unsigned int len, unsigned int prefix_len)
unsigned int len, unsigned int prefix_len,
struct iosys_map map)
{
struct drm_framebuffer *fb = scanout->buffer->fb;
struct iosys_map map;
const struct font_desc *font = scanout->font;
size_t font_pitch = DIV_ROUND_UP(font->width, 8);
const u8 *src;
@ -116,10 +112,9 @@ static void drm_log_draw_line(struct drm_log_scanout *scanout, const char *s,
fb->width, (scanout->line + 1) * scanout->scaled_font_h);
u32 i;
if (drm_client_buffer_vmap_local(scanout->buffer, &map))
return;
iosys_map_incr(&map, r.y1 * fb->pitches[0]);
for (i = 0; i < len && i < scanout->columns; i++) {
u32 color = (i < prefix_len) ? scanout->prefix_color : scanout->front_color;
src = font_data_glyph_buf(font->data, font->width, font->height,
@ -134,21 +129,40 @@ static void drm_log_draw_line(struct drm_log_scanout *scanout, const char *s,
scanout->line++;
if (scanout->line >= scanout->rows)
scanout->line = 0;
drm_client_buffer_vunmap_local(scanout->buffer);
drm_client_buffer_flush(scanout->buffer, &r);
}
static void drm_log_draw_new_line(struct drm_log_scanout *scanout,
const char *s, unsigned int len, unsigned int prefix_len)
const char *s, unsigned int len,
unsigned int prefix_len)
{
if (scanout->line == 0) {
drm_log_clear_line(scanout, 0);
drm_log_clear_line(scanout, 1);
drm_log_clear_line(scanout, 2);
} else if (scanout->line + 2 < scanout->rows)
drm_log_clear_line(scanout, scanout->line + 2);
struct iosys_map map;
struct drm_framebuffer *fb = scanout->buffer->fb;
u32 height = scanout->scaled_font_h;
u32 line = scanout->line;
u32 y2;
struct drm_rect dirty;
drm_log_draw_line(scanout, s, len, prefix_len);
if (drm_client_buffer_vmap_local(scanout->buffer, &map))
return;
if (scanout->line == 0) {
drm_log_clear_line(scanout, 0, map);
drm_log_clear_line(scanout, 1, map);
drm_log_clear_line(scanout, 2, map);
y2 = min(3, scanout->rows) * height;
} else if (scanout->line + 2 < scanout->rows) {
drm_log_clear_line(scanout, scanout->line + 2, map);
y2 = (line + 3) * height;
} else {
y2 = (line + 1) * height;
}
drm_log_draw_line(scanout, s, len, prefix_len, map);
drm_client_buffer_vunmap_local(scanout->buffer);
dirty = DRM_RECT_INIT(0, line * height, fb->width, y2 - line * height);
drm_client_buffer_flush(scanout->buffer, &dirty);
}
/*

View File

@ -263,6 +263,9 @@ static void drm_bridge_connector_debugfs_init(struct drm_connector *connector,
if (bridge->funcs->debugfs_init)
bridge->funcs->debugfs_init(bridge, root);
}
if (bridge_connector->bridge_hdmi)
drm_hdmi_connector_debugfs_init(connector, root);
}
static struct drm_connector_state *

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: MIT
#include <linux/debugfs.h>
#include <linux/export.h>
#include <drm/drm_atomic.h>
@ -12,6 +13,7 @@
#include <drm/display/drm_hdmi_cec_helper.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
#include <drm/display/drm_scdc_helper.h>
/**
* DOC: hdmi helpers
@ -965,6 +967,160 @@ drm_hdmi_connector_mode_valid(struct drm_connector *connector,
}
EXPORT_SYMBOL(drm_hdmi_connector_mode_valid);
static ssize_t
audio_infoframe_read(struct file *filp, char __user *ubuf, size_t count, loff_t *ppos)
{
struct drm_connector_hdmi_infoframe *infoframe;
struct drm_connector *connector;
union hdmi_infoframe *frame;
u8 buf[HDMI_INFOFRAME_SIZE(AUDIO)];
ssize_t len = 0;
connector = filp->private_data;
mutex_lock(&connector->hdmi.infoframes.lock);
infoframe = &connector->hdmi.infoframes.audio;
if (!infoframe->set)
goto out;
frame = &infoframe->data;
len = hdmi_infoframe_pack(frame, buf, sizeof(buf));
if (len < 0)
goto out;
len = simple_read_from_buffer(ubuf, count, ppos, buf, len);
out:
mutex_unlock(&connector->hdmi.infoframes.lock);
return len;
}
static const struct file_operations audio_infoframe_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = audio_infoframe_read,
};
static int create_hdmi_audio_infoframe_file(struct drm_connector *connector,
struct dentry *parent)
{
struct dentry *file;
if (!connector->hdmi.funcs ||
!connector->hdmi.funcs->audio.write_infoframe)
return 0;
file = debugfs_create_file("audio", 0400, parent, connector, &audio_infoframe_fops);
if (IS_ERR(file))
return PTR_ERR(file);
return 0;
}
#define DEFINE_INFOFRAME_FILE(_f) \
static ssize_t _f##_read_infoframe(struct file *filp, \
char __user *ubuf, \
size_t count, \
loff_t *ppos) \
{ \
struct drm_connector_hdmi_infoframe *infoframe; \
struct drm_connector_state *conn_state; \
struct drm_connector *connector; \
union hdmi_infoframe *frame; \
struct drm_device *dev; \
u8 buf[HDMI_INFOFRAME_SIZE(MAX)]; \
ssize_t len = 0; \
\
connector = filp->private_data; \
dev = connector->dev; \
\
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); \
\
conn_state = connector->state; \
infoframe = &conn_state->hdmi.infoframes._f; \
if (!infoframe->set) \
goto out; \
\
frame = &infoframe->data; \
len = hdmi_infoframe_pack(frame, buf, sizeof(buf)); \
if (len < 0) \
goto out; \
\
len = simple_read_from_buffer(ubuf, count, ppos, buf, len); \
\
out: \
drm_modeset_unlock(&dev->mode_config.connection_mutex); \
return len; \
} \
\
static const struct file_operations _f##_infoframe_fops = { \
.owner = THIS_MODULE, \
.open = simple_open, \
.read = _f##_read_infoframe, \
}; \
\
static int create_hdmi_## _f ## _infoframe_file(struct drm_connector *connector, \
struct dentry *parent) \
{ \
struct dentry *file; \
\
if (!connector->hdmi.funcs || \
!connector->hdmi.funcs->_f.write_infoframe) \
return 0; \
file = debugfs_create_file(#_f, 0400, parent, connector, &_f ## _infoframe_fops); \
if (IS_ERR(file)) \
return PTR_ERR(file); \
\
return 0; \
}
DEFINE_INFOFRAME_FILE(avi);
DEFINE_INFOFRAME_FILE(hdmi);
DEFINE_INFOFRAME_FILE(hdr_drm);
DEFINE_INFOFRAME_FILE(spd);
static int create_hdmi_infoframe_files(struct drm_connector *connector,
struct dentry *parent)
{
int ret;
ret = create_hdmi_audio_infoframe_file(connector, parent);
if (ret)
return ret;
ret = create_hdmi_avi_infoframe_file(connector, parent);
if (ret)
return ret;
ret = create_hdmi_hdmi_infoframe_file(connector, parent);
if (ret)
return ret;
ret = create_hdmi_hdr_drm_infoframe_file(connector, parent);
if (ret)
return ret;
ret = create_hdmi_spd_infoframe_file(connector, parent);
if (ret)
return ret;
return 0;
}
void drm_hdmi_connector_debugfs_init(struct drm_connector *connector,
struct dentry *root)
{
struct dentry *dir;
dir = debugfs_create_dir("infoframes", root);
if (IS_ERR(dir))
return;
create_hdmi_infoframe_files(connector, dir);
drm_scdc_debugfs_init(connector, root);
}
EXPORT_SYMBOL(drm_hdmi_connector_debugfs_init);
static int clear_infoframe(struct drm_connector *connector,
const struct drm_connector_infoframe_funcs *funcs,
const char *type)

View File

@ -21,10 +21,13 @@
* DEALINGS IN THE SOFTWARE.
*/
#include <linux/bitfield.h>
#include <linux/export.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/overflow.h>
#include <drm/display/drm_scdc_helper.h>
#include <drm/drm_connector.h>
@ -55,6 +58,38 @@
#define SCDC_I2C_SLAVE_ADDRESS 0x54
static const char *drm_scdc_frl_rate_str(enum drm_scdc_frl_rate rate)
{
switch (rate) {
case SCDC_FRL_RATE_OFF:
return "Off";
case SCDC_FRL_RATE_3X3:
return "3 Gbit/s x 3 lanes";
case SCDC_FRL_RATE_6X3:
return "6 Gbit/s x 3 lanes";
case SCDC_FRL_RATE_6X4:
return "6 Gbit/s x 4 lanes";
case SCDC_FRL_RATE_8X4:
return "8 Gbit/s x 4 lanes";
case SCDC_FRL_RATE_10X4:
return "10 Gbit/s x 4 lanes";
case SCDC_FRL_RATE_12X4:
return "12 Gbit/s x 4 lanes";
case SCDC_FRL_RATE_RESV_7:
case SCDC_FRL_RATE_RESV_8:
case SCDC_FRL_RATE_RESV_9:
case SCDC_FRL_RATE_RESV_10:
case SCDC_FRL_RATE_RESV_11:
case SCDC_FRL_RATE_RESV_12:
case SCDC_FRL_RATE_RESV_13:
case SCDC_FRL_RATE_RESV_14:
case SCDC_FRL_RATE_RESV_15:
return "(Reserved)";
default:
return NULL;
}
}
/**
* drm_scdc_read - read a block of data from SCDC
* @adapter: I2C controller
@ -67,8 +102,8 @@
* Returns:
* 0 on success, negative error code on failure.
*/
ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
size_t size)
int drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
size_t size)
{
int ret;
struct i2c_msg msgs[2] = {
@ -107,8 +142,8 @@ EXPORT_SYMBOL(drm_scdc_read);
* Returns:
* 0 on success, negative error code on failure.
*/
ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset,
const void *buffer, size_t size)
int drm_scdc_write(struct i2c_adapter *adapter, u8 offset, const void *buffer,
size_t size)
{
struct i2c_msg msg = {
.addr = SCDC_I2C_SLAVE_ADDRESS,
@ -276,3 +311,249 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector,
return true;
}
EXPORT_SYMBOL(drm_scdc_set_high_tmds_clock_ratio);
static void
drm_scdc_parse_status0_flags(u8 val, struct drm_scdc_status_flags *flags)
{
flags->clock_detected = val & SCDC_CLOCK_DETECT;
flags->ch0_locked = val & SCDC_CH0_LOCK;
flags->ch1_locked = val & SCDC_CH1_LOCK;
flags->ch2_locked = val & SCDC_CH2_LOCK;
flags->ln3_locked = val & SCDC_LN3_LOCK;
flags->flt_ready = val & SCDC_FLT_READY;
flags->dsc_fail = val & SCDC_DSC_FAIL;
}
static void
drm_scdc_parse_status1_2_flags(u8 val_flag1, u8 val_flag2,
struct drm_scdc_status_flags *flags)
{
flags->ln0_training_pattern = FIELD_GET(SCDC_LN_EVEN_TRAIN_PTRN, val_flag1);
flags->ln1_training_pattern = FIELD_GET(SCDC_LN_ODD_TRAIN_PTRN, val_flag1);
flags->ln2_training_pattern = FIELD_GET(SCDC_LN_EVEN_TRAIN_PTRN, val_flag2);
flags->ln3_training_pattern = FIELD_GET(SCDC_LN_ODD_TRAIN_PTRN, val_flag2);
}
static int drm_scdc_parse_error_counters(const u8 scdc[256], u16 counter[4],
unsigned int num_lanes)
{
u8 end_reg;
u8 sum = 0;
int i;
switch (num_lanes) {
case 3:
end_reg = SCDC_ERR_DET_CHECKSUM;
break;
case 4:
end_reg = SCDC_ERR_DET_3_H;
break;
default:
return -EINVAL;
}
for (i = SCDC_ERR_DET_0_L; i <= end_reg; i++)
sum = wrapping_add(u8, sum, scdc[i]);
if (sum)
return -EPROTO;
for (i = 0; i < 3; i++) {
if (scdc[SCDC_ERR_DET_0_H + i * 2] & SCDC_CHANNEL_VALID)
counter[i] = (scdc[SCDC_ERR_DET_0_H + i * 2] &
~SCDC_CHANNEL_VALID) << 8 |
scdc[SCDC_ERR_DET_0_L + i * 2];
else
counter[i] = 0;
}
if (num_lanes == 4 && scdc[SCDC_ERR_DET_3_H] & SCDC_CHANNEL_VALID)
counter[3] = (scdc[SCDC_ERR_DET_3_H] & ~SCDC_CHANNEL_VALID) << 8 |
scdc[SCDC_ERR_DET_3_L];
else
counter[3] = 0;
return 0;
}
/**
* drm_scdc_read_state - Update state from SCDC
* @connector: pointer to a &struct drm_connector on which to operate on
* @state: pointer to a &struct drm_scdc_state to fill
*
* Reads the entire 256 byte SCDC state and parses it.
*
* Returns: %0 on success, negative errno on failure.
*/
int drm_scdc_read_state(struct drm_connector *connector, struct drm_scdc_state *state)
{
struct i2c_adapter *ddc;
struct drm_scdc *scdc;
u8 *buf = state->scdc;
int num_lanes;
int ret;
if (!state || !connector)
return -ENODEV;
scdc = &connector->display_info.hdmi.scdc;
ddc = connector->ddc;
if (!scdc->supported || !ddc)
return -EOPNOTSUPP;
/* Read in 128-byte chunks, to work around DP<->HDMI converters with issues. */
ret = drm_scdc_read(ddc, 0, buf, 128);
if (ret)
return ret;
ret = drm_scdc_read(ddc, 128, &buf[128], 128);
if (ret)
return ret;
state->scrambling_enabled = buf[SCDC_TMDS_CONFIG] & SCDC_SCRAMBLING_ENABLE;
state->tmds_bclk_x40 = buf[SCDC_TMDS_CONFIG] & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40;
state->scrambling_detected = buf[SCDC_SCRAMBLER_STATUS] & SCDC_SCRAMBLING_STATUS;
state->rate = FIELD_GET(SCDC_FRL_RATE, buf[SCDC_CONFIG_1]);
num_lanes = drm_scdc_num_frl_lanes(state->rate);
if (num_lanes < 0)
return num_lanes;
if (!num_lanes)
num_lanes = 3;
state->ffe_levels = FIELD_GET(SCDC_FFE_LEVELS, buf[SCDC_CONFIG_1]);
drm_scdc_parse_status0_flags(buf[SCDC_STATUS_FLAGS_0], &state->stf);
drm_scdc_parse_status1_2_flags(buf[SCDC_STATUS_FLAGS_1],
buf[SCDC_STATUS_FLAGS_2], &state->stf);
ret = drm_scdc_parse_error_counters(buf, state->error_count, num_lanes);
if (ret)
return ret;
if (state->rate && (buf[SCDC_ERR_DET_RS_H] & SCDC_CHANNEL_VALID))
state->rs_corrections = (buf[SCDC_ERR_DET_RS_H] & ~SCDC_CHANNEL_VALID) << 8 |
buf[SCDC_ERR_DET_RS_L];
return 0;
}
EXPORT_SYMBOL(drm_scdc_read_state);
#define scdc_print_str(_f, key, s) \
(seq_printf((_f), "%-30s: %s\n", (key), (s)))
#define scdc_print_flag(_f, key, val) \
(scdc_print_str((_f), (key), str_yes_no((val))))
#define scdc_print_dec(_f, key, val) \
(seq_printf((_f), "%-30s: %d\n", (key), (val)))
static int scdc_status_show(struct seq_file *m, void *data)
{
struct drm_connector *connector = m->private;
struct drm_scdc *scdc = &connector->display_info.hdmi.scdc;
struct drm_scdc_state *st;
int i, ret, frl_lanes;
drm_connector_get(connector);
ret = mutex_lock_interruptible(&connector->dev->mode_config.mutex);
if (ret)
goto err_conn_put;
if (connector->status != connector_status_connected) {
ret = -ENODEV;
goto err_unlock;
}
if (scdc->supported) {
st = kzalloc_obj(*st);
if (!st) {
ret = -ENOMEM;
goto err_unlock;
}
ret = drm_scdc_read_state(connector, st);
if (ret)
goto err_free_state;
for (i = 0; i < ARRAY_SIZE(st->scdc); i += 16)
seq_printf(m, "%*ph\n", 16, &st->scdc[i]);
seq_puts(m, "\n----------------\n\n");
}
scdc_print_flag(m, "SCDC Supported", scdc->supported);
if (!scdc->supported) {
ret = 0;
goto err_unlock;
}
scdc_print_flag(m, "Sink Read Request Capable", scdc->read_request);
scdc_print_flag(m, "Scrambling Supported", scdc->scrambling.supported);
scdc_print_flag(m, "Low Rate Scrambling Supported", scdc->scrambling.low_rates);
mutex_unlock(&connector->dev->mode_config.mutex);
drm_connector_put(connector);
frl_lanes = drm_scdc_num_frl_lanes(st->rate);
scdc_print_flag(m, "Scrambling Enabled", st->scrambling_enabled);
scdc_print_flag(m, "Scrambling Detected", st->scrambling_detected);
scdc_print_str(m, "FRL Rate", drm_scdc_frl_rate_str(st->rate));
scdc_print_dec(m, "FFE Levels", st->ffe_levels);
if (st->tmds_bclk_x40)
scdc_print_str(m, "TMDS Bit Clock Ratio", "1/40");
else
scdc_print_str(m, "TMDS Bit Clock Ratio", "1/10");
scdc_print_flag(m, "Clock Detected", st->stf.clock_detected);
scdc_print_flag(m, "Channel 0 Locked", st->stf.ch0_locked);
scdc_print_flag(m, "Channel 1 Locked", st->stf.ch1_locked);
scdc_print_flag(m, "Channel 2 Locked", st->stf.ch2_locked);
if (frl_lanes == 4)
scdc_print_flag(m, "Lane 3 Locked", st->stf.ln3_locked);
scdc_print_flag(m, "Sink Ready For Link Training", st->stf.flt_ready);
scdc_print_flag(m, "Sink Failed To Decode DSC", st->stf.dsc_fail);
scdc_print_dec(m, "Channel 0 Errors", st->error_count[0]);
scdc_print_dec(m, "Channel 1 Errors", st->error_count[1]);
scdc_print_dec(m, "Channel 2 Errors", st->error_count[2]);
if (frl_lanes == 4)
scdc_print_dec(m, "Lane 3 Errors", st->error_count[3]);
if (frl_lanes > 0)
scdc_print_dec(m, "Reed-Solomon Corrections", st->rs_corrections);
kfree(st);
return 0;
err_free_state:
kfree(st);
err_unlock:
mutex_unlock(&connector->dev->mode_config.mutex);
err_conn_put:
drm_connector_put(connector);
return ret;
}
DEFINE_SHOW_ATTRIBUTE(scdc_status);
/**
* drm_scdc_debugfs_init - Initialize scdc files in connector debugfs
* @connector: pointer to &struct drm_connector to operate on
* @root: debugfs &struct dentry for the debugfs root of @connector
*
* Creates SCDC-related debugfs files for @connector. Must be called after
* @root is already created.
*/
void drm_scdc_debugfs_init(struct drm_connector *connector, struct dentry *root)
{
if (!root || !connector)
return;
debugfs_create_file("scdc_status", 0444, root, connector, &scdc_status_fops);
}
EXPORT_SYMBOL(drm_scdc_debugfs_init);

View File

@ -925,6 +925,10 @@ static void drm_atomic_colorop_print_state(struct drm_printer *p,
drm_get_colorop_lut3d_interpolation_name(state->lut3d_interpolation));
drm_printf_indent(p, 1, "data blob id=%d\n", state->data ? state->data->base.id : 0);
break;
case DRM_COLOROP_FIXED_MATRIX:
drm_printf_indent(p, 1, "fixed_matrix_type=%s\n",
drm_get_colorop_fixed_matrix_type_name(state->fixed_matrix_type));
break;
default:
break;
}

View File

@ -786,6 +786,11 @@ static int drm_atomic_colorop_set_property(struct drm_colorop *colorop,
return drm_atomic_color_set_data_property(colorop, state,
property, val,
replaced);
} else if (property == colorop->fixed_matrix_type_property) {
if (state->fixed_matrix_type != val) {
state->fixed_matrix_type = val;
*replaced = true;
}
} else {
drm_dbg_atomic(colorop->dev,
"[COLOROP:%d:%d] unknown property [PROP:%d:%s]\n",
@ -818,6 +823,8 @@ drm_atomic_colorop_get_property(struct drm_colorop *colorop,
*val = state->lut3d_interpolation;
else if (property == colorop->data_property)
*val = (state->data) ? state->data->base.id : 0;
else if (property == colorop->fixed_matrix_type_property)
*val = state->fixed_matrix_type;
else
return -EINVAL;

View File

@ -44,7 +44,8 @@ void drm_buddy_print(struct gpu_buddy *mm, struct drm_printer *p)
gpu_buddy_driver_lock_held(mm);
drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB, clear_free: %lluMiB\n",
mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, mm->clear_avail >> 20);
mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20,
gpu_buddy_clear_avail(mm) >> 20);
for (order = mm->max_order; order >= 0; order--) {
u64 free_count = mm->free_scoreboard[order];

View File

@ -68,6 +68,7 @@ static const struct drm_prop_enum_list drm_colorop_type_enum_list[] = {
{ DRM_COLOROP_CTM_3X4, "3x4 Matrix"},
{ DRM_COLOROP_MULTIPLIER, "Multiplier"},
{ DRM_COLOROP_3D_LUT, "3D LUT"},
{ DRM_COLOROP_FIXED_MATRIX, "Fixed Matrix"},
};
static const char * const colorop_curve_1d_type_names[] = {
@ -90,6 +91,15 @@ static const struct drm_prop_enum_list drm_colorop_lut3d_interpolation_list[] =
{ DRM_COLOROP_LUT3D_INTERPOLATION_TETRAHEDRAL, "Tetrahedral" },
};
static const char * const colorop_fixed_matrix_type_names[] = {
[DRM_COLOROP_FM_YCBCR601_FULL_RGB] = "YCbCr 601 Full to RGB",
[DRM_COLOROP_FM_YCBCR601_LIMITED_RGB] = "YCbCr 601 Limited to RGB",
[DRM_COLOROP_FM_YCBCR709_FULL_RGB] = "YCbCr 709 Full to RGB",
[DRM_COLOROP_FM_YCBCR709_LIMITED_RGB] = "YCbCr 709 Limited to RGB",
[DRM_COLOROP_FM_YCBCR2020_NC_FULL_RGB] = "YCbCr 2020 NC Full to RGB",
[DRM_COLOROP_FM_YCBCR2020_NC_LIMITED_RGB] = "YCbCr 2020 NC Limited to RGB",
};
/* Init Helpers */
static int drm_plane_colorop_init(struct drm_device *dev, struct drm_colorop *colorop,
@ -453,6 +463,80 @@ int drm_plane_colorop_3dlut_init(struct drm_device *dev, struct drm_colorop *col
}
EXPORT_SYMBOL(drm_plane_colorop_3dlut_init);
/**
* drm_plane_colorop_fixed_matrix_init - Initialize a DRM_COLOROP_FIXED_MATRIX
*
* @dev: DRM device
* @colorop: The drm_colorop object to initialize
* @plane: The associated drm_plane
* @funcs: control functions for the new colorop
* @supported_fm: A bitfield of supported drm_colorop_fixed_matrix_type enum values,
* created using BIT(fixed_matrix_type) and combined with the OR '|'
* operator.
* @flags: bitmask of misc, see DRM_COLOROP_FLAG_* defines.
* @return zero on success, -E value on failure
*/
int drm_plane_colorop_fixed_matrix_init(struct drm_device *dev, struct drm_colorop *colorop,
struct drm_plane *plane,
const struct drm_colorop_funcs *funcs,
u64 supported_fm, uint32_t flags)
{
struct drm_prop_enum_list enum_list[DRM_COLOROP_FM_COUNT];
int i, len;
struct drm_property *prop;
int ret;
if (!supported_fm) {
drm_err(dev,
"No supported FM type op for new Fixed Matrix colorop on [PLANE:%d:%s]\n",
plane->base.id, plane->name);
return -EINVAL;
}
if ((supported_fm & -BIT(DRM_COLOROP_FM_COUNT)) != 0) {
drm_err(dev, "Unknown Fixed Matrix provided on [PLANE:%d:%s]\n",
plane->base.id, plane->name);
return -EINVAL;
}
ret = drm_plane_colorop_init(dev, colorop, plane, funcs, DRM_COLOROP_FIXED_MATRIX, flags);
if (ret)
return ret;
len = 0;
for (i = 0; i < DRM_COLOROP_FM_COUNT; i++) {
if ((supported_fm & BIT(i)) == 0)
continue;
enum_list[len].type = i;
enum_list[len].name = colorop_fixed_matrix_type_names[i];
len++;
}
if (WARN_ON(len <= 0))
return -EINVAL;
prop = drm_property_create_enum(dev, DRM_MODE_PROP_ATOMIC, "FIXED_MATRIX_TYPE",
enum_list, len);
if (!prop)
return -ENOMEM;
colorop->fixed_matrix_type_property = prop;
/*
* Default to the first supported CSC mode as provided by the driver.
* Intuitively this should be something that keeps the colorop in pixel bypass
* mode but that is already handled via the standard colorop bypass
* property.
*/
drm_object_attach_property(&colorop->base, colorop->fixed_matrix_type_property,
enum_list[0].type);
drm_colorop_reset(colorop);
return 0;
}
EXPORT_SYMBOL(drm_plane_colorop_fixed_matrix_init);
static void __drm_atomic_helper_colorop_duplicate_state(struct drm_colorop *colorop,
struct drm_colorop_state *state)
{
@ -533,6 +617,13 @@ static void __drm_colorop_state_init(struct drm_colorop_state *colorop_state,
&val))
colorop_state->lut3d_interpolation = val;
}
if (colorop->fixed_matrix_type_property) {
if (!drm_object_property_get_default_value(&colorop->base,
colorop->fixed_matrix_type_property,
&val))
colorop_state->fixed_matrix_type = val;
}
}
/**
@ -596,6 +687,7 @@ static const char * const colorop_type_name[] = {
[DRM_COLOROP_CTM_3X4] = "3x4 Matrix",
[DRM_COLOROP_MULTIPLIER] = "Multiplier",
[DRM_COLOROP_3D_LUT] = "3D LUT",
[DRM_COLOROP_FIXED_MATRIX] = "Fixed Matrix",
};
static const char * const colorop_lu3d_interpolation_name[] = {
@ -652,6 +744,21 @@ const char *drm_get_colorop_lut3d_interpolation_name(enum drm_colorop_lut3d_inte
return colorop_lu3d_interpolation_name[type];
}
/**
* drm_get_colorop_fixed_matrix_type_name: return a string for fixed matrix type
* @type: fixed matrix type to compute name of
*
* In contrast to the other drm_get_*_name functions this one here returns a
* const pointer and hence is threadsafe.
*/
const char *drm_get_colorop_fixed_matrix_type_name(enum drm_colorop_fixed_matrix_type type)
{
if (WARN_ON(type >= ARRAY_SIZE(colorop_fixed_matrix_type_names)))
return "unknown";
return colorop_fixed_matrix_type_names[type];
}
/**
* drm_colorop_set_next_property - sets the next pointer
* @colorop: drm colorop

View File

@ -633,161 +633,6 @@ static const struct file_operations drm_connector_fops = {
.write = connector_write
};
static ssize_t
audio_infoframe_read(struct file *filp, char __user *ubuf, size_t count, loff_t *ppos)
{
struct drm_connector_hdmi_infoframe *infoframe;
struct drm_connector *connector;
union hdmi_infoframe *frame;
u8 buf[HDMI_INFOFRAME_SIZE(AUDIO)];
ssize_t len = 0;
connector = filp->private_data;
mutex_lock(&connector->hdmi.infoframes.lock);
infoframe = &connector->hdmi.infoframes.audio;
if (!infoframe->set)
goto out;
frame = &infoframe->data;
len = hdmi_infoframe_pack(frame, buf, sizeof(buf));
if (len < 0)
goto out;
len = simple_read_from_buffer(ubuf, count, ppos, buf, len);
out:
mutex_unlock(&connector->hdmi.infoframes.lock);
return len;
}
static const struct file_operations audio_infoframe_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = audio_infoframe_read,
};
static int create_hdmi_audio_infoframe_file(struct drm_connector *connector,
struct dentry *parent)
{
struct dentry *file;
if (!connector->hdmi.funcs ||
!connector->hdmi.funcs->audio.write_infoframe)
return 0;
file = debugfs_create_file("audio", 0400, parent, connector, &audio_infoframe_fops);
if (IS_ERR(file))
return PTR_ERR(file);
return 0;
}
#define DEFINE_INFOFRAME_FILE(_f) \
static ssize_t _f##_read_infoframe(struct file *filp, \
char __user *ubuf, \
size_t count, \
loff_t *ppos) \
{ \
struct drm_connector_hdmi_infoframe *infoframe; \
struct drm_connector_state *conn_state; \
struct drm_connector *connector; \
union hdmi_infoframe *frame; \
struct drm_device *dev; \
u8 buf[HDMI_INFOFRAME_SIZE(MAX)]; \
ssize_t len = 0; \
\
connector = filp->private_data; \
dev = connector->dev; \
\
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); \
\
conn_state = connector->state; \
infoframe = &conn_state->hdmi.infoframes._f; \
if (!infoframe->set) \
goto out; \
\
frame = &infoframe->data; \
len = hdmi_infoframe_pack(frame, buf, sizeof(buf)); \
if (len < 0) \
goto out; \
\
len = simple_read_from_buffer(ubuf, count, ppos, buf, len); \
\
out: \
drm_modeset_unlock(&dev->mode_config.connection_mutex); \
return len; \
} \
\
static const struct file_operations _f##_infoframe_fops = { \
.owner = THIS_MODULE, \
.open = simple_open, \
.read = _f##_read_infoframe, \
}; \
\
static int create_hdmi_## _f ## _infoframe_file(struct drm_connector *connector, \
struct dentry *parent) \
{ \
struct dentry *file; \
\
if (!connector->hdmi.funcs || \
!connector->hdmi.funcs->_f.write_infoframe) \
return 0; \
file = debugfs_create_file(#_f, 0400, parent, connector, &_f ## _infoframe_fops); \
if (IS_ERR(file)) \
return PTR_ERR(file); \
\
return 0; \
}
DEFINE_INFOFRAME_FILE(avi);
DEFINE_INFOFRAME_FILE(hdmi);
DEFINE_INFOFRAME_FILE(hdr_drm);
DEFINE_INFOFRAME_FILE(spd);
static int create_hdmi_infoframe_files(struct drm_connector *connector,
struct dentry *parent)
{
int ret;
ret = create_hdmi_audio_infoframe_file(connector, parent);
if (ret)
return ret;
ret = create_hdmi_avi_infoframe_file(connector, parent);
if (ret)
return ret;
ret = create_hdmi_hdmi_infoframe_file(connector, parent);
if (ret)
return ret;
ret = create_hdmi_hdr_drm_infoframe_file(connector, parent);
if (ret)
return ret;
ret = create_hdmi_spd_infoframe_file(connector, parent);
if (ret)
return ret;
return 0;
}
static void hdmi_debugfs_add(struct drm_connector *connector)
{
struct dentry *dir;
if (!(connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
connector->connector_type == DRM_MODE_CONNECTOR_HDMIB))
return;
dir = debugfs_create_dir("infoframes", connector->debugfs_entry);
if (IS_ERR(dir))
return;
create_hdmi_infoframe_files(connector, dir);
}
void drm_debugfs_connector_add(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
@ -815,8 +660,6 @@ void drm_debugfs_connector_add(struct drm_connector *connector)
debugfs_create_file("output_bpc", 0444, root, connector,
&output_bpc_fops);
hdmi_debugfs_add(connector);
if (connector->funcs->debugfs_init)
connector->funcs->debugfs_init(connector, root);
}

View File

@ -36,6 +36,7 @@
#include <linux/mount.h>
#include <linux/pseudo_fs.h>
#include <linux/sched.h>
#include <linux/seq_buf.h>
#include <linux/slab.h>
#include <linux/sprintf.h>
#include <linux/srcu.h>
@ -576,27 +577,31 @@ static const char *drm_get_wedge_recovery(unsigned int opt)
int drm_dev_wedged_event(struct drm_device *dev, unsigned long method,
struct drm_wedge_task_info *info)
{
char event_string[WEDGE_STR_LEN], pid_string[PID_STR_LEN], comm_string[COMM_STR_LEN];
char *envp[] = { event_string, NULL, NULL, NULL };
const char *recovery = NULL;
unsigned int len, opt;
DECLARE_SEQ_BUF(event_string, WEDGE_STR_LEN);
char pid_string[PID_STR_LEN], comm_string[COMM_STR_LEN];
char *envp[4] = { };
unsigned int len = 0, opt;
len = scnprintf(event_string, sizeof(event_string), "%s", "WEDGED=");
seq_buf_puts(&event_string, "WEDGED=");
envp[0] = event_string.buffer;
for_each_set_bit(opt, &method, BITS_PER_TYPE(method)) {
recovery = drm_get_wedge_recovery(opt);
const char *recovery = drm_get_wedge_recovery(opt);
if (drm_WARN_ONCE(dev, !recovery, "invalid recovery method %u\n", opt))
break;
len += scnprintf(event_string + len, sizeof(event_string) - len, "%s,", recovery);
if (drm_WARN_ON_ONCE(dev, seq_buf_printf(&event_string, "%s,", recovery)))
break;
len = seq_buf_used(&event_string);
}
if (recovery)
/* Get rid of trailing comma */
event_string[len - 1] = '\0';
if (len)
/* Strip trailing comma; also discards any partial overflow entry */
event_string.buffer[len - 1] = '\0';
else
/* Caller is unsure about recovery, do the best we can at this point. */
snprintf(event_string, sizeof(event_string), "%s", "WEDGED=unknown");
/* No complete entry written, do the best we can at this point. */
snprintf(event_string.buffer, event_string.size, "%s", "WEDGED=unknown");
drm_info(dev, "device wedged, %s\n", method == DRM_WEDGE_RECOVERY_NONE ?
"but no recovery needed" : "needs recovery");

View File

@ -101,20 +101,42 @@ enum drm_edid_internal_quirk {
#define MICROSOFT_IEEE_OUI 0xca125c
#define AMD_IEEE_OUI 0x00001A
#define AMD_VSDB_V1_PAYLOAD_LEN 8
#define AMD_VSDB_V2_PAYLOAD_LEN 13
#define AMD_VSDB_V3_PAYLOAD_MIN_LEN 15
#define AMD_VSDB_V3_PAYLOAD_MAX_LEN 20
#define AMD_VSDB_V3_PAYLOAD_MAX_LEN 21
struct amd_vsdb_v3_payload {
#define AMD_VSDB_V3_MAX_VFREQ_EXT2_LEN 21
struct amd_vsdb_common_payload {
u8 oui[3];
u8 version;
} __packed;
struct amd_vsdb_v1_payload {
struct amd_vsdb_common_payload common;
u8 feature_caps;
u8 rsvd0[3];
u8 min_vfreq;
u8 max_vfreq;
u8 freesync_vcp_code;
} __packed;
struct amd_vsdb_v2_payload {
struct amd_vsdb_v1_payload v1;
u8 cs_eotf_support;
u8 lum1_max;
u8 lum1_min;
u8 lum2_max;
u8 lum2_min;
u8 rsvd1[2];
} __packed;
struct amd_vsdb_v3_payload {
struct amd_vsdb_v2_payload v2;
u8 max_vfreq_ext_low;
/*
* byte 14: bits 0-1 extend MSB of max refresh rate
*/
u8 max_vfreq_ext_high;
/*
* Bytes beyond AMD_VSDB_V3_PAYLOAD_MIN_LEN are optional; a
* monitor may provide a payload as short as 15 bytes. Always
@ -123,6 +145,12 @@ struct amd_vsdb_v3_payload {
u8 extra[AMD_VSDB_V3_PAYLOAD_MAX_LEN - AMD_VSDB_V3_PAYLOAD_MIN_LEN];
} __packed;
static const u8 amd_vsdb_min_len[] = {
[1] = AMD_VSDB_V1_PAYLOAD_LEN,
[2] = AMD_VSDB_V2_PAYLOAD_LEN,
[3] = AMD_VSDB_V3_PAYLOAD_MIN_LEN,
};
struct detailed_mode_closure {
struct drm_connector *connector;
const struct drm_edid *drm_edid;
@ -5231,7 +5259,7 @@ static bool cea_db_is_microsoft_vsdb(const struct cea_db *db)
static bool cea_db_is_amd_vsdb(const struct cea_db *db)
{
return cea_db_is_vendor(db, AMD_IEEE_OUI) &&
cea_db_payload_len(db) >= AMD_VSDB_V3_PAYLOAD_MIN_LEN &&
cea_db_payload_len(db) >= AMD_VSDB_V1_PAYLOAD_LEN &&
cea_db_payload_len(db) <= AMD_VSDB_V3_PAYLOAD_MAX_LEN;
}
@ -6182,6 +6210,33 @@ static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector,
hdmi->y420_dc_modes = dc_mask;
}
static void drm_parse_hdmi_gaming_info(struct drm_hdmi_info *hdmi, const u8 *db)
{
struct drm_hdmi_vrr_cap *vrr = &hdmi->vrr_cap;
if (cea_db_payload_len(db) < 8)
return;
hdmi->fapa_start_location = db[8] & DRM_EDID_FAPA_START_LOCATION;
hdmi->allm = db[8] & DRM_EDID_ALLM;
vrr->fva = db[8] & DRM_EDID_FVA;
vrr->cnmvrr = db[8] & DRM_EDID_CNMVRR;
vrr->cinema_vrr = db[8] & DRM_EDID_CINEMA_VRR;
vrr->mdelta = db[8] & DRM_EDID_MDELTA;
if (cea_db_payload_len(db) < 9)
return;
vrr->vrr_min = db[9] & DRM_EDID_VRR_MIN_MASK;
vrr->supported = (vrr->vrr_min > 0 && vrr->vrr_min <= 48);
if (cea_db_payload_len(db) < 10)
return;
vrr->vrr_max = (db[9] & DRM_EDID_VRR_MAX_UPPER_MASK) << 2 | db[10];
vrr->supported &= (vrr->vrr_max == 0 || vrr->vrr_max >= 100);
}
static void drm_parse_dsc_info(struct drm_hdmi_dsc_cap *hdmi_dsc,
const u8 *hf_scds)
{
@ -6308,6 +6363,8 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
drm_parse_ycbcr420_deep_color_info(connector, hf_scds);
drm_parse_hdmi_gaming_info(&connector->display_info.hdmi, hf_scds);
if (cea_db_payload_len(hf_scds) >= 11 && hf_scds[11]) {
drm_parse_dsc_info(hdmi_dsc, hf_scds);
dsc_support = true;
@ -6317,6 +6374,19 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
"[CONNECTOR:%d:%s] HF-VSDB: max TMDS clock: %d KHz, HDMI 2.1 support: %s, DSC 1.2 support: %s\n",
connector->base.id, connector->name,
max_tmds_clock, str_yes_no(max_frl_rate), str_yes_no(dsc_support));
drm_dbg_kms(connector->dev,
"[CONNECTOR:%d:%s] FAPA in blanking: %s, ALLM support: %s, Fast Vactive support: %s\n",
connector->base.id, connector->name, str_yes_no(hdmi->fapa_start_location),
str_yes_no(hdmi->allm), str_yes_no(hdmi->vrr_cap.fva));
drm_dbg_kms(connector->dev,
"[CONNECTOR:%d:%s] Negative M VRR support: %s, CinemaVRR support: %s, Mdelta: %d\n",
connector->base.id, connector->name, str_yes_no(hdmi->vrr_cap.cnmvrr),
str_yes_no(hdmi->vrr_cap.cinema_vrr), hdmi->vrr_cap.mdelta);
drm_dbg_kms(connector->dev,
"[CONNECTOR:%d:%s] VRRmin: %u, VRRmax: %u, VRR supported: %s\n",
connector->base.id, connector->name, hdmi->vrr_cap.vrr_min,
hdmi->vrr_cap.vrr_max, str_yes_no(hdmi->vrr_cap.supported));
}
static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
@ -6431,43 +6501,104 @@ static void drm_parse_microsoft_vsdb(struct drm_connector *connector,
connector->base.id, connector->name, version, db[5]);
}
static void drm_parse_amd_vsdb_common(struct drm_display_info *info,
const struct amd_vsdb_common_payload *data)
{
info->amd_vsdb.version = data->version;
}
static void drm_parse_amd_vsdb_v1(struct drm_display_info *info,
const struct amd_vsdb_v1_payload *data)
{
info->amd_vsdb.freesync_supported = data->feature_caps & 0x1;
info->amd_vsdb.min_frame_rate = data->min_vfreq;
info->amd_vsdb.max_frame_rate = data->max_vfreq;
info->amd_vsdb.freesync_vcp_code = data->freesync_vcp_code;
drm_parse_amd_vsdb_common(info, &data->common);
}
static void drm_parse_amd_vsdb_v2(struct drm_display_info *info,
const struct amd_vsdb_v2_payload *data)
{
info->amd_vsdb.luminance_range1.max_luminance = data->lum1_max;
info->amd_vsdb.luminance_range1.min_luminance = data->lum1_min;
info->amd_vsdb.luminance_range2.max_luminance = data->lum2_max;
info->amd_vsdb.luminance_range2.min_luminance = data->lum2_min;
drm_parse_amd_vsdb_v1(info, &data->v1);
}
static void drm_parse_amd_vsdb_v3(struct drm_display_info *info,
const struct amd_vsdb_v3_payload *data,
int payload_len)
{
u16 max_frame_rate;
info->amd_vsdb.replay_mode = data->v2.v1.feature_caps & 0x40;
info->amd_vsdb.panel_type = (data->v2.cs_eotf_support & 0xC0) >> 6;
drm_parse_amd_vsdb_v2(info, &data->v2);
/* vfreq is provided in a different set of fields for v3. */
max_frame_rate = data->max_vfreq_ext_low |
(data->max_vfreq_ext_high & 0x3) << 8;
/*
* The AMD VSDB v3 payload length is variable (15..21 bytes).
* All fields through max_vfreq_ext_high (byte 14) are always
* present, but data->extra[] (bytes 15+) may not be, so any access
* to extra[] must be guarded with a runtime length check to
* avoid out-of-bounds reads on shorter (but spec-valid) payloads.
*/
if (payload_len >= AMD_VSDB_V3_MAX_VFREQ_EXT2_LEN)
max_frame_rate |= (data->extra[5] & 0x3) << 10;
info->amd_vsdb.max_frame_rate = max_frame_rate;
}
static void drm_parse_amd_vsdb(struct drm_connector *connector,
const struct cea_db *db)
{
struct drm_display_info *info = &connector->display_info;
const u8 *data = cea_db_data(db);
const struct amd_vsdb_v3_payload *p;
int payload_len = cea_db_payload_len(db);
u8 version;
p = (const struct amd_vsdb_v3_payload *)data;
version = ((const struct amd_vsdb_common_payload *)data)->version;
if (p->version != 0x03) {
if (version < 1) {
drm_dbg_kms(connector->dev,
"[CONNECTOR:%d:%s] Unsupported AMD VSDB version %u\n",
connector->base.id, connector->name, p->version);
connector->base.id, connector->name, version);
return;
}
info->amd_vsdb.version = p->version;
info->amd_vsdb.replay_mode = p->feature_caps & 0x40;
info->amd_vsdb.panel_type = (p->cs_eotf_support & 0xC0) >> 6;
info->amd_vsdb.luminance_range1.max_luminance = p->lum1_max;
info->amd_vsdb.luminance_range1.min_luminance = p->lum1_min;
info->amd_vsdb.luminance_range2.max_luminance = p->lum2_max;
info->amd_vsdb.luminance_range2.min_luminance = p->lum2_min;
if ((version <= 3 && payload_len < amd_vsdb_min_len[version]) ||
(version > 3 && payload_len < AMD_VSDB_V3_PAYLOAD_MIN_LEN)) {
drm_dbg_kms(connector->dev,
"[CONNECTOR:%d:%s] AMD VSDB v%u payload too short (%d bytes)\n",
connector->base.id, connector->name, version, payload_len);
return;
}
/*
* The AMD VSDB v3 payload length is variable (15..20 bytes).
* All fields through p->rsvd1 (byte 14) are always present,
* but p->extra[] (bytes 15+) may not be. Any future access to
* extra[] must be guarded with a runtime length check to avoid
* out-of-bounds reads on shorter (but spec-valid) payloads.
* For example:
*
* int len = cea_db_payload_len(db);
*
* if (len > AMD_VSDB_V3_PAYLOAD_MIN_LEN)
* info->amd_vsdb.foo = p->extra[0];
*/
switch (version) {
default:
drm_dbg_kms(connector->dev,
"[CONNECTOR:%d:%s] AMD VSDB v%u is unsupported, VSDB will be parsed as v3.\n",
connector->base.id, connector->name, version);
fallthrough;
case 3:
drm_parse_amd_vsdb_v3(info, (const struct amd_vsdb_v3_payload *)data,
payload_len);
break;
case 2:
drm_parse_amd_vsdb_v2(info, (const struct amd_vsdb_v2_payload *)data);
break;
case 1:
drm_parse_amd_vsdb_v1(info, (const struct amd_vsdb_v1_payload *)data);
break;
}
}
static void drm_parse_cea_ext(struct drm_connector *connector,

View File

@ -180,6 +180,48 @@ EXPORT_SYMBOL_GPL(drm_gem_plane_helper_prepare_fb);
* Shadow-buffered Planes
*/
/**
* __drm_gem_shadow_plane_state_init - initializes shadow-buffered plane state
* @plane: the plane
* @shadow_plane_state: the shadow-buffered plane state
*
* This function initializes a pre-allocated shadow-buffered plane state.
* Helpful for drivers that subclass struct drm_shadow_plane_state.
*/
void __drm_gem_shadow_plane_state_init(struct drm_plane *plane,
struct drm_shadow_plane_state *shadow_plane_state)
{
__drm_atomic_helper_plane_state_init(&shadow_plane_state->base, plane);
drm_format_conv_state_init(&shadow_plane_state->fmtcnv_state);
}
EXPORT_SYMBOL(__drm_gem_shadow_plane_state_init);
/**
* drm_gem_create_shadow_plane_state - creates a shadow-buffered plane state
* @plane: the plane
*
* This function implements struct &drm_plane_funcs.atomic_create_state for
* shadow-buffered planes. It assumes the new state to be of type
* struct drm_shadow_plane_state.
*
* Returns:
* A pointer to a new plane state on success, or an ERR_PTR()-encoded
* error code otherwise.
*/
struct drm_plane_state *drm_gem_create_shadow_plane_state(struct drm_plane *plane)
{
struct drm_shadow_plane_state *shadow_plane_state;
shadow_plane_state = kzalloc_obj(*shadow_plane_state);
if (!shadow_plane_state)
return ERR_PTR(-ENOMEM);
__drm_gem_shadow_plane_state_init(plane, shadow_plane_state);
return &shadow_plane_state->base;
}
EXPORT_SYMBOL(drm_gem_create_shadow_plane_state);
/**
* __drm_gem_duplicate_shadow_plane_state - duplicates shadow-buffered plane state
* @plane: the plane
@ -297,29 +339,6 @@ void __drm_gem_reset_shadow_plane(struct drm_plane *plane,
}
EXPORT_SYMBOL(__drm_gem_reset_shadow_plane);
/**
* drm_gem_reset_shadow_plane - resets a shadow-buffered plane
* @plane: the plane
*
* This function implements struct &drm_plane_funcs.reset_plane for
* shadow-buffered planes. It assumes the current plane state to be
* of type struct drm_shadow_plane and it allocates the new state of
* this type.
*/
void drm_gem_reset_shadow_plane(struct drm_plane *plane)
{
struct drm_shadow_plane_state *shadow_plane_state;
if (plane->state) {
drm_gem_destroy_shadow_plane_state(plane, plane->state);
plane->state = NULL; /* must be set to NULL here */
}
shadow_plane_state = kzalloc_obj(*shadow_plane_state);
__drm_gem_reset_shadow_plane(plane, shadow_plane_state);
}
EXPORT_SYMBOL(drm_gem_reset_shadow_plane);
/**
* drm_gem_begin_shadow_fb_access - prepares shadow framebuffers for CPU access
* @plane: the plane
@ -408,17 +427,22 @@ void drm_gem_simple_kms_end_shadow_fb_access(struct drm_simple_display_pipe *pip
EXPORT_SYMBOL(drm_gem_simple_kms_end_shadow_fb_access);
/**
* drm_gem_simple_kms_reset_shadow_plane - resets a shadow-buffered plane
* drm_gem_simple_kms_create_shadow_plane_state - creates shadow-buffered plane state
* @pipe: the simple display pipe
*
* This function implements struct drm_simple_display_funcs.reset_plane
* This function implements struct drm_simple_display_pipe_funcs.create_plane_state
* for shadow-buffered planes.
*
* Returns:
* A pointer to a new plane state on success, or an ERR_PTR()-encoded
* error code otherwise.
*/
void drm_gem_simple_kms_reset_shadow_plane(struct drm_simple_display_pipe *pipe)
struct drm_plane_state *
drm_gem_simple_kms_create_shadow_plane_state(struct drm_simple_display_pipe *pipe)
{
drm_gem_reset_shadow_plane(&pipe->plane);
return drm_gem_create_shadow_plane_state(&pipe->plane);
}
EXPORT_SYMBOL(drm_gem_simple_kms_reset_shadow_plane);
EXPORT_SYMBOL(drm_gem_simple_kms_create_shadow_plane_state);
/**
* drm_gem_simple_kms_duplicate_shadow_plane_state - duplicates shadow-buffered plane state

View File

@ -287,13 +287,12 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
struct drm_panel **panel,
struct drm_bridge **bridge)
{
int ret = -EPROBE_DEFER;
struct device_node *remote;
if (WARN_ON(!panel))
return -EINVAL;
*panel = NULL;
if (bridge)
*bridge = NULL;
/*
* of_graph_get_remote_node() produces a noisy error message if port
@ -304,30 +303,27 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
if (!of_graph_is_present(np))
return -ENODEV;
remote = of_graph_get_remote_node(np, port, endpoint);
struct device_node *remote __free(device_node) =
of_graph_get_remote_node(np, port, endpoint);
if (!remote)
return -ENODEV;
*panel = of_drm_find_panel(remote);
if (!IS_ERR(*panel))
ret = 0;
else
*panel = NULL;
return 0;
*panel = NULL;
if (bridge) {
if (ret) {
/* No panel found yet, check for a bridge next. */
*bridge = of_drm_find_bridge(remote);
if (*bridge)
ret = 0;
} else {
*bridge = NULL;
}
/* No panel found yet, check for a bridge next. */
*bridge = of_drm_find_bridge(remote);
if (*bridge)
return 0;
*bridge = NULL;
}
of_node_put(remote);
return ret;
return -EPROBE_DEFER;
}
EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge);
@ -550,8 +546,8 @@ EXPORT_SYMBOL_GPL(drm_of_lvds_get_data_mapping);
*
* Return:
* * min..max - positive integer count of "data-lanes" elements
* * -ve - the "data-lanes" property is missing or invalid
* * -EINVAL - the "data-lanes" property is unsupported
* * -ENODATA - the property does not have a value.
* * -EINVAL - the "data-lanes" property is missing or invalid
*/
int drm_of_get_data_lanes_count(const struct device_node *endpoint,
const unsigned int min, const unsigned int max)
@ -582,8 +578,8 @@ EXPORT_SYMBOL_GPL(drm_of_get_data_lanes_count);
*
* Return:
* * min..max - positive integer count of "data-lanes" elements
* * -EINVAL - the "data-mapping" property is unsupported
* * -ENODEV - the "data-mapping" property is missing
* * -ENODATA - the property does not have a value.
* * -EINVAL - the "data-lanes" property is missing or invalid
*/
int drm_of_get_data_lanes_count_ep(const struct device_node *port,
int port_reg, int reg,

View File

@ -20,16 +20,6 @@ static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup = {
.destroy = drm_encoder_cleanup,
};
int drm_simple_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
int encoder_type)
{
return drm_encoder_init(dev, encoder,
&drm_simple_encoder_funcs_cleanup,
encoder_type, NULL);
}
EXPORT_SYMBOL(drm_simple_encoder_init);
void *__drmm_simple_encoder_alloc(struct drm_device *dev, size_t size,
size_t offset, int encoder_type)
{
@ -102,17 +92,6 @@ static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
.atomic_disable = drm_simple_kms_crtc_disable,
};
static void drm_simple_kms_crtc_reset(struct drm_crtc *crtc)
{
struct drm_simple_display_pipe *pipe;
pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
if (!pipe->funcs || !pipe->funcs->reset_crtc)
return drm_atomic_helper_crtc_reset(crtc);
return pipe->funcs->reset_crtc(pipe);
}
static struct drm_crtc_state *drm_simple_kms_crtc_duplicate_state(struct drm_crtc *crtc)
{
struct drm_simple_display_pipe *pipe;
@ -158,7 +137,7 @@ static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc *crtc)
}
static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = {
.reset = drm_simple_kms_crtc_reset,
.atomic_create_state = drm_atomic_helper_crtc_create_state,
.destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
@ -281,15 +260,16 @@ static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
.atomic_update = drm_simple_kms_plane_atomic_update,
};
static void drm_simple_kms_plane_reset(struct drm_plane *plane)
static struct drm_plane_state *
drm_simple_kms_plane_create_state(struct drm_plane *plane)
{
struct drm_simple_display_pipe *pipe;
pipe = container_of(plane, struct drm_simple_display_pipe, plane);
if (!pipe->funcs || !pipe->funcs->reset_plane)
return drm_atomic_helper_plane_reset(plane);
if (!pipe->funcs || !pipe->funcs->create_plane_state)
return drm_atomic_helper_plane_create_state(plane);
return pipe->funcs->reset_plane(pipe);
return pipe->funcs->create_plane_state(pipe);
}
static struct drm_plane_state *drm_simple_kms_plane_duplicate_state(struct drm_plane *plane)
@ -319,7 +299,7 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = drm_plane_cleanup,
.reset = drm_simple_kms_plane_reset,
.atomic_create_state = drm_simple_kms_plane_create_state,
.atomic_duplicate_state = drm_simple_kms_plane_duplicate_state,
.atomic_destroy_state = drm_simple_kms_plane_destroy_state,
.format_mod_supported = drm_simple_kms_format_mod_supported,
@ -363,7 +343,8 @@ int drm_simple_display_pipe_init(struct drm_device *dev,
return ret;
encoder->possible_crtcs = drm_crtc_mask(crtc);
ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE);
ret = drm_encoder_init(dev, encoder, &drm_simple_encoder_funcs_cleanup,
DRM_MODE_ENCODER_NONE, NULL);
if (ret || !connector)
return ret;

View File

@ -163,7 +163,7 @@ static const struct drm_crtc_funcs exynos_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.destroy = exynos_drm_crtc_destroy,
.reset = drm_atomic_helper_crtc_reset,
.atomic_create_state = drm_atomic_helper_crtc_create_state,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.enable_vblank = exynos_drm_crtc_enable_vblank,

View File

@ -201,8 +201,7 @@ int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder)
ret = drm_encoder_init(dev, encoder, &exynos_dpi_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
if (ret) {
DRM_DEV_ERROR(encoder_to_dpi(encoder)->dev,
"failed to create encoder ret = %d\n", ret);
drm_err(dev, "failed to create encoder ret = %d\n", ret);
return ret;
}

View File

@ -452,8 +452,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
ret = drm_encoder_init(drm_dev, encoder, &exynos_vidi_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
if (ret) {
DRM_DEV_ERROR(dev, "failed to initialize encoder ret = %d\n",
ret);
drm_err(drm_dev, "failed to initialize encoder ret = %d\n", ret);
return ret;
}

View File

@ -1869,8 +1869,7 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
ret = drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
if (ret) {
DRM_DEV_ERROR(dev, "failed to initialize encoder ret = %d\n",
ret);
drm_err(drm_dev, "failed to initialize encoder ret = %d\n", ret);
return ret;
}

View File

@ -161,7 +161,7 @@ static const struct drm_crtc_funcs fsl_dcu_drm_crtc_funcs = {
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.destroy = drm_crtc_cleanup,
.page_flip = drm_atomic_helper_page_flip,
.reset = drm_atomic_helper_crtc_reset,
.atomic_create_state = drm_atomic_helper_crtc_create_state,
.set_config = drm_atomic_helper_set_config,
.enable_vblank = fsl_dcu_drm_crtc_enable_vblank,
.disable_vblank = fsl_dcu_drm_crtc_disable_vblank,

View File

@ -11,14 +11,18 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_encoder.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include "fsl_dcu_drm_drv.h"
#include "fsl_tcon.h"
static const struct drm_encoder_funcs fsl_dcu_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
struct drm_crtc *crtc)
{
@ -31,8 +35,8 @@ int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
if (fsl_dev->tcon)
fsl_tcon_bypass_enable(fsl_dev->tcon);
ret = drm_simple_encoder_init(fsl_dev->drm, encoder,
DRM_MODE_ENCODER_LVDS);
ret = drm_encoder_init(fsl_dev->drm, encoder, &fsl_dcu_encoder_funcs,
DRM_MODE_ENCODER_LVDS, NULL);
if (ret < 0)
return ret;

View File

@ -347,7 +347,7 @@ static const struct drm_crtc_helper_funcs gud_crtc_helper_funcs = {
};
static const struct drm_crtc_funcs gud_crtc_funcs = {
.reset = drm_atomic_helper_crtc_reset,
.atomic_create_state = drm_atomic_helper_crtc_create_state,
.destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,

View File

@ -491,7 +491,7 @@ static const struct drm_crtc_funcs hibmc_crtc_funcs = {
.page_flip = drm_atomic_helper_page_flip,
.set_config = drm_atomic_helper_set_config,
.destroy = drm_crtc_cleanup,
.reset = drm_atomic_helper_crtc_reset,
.atomic_create_state = drm_atomic_helper_crtc_create_state,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.enable_vblank = hibmc_crtc_enable_vblank,

View File

@ -20,11 +20,11 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_device.h>
#include <drm/drm_encoder.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include "dw_dsi_reg.h"
@ -687,6 +687,10 @@ static int dsi_encoder_atomic_check(struct drm_encoder *encoder,
return 0;
}
static const struct drm_encoder_funcs dw_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
static const struct drm_encoder_helper_funcs dw_encoder_helper_funcs = {
.atomic_check = dsi_encoder_atomic_check,
.mode_valid = dsi_encoder_mode_valid,
@ -708,7 +712,8 @@ static int dw_drm_encoder_init(struct device *dev,
}
encoder->possible_crtcs = crtc_mask;
ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_DSI);
ret = drm_encoder_init(drm_dev, encoder, &dw_encoder_funcs,
DRM_MODE_ENCODER_DSI, NULL);
if (ret) {
DRM_ERROR("failed to init dsi encoder\n");
return ret;

View File

@ -540,7 +540,7 @@ static const struct drm_crtc_funcs ade_crtc_funcs = {
.destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.reset = drm_atomic_helper_crtc_reset,
.atomic_create_state = drm_atomic_helper_crtc_create_state,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.enable_vblank = ade_crtc_enable_vblank,

View File

@ -29,7 +29,6 @@ struct hv_drm_device {
unsigned long fb_base;
unsigned long fb_size;
struct completion wait;
u32 synthvid_version;
u32 mmio_megabytes;
bool dirt_needed;

View File

@ -126,7 +126,7 @@ static const struct drm_crtc_helper_funcs hv_drm_crtc_helper_funcs = {
};
static const struct drm_crtc_funcs hv_drm_crtc_funcs = {
.reset = drm_atomic_helper_crtc_reset,
.atomic_create_state = drm_atomic_helper_crtc_create_state,
.destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,

View File

@ -17,7 +17,7 @@
#define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x0000ffff)
#define SYNTHVID_VER_GET_MINOR(ver) ((ver & 0xffff0000) >> 16)
/* Support for VERSION_WIN7 is removed. #define is retained for reference. */
/* Support for WIN7 and WIN8 is removed. #define's retained for reference. */
#define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
#define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
#define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
@ -181,16 +181,6 @@ struct synthvid_msg {
};
} __packed;
static inline bool hv_drm_version_ge(u32 ver1, u32 ver2)
{
if (SYNTHVID_VER_GET_MAJOR(ver1) > SYNTHVID_VER_GET_MAJOR(ver2) ||
(SYNTHVID_VER_GET_MAJOR(ver1) == SYNTHVID_VER_GET_MAJOR(ver2) &&
SYNTHVID_VER_GET_MINOR(ver1) >= SYNTHVID_VER_GET_MINOR(ver2)))
return true;
return false;
}
static inline int hv_drm_sendpacket(struct hv_device *hdev, struct synthvid_msg *msg)
{
static atomic64_t request_id = ATOMIC64_INIT(0);
@ -236,7 +226,6 @@ static int hv_drm_negotiate_version(struct hv_device *hdev, u32 ver)
return -ENODEV;
}
hv->synthvid_version = ver;
drm_info(dev, "Synthvid Version major %d, minor %d\n",
SYNTHVID_VER_GET_MAJOR(ver), SYNTHVID_VER_GET_MINOR(ver));
@ -557,23 +546,12 @@ int hv_drm_connect_vsp(struct hv_device *hdev)
return ret;
}
/* Negotiate the protocol version with host */
switch (vmbus_proto_version) {
case VERSION_WIN10:
case VERSION_WIN10_V5:
ret = hv_drm_negotiate_version(hdev, SYNTHVID_VERSION_WIN10);
if (!ret)
break;
fallthrough;
case VERSION_WIN8:
case VERSION_WIN8_1:
ret = hv_drm_negotiate_version(hdev, SYNTHVID_VERSION_WIN8);
break;
default:
ret = hv_drm_negotiate_version(hdev, SYNTHVID_VERSION_WIN10);
break;
}
/*
* Negotiate the protocol version with host. Since support for hosts
* older than WIN10 has been removed from Linux, only negotiate the
* WIN10 version.
*/
ret = hv_drm_negotiate_version(hdev, SYNTHVID_VERSION_WIN10);
if (ret) {
drm_err(dev, "Synthetic video device version not accepted %d\n", ret);
goto error;
@ -581,11 +559,9 @@ int hv_drm_connect_vsp(struct hv_device *hdev)
hv->screen_depth = SYNTHVID_DEPTH_WIN8;
if (hv_drm_version_ge(hv->synthvid_version, SYNTHVID_VERSION_WIN10)) {
ret = hv_drm_get_supported_resolution(hdev);
if (ret)
drm_err(dev, "Failed to get supported resolution from host, use default\n");
}
ret = hv_drm_get_supported_resolution(hdev);
if (ret)
drm_err(dev, "Failed to get supported resolution from host, use default\n");
if (!hv->screen_width_max) {
hv->screen_width_max = SYNTHVID_WIDTH_WIN8;

View File

@ -98,7 +98,7 @@ static void dc_crtc_disable_vblank(struct drm_crtc *crtc)
}
static const struct drm_crtc_funcs dc_crtc_funcs = {
.reset = drm_atomic_helper_crtc_reset,
.atomic_create_state = drm_atomic_helper_crtc_create_state,
.destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,

View File

@ -17,7 +17,6 @@
#include <drm/drm_mode_config.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include <drm/drm_vblank.h>
#include "dc-de.h"
@ -30,6 +29,10 @@ static const struct drm_mode_config_funcs dc_drm_mode_config_funcs = {
.atomic_commit = drm_atomic_helper_commit,
};
static const struct drm_encoder_funcs dc_kms_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
static int dc_kms_init_encoder_per_crtc(struct dc_drm_device *dc_drm,
int crtc_index)
{
@ -55,7 +58,8 @@ static int dc_kms_init_encoder_per_crtc(struct dc_drm_device *dc_drm,
}
encoder = &dc_drm->encoder[crtc_index];
ret = drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_NONE);
ret = drm_encoder_init(drm, encoder, &dc_kms_encoder_funcs,
DRM_MODE_ENCODER_NONE, NULL);
if (ret) {
dev_err(dev, "failed to initialize encoder for CRTC%u: %d\n",
crtc->index, ret);

View File

@ -45,7 +45,7 @@ static const struct drm_crtc_funcs dcss_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
.destroy = drm_crtc_cleanup,
.page_flip = drm_atomic_helper_page_flip,
.reset = drm_atomic_helper_crtc_reset,
.atomic_create_state = drm_atomic_helper_crtc_create_state,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.enable_vblank = dcss_enable_vblank,

View File

@ -96,7 +96,7 @@ static const struct drm_plane_funcs dcss_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = dcss_plane_destroy,
.reset = drm_atomic_helper_plane_reset,
.atomic_create_state = drm_atomic_helper_plane_create_state,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
.format_mod_supported = dcss_plane_format_mod_supported,

View File

@ -107,19 +107,17 @@ static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
spin_unlock_irq(&crtc->dev->event_lock);
}
static void imx_drm_crtc_reset(struct drm_crtc *crtc)
static struct drm_crtc_state *imx_drm_crtc_create_state(struct drm_crtc *crtc)
{
struct imx_crtc_state *state;
if (crtc->state)
__drm_atomic_helper_crtc_destroy_state(crtc->state);
kfree(to_imx_crtc_state(crtc->state));
crtc->state = NULL;
state = kzalloc_obj(*state);
if (state)
__drm_atomic_helper_crtc_reset(crtc, &state->base);
if (!state)
return ERR_PTR(-ENOMEM);
__drm_atomic_helper_crtc_state_init(&state->base, crtc);
return &state->base;
}
static struct drm_crtc_state *imx_drm_crtc_duplicate_state(struct drm_crtc *crtc)
@ -164,7 +162,7 @@ static void ipu_disable_vblank(struct drm_crtc *crtc)
static const struct drm_crtc_funcs ipu_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.reset = imx_drm_crtc_reset,
.atomic_create_state = imx_drm_crtc_create_state,
.atomic_duplicate_state = imx_drm_crtc_duplicate_state,
.atomic_destroy_state = imx_drm_crtc_destroy_state,
.enable_vblank = ipu_enable_vblank,

View File

@ -987,7 +987,7 @@ static const struct drm_driver ingenic_drm_driver_data = {
static const struct drm_plane_funcs ingenic_drm_primary_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.reset = drm_atomic_helper_plane_reset,
.atomic_create_state = drm_atomic_helper_plane_create_state,
.destroy = drm_plane_cleanup,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
@ -997,7 +997,7 @@ static const struct drm_plane_funcs ingenic_drm_primary_plane_funcs = {
static const struct drm_crtc_funcs ingenic_drm_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.reset = drm_atomic_helper_crtc_reset,
.atomic_create_state = drm_atomic_helper_crtc_create_state,
.destroy = drm_crtc_cleanup,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,

View File

@ -718,7 +718,7 @@ ingenic_ipu_plane_atomic_set_property(struct drm_plane *plane,
static const struct drm_plane_funcs ingenic_ipu_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.reset = drm_atomic_helper_plane_reset,
.atomic_create_state = drm_atomic_helper_plane_create_state,
.destroy = drm_plane_cleanup,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,

View File

@ -58,7 +58,7 @@ static const struct drm_crtc_funcs kmb_crtc_funcs = {
.destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.reset = drm_atomic_helper_crtc_reset,
.atomic_create_state = drm_atomic_helper_crtc_create_state,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.enable_vblank = kmb_crtc_enable_vblank,

View File

@ -14,8 +14,8 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_encoder.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_simple_kms_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@ -1427,6 +1427,10 @@ struct kmb_dsi *kmb_dsi_init(struct platform_device *pdev)
return kmb_dsi;
}
static const struct drm_encoder_funcs kmb_dsi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
int kmb_dsi_encoder_init(struct drm_device *dev, struct kmb_dsi *kmb_dsi)
{
struct drm_encoder *encoder;
@ -1437,7 +1441,8 @@ int kmb_dsi_encoder_init(struct drm_device *dev, struct kmb_dsi *kmb_dsi)
encoder->possible_crtcs = 1;
encoder->possible_clones = 0;
ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_DSI);
ret = drm_encoder_init(dev, encoder, &kmb_dsi_encoder_funcs,
DRM_MODE_ENCODER_DSI, NULL);
if (ret) {
dev_err(kmb_dsi->dev, "Failed to init encoder %d\n", ret);
return ret;

View File

@ -21,12 +21,12 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_encoder.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include "mtk_ddp_comp.h"
#include "mtk_disp_drv.h"
@ -914,12 +914,16 @@ void mtk_dsi_ddp_stop(struct device *dev)
mtk_dsi_poweroff(dsi);
}
static const struct drm_encoder_funcs mtk_dsi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi)
{
int ret;
ret = drm_simple_encoder_init(drm, &dsi->encoder,
DRM_MODE_ENCODER_DSI);
ret = drm_encoder_init(drm, &dsi->encoder, &mtk_dsi_encoder_funcs,
DRM_MODE_ENCODER_DSI, NULL);
if (ret) {
drm_err(drm, "Failed to encoder init to drm\n");
return ret;

View File

@ -74,7 +74,7 @@ static const struct drm_crtc_funcs meson_crtc_funcs = {
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.destroy = drm_crtc_cleanup,
.page_flip = drm_atomic_helper_page_flip,
.reset = drm_atomic_helper_crtc_reset,
.atomic_create_state = drm_atomic_helper_crtc_create_state,
.set_config = drm_atomic_helper_set_config,
.enable_vblank = meson_crtc_enable_vblank,
.disable_vblank = meson_crtc_disable_vblank,

View File

@ -17,8 +17,8 @@
#include <drm/drm_bridge_connector.h>
#include <drm/drm_device.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include "meson_registers.h"
#include "meson_vclk.h"
@ -218,6 +218,10 @@ static const struct drm_bridge_funcs meson_encoder_cvbs_bridge_funcs = {
.atomic_create_state = drm_atomic_helper_bridge_create_state,
};
static const struct drm_encoder_funcs meson_encoder_cvbs_funcs = {
.destroy = drm_encoder_cleanup,
};
int meson_encoder_cvbs_probe(struct meson_drm *priv)
{
struct drm_device *drm = priv->drm;
@ -257,8 +261,9 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
meson_encoder_cvbs->priv = priv;
/* Encoder */
ret = drm_simple_encoder_init(priv->drm, &meson_encoder_cvbs->encoder,
DRM_MODE_ENCODER_TVDAC);
ret = drm_encoder_init(priv->drm, &meson_encoder_cvbs->encoder,
&meson_encoder_cvbs_funcs,
DRM_MODE_ENCODER_TVDAC, NULL);
if (ret)
return dev_err_probe(priv->dev, ret,
"Failed to init CVBS encoder\n");

View File

@ -10,10 +10,10 @@
#include <linux/of_graph.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_device.h>
#include <drm/drm_encoder.h>
#include <drm/drm_probe_helper.h>
#include "meson_drv.h"
@ -99,6 +99,10 @@ static const struct drm_bridge_funcs meson_encoder_dsi_bridge_funcs = {
.atomic_create_state = drm_atomic_helper_bridge_create_state,
};
static const struct drm_encoder_funcs meson_encoder_dsi_funcs = {
.destroy = drm_encoder_cleanup,
};
int meson_encoder_dsi_probe(struct meson_drm *priv)
{
struct meson_encoder_dsi *meson_encoder_dsi;
@ -133,8 +137,9 @@ int meson_encoder_dsi_probe(struct meson_drm *priv)
meson_encoder_dsi->priv = priv;
/* Encoder */
ret = drm_simple_encoder_init(priv->drm, &meson_encoder_dsi->encoder,
DRM_MODE_ENCODER_DSI);
ret = drm_encoder_init(priv->drm, &meson_encoder_dsi->encoder,
&meson_encoder_dsi_funcs, DRM_MODE_ENCODER_DSI,
NULL);
if (ret)
return dev_err_probe(priv->dev, ret,
"Failed to init DSI encoder\n");

View File

@ -23,8 +23,8 @@
#include <drm/drm_bridge_connector.h>
#include <drm/drm_device.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include <linux/media-bus-format.h>
#include <linux/videodev2.h>
@ -369,6 +369,10 @@ static const struct drm_bridge_funcs meson_encoder_hdmi_bridge_funcs = {
.atomic_create_state = drm_atomic_helper_bridge_create_state,
};
static const struct drm_encoder_funcs meson_encoder_hdmi_funcs = {
.destroy = drm_encoder_cleanup,
};
int meson_encoder_hdmi_probe(struct meson_drm *priv)
{
struct meson_encoder_hdmi *meson_encoder_hdmi;
@ -407,8 +411,9 @@ int meson_encoder_hdmi_probe(struct meson_drm *priv)
meson_encoder_hdmi->priv = priv;
/* Encoder */
ret = drm_simple_encoder_init(priv->drm, &meson_encoder_hdmi->encoder,
DRM_MODE_ENCODER_TMDS);
ret = drm_encoder_init(priv->drm, &meson_encoder_hdmi->encoder,
&meson_encoder_hdmi_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
if (ret) {
dev_err_probe(priv->dev, ret, "Failed to init HDMI encoder\n");
goto err_put_node;

View File

@ -802,7 +802,7 @@ static const struct drm_plane_funcs meson_overlay_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = drm_plane_cleanup,
.reset = drm_atomic_helper_plane_reset,
.atomic_create_state = drm_atomic_helper_plane_create_state,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
.format_mod_supported = meson_overlay_format_mod_supported,

Some files were not shown because too many files have changed in this diff Show More