mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
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:
commit
483ece619b
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -34,7 +34,7 @@ required:
|
|||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
|
|
|||
|
|
@ -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
|
||||
------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
22
MAINTAINERS
22
MAINTAINERS
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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__)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
1342
drivers/gpu/buddy.c
1342
drivers/gpu/buddy.c
File diff suppressed because it is too large
Load Diff
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue
Block a user