drm-misc-next for v5.18:

UAPI Changes:
 - Fix invalid IN_FORMATS blob when plane->format_mod_supported is NULL.
 
 Cross-subsystem Changes:
 - Assorted dt bindings updates.
 - Fix vga16fb vga checking on x86.
 - Fix extra semicolon in rwsem.h's _down_write_nest_lock.
 - Assorted small fixes to agp and fbdev drivers.
 - Fix oops in creating a udmabuf with 0 pages.
 - Hot-unplug firmware fb devices on forced removal
 - Reqquest memory region in simplefb and simpledrm, and don't make the ioresource as busy.
 
 Core Changes:
 - Mock a drm_plane in drm-plane-helper selftest.
 - Assorted bug fixes to device logging, dbi.
 - Use DP helper for sink count in mst.
 - Assorted documentation fixes.
 - Assorted small fixes.
 - Move DP headers to drm/dp, and add a drm dp helper module.
 - Move the buddy allocator from i915 to common drm.
 - Add simple pci and platform module init macros to remove a lot of boilerplate from some drivers.
 - Support microsoft extension for HMDs and specialized monitors.
 - Improve edid parser's deep color handling.
 - Add type 7 timing support to edid parser.
 - Add a weak backpointer to the ttm_bo from ttm_resource
 - Add 3 eDP panels.
 
 Driver Changes:
 - Add support for HDMI and JZ4780 to ingenic.
 - Add support for higher DP/eDP bitrates to nouveau.
 - Assorted driver fixes to tilcdc, vmwgfx, sn65dsi83, meson, stm, panfrost, v3d, gma500, vc4, virtio, mgag200, ast, radeon, amdgpu, nouveau, various bridge drivers.
 - Convert and revert exynos dsi support to bridge driver.
 - Add vcc supply regulator support for sn65dsi83.
 - More conversion of bridge/chipone-icn6211 to atomic.
 - Remove conflicting fb's from stm, and add support for new hw version.
 - Add device link in parade-ps8640 to fix suspend/resume.
 - Update Boe-tv110c9m init sequence.
 - Add wide screen support to AST2600.
 - Fix omapdrm implicit dma_buf fencing.
 - Add support for multiple overlay planes to vkms.
 - Convert bridge/anx7625 to atomic, add HDCP support,
   add eld support for audio, and fix HPD.
 - Add driver for ChromeOS privacy screen.
 - Handover display from firmware to vc4 more gracefully, and support nomodeset.
 - Add flexible and ycbcr pixel formats to stm/ltdc.
 - Convert exynos mipi dsi to atomic.
 - Add initial dual core group GPUs support to panfrost.
 - No longer add exclusive fence in amdgpu as shared fence.
 - Add CSC and full range supoprt to vc4.
 - Shutdown the display on system shutdown and unbind.
 - Add Multi-Inno Technology MI0700S4T-6 simple panel.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAmHyiHMACgkQ/lWMcqZw
 E8OLfQ//Xd1njt93nRGoQofuQkz23n2AUTAnmbwzQKcvmat8ugXbRJ5JaVQJrFpu
 OQEYM46eZIyu2LekMiz4HgPK8CjS156QJ1WtltUFglOY1KLejb6HF5boBYxLkIC7
 wLhkaRiwed4t7WOTrftgzpH5FNj/7Vi+Hav9l8rYRC74sWanEZNGBJL2OD9GRdlU
 3tlmY8oXVAN8YDD/43Cv+foOTzLS/COI7JCFgFRhfzoFss3EVR061u55uOq18STB
 UI29NusqX7/K6hQAWCKl0EQBEZWMR02/dgu3ZpOEHHAa96RgHxIuRYsIO9kvGgiF
 VyW0EW6AyD/KsOSBYnsfUqkFfNchx9Xb8ZDjIhHUYxPsxe4iUJneCrdIKEmLWgSd
 1bVNrltLJKBQARW4Whpy/gaiKV8RD8YVJobA/+/COeCUXCnNAT43O9aJmix/7253
 Q7ORXTss5WRpuYswMWmObebf8p3IhFjTvlzzenXynl7mkaohGzHPf6SUSUZbJ8Df
 PZCh17McwIEQ1BtYeegeAGM6s8lrv5+yZaY4bnkQsJNOHeab0cPqmQ8/s+hUeRtp
 3VDRVhkgzz2XuTaiKia0gWcAQbdZ2KornkP4QMyDH7w0+6bsuJnNXe4L1XY9lt4J
 5v411FaD61FbGDhu5PFtYI7+ZlgM0h5sqlhVkUEzbckzTF3SC9c=
 =IMtm
 -----END PGP SIGNATURE-----

Merge tag 'drm-misc-next-2022-01-27' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

[airlied: add two missing Kconfig]

drm-misc-next for v5.18:

UAPI Changes:
- Fix invalid IN_FORMATS blob when plane->format_mod_supported is NULL.

Cross-subsystem Changes:
- Assorted dt bindings updates.
- Fix vga16fb vga checking on x86.
- Fix extra semicolon in rwsem.h's _down_write_nest_lock.
- Assorted small fixes to agp and fbdev drivers.
- Fix oops in creating a udmabuf with 0 pages.
- Hot-unplug firmware fb devices on forced removal
- Reqquest memory region in simplefb and simpledrm, and don't make the ioresource as busy.

Core Changes:
- Mock a drm_plane in drm-plane-helper selftest.
- Assorted bug fixes to device logging, dbi.
- Use DP helper for sink count in mst.
- Assorted documentation fixes.
- Assorted small fixes.
- Move DP headers to drm/dp, and add a drm dp helper module.
- Move the buddy allocator from i915 to common drm.
- Add simple pci and platform module init macros to remove a lot of boilerplate from some drivers.
- Support microsoft extension for HMDs and specialized monitors.
- Improve edid parser's deep color handling.
- Add type 7 timing support to edid parser.
- Add a weak backpointer to the ttm_bo from ttm_resource
- Add 3 eDP panels.

Driver Changes:
- Add support for HDMI and JZ4780 to ingenic.
- Add support for higher DP/eDP bitrates to nouveau.
- Assorted driver fixes to tilcdc, vmwgfx, sn65dsi83, meson, stm, panfrost, v3d, gma500, vc4, virtio, mgag200, ast, radeon, amdgpu, nouveau, various bridge drivers.
- Convert and revert exynos dsi support to bridge driver.
- Add vcc supply regulator support for sn65dsi83.
- More conversion of bridge/chipone-icn6211 to atomic.
- Remove conflicting fb's from stm, and add support for new hw version.
- Add device link in parade-ps8640 to fix suspend/resume.
- Update Boe-tv110c9m init sequence.
- Add wide screen support to AST2600.
- Fix omapdrm implicit dma_buf fencing.
- Add support for multiple overlay planes to vkms.
- Convert bridge/anx7625 to atomic, add HDCP support,
  add eld support for audio, and fix HPD.
- Add driver for ChromeOS privacy screen.
- Handover display from firmware to vc4 more gracefully, and support nomodeset.
- Add flexible and ycbcr pixel formats to stm/ltdc.
- Convert exynos mipi dsi to atomic.
- Add initial dual core group GPUs support to panfrost.
- No longer add exclusive fence in amdgpu as shared fence.
- Add CSC and full range supoprt to vc4.
- Shutdown the display on system shutdown and unbind.
- Add Multi-Inno Technology MI0700S4T-6 simple panel.

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

From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/456a23c6-7324-7543-0c45-751f30ef83f7@linux.intel.com
This commit is contained in:
Dave Airlie 2022-01-31 16:33:54 +10:00
commit 53dbee4926
233 changed files with 5380 additions and 2616 deletions

View File

@ -39,6 +39,7 @@ properties:
- const: lvds-encoder # Generic LVDS encoder compatible fallback
- items:
- enum:
- ti,ds90cf364a # For the DS90CF364A FPD-Link LVDS Receiver
- ti,ds90cf384a # For the DS90CF384A FPD-Link LVDS Receiver
- const: lvds-decoder # Generic LVDS decoders compatible fallback
- enum:

View File

@ -32,6 +32,9 @@ properties:
maxItems: 1
description: GPIO specifier for bridge_en pin (active high).
vcc-supply:
description: A 1.8V power supply (see regulator/regulator.yaml).
ports:
$ref: /schemas/graph.yaml#/properties/ports
@ -91,7 +94,6 @@ properties:
required:
- compatible
- reg
- enable-gpios
- ports
allOf:
@ -133,6 +135,7 @@ examples:
reg = <0x2d>;
enable-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
vcc-supply = <&reg_sn65dsi83_1v8>;
ports {
#address-cells = <1>;

View File

@ -222,6 +222,8 @@ properties:
- logictechno,lttd800480070-l6wh-rt
# Mitsubishi "AA070MC01 7.0" WVGA TFT LCD panel
- mitsubishi,aa070mc01-ca1
# Multi-Inno Technology Co.,Ltd MI0700S4T-6 7" 800x480 TFT Resistive Touch Module
- multi-inno,mi0700s4t-6
# Multi-Inno Technology Co.,Ltd MI1010AIT-1CP 10.1" 1280x800 LVDS IPS Cap Touch Mod.
- multi-inno,mi1010ait-1cp
# NEC LCD Technologies, Ltd. 12.1" WXGA (1280x800) LVDS TFT LCD panel

View File

@ -4,7 +4,12 @@
$id: http://devicetree.org/schemas/display/panel/sony,acx424akp.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Sony ACX424AKP 4" 480x864 AMOLED panel
title: Sony ACX424AKP/ACX424AKM 4" 480x864/480x854 AMOLED panel
description: The Sony ACX424AKP and ACX424AKM are panels built around
the Novatek NT35560 display controller. The only difference is that
the AKM is configured to use 10 pixels less in the Y axis than the
AKP.
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
@ -14,7 +19,9 @@ allOf:
properties:
compatible:
const: sony,acx424akp
enum:
- sony,acx424akp
- sony,acx424akm
reg: true
reset-gpios: true
vddi-supply:

View File

@ -75,6 +75,12 @@ update it, its value is mostly useless. The DRM core prints it to the
kernel log at initialization time and passes it to userspace through the
DRM_IOCTL_VERSION ioctl.
Module Initialization
---------------------
.. kernel-doc:: include/drm/drm_module.h
:doc: overview
Managing Ownership of the Framebuffer Aperture
----------------------------------------------

View File

@ -232,34 +232,34 @@ HDCP Helper Functions Reference
Display Port Helper Functions Reference
=======================================
.. kernel-doc:: drivers/gpu/drm/drm_dp_helper.c
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp.c
:doc: dp helpers
.. kernel-doc:: include/drm/drm_dp_helper.h
.. kernel-doc:: include/drm/dp/drm_dp_helper.h
:internal:
.. kernel-doc:: drivers/gpu/drm/drm_dp_helper.c
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp.c
:export:
Display Port CEC Helper Functions Reference
===========================================
.. kernel-doc:: drivers/gpu/drm/drm_dp_cec.c
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_cec.c
:doc: dp cec helpers
.. kernel-doc:: drivers/gpu/drm/drm_dp_cec.c
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_cec.c
:export:
Display Port Dual Mode Adaptor Helper Functions Reference
=========================================================
.. kernel-doc:: drivers/gpu/drm/drm_dp_dual_mode_helper.c
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_dual_mode_helper.c
:doc: dp dual mode helpers
.. kernel-doc:: include/drm/drm_dp_dual_mode_helper.h
.. kernel-doc:: include/drm/dp/drm_dp_dual_mode_helper.h
:internal:
.. kernel-doc:: drivers/gpu/drm/drm_dp_dual_mode_helper.c
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_dual_mode_helper.c
:export:
Display Port MST Helpers
@ -268,19 +268,19 @@ Display Port MST Helpers
Overview
--------
.. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c
:doc: dp mst helper
.. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c
:doc: Branch device and port refcounting
Functions Reference
-------------------
.. kernel-doc:: include/drm/drm_dp_mst_helper.h
.. kernel-doc:: include/drm/dp/drm_dp_mst_helper.h
:internal:
.. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c
:export:
Topology Lifetime Internals
@ -289,7 +289,7 @@ Topology Lifetime Internals
These functions aren't exported to drivers, but are documented here to help make
the MST topology helpers easier to understand
.. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c
:functions: drm_dp_mst_topology_try_get_mstb drm_dp_mst_topology_get_mstb
drm_dp_mst_topology_put_mstb
drm_dp_mst_topology_try_get_port drm_dp_mst_topology_get_port

View File

@ -423,12 +423,12 @@ Connector Functions Reference
Writeback Connectors
--------------------
.. kernel-doc:: include/drm/drm_writeback.h
:internal:
.. kernel-doc:: drivers/gpu/drm/drm_writeback.c
:doc: overview
.. kernel-doc:: include/drm/drm_writeback.h
:internal:
.. kernel-doc:: drivers/gpu/drm/drm_writeback.c
:export:

View File

@ -8,7 +8,7 @@ the very dynamic nature of many of that data, managing graphics memory
efficiently is thus crucial for the graphics stack and plays a central
role in the DRM infrastructure.
The DRM core includes two memory managers, namely Translation Table Maps
The DRM core includes two memory managers, namely Translation Table Manager
(TTM) and Graphics Execution Manager (GEM). TTM was the first DRM memory
manager to be developed and tried to be a one-size-fits-them all
solution. It provides a single userspace API to accommodate the need of

View File

@ -467,6 +467,21 @@ Contact: Thomas Zimmermann <tzimmermann@suse.de>
Level: Intermediate
Request memory regions in all drivers
-------------------------------------
Go through all drivers and add code to request the memory regions that the
driver uses. This requires adding calls to request_mem_region(),
pci_request_region() or similar functions. Use helpers for managed cleanup
where possible.
Drivers are pretty bad at doing this and there used to be conflicts among
DRM and fbdev drivers. Still, it's the correct thing to do.
Contact: Thomas Zimmermann <tzimmermann@suse.de>
Level: Starter
Core refactorings
=================

View File

@ -124,8 +124,6 @@ Add Plane Features
There's lots of plane features we could add support for:
- Multiple overlay planes. [Good to get started]
- Clearing primary plane: clear primary plane before plane composition (at the
start) for correctness of pixel blend ops. It also guarantees alpha channel
is cleared in the target buffer for stable crc. [Good to get started]

View File

@ -55,7 +55,7 @@ static struct _ati_generic_private {
static int ati_create_page_map(struct ati_page_map *page_map)
{
int i, err = 0;
int i, err;
page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
if (page_map->real == NULL)
@ -63,6 +63,10 @@ static int ati_create_page_map(struct ati_page_map *page_map)
set_memory_uc((unsigned long)page_map->real, 1);
err = map_page_into_agp(virt_to_page(page_map->real));
if (err) {
free_page((unsigned long)page_map->real);
return err;
}
page_map->remapped = page_map->real;
for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
@ -303,7 +307,7 @@ static int ati_insert_memory(struct agp_memory * mem,
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
cur_gatt = GET_GATT(addr);
writel(agp_bridge->driver->mask_memory(agp_bridge,
writel(agp_bridge->driver->mask_memory(agp_bridge,
page_to_phys(mem->pages[i]),
mem->type),
cur_gatt+GET_GATT_OFF(addr));

View File

@ -62,6 +62,7 @@ EXPORT_SYMBOL(agp_find_bridge);
/**
* agp_backend_acquire - attempt to acquire an agp backend.
* @pdev: the PCI device
*
*/
struct agp_bridge_data *agp_backend_acquire(struct pci_dev *pdev)
@ -83,6 +84,7 @@ EXPORT_SYMBOL(agp_backend_acquire);
/**
* agp_backend_release - release the lock on the agp backend.
* @bridge: the AGP backend to release
*
* The caller must insure that the graphics aperture translation table
* is read for use by another entity.

View File

@ -39,7 +39,9 @@
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include "agp.h"
#include "compat_ioctl.h"
struct agp_front_data agp_fe;
@ -1017,7 +1019,7 @@ static long agp_ioctl(struct file *file,
case AGPIOC_UNBIND:
ret_val = agpioc_unbind_wrap(curr_priv, (void __user *) arg);
break;
case AGPIOC_CHIPSET_FLUSH:
break;
}

View File

@ -261,7 +261,8 @@ static int nvidia_remove_memory(struct agp_memory *mem, off_t pg_start, int type
static void nvidia_tlbflush(struct agp_memory *mem)
{
unsigned long end;
u32 wbc_reg, temp;
u32 wbc_reg;
u32 __maybe_unused temp;
int i;
/* flush chipset */

View File

@ -262,13 +262,10 @@ static void serverworks_tlbflush(struct agp_memory *temp)
static int serverworks_configure(void)
{
struct aper_size_info_lvl2 *current_size;
u32 temp;
u8 enable_reg;
u16 cap_reg;
current_size = A_SIZE_LVL2(agp_bridge->current_size);
/* Get the memory mapped registers */
pci_read_config_dword(agp_bridge->dev, serverworks_private.mm_addr_ofs, &temp);
temp = (temp & PCI_BASE_ADDRESS_MEM_MASK);
@ -350,7 +347,7 @@ static int serverworks_insert_memory(struct agp_memory *mem,
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
cur_gatt = SVRWRKS_GET_GATT(addr);
writel(agp_bridge->driver->mask_memory(agp_bridge,
writel(agp_bridge->driver->mask_memory(agp_bridge,
page_to_phys(mem->pages[i]), mem->type),
cur_gatt+GET_GATT_OFF(addr));
}

View File

@ -128,9 +128,6 @@ static int via_fetch_size_agp3(void)
static int via_configure_agp3(void)
{
u32 temp;
struct aper_size_info_16 *current_size;
current_size = A_SIZE_16(agp_bridge->current_size);
/* address to map to */
agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,

View File

@ -542,57 +542,45 @@ EXPORT_SYMBOL(dma_resv_copy_fences);
* dma_resv_get_fences - Get an object's shared and exclusive
* fences without update side lock held
* @obj: the reservation object
* @fence_excl: the returned exclusive fence (or NULL)
* @shared_count: the number of shared fences returned
* @shared: the array of shared fence ptrs returned (array is krealloc'd to
* the required size, and must be freed by caller)
* @write: true if we should return all fences
* @num_fences: the number of fences returned
* @fences: the array of fence ptrs returned (array is krealloc'd to the
* required size, and must be freed by caller)
*
* Retrieve all fences from the reservation object. If the pointer for the
* exclusive fence is not specified the fence is put into the array of the
* shared fences as well. Returns either zero or -ENOMEM.
* Retrieve all fences from the reservation object.
* Returns either zero or -ENOMEM.
*/
int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **fence_excl,
unsigned int *shared_count, struct dma_fence ***shared)
int dma_resv_get_fences(struct dma_resv *obj, bool write,
unsigned int *num_fences, struct dma_fence ***fences)
{
struct dma_resv_iter cursor;
struct dma_fence *fence;
*shared_count = 0;
*shared = NULL;
*num_fences = 0;
*fences = NULL;
if (fence_excl)
*fence_excl = NULL;
dma_resv_iter_begin(&cursor, obj, true);
dma_resv_iter_begin(&cursor, obj, write);
dma_resv_for_each_fence_unlocked(&cursor, fence) {
if (dma_resv_iter_is_restarted(&cursor)) {
unsigned int count;
while (*shared_count)
dma_fence_put((*shared)[--(*shared_count)]);
while (*num_fences)
dma_fence_put((*fences)[--(*num_fences)]);
if (fence_excl)
dma_fence_put(*fence_excl);
count = cursor.shared_count;
count += fence_excl ? 0 : 1;
count = cursor.shared_count + 1;
/* Eventually re-allocate the array */
*shared = krealloc_array(*shared, count,
*fences = krealloc_array(*fences, count,
sizeof(void *),
GFP_KERNEL);
if (count && !*shared) {
if (count && !*fences) {
dma_resv_iter_end(&cursor);
return -ENOMEM;
}
}
dma_fence_get(fence);
if (dma_resv_iter_is_exclusive(&cursor) && fence_excl)
*fence_excl = fence;
else
(*shared)[(*shared_count)++] = fence;
(*fences)[(*num_fences)++] = dma_fence_get(fence);
}
dma_resv_iter_end(&cursor);

View File

@ -275,7 +275,7 @@ static int test_shared_for_each_unlocked(void *arg)
static int test_get_fences(void *arg, bool shared)
{
struct dma_fence *f, *excl = NULL, **fences = NULL;
struct dma_fence *f, **fences = NULL;
struct dma_resv resv;
int r, i;
@ -304,35 +304,19 @@ static int test_get_fences(void *arg, bool shared)
}
dma_resv_unlock(&resv);
r = dma_resv_get_fences(&resv, &excl, &i, &fences);
r = dma_resv_get_fences(&resv, shared, &i, &fences);
if (r) {
pr_err("get_fences failed\n");
goto err_free;
}
if (shared) {
if (excl != NULL) {
pr_err("get_fences returned unexpected excl fence\n");
goto err_free;
}
if (i != 1 || fences[0] != f) {
pr_err("get_fences returned unexpected shared fence\n");
goto err_free;
}
} else {
if (excl != f) {
pr_err("get_fences returned unexpected excl fence\n");
goto err_free;
}
if (i != 0) {
pr_err("get_fences returned unexpected shared fence\n");
goto err_free;
}
if (i != 1 || fences[0] != f) {
pr_err("get_fences returned unexpected fence\n");
goto err_free;
}
dma_fence_signal(f);
err_free:
dma_fence_put(excl);
while (i--)
dma_fence_put(fences[i]);
kfree(fences);

View File

@ -190,6 +190,10 @@ static long udmabuf_create(struct miscdevice *device,
if (ubuf->pagecount > pglimit)
goto err;
}
if (!ubuf->pagecount)
goto err;
ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(*ubuf->pages),
GFP_KERNEL);
if (!ubuf->pages) {

View File

@ -99,7 +99,7 @@ __init int sysfb_create_simplefb(const struct screen_info *si,
/* setup IORESOURCE_MEM as framebuffer memory */
memset(&res, 0, sizeof(res));
res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
res.flags = IORESOURCE_MEM;
res.name = simplefb_resname;
res.start = base;
res.end = res.start + length - 1;

View File

@ -68,6 +68,7 @@ config DRM_DEBUG_SELFTEST
depends on DRM
depends on DEBUG_KERNEL
select PRIME_NUMBERS
select DRM_DP_HELPER
select DRM_LIB_RANDOM
select DRM_KMS_HELPER
select DRM_EXPORT_FOR_TESTS if m
@ -80,6 +81,12 @@ config DRM_DEBUG_SELFTEST
If in doubt, say "N".
config DRM_DP_HELPER
tristate
depends on DRM
help
DRM helpers for DisplayPort.
config DRM_KMS_HELPER
tristate
depends on DRM
@ -198,6 +205,12 @@ config DRM_TTM
GPU memory types. Will be enabled automatically if a device driver
uses it.
config DRM_BUDDY
tristate
depends on DRM
help
A page based buddy allocator
config DRM_VRAM_HELPER
tristate
depends on DRM
@ -236,6 +249,7 @@ config DRM_RADEON
depends on DRM && PCI && MMU
depends on AGP || !AGP
select FW_LOADER
select DRM_DP_HELPER
select DRM_KMS_HELPER
select DRM_TTM
select DRM_TTM_HELPER
@ -256,6 +270,7 @@ config DRM_AMDGPU
tristate "AMD GPU"
depends on DRM && PCI && MMU
select FW_LOADER
select DRM_DP_HELPER
select DRM_KMS_HELPER
select DRM_SCHED
select DRM_TTM

View File

@ -31,8 +31,6 @@ drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
drm-$(CONFIG_DRM_PRIVACY_SCREEN) += drm_privacy_screen.o drm_privacy_screen_x86.o
obj-$(CONFIG_DRM_DP_AUX_BUS) += drm_dp_aux_bus.o
obj-$(CONFIG_DRM_NOMODESET) += drm_nomodeset.o
drm_cma_helper-y := drm_gem_cma_helper.o
@ -42,27 +40,26 @@ obj-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_cma_helper.o
drm_shmem_helper-y := drm_gem_shmem_helper.o
obj-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_shmem_helper.o
obj-$(CONFIG_DRM_BUDDY) += drm_buddy.o
drm_vram_helper-y := drm_gem_vram_helper.o
obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
drm_ttm_helper-y := drm_gem_ttm_helper.o
obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o
drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o drm_dp_helper.o \
drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o \
drm_dsc.o drm_encoder_slave.o drm_flip_work.o drm_hdcp.o \
drm_probe_helper.o \
drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
drm_plane_helper.o drm_atomic_helper.o \
drm_kms_helper_common.o \
drm_simple_kms_helper.o drm_modeset_helper.o \
drm_scdc_helper.o drm_gem_atomic_helper.o \
drm_gem_framebuffer_helper.o \
drm_atomic_state_helper.o drm_damage_helper.o \
drm_format_helper.o drm_self_refresh_helper.o drm_rect.o
drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o
drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o
obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/
@ -72,6 +69,7 @@ obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
obj-y += arm/
obj-y += dp/
obj-$(CONFIG_DRM_TTM) += ttm/
obj-$(CONFIG_DRM_SCHED) += scheduler/
obj-$(CONFIG_DRM_TDFX) += tdfx/

View File

@ -26,7 +26,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/amdgpu_drm.h>
#include "amdgpu.h"
@ -175,7 +175,7 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector)
/* Check if bpc is within clock limit. Try to degrade gracefully otherwise */
if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) {
if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) &&
if ((connector->display_info.edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30) &&
(mode_clock * 5/4 <= max_tmds_clock))
bpc = 10;
else

View File

@ -1274,14 +1274,11 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
/*
* Work around dma_resv shortcommings by wrapping up the
* submission in a dma_fence_chain and add it as exclusive
* fence, but first add the submission as shared fence to make
* sure that shared fences never signal before the exclusive
* one.
* fence.
*/
dma_fence_chain_init(chain, dma_resv_excl_fence(resv),
dma_fence_get(p->fence), 1);
dma_resv_add_shared_fence(resv, p->fence);
rcu_assign_pointer(resv->fence_excl, &chain->base);
e->chain = NULL;
}

View File

@ -200,8 +200,10 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc,
goto unpin;
}
r = dma_resv_get_fences(new_abo->tbo.base.resv, NULL,
&work->shared_count, &work->shared);
/* TODO: Unify this with other drivers */
r = dma_resv_get_fences(new_abo->tbo.base.resv, true,
&work->shared_count,
&work->shared);
if (unlikely(r != 0)) {
DRM_ERROR("failed to get fences for buffer\n");
goto unpin;

View File

@ -226,12 +226,6 @@ static void amdgpu_gem_object_close(struct drm_gem_object *obj,
if (!amdgpu_vm_ready(vm))
goto out_unlock;
fence = dma_resv_excl_fence(bo->tbo.base.resv);
if (fence) {
amdgpu_bo_fence(bo, fence, true);
fence = NULL;
}
r = amdgpu_vm_clear_freed(adev, vm, &fence);
if (r || !fence)
goto out_unlock;

View File

@ -167,6 +167,7 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man,
return 0;
err_free:
ttm_resource_fini(man, &node->base.base);
kfree(node);
err_out:
@ -198,6 +199,7 @@ static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man,
if (!(res->placement & TTM_PL_FLAG_TEMPORARY))
atomic64_sub(res->num_pages, &mgr->used);
ttm_resource_fini(man, res);
kfree(node);
}
@ -286,7 +288,8 @@ int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size)
man->use_tt = true;
man->func = &amdgpu_gtt_mgr_func;
ttm_resource_manager_init(man, gtt_size >> PAGE_SHIFT);
ttm_resource_manager_init(man, &adev->mman.bdev,
gtt_size >> PAGE_SHIFT);
start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS;
size = (adev->gmc.gart_size >> PAGE_SHIFT) - start;

View File

@ -112,7 +112,7 @@ void amdgpu_pasid_free_delayed(struct dma_resv *resv,
unsigned count;
int r;
r = dma_resv_get_fences(resv, NULL, &count, &fences);
r = dma_resv_get_fences(resv, true, &count, &fences);
if (r)
goto fallback;

View File

@ -33,7 +33,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/drm_fixed.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
@ -44,7 +44,7 @@
#include <linux/hrtimer.h>
#include "amdgpu_irq.h"
#include <drm/drm_dp_mst_helper.h>
#include <drm/dp/drm_dp_mst_helper.h>
#include "modules/inc/mod_freesync.h"
#include "amdgpu_dm_irq_params.h"

View File

@ -95,6 +95,7 @@ static void amdgpu_preempt_mgr_del(struct ttm_resource_manager *man,
struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man);
atomic64_sub(res->num_pages, &mgr->used);
ttm_resource_fini(man, res);
kfree(res);
}
@ -152,7 +153,7 @@ int amdgpu_preempt_mgr_init(struct amdgpu_device *adev)
man->use_tt = true;
man->func = &amdgpu_preempt_mgr_func;
ttm_resource_manager_init(man, (1 << 30));
ttm_resource_manager_init(man, &adev->mman.bdev, (1 << 30));
atomic64_set(&mgr->used, 0);

View File

@ -2087,7 +2087,7 @@ static int amdgpu_mm_vram_table_show(struct seq_file *m, void *unused)
TTM_PL_VRAM);
struct drm_printer p = drm_seq_file_printer(m);
man->func->debug(man, &p);
ttm_resource_manager_debug(man, &p);
return 0;
}
@ -2105,7 +2105,7 @@ static int amdgpu_mm_tt_table_show(struct seq_file *m, void *unused)
TTM_PL_TT);
struct drm_printer p = drm_seq_file_printer(m);
man->func->debug(man, &p);
ttm_resource_manager_debug(man, &p);
return 0;
}
@ -2116,7 +2116,7 @@ static int amdgpu_mm_gds_table_show(struct seq_file *m, void *unused)
AMDGPU_PL_GDS);
struct drm_printer p = drm_seq_file_printer(m);
man->func->debug(man, &p);
ttm_resource_manager_debug(man, &p);
return 0;
}
@ -2127,7 +2127,7 @@ static int amdgpu_mm_gws_table_show(struct seq_file *m, void *unused)
AMDGPU_PL_GWS);
struct drm_printer p = drm_seq_file_printer(m);
man->func->debug(man, &p);
ttm_resource_manager_debug(man, &p);
return 0;
}
@ -2138,7 +2138,7 @@ static int amdgpu_mm_oa_table_show(struct seq_file *m, void *unused)
AMDGPU_PL_OA);
struct drm_printer p = drm_seq_file_printer(m);
man->func->debug(man, &p);
ttm_resource_manager_debug(man, &p);
return 0;
}

View File

@ -472,6 +472,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
while (i--)
drm_mm_remove_node(&node->mm_nodes[i]);
spin_unlock(&mgr->lock);
ttm_resource_fini(man, &node->base);
kvfree(node);
error_sub:
@ -511,6 +512,7 @@ static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man,
atomic64_sub(usage, &mgr->usage);
atomic64_sub(vis_usage, &mgr->vis_usage);
ttm_resource_fini(man, res);
kvfree(node);
}
@ -689,7 +691,8 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
struct ttm_resource_manager *man = &mgr->manager;
ttm_resource_manager_init(man, adev->gmc.real_vram_size >> PAGE_SHIFT);
ttm_resource_manager_init(man, &adev->mman.bdev,
adev->gmc.real_vram_size >> PAGE_SHIFT);
man->func = &amdgpu_vram_mgr_func;

View File

@ -34,7 +34,7 @@
#include "atombios_dp.h"
#include "amdgpu_connectors.h"
#include "amdgpu_atombios.h"
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
/* move these to drm_dp_helper.c/h */
#define DP_LINK_CONFIGURATION_SIZE 9

View File

@ -76,7 +76,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_dp_mst_helper.h>
#include <drm/dp/drm_dp_mst_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_edid.h>
@ -5856,7 +5856,7 @@ static void fill_stream_properties_from_drm_display_mode(
else if (drm_mode_is_420_also(info, mode_in)
&& aconnector->force_yuv420_output)
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444)
else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR444)
&& stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;
else

View File

@ -29,7 +29,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_dp_mst_helper.h>
#include <drm/dp/drm_dp_mst_helper.h>
#include <drm/drm_plane.h>
/*

View File

@ -25,8 +25,8 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_dp_mst_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_mst_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include "dm_services.h"
#include "amdgpu.h"
#include "amdgpu_dm.h"

View File

@ -27,7 +27,7 @@
#include <dc_link.h>
#include <inc/link_hwss.h>
#include <inc/link_dpcd.h>
#include "drm/drm_dp_helper.h"
#include <drm/dp/drm_dp_helper.h>
#include <dc_dp_types.h>
#include "dm_helpers.h"

View File

@ -25,7 +25,7 @@
#include <drm/drm_dsc.h>
#include "dc_hw_types.h"
#include "dsc.h"
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include "dc.h"
#include "rc_calc.h"
#include "fixed31_32.h"

View File

@ -36,7 +36,7 @@
#include <asm/byteorder.h>
#include <drm/drm_print.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include "cgs_common.h"

View File

@ -26,7 +26,7 @@
#ifndef __DAL_DPCD_DEFS_H__
#define __DAL_DPCD_DEFS_H__
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#ifndef DP_SINK_HW_REVISION_START // can remove this once the define gets into linux drm_dp_helper.h
#define DP_SINK_HW_REVISION_START 0x409
#endif

View File

@ -30,7 +30,7 @@
#include "hdcp_log.h"
#include <drm/drm_hdcp.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
enum mod_hdcp_trans_input_result {
UNKNOWN = 0,

View File

@ -1078,11 +1078,11 @@ static void d71_improc_update(struct komeda_component *c,
mask |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420;
/* config color format */
if (st->color_format == DRM_COLOR_FORMAT_YCRCB420)
if (st->color_format == DRM_COLOR_FORMAT_YCBCR420)
ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420;
else if (st->color_format == DRM_COLOR_FORMAT_YCRCB422)
else if (st->color_format == DRM_COLOR_FORMAT_YCBCR422)
ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422;
else if (st->color_format == DRM_COLOR_FORMAT_YCRCB444)
else if (st->color_format == DRM_COLOR_FORMAT_YCBCR444)
ctrl |= IPS_CTRL_YUV;
malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);
@ -1144,11 +1144,11 @@ static int d71_improc_init(struct d71_dev *d71,
improc = to_improc(c);
improc->supported_color_depths = BIT(8) | BIT(10);
improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 |
DRM_COLOR_FORMAT_YCRCB444 |
DRM_COLOR_FORMAT_YCRCB422;
DRM_COLOR_FORMAT_YCBCR444 |
DRM_COLOR_FORMAT_YCBCR422;
value = malidp_read32(reg, BLK_INFO);
if (value & IPS_INFO_CHD420)
improc->supported_color_formats |= DRM_COLOR_FORMAT_YCRCB420;
improc->supported_color_formats |= DRM_COLOR_FORMAT_YCBCR420;
improc->supports_csc = true;
improc->supports_gamma = true;

View File

@ -9,6 +9,7 @@
#include <linux/platform_device.h>
#include <linux/component.h>
#include <linux/pm_runtime.h>
#include <drm/drm_module.h>
#include <drm/drm_of.h>
#include "komeda_dev.h"
#include "komeda_kms.h"
@ -198,7 +199,7 @@ static struct platform_driver komeda_platform_driver = {
},
};
module_platform_driver(komeda_platform_driver);
drm_module_platform_driver(komeda_platform_driver);
MODULE_AUTHOR("James.Qian.Wang <james.qian.wang@arm.com>");
MODULE_DESCRIPTION("Komeda KMS driver");

View File

@ -30,6 +30,7 @@
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_modeset_helper.h>
#include <drm/drm_module.h>
#include <drm/drm_of.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
@ -434,7 +435,7 @@ static struct platform_driver hdlcd_platform_driver = {
},
};
module_platform_driver(hdlcd_platform_driver);
drm_module_platform_driver(hdlcd_platform_driver);
MODULE_AUTHOR("Liviu Dudau");
MODULE_DESCRIPTION("ARM HDLCD DRM driver");

View File

@ -25,6 +25,7 @@
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_modeset_helper.h>
#include <drm/drm_module.h>
#include <drm/drm_of.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
@ -1008,7 +1009,7 @@ static struct platform_driver malidp_platform_driver = {
},
};
module_platform_driver(malidp_platform_driver);
drm_module_platform_driver(malidp_platform_driver);
MODULE_AUTHOR("Liviu Dudau <Liviu.Dudau@arm.com>");
MODULE_DESCRIPTION("ARM Mali DP DRM driver");

View File

@ -34,6 +34,7 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem_vram_helper.h>
#include <drm/drm_module.h>
#include <drm/drm_probe_helper.h>
#include "ast_drv.h"
@ -230,22 +231,7 @@ static struct pci_driver ast_pci_driver = {
.driver.pm = &ast_pm_ops,
};
static int __init ast_init(void)
{
if (drm_firmware_drivers_only() && ast_modeset == -1)
return -EINVAL;
if (ast_modeset == 0)
return -EINVAL;
return pci_register_driver(&ast_pci_driver);
}
static void __exit ast_exit(void)
{
pci_unregister_driver(&ast_pci_driver);
}
module_init(ast_init);
module_exit(ast_exit);
drm_module_pci_driver_if_modeset(ast_pci_driver, ast_modeset);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);

View File

@ -209,6 +209,8 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post)
if (ast->chip == AST2500 &&
scu_rev == 0x100) /* ast2510 */
ast->support_wide_screen = true;
if (ast->chip == AST2600) /* ast2600 */
ast->support_wide_screen = true;
}
break;
}

View File

@ -471,7 +471,10 @@ static void ast_set_color_reg(struct ast_private *ast,
static void ast_set_crtthd_reg(struct ast_private *ast)
{
/* Set Threshold */
if (ast->chip == AST2300 || ast->chip == AST2400 ||
if (ast->chip == AST2600) {
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0xe0);
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0xa0);
} else if (ast->chip == AST2300 || ast->chip == AST2400 ||
ast->chip == AST2500) {
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x78);
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x60);

View File

@ -30,6 +30,7 @@ config DRM_CDNS_DSI
config DRM_CHIPONE_ICN6211
tristate "Chipone ICN6211 MIPI-DSI/RGB Converter bridge"
depends on OF
depends on DRM_KMS_HELPER
select DRM_MIPI_DSI
select DRM_PANEL_BRIDGE
help
@ -183,6 +184,7 @@ config DRM_PARADE_PS8640
tristate "Parade PS8640 MIPI DSI to eDP Converter"
depends on OF
select DRM_DP_AUX_BUS
select DRM_DP_HELPER
select DRM_KMS_HELPER
select DRM_MIPI_DSI
select DRM_PANEL
@ -253,6 +255,7 @@ config DRM_TOSHIBA_TC358764
config DRM_TOSHIBA_TC358767
tristate "Toshiba TC358767 eDP bridge"
depends on OF
select DRM_DP_HELPER
select DRM_KMS_HELPER
select REGMAP_I2C
select DRM_PANEL
@ -272,6 +275,7 @@ config DRM_TOSHIBA_TC358768
config DRM_TOSHIBA_TC358775
tristate "Toshiba TC358775 DSI/LVDS bridge"
depends on OF
select DRM_DP_HELPER
select DRM_KMS_HELPER
select REGMAP_I2C
select DRM_PANEL
@ -299,6 +303,7 @@ config DRM_TI_SN65DSI83
config DRM_TI_SN65DSI86
tristate "TI SN65DSI86 DSI to eDP bridge"
depends on OF
select DRM_DP_HELPER
select DRM_KMS_HELPER
select REGMAP_I2C
select DRM_PANEL

View File

@ -169,6 +169,7 @@
#define ADV7511_PACKET_ENABLE_SPARE2 BIT(1)
#define ADV7511_PACKET_ENABLE_SPARE1 BIT(0)
#define ADV7535_REG_POWER2_HPD_OVERRIDE BIT(6)
#define ADV7511_REG_POWER2_HPD_SRC_MASK 0xc0
#define ADV7511_REG_POWER2_HPD_SRC_BOTH 0x00
#define ADV7511_REG_POWER2_HPD_SRC_HPD 0x40

View File

@ -223,7 +223,7 @@ static void adv7511_set_config_csc(struct adv7511 *adv7511,
config.csc_coefficents = adv7511_csc_ycbcr_to_rgb;
if ((connector->display_info.color_formats &
DRM_COLOR_FORMAT_YCRCB422) &&
DRM_COLOR_FORMAT_YCBCR422) &&
config.hdmi_mode) {
config.csc_enable = false;
config.avi_infoframe.colorspace =
@ -351,11 +351,17 @@ static void __adv7511_power_on(struct adv7511 *adv7511)
* from standby or are enabled. When the HPD goes low the adv7511 is
* reset and the outputs are disabled which might cause the monitor to
* go to standby again. To avoid this we ignore the HPD pin for the
* first few seconds after enabling the output.
* first few seconds after enabling the output. On the other hand
* adv7535 require to enable HPD Override bit for proper HPD.
*/
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
ADV7511_REG_POWER2_HPD_SRC_MASK,
ADV7511_REG_POWER2_HPD_SRC_NONE);
if (adv7511->type == ADV7535)
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
ADV7535_REG_POWER2_HPD_OVERRIDE,
ADV7535_REG_POWER2_HPD_OVERRIDE);
else
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
ADV7511_REG_POWER2_HPD_SRC_MASK,
ADV7511_REG_POWER2_HPD_SRC_NONE);
}
static void adv7511_power_on(struct adv7511 *adv7511)
@ -375,6 +381,10 @@ static void adv7511_power_on(struct adv7511 *adv7511)
static void __adv7511_power_off(struct adv7511 *adv7511)
{
/* TODO: setup additional power down modes */
if (adv7511->type == ADV7535)
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
ADV7535_REG_POWER2_HPD_OVERRIDE, 0);
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
ADV7511_POWER_POWER_DOWN,
ADV7511_POWER_POWER_DOWN);
@ -672,9 +682,14 @@ adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector)
status = connector_status_disconnected;
} else {
/* Renable HPD sensing */
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
ADV7511_REG_POWER2_HPD_SRC_MASK,
ADV7511_REG_POWER2_HPD_SRC_BOTH);
if (adv7511->type == ADV7535)
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
ADV7535_REG_POWER2_HPD_OVERRIDE,
ADV7535_REG_POWER2_HPD_OVERRIDE);
else
regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
ADV7511_REG_POWER2_HPD_SRC_MASK,
ADV7511_REG_POWER2_HPD_SRC_BOTH);
}
adv7511->status = status;

View File

@ -29,7 +29,7 @@ static void adv7511_dsi_config_timing_gen(struct adv7511 *adv)
struct mipi_dsi_device *dsi = adv->dsi;
struct drm_display_mode *mode = &adv->curr_mode;
unsigned int hsw, hfp, hbp, vsw, vfp, vbp;
u8 clock_div_by_lanes[] = { 6, 4, 3 }; /* 2, 3, 4 lanes */
static const u8 clock_div_by_lanes[] = { 6, 4, 3 }; /* 2, 3, 4 lanes */
hsw = mode->hsync_end - mode->hsync_start;
hfp = mode->hsync_start - mode->hdisplay;

View File

@ -3,6 +3,7 @@ config DRM_ANALOGIX_ANX6345
tristate "Analogix ANX6345 bridge"
depends on OF
select DRM_ANALOGIX_DP
select DRM_DP_HELPER
select DRM_KMS_HELPER
select REGMAP_I2C
help
@ -14,6 +15,7 @@ config DRM_ANALOGIX_ANX6345
config DRM_ANALOGIX_ANX78XX
tristate "Analogix ANX78XX bridge"
select DRM_ANALOGIX_DP
select DRM_DP_HELPER
select DRM_KMS_HELPER
select REGMAP_I2C
help

View File

@ -22,7 +22,7 @@
#include <drm/drm_bridge.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>

View File

@ -21,7 +21,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_crtc.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>

View File

@ -8,7 +8,7 @@
#include <linux/regmap.h>
#include <drm/drm.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/drm_print.h>
#include "analogix-i2c-dptx.h"

View File

@ -1537,9 +1537,9 @@ static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge,
video->color_depth = COLOR_8;
break;
}
if (display_info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
video->color_space = COLOR_YCBCR444;
else if (display_info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
else if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR422)
video->color_space = COLOR_YCBCR422;
else
video->color_space = COLOR_RGB;

View File

@ -10,7 +10,7 @@
#define _ANALOGIX_DP_CORE_H
#include <drm/drm_crtc.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#define DP_TIMEOUT_LOOP_COUNT 100
#define MAX_CR_LOOP 5

View File

@ -24,8 +24,9 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_hdcp.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
@ -213,6 +214,65 @@ static int wait_aux_op_finish(struct anx7625_data *ctx)
return 0;
}
static int anx7625_aux_dpcd_read(struct anx7625_data *ctx,
u32 address, u8 len, u8 *buf)
{
struct device *dev = &ctx->client->dev;
int ret;
u8 addrh, addrm, addrl;
u8 cmd;
if (len > MAX_DPCD_BUFFER_SIZE) {
dev_err(dev, "exceed aux buffer len.\n");
return -EINVAL;
}
addrl = address & 0xFF;
addrm = (address >> 8) & 0xFF;
addrh = (address >> 16) & 0xFF;
cmd = DPCD_CMD(len, DPCD_READ);
cmd = ((len - 1) << 4) | 0x09;
/* Set command and length */
ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
AP_AUX_COMMAND, cmd);
/* Set aux access address */
ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
AP_AUX_ADDR_7_0, addrl);
ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
AP_AUX_ADDR_15_8, addrm);
ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
AP_AUX_ADDR_19_16, addrh);
/* Enable aux access */
ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client,
AP_AUX_CTRL_STATUS, AP_AUX_CTRL_OP_EN);
if (ret < 0) {
dev_err(dev, "cannot access aux related register.\n");
return -EIO;
}
usleep_range(2000, 2100);
ret = wait_aux_op_finish(ctx);
if (ret) {
dev_err(dev, "aux IO error: wait aux op finish.\n");
return ret;
}
ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,
AP_AUX_BUFF_START, len, buf);
if (ret < 0) {
dev_err(dev, "read dpcd register failed\n");
return -EIO;
}
return 0;
}
static int anx7625_video_mute_control(struct anx7625_data *ctx,
u8 status)
{
@ -669,6 +729,165 @@ static int anx7625_dpi_config(struct anx7625_data *ctx)
return ret;
}
static int anx7625_read_flash_status(struct anx7625_data *ctx)
{
return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, R_RAM_CTRL);
}
static int anx7625_hdcp_key_probe(struct anx7625_data *ctx)
{
int ret, val;
struct device *dev = &ctx->client->dev;
u8 ident[FLASH_BUF_LEN];
ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
FLASH_ADDR_HIGH, 0x91);
ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
FLASH_ADDR_LOW, 0xA0);
if (ret < 0) {
dev_err(dev, "IO error : set key flash address.\n");
return ret;
}
ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
FLASH_LEN_HIGH, (FLASH_BUF_LEN - 1) >> 8);
ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
FLASH_LEN_LOW, (FLASH_BUF_LEN - 1) & 0xFF);
if (ret < 0) {
dev_err(dev, "IO error : set key flash len.\n");
return ret;
}
ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
R_FLASH_RW_CTRL, FLASH_READ);
ret |= readx_poll_timeout(anx7625_read_flash_status,
ctx, val,
((val & FLASH_DONE) || (val < 0)),
2000,
2000 * 150);
if (ret) {
dev_err(dev, "flash read access fail!\n");
return -EIO;
}
ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,
FLASH_BUF_BASE_ADDR,
FLASH_BUF_LEN, ident);
if (ret < 0) {
dev_err(dev, "read flash data fail!\n");
return -EIO;
}
if (ident[29] == 0xFF && ident[30] == 0xFF && ident[31] == 0xFF)
return -EINVAL;
return 0;
}
static int anx7625_hdcp_key_load(struct anx7625_data *ctx)
{
int ret;
struct device *dev = &ctx->client->dev;
/* Select HDCP 1.4 KEY */
ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
R_BOOT_RETRY, 0x12);
ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
FLASH_ADDR_HIGH, HDCP14KEY_START_ADDR >> 8);
ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
FLASH_ADDR_LOW, HDCP14KEY_START_ADDR & 0xFF);
ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
R_RAM_LEN_H, HDCP14KEY_SIZE >> 12);
ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
R_RAM_LEN_L, HDCP14KEY_SIZE >> 4);
ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
R_RAM_ADDR_H, 0);
ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
R_RAM_ADDR_L, 0);
/* Enable HDCP 1.4 KEY load */
ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
R_RAM_CTRL, DECRYPT_EN | LOAD_START);
dev_dbg(dev, "load HDCP 1.4 key done\n");
return ret;
}
static int anx7625_hdcp_disable(struct anx7625_data *ctx)
{
int ret;
struct device *dev = &ctx->client->dev;
dev_dbg(dev, "disable HDCP 1.4\n");
/* Disable HDCP */
ret = anx7625_write_and(ctx, ctx->i2c.rx_p1_client, 0xee, 0x9f);
/* Try auth flag */
ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xec, 0x10);
/* Interrupt for DRM */
ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xff, 0x01);
if (ret < 0)
dev_err(dev, "fail to disable HDCP\n");
return anx7625_write_and(ctx, ctx->i2c.tx_p0_client,
TX_HDCP_CTRL0, ~HARD_AUTH_EN & 0xFF);
}
static int anx7625_hdcp_enable(struct anx7625_data *ctx)
{
u8 bcap;
int ret;
struct device *dev = &ctx->client->dev;
ret = anx7625_hdcp_key_probe(ctx);
if (ret) {
dev_dbg(dev, "no key found, not to do hdcp\n");
return ret;
}
/* Read downstream capability */
anx7625_aux_dpcd_read(ctx, 0x68028, 1, &bcap);
if (!(bcap & 0x01)) {
pr_warn("downstream not support HDCP 1.4, cap(%x).\n", bcap);
return 0;
}
dev_dbg(dev, "enable HDCP 1.4\n");
/* First clear HDCP state */
ret = anx7625_reg_write(ctx, ctx->i2c.tx_p0_client,
TX_HDCP_CTRL0,
KSVLIST_VLD | BKSV_SRM_PASS | RE_AUTHEN);
usleep_range(1000, 1100);
/* Second clear HDCP state */
ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client,
TX_HDCP_CTRL0,
KSVLIST_VLD | BKSV_SRM_PASS | RE_AUTHEN);
/* Set time for waiting KSVR */
ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client,
SP_TX_WAIT_KSVR_TIME, 0xc8);
/* Set time for waiting R0 */
ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client,
SP_TX_WAIT_R0_TIME, 0xb0);
ret |= anx7625_hdcp_key_load(ctx);
if (ret) {
pr_warn("prepare HDCP key failed.\n");
return ret;
}
ret = anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xee, 0x20);
/* Try auth flag */
ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xec, 0x10);
/* Interrupt for DRM */
ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xff, 0x01);
if (ret < 0)
dev_err(dev, "fail to enable HDCP\n");
return anx7625_write_or(ctx, ctx->i2c.tx_p0_client,
TX_HDCP_CTRL0, HARD_AUTH_EN);
}
static void anx7625_dp_start(struct anx7625_data *ctx)
{
int ret;
@ -679,6 +898,9 @@ static void anx7625_dp_start(struct anx7625_data *ctx)
return;
}
/* Disable HDCP */
anx7625_write_and(ctx, ctx->i2c.rx_p1_client, 0xee, 0x9f);
if (ctx->pdata.is_dpi)
ret = anx7625_dpi_config(ctx);
else
@ -686,6 +908,10 @@ static void anx7625_dp_start(struct anx7625_data *ctx)
if (ret < 0)
DRM_DEV_ERROR(dev, "MIPI phy setup error.\n");
ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
ctx->dp_en = 1;
}
static void anx7625_dp_stop(struct anx7625_data *ctx)
@ -705,6 +931,10 @@ static void anx7625_dp_stop(struct anx7625_data *ctx)
ret |= anx7625_video_mute_control(ctx, 1);
if (ret < 0)
DRM_DEV_ERROR(dev, "IO error : mute video fail\n");
ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
ctx->dp_en = 0;
}
static int sp_tx_rst_aux(struct anx7625_data *ctx)
@ -1098,9 +1328,18 @@ static void anx7625_init_gpio(struct anx7625_data *platform)
/* Gpio for chip power enable */
platform->pdata.gpio_p_on =
devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
if (IS_ERR_OR_NULL(platform->pdata.gpio_p_on)) {
DRM_DEV_DEBUG_DRIVER(dev, "no enable gpio found\n");
platform->pdata.gpio_p_on = NULL;
}
/* Gpio for chip reset */
platform->pdata.gpio_reset =
devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR_OR_NULL(platform->pdata.gpio_reset)) {
DRM_DEV_DEBUG_DRIVER(dev, "no reset gpio found\n");
platform->pdata.gpio_reset = NULL;
}
if (platform->pdata.gpio_p_on && platform->pdata.gpio_reset) {
platform->pdata.low_power_mode = 1;
@ -1601,9 +1840,27 @@ static int anx7625_audio_hook_plugged_cb(struct device *dev, void *data,
return 0;
}
static int anx7625_audio_get_eld(struct device *dev, void *data,
u8 *buf, size_t len)
{
struct anx7625_data *ctx = dev_get_drvdata(dev);
if (!ctx->connector) {
dev_err(dev, "connector not initial\n");
return -EINVAL;
}
dev_dbg(dev, "audio copy eld\n");
memcpy(buf, ctx->connector->eld,
min(sizeof(ctx->connector->eld), len));
return 0;
}
static const struct hdmi_codec_ops anx7625_codec_ops = {
.hw_params = anx7625_audio_hw_params,
.audio_shutdown = anx7625_audio_shutdown,
.get_eld = anx7625_audio_get_eld,
.get_dai_id = anx7625_hdmi_i2s_get_dai_id,
.hook_plugged_cb = anx7625_audio_hook_plugged_cb,
};
@ -1660,7 +1917,7 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx)
host = of_find_mipi_dsi_host_by_node(ctx->pdata.mipi_host_node);
if (!host) {
DRM_DEV_ERROR(dev, "fail to find dsi host.\n");
return -EINVAL;
return -EPROBE_DEFER;
}
dsi = devm_mipi_dsi_device_register_full(dev, host, &info);
@ -1688,6 +1945,83 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx)
return 0;
}
static void hdcp_check_work_func(struct work_struct *work)
{
u8 status;
struct delayed_work *dwork;
struct anx7625_data *ctx;
struct device *dev;
struct drm_device *drm_dev;
dwork = to_delayed_work(work);
ctx = container_of(dwork, struct anx7625_data, hdcp_work);
dev = &ctx->client->dev;
if (!ctx->connector) {
dev_err(dev, "HDCP connector is null!");
return;
}
drm_dev = ctx->connector->dev;
drm_modeset_lock(&drm_dev->mode_config.connection_mutex, NULL);
mutex_lock(&ctx->hdcp_wq_lock);
status = anx7625_reg_read(ctx, ctx->i2c.tx_p0_client, 0);
dev_dbg(dev, "sink HDCP status check: %.02x\n", status);
if (status & BIT(1)) {
ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_ENABLED;
drm_hdcp_update_content_protection(ctx->connector,
ctx->hdcp_cp);
dev_dbg(dev, "update CP to ENABLE\n");
}
mutex_unlock(&ctx->hdcp_wq_lock);
drm_modeset_unlock(&drm_dev->mode_config.connection_mutex);
}
static int anx7625_connector_atomic_check(struct anx7625_data *ctx,
struct drm_connector_state *state)
{
struct device *dev = &ctx->client->dev;
int cp;
dev_dbg(dev, "hdcp state check\n");
cp = state->content_protection;
if (cp == ctx->hdcp_cp)
return 0;
if (cp == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
if (ctx->dp_en) {
dev_dbg(dev, "enable HDCP\n");
anx7625_hdcp_enable(ctx);
queue_delayed_work(ctx->hdcp_workqueue,
&ctx->hdcp_work,
msecs_to_jiffies(2000));
}
}
if (cp == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
if (ctx->hdcp_cp != DRM_MODE_CONTENT_PROTECTION_ENABLED) {
dev_err(dev, "current CP is not ENABLED\n");
return -EINVAL;
}
anx7625_hdcp_disable(ctx);
ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
drm_hdcp_update_content_protection(ctx->connector,
ctx->hdcp_cp);
dev_dbg(dev, "update CP to UNDESIRE\n");
}
if (cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
dev_err(dev, "Userspace illegal set to PROTECTION ENABLE\n");
return -EINVAL;
}
return 0;
}
static int anx7625_bridge_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
@ -1902,25 +2236,57 @@ static bool anx7625_bridge_mode_fixup(struct drm_bridge *bridge,
return true;
}
static void anx7625_bridge_enable(struct drm_bridge *bridge)
static int anx7625_bridge_atomic_check(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
struct anx7625_data *ctx = bridge_to_anx7625(bridge);
struct device *dev = &ctx->client->dev;
DRM_DEV_DEBUG_DRIVER(dev, "drm enable\n");
dev_dbg(dev, "drm bridge atomic check\n");
anx7625_bridge_mode_fixup(bridge, &crtc_state->mode,
&crtc_state->adjusted_mode);
return anx7625_connector_atomic_check(ctx, conn_state);
}
static void anx7625_bridge_atomic_enable(struct drm_bridge *bridge,
struct drm_bridge_state *state)
{
struct anx7625_data *ctx = bridge_to_anx7625(bridge);
struct device *dev = &ctx->client->dev;
struct drm_connector *connector;
dev_dbg(dev, "drm atomic enable\n");
if (!bridge->encoder) {
dev_err(dev, "Parent encoder object not found");
return;
}
connector = drm_atomic_get_new_connector_for_encoder(state->base.state,
bridge->encoder);
if (!connector)
return;
ctx->connector = connector;
pm_runtime_get_sync(dev);
anx7625_dp_start(ctx);
}
static void anx7625_bridge_disable(struct drm_bridge *bridge)
static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge,
struct drm_bridge_state *old)
{
struct anx7625_data *ctx = bridge_to_anx7625(bridge);
struct device *dev = &ctx->client->dev;
DRM_DEV_DEBUG_DRIVER(dev, "drm disable\n");
dev_dbg(dev, "drm atomic disable\n");
ctx->connector = NULL;
anx7625_dp_stop(ctx);
pm_runtime_put_sync(dev);
@ -1950,11 +2316,14 @@ static struct edid *anx7625_bridge_get_edid(struct drm_bridge *bridge,
static const struct drm_bridge_funcs anx7625_bridge_funcs = {
.attach = anx7625_bridge_attach,
.disable = anx7625_bridge_disable,
.mode_valid = anx7625_bridge_mode_valid,
.mode_set = anx7625_bridge_mode_set,
.mode_fixup = anx7625_bridge_mode_fixup,
.enable = anx7625_bridge_enable,
.atomic_check = anx7625_bridge_atomic_check,
.atomic_enable = anx7625_bridge_atomic_enable,
.atomic_disable = anx7625_bridge_atomic_disable,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_reset = drm_atomic_helper_bridge_reset,
.detect = anx7625_bridge_detect,
.get_edid = anx7625_bridge_get_edid,
};
@ -1962,40 +2331,54 @@ static const struct drm_bridge_funcs anx7625_bridge_funcs = {
static int anx7625_register_i2c_dummy_clients(struct anx7625_data *ctx,
struct i2c_client *client)
{
int err = 0;
ctx->i2c.tx_p0_client = i2c_new_dummy_device(client->adapter,
TX_P0_ADDR >> 1);
if (!ctx->i2c.tx_p0_client)
return -ENOMEM;
if (IS_ERR(ctx->i2c.tx_p0_client))
return PTR_ERR(ctx->i2c.tx_p0_client);
ctx->i2c.tx_p1_client = i2c_new_dummy_device(client->adapter,
TX_P1_ADDR >> 1);
if (!ctx->i2c.tx_p1_client)
if (IS_ERR(ctx->i2c.tx_p1_client)) {
err = PTR_ERR(ctx->i2c.tx_p1_client);
goto free_tx_p0;
}
ctx->i2c.tx_p2_client = i2c_new_dummy_device(client->adapter,
TX_P2_ADDR >> 1);
if (!ctx->i2c.tx_p2_client)
if (IS_ERR(ctx->i2c.tx_p2_client)) {
err = PTR_ERR(ctx->i2c.tx_p2_client);
goto free_tx_p1;
}
ctx->i2c.rx_p0_client = i2c_new_dummy_device(client->adapter,
RX_P0_ADDR >> 1);
if (!ctx->i2c.rx_p0_client)
if (IS_ERR(ctx->i2c.rx_p0_client)) {
err = PTR_ERR(ctx->i2c.rx_p0_client);
goto free_tx_p2;
}
ctx->i2c.rx_p1_client = i2c_new_dummy_device(client->adapter,
RX_P1_ADDR >> 1);
if (!ctx->i2c.rx_p1_client)
if (IS_ERR(ctx->i2c.rx_p1_client)) {
err = PTR_ERR(ctx->i2c.rx_p1_client);
goto free_rx_p0;
}
ctx->i2c.rx_p2_client = i2c_new_dummy_device(client->adapter,
RX_P2_ADDR >> 1);
if (!ctx->i2c.rx_p2_client)
if (IS_ERR(ctx->i2c.rx_p2_client)) {
err = PTR_ERR(ctx->i2c.rx_p2_client);
goto free_rx_p1;
}
ctx->i2c.tcpc_client = i2c_new_dummy_device(client->adapter,
TCPC_INTERFACE_ADDR >> 1);
if (!ctx->i2c.tcpc_client)
if (IS_ERR(ctx->i2c.tcpc_client)) {
err = PTR_ERR(ctx->i2c.tcpc_client);
goto free_rx_p2;
}
return 0;
@ -2012,7 +2395,7 @@ static int anx7625_register_i2c_dummy_clients(struct anx7625_data *ctx,
free_tx_p0:
i2c_unregister_device(ctx->i2c.tx_p0_client);
return -ENOMEM;
return err;
}
static void anx7625_unregister_i2c_dummy_clients(struct anx7625_data *ctx)
@ -2134,6 +2517,15 @@ static int anx7625_i2c_probe(struct i2c_client *client,
anx7625_init_gpio(platform);
mutex_init(&platform->lock);
mutex_init(&platform->hdcp_wq_lock);
INIT_DELAYED_WORK(&platform->hdcp_work, hdcp_check_work_func);
platform->hdcp_workqueue = create_workqueue("hdcp workqueue");
if (!platform->hdcp_workqueue) {
dev_err(dev, "fail to create work queue\n");
ret = -ENOMEM;
goto free_platform;
}
platform->pdata.intp_irq = client->irq;
if (platform->pdata.intp_irq) {
@ -2143,7 +2535,7 @@ static int anx7625_i2c_probe(struct i2c_client *client,
if (!platform->workqueue) {
DRM_DEV_ERROR(dev, "fail to create work queue\n");
ret = -ENOMEM;
goto free_platform;
goto free_hdcp_wq;
}
ret = devm_request_threaded_irq(dev, platform->pdata.intp_irq,
@ -2213,6 +2605,10 @@ static int anx7625_i2c_probe(struct i2c_client *client,
if (platform->workqueue)
destroy_workqueue(platform->workqueue);
free_hdcp_wq:
if (platform->hdcp_workqueue)
destroy_workqueue(platform->hdcp_workqueue);
free_platform:
kfree(platform);
@ -2228,6 +2624,12 @@ static int anx7625_i2c_remove(struct i2c_client *client)
if (platform->pdata.intp_irq)
destroy_workqueue(platform->workqueue);
if (platform->hdcp_workqueue) {
cancel_delayed_work(&platform->hdcp_work);
flush_workqueue(platform->workqueue);
destroy_workqueue(platform->workqueue);
}
if (!platform->pdata.low_power_mode)
pm_runtime_put_sync_suspend(&client->dev);

View File

@ -59,10 +59,23 @@
/***************************************************************/
/* Register definition of device address 0x70 */
#define I2C_ADDR_70_DPTX 0x70
#define TX_HDCP_CTRL0 0x01
#define STORE_AN BIT(7)
#define RX_REPEATER BIT(6)
#define RE_AUTHEN BIT(5)
#define SW_AUTH_OK BIT(4)
#define HARD_AUTH_EN BIT(3)
#define ENC_EN BIT(2)
#define BKSV_SRM_PASS BIT(1)
#define KSVLIST_VLD BIT(0)
#define SP_TX_LINK_BW_SET_REG 0xA0
#define SP_TX_LANE_COUNT_SET_REG 0xA1
#define SP_TX_WAIT_R0_TIME 0x40
#define SP_TX_WAIT_KSVR_TIME 0x42
#define SP_TX_SYS_CTRL1_REG 0x80
#define HDCP2TX_FW_EN BIT(4)
#define SP_TX_LINK_BW_SET_REG 0xA0
#define SP_TX_LANE_COUNT_SET_REG 0xA1
#define M_VID_0 0xC0
#define M_VID_1 0xC1
@ -71,6 +84,12 @@
#define N_VID_1 0xC4
#define N_VID_2 0xC5
#define KEY_START_ADDR 0x9000
#define KEY_RESERVED 416
#define HDCP14KEY_START_ADDR (KEY_START_ADDR + KEY_RESERVED)
#define HDCP14KEY_SIZE 624
/***************************************************************/
/* Register definition of device address 0x72 */
#define AUX_RST 0x04
@ -155,9 +174,43 @@
#define I2C_ADDR_7E_FLASH_CONTROLLER 0x7E
#define R_BOOT_RETRY 0x00
#define R_RAM_ADDR_H 0x01
#define R_RAM_ADDR_L 0x02
#define R_RAM_LEN_H 0x03
#define R_RAM_LEN_L 0x04
#define FLASH_LOAD_STA 0x05
#define FLASH_LOAD_STA_CHK BIT(7)
#define R_RAM_CTRL 0x05
/* bit positions */
#define FLASH_DONE BIT(7)
#define BOOT_LOAD_DONE BIT(6)
#define CRC_OK BIT(5)
#define LOAD_DONE BIT(4)
#define O_RW_DONE BIT(3)
#define FUSE_BUSY BIT(2)
#define DECRYPT_EN BIT(1)
#define LOAD_START BIT(0)
#define FLASH_ADDR_HIGH 0x0F
#define FLASH_ADDR_LOW 0x10
#define FLASH_LEN_HIGH 0x31
#define FLASH_LEN_LOW 0x32
#define R_FLASH_RW_CTRL 0x33
/* bit positions */
#define READ_DELAY_SELECT BIT(7)
#define GENERAL_INSTRUCTION_EN BIT(6)
#define FLASH_ERASE_EN BIT(5)
#define RDID_READ_EN BIT(4)
#define REMS_READ_EN BIT(3)
#define WRITE_STATUS_EN BIT(2)
#define FLASH_READ BIT(1)
#define FLASH_WRITE BIT(0)
#define FLASH_BUF_BASE_ADDR 0x60
#define FLASH_BUF_LEN 0x20
#define XTAL_FRQ_SEL 0x3F
/* bit field positions */
#define XTAL_FRQ_SEL_POS 5
@ -184,10 +237,15 @@
#define AP_AUX_CTRL_ADDRONLY 0x20
#define AP_AUX_BUFF_START 0x15
#define PIXEL_CLOCK_L 0x25
#define PIXEL_CLOCK_H 0x26
#define PIXEL_CLOCK_L 0x25
#define PIXEL_CLOCK_H 0x26
#define AP_AUX_COMMAND 0x27 /* com+len */
#define LENGTH_SHIFT 4
#define DPCD_READ 0x09
#define DPCD_WRITE 0x08
#define DPCD_CMD(len, cmd) ((((len) - 1) << LENGTH_SHIFT) | (cmd))
#define AP_AUX_COMMAND 0x27 /* com+len */
/* Bit 0&1: 3D video structure */
/* 0x01: frame packing, 0x02:Line alternative, 0x03:Side-by-side(full) */
#define AP_AV_STATUS 0x28
@ -392,21 +450,29 @@ struct anx7625_data {
struct platform_device *audio_pdev;
int hpd_status;
int hpd_high_cnt;
int dp_en;
int hdcp_cp;
/* Lock for work queue */
struct mutex lock;
struct i2c_client *client;
struct anx7625_i2c_client i2c;
struct i2c_client *last_client;
struct timer_list hdcp_timer;
struct s_edid_data slimport_edid_p;
struct device *codec_dev;
hdmi_codec_plugged_cb plugged_cb;
struct work_struct work;
struct workqueue_struct *workqueue;
struct delayed_work hdcp_work;
struct workqueue_struct *hdcp_workqueue;
/* Lock for hdcp work queue */
struct mutex hdcp_wq_lock;
char edid_block;
struct display_timing dt;
u8 display_timing_valid;
struct drm_bridge bridge;
u8 bridge_attached;
struct drm_connector *connector;
struct mipi_dsi_device *dsi;
};

View File

@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config DRM_CDNS_MHDP8546
tristate "Cadence DPI/DP bridge"
select DRM_DP_HELPER
select DRM_KMS_HELPER
select DRM_PANEL_BRIDGE
depends on OF

View File

@ -41,7 +41,7 @@
#include <drm/drm_bridge.h>
#include <drm/drm_connector.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/drm_hdcp.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
@ -1553,13 +1553,13 @@ static u32 cdns_mhdp_get_bpp(struct cdns_mhdp_display_fmt *fmt)
switch (fmt->color_format) {
case DRM_COLOR_FORMAT_RGB444:
case DRM_COLOR_FORMAT_YCRCB444:
case DRM_COLOR_FORMAT_YCBCR444:
bpp = fmt->bpc * 3;
break;
case DRM_COLOR_FORMAT_YCRCB422:
case DRM_COLOR_FORMAT_YCBCR422:
bpp = fmt->bpc * 2;
break;
case DRM_COLOR_FORMAT_YCRCB420:
case DRM_COLOR_FORMAT_YCBCR420:
bpp = fmt->bpc * 3 / 2;
break;
default:
@ -1767,8 +1767,8 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp,
* If YCBCR supported and stream not SD, use ITU709
* Need to handle ITU version with YCBCR420 when supported
*/
if ((pxlfmt == DRM_COLOR_FORMAT_YCRCB444 ||
pxlfmt == DRM_COLOR_FORMAT_YCRCB422) && mode->crtc_vdisplay >= 720)
if ((pxlfmt == DRM_COLOR_FORMAT_YCBCR444 ||
pxlfmt == DRM_COLOR_FORMAT_YCBCR422) && mode->crtc_vdisplay >= 720)
misc0 = DP_YCBCR_COEFFICIENTS_ITU709;
bpp = cdns_mhdp_get_bpp(&mhdp->display_fmt);
@ -1778,15 +1778,15 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp,
pxl_repr = CDNS_DP_FRAMER_RGB << CDNS_DP_FRAMER_PXL_FORMAT;
misc0 |= DP_COLOR_FORMAT_RGB;
break;
case DRM_COLOR_FORMAT_YCRCB444:
case DRM_COLOR_FORMAT_YCBCR444:
pxl_repr = CDNS_DP_FRAMER_YCBCR444 << CDNS_DP_FRAMER_PXL_FORMAT;
misc0 |= DP_COLOR_FORMAT_YCbCr444 | DP_TEST_DYNAMIC_RANGE_CEA;
break;
case DRM_COLOR_FORMAT_YCRCB422:
case DRM_COLOR_FORMAT_YCBCR422:
pxl_repr = CDNS_DP_FRAMER_YCBCR422 << CDNS_DP_FRAMER_PXL_FORMAT;
misc0 |= DP_COLOR_FORMAT_YCbCr422 | DP_TEST_DYNAMIC_RANGE_CEA;
break;
case DRM_COLOR_FORMAT_YCRCB420:
case DRM_COLOR_FORMAT_YCBCR420:
pxl_repr = CDNS_DP_FRAMER_YCBCR420 << CDNS_DP_FRAMER_PXL_FORMAT;
break;
default:
@ -1882,7 +1882,7 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp,
if (mhdp->display_fmt.y_only)
misc1 |= CDNS_DP_TEST_COLOR_FORMAT_RAW_Y_ONLY;
/* Use VSC SDP for Y420 */
if (pxlfmt == DRM_COLOR_FORMAT_YCRCB420)
if (pxlfmt == DRM_COLOR_FORMAT_YCBCR420)
misc1 = CDNS_DP_TEST_VSC_SDP;
cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_MISC(stream_id),

View File

@ -17,7 +17,7 @@
#include <drm/drm_bridge.h>
#include <drm/drm_connector.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
struct clk;
struct device;

View File

@ -4,6 +4,7 @@
* Author: Jagan Teki <jagan@amarulasolutions.com>
*/
#include <drm/drm_atomic_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_mipi_dsi.h>
@ -30,6 +31,7 @@
struct chipone {
struct device *dev;
struct drm_bridge bridge;
struct drm_display_mode mode;
struct drm_bridge *panel_bridge;
struct gpio_desc *enable_gpio;
struct regulator *vdd1;
@ -42,11 +44,6 @@ static inline struct chipone *bridge_to_chipone(struct drm_bridge *bridge)
return container_of(bridge, struct chipone, bridge);
}
static struct drm_display_mode *bridge_to_mode(struct drm_bridge *bridge)
{
return &bridge->encoder->crtc->state->adjusted_mode;
}
static inline int chipone_dsi_write(struct chipone *icn, const void *seq,
size_t len)
{
@ -61,10 +58,11 @@ static inline int chipone_dsi_write(struct chipone *icn, const void *seq,
chipone_dsi_write(icn, d, ARRAY_SIZE(d)); \
}
static void chipone_enable(struct drm_bridge *bridge)
static void chipone_atomic_enable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct chipone *icn = bridge_to_chipone(bridge);
struct drm_display_mode *mode = bridge_to_mode(bridge);
struct drm_display_mode *mode = &icn->mode;
ICN6211_DSI(icn, 0x7a, 0xc1);
@ -114,7 +112,8 @@ static void chipone_enable(struct drm_bridge *bridge)
usleep_range(10000, 11000);
}
static void chipone_pre_enable(struct drm_bridge *bridge)
static void chipone_atomic_pre_enable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct chipone *icn = bridge_to_chipone(bridge);
int ret;
@ -145,7 +144,8 @@ static void chipone_pre_enable(struct drm_bridge *bridge)
usleep_range(10000, 11000);
}
static void chipone_post_disable(struct drm_bridge *bridge)
static void chipone_atomic_post_disable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct chipone *icn = bridge_to_chipone(bridge);
@ -161,6 +161,15 @@ static void chipone_post_disable(struct drm_bridge *bridge)
gpiod_set_value(icn->enable_gpio, 0);
}
static void chipone_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
const struct drm_display_mode *adjusted_mode)
{
struct chipone *icn = bridge_to_chipone(bridge);
drm_mode_copy(&icn->mode, adjusted_mode);
}
static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags)
{
struct chipone *icn = bridge_to_chipone(bridge);
@ -169,10 +178,14 @@ static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flag
}
static const struct drm_bridge_funcs chipone_bridge_funcs = {
.attach = chipone_attach,
.post_disable = chipone_post_disable,
.pre_enable = chipone_pre_enable,
.enable = chipone_enable,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_pre_enable = chipone_atomic_pre_enable,
.atomic_enable = chipone_atomic_enable,
.atomic_post_disable = chipone_atomic_post_disable,
.mode_set = chipone_mode_set,
.attach = chipone_attach,
};
static int chipone_parse_dt(struct chipone *icn)

View File

@ -936,9 +936,6 @@ static int it66121_probe(struct i2c_client *client,
return -EPROBE_DEFER;
}
if (!ctx->next_bridge)
return -EPROBE_DEFER;
i2c_set_clientdata(client, ctx);
mutex_init(&ctx->lock);

View File

@ -1090,7 +1090,7 @@ static int lt9611_probe(struct i2c_client *client,
if (!lt9611)
return -ENOMEM;
lt9611->dev = &client->dev;
lt9611->dev = dev;
lt9611->client = client;
lt9611->sleep = false;
@ -1100,7 +1100,7 @@ static int lt9611_probe(struct i2c_client *client,
return PTR_ERR(lt9611->regmap);
}
ret = lt9611_parse_dt(&client->dev, lt9611);
ret = lt9611_parse_dt(dev, lt9611);
if (ret) {
dev_err(dev, "failed to parse device tree\n");
return ret;

View File

@ -860,7 +860,7 @@ static int lt9611uxc_probe(struct i2c_client *client,
if (!lt9611uxc)
return -ENOMEM;
lt9611uxc->dev = &client->dev;
lt9611uxc->dev = dev;
lt9611uxc->client = client;
mutex_init(&lt9611uxc->ocm_lock);
@ -870,7 +870,7 @@ static int lt9611uxc_probe(struct i2c_client *client,
return PTR_ERR(lt9611uxc->regmap);
}
ret = lt9611uxc_parse_dt(&client->dev, lt9611uxc);
ret = lt9611uxc_parse_dt(dev, lt9611uxc);
if (ret) {
dev_err(dev, "failed to parse device tree\n");
return ret;

View File

@ -65,7 +65,6 @@ struct nwl_dsi_transfer {
struct nwl_dsi {
struct drm_bridge bridge;
struct mipi_dsi_host dsi_host;
struct drm_bridge *panel_bridge;
struct device *dev;
struct phy *phy;
union phy_configure_opts phy_cfg;
@ -924,13 +923,11 @@ static int nwl_dsi_bridge_attach(struct drm_bridge *bridge,
if (IS_ERR(panel_bridge))
return PTR_ERR(panel_bridge);
}
dsi->panel_bridge = panel_bridge;
if (!dsi->panel_bridge)
if (!panel_bridge)
return -EPROBE_DEFER;
return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge,
flags);
return drm_bridge_attach(bridge->encoder, panel_bridge, bridge, flags);
}
static void nwl_dsi_bridge_detach(struct drm_bridge *bridge)
@ -1206,6 +1203,7 @@ static int nwl_dsi_probe(struct platform_device *pdev)
ret = nwl_dsi_select_input(dsi);
if (ret < 0) {
pm_runtime_disable(dev);
mipi_dsi_host_unregister(&dsi->dsi_host);
return ret;
}

View File

@ -14,8 +14,8 @@
#include <linux/regulator/consumer.h>
#include <drm/drm_bridge.h>
#include <drm/drm_dp_aux_bus.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_aux_bus.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
@ -102,6 +102,7 @@ struct ps8640 {
struct regulator_bulk_data supplies[2];
struct gpio_desc *gpio_reset;
struct gpio_desc *gpio_powerdown;
struct device_link *link;
bool pre_enabled;
};
@ -456,14 +457,36 @@ static int ps8640_bridge_attach(struct drm_bridge *bridge,
return ret;
}
ps_bridge->link = device_link_add(bridge->dev->dev, dev, DL_FLAG_STATELESS);
if (!ps_bridge->link) {
dev_err(dev, "failed to create device link");
ret = -EINVAL;
goto err_devlink;
}
/* Attach the panel-bridge to the dsi bridge */
return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
&ps_bridge->bridge, flags);
ret = drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
&ps_bridge->bridge, flags);
if (ret)
goto err_bridge_attach;
return 0;
err_bridge_attach:
device_link_del(ps_bridge->link);
err_devlink:
drm_dp_aux_unregister(&ps_bridge->aux);
return ret;
}
static void ps8640_bridge_detach(struct drm_bridge *bridge)
{
drm_dp_aux_unregister(&bridge_to_ps8640(bridge)->aux);
struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
drm_dp_aux_unregister(&ps_bridge->aux);
if (ps_bridge->link)
device_link_del(ps_bridge->link);
}
static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,

View File

@ -166,10 +166,12 @@ struct sii902x {
struct i2c_client *i2c;
struct regmap *regmap;
struct drm_bridge bridge;
struct drm_bridge *next_bridge;
struct drm_connector connector;
struct gpio_desc *reset_gpio;
struct i2c_mux_core *i2cmux;
struct regulator_bulk_data supplies[2];
bool sink_is_hdmi;
/*
* Mutex protects audio and video functions from interfering
* each other, by keeping their i2c command sequences atomic.
@ -245,10 +247,8 @@ static void sii902x_reset(struct sii902x *sii902x)
gpiod_set_value(sii902x->reset_gpio, 0);
}
static enum drm_connector_status
sii902x_connector_detect(struct drm_connector *connector, bool force)
static enum drm_connector_status sii902x_detect(struct sii902x *sii902x)
{
struct sii902x *sii902x = connector_to_sii902x(connector);
unsigned int status;
mutex_lock(&sii902x->mutex);
@ -261,6 +261,14 @@ sii902x_connector_detect(struct drm_connector *connector, bool force)
connector_status_connected : connector_status_disconnected;
}
static enum drm_connector_status
sii902x_connector_detect(struct drm_connector *connector, bool force)
{
struct sii902x *sii902x = connector_to_sii902x(connector);
return sii902x_detect(sii902x);
}
static const struct drm_connector_funcs sii902x_connector_funcs = {
.detect = sii902x_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
@ -270,42 +278,40 @@ static const struct drm_connector_funcs sii902x_connector_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int sii902x_get_modes(struct drm_connector *connector)
static struct edid *sii902x_get_edid(struct sii902x *sii902x,
struct drm_connector *connector)
{
struct sii902x *sii902x = connector_to_sii902x(connector);
u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI;
struct edid *edid;
int num = 0, ret;
mutex_lock(&sii902x->mutex);
edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]);
drm_connector_update_edid_property(connector, edid);
if (edid) {
if (drm_detect_hdmi_monitor(edid))
output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI;
sii902x->sink_is_hdmi = true;
else
sii902x->sink_is_hdmi = false;
}
mutex_unlock(&sii902x->mutex);
return edid;
}
static int sii902x_get_modes(struct drm_connector *connector)
{
struct sii902x *sii902x = connector_to_sii902x(connector);
struct edid *edid;
int num = 0;
edid = sii902x_get_edid(sii902x, connector);
drm_connector_update_edid_property(connector, edid);
if (edid) {
num = drm_add_edid_modes(connector, edid);
kfree(edid);
}
ret = drm_display_info_set_bus_formats(&connector->display_info,
&bus_format, 1);
if (ret)
goto error_out;
ret = regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA,
SII902X_SYS_CTRL_OUTPUT_MODE, output_mode);
if (ret)
goto error_out;
ret = num;
error_out:
mutex_unlock(&sii902x->mutex);
return ret;
return num;
}
static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector,
@ -354,12 +360,16 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *adj)
{
struct sii902x *sii902x = bridge_to_sii902x(bridge);
u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI;
struct regmap *regmap = sii902x->regmap;
u8 buf[HDMI_INFOFRAME_SIZE(AVI)];
struct hdmi_avi_infoframe frame;
u16 pixel_clock_10kHz = adj->clock / 10;
int ret;
if (sii902x->sink_is_hdmi)
output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI;
buf[0] = pixel_clock_10kHz & 0xff;
buf[1] = pixel_clock_10kHz >> 8;
buf[2] = drm_mode_vrefresh(adj);
@ -375,6 +385,11 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge,
mutex_lock(&sii902x->mutex);
ret = regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA,
SII902X_SYS_CTRL_OUTPUT_MODE, output_mode);
if (ret)
goto out;
ret = regmap_bulk_write(regmap, SII902X_TPI_VIDEO_DATA, buf, 10);
if (ret)
goto out;
@ -405,13 +420,13 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
struct sii902x *sii902x = bridge_to_sii902x(bridge);
u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
struct drm_device *drm = bridge->dev;
int ret;
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
DRM_ERROR("Fix bridge driver to make connector optional!");
return -EINVAL;
}
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
return drm_bridge_attach(bridge->encoder, sii902x->next_bridge,
bridge, flags);
drm_connector_helper_add(&sii902x->connector,
&sii902x_connector_helper_funcs);
@ -433,16 +448,38 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge,
else
sii902x->connector.polled = DRM_CONNECTOR_POLL_CONNECT;
ret = drm_display_info_set_bus_formats(&sii902x->connector.display_info,
&bus_format, 1);
if (ret)
return ret;
drm_connector_attach_encoder(&sii902x->connector, bridge->encoder);
return 0;
}
static enum drm_connector_status sii902x_bridge_detect(struct drm_bridge *bridge)
{
struct sii902x *sii902x = bridge_to_sii902x(bridge);
return sii902x_detect(sii902x);
}
static struct edid *sii902x_bridge_get_edid(struct drm_bridge *bridge,
struct drm_connector *connector)
{
struct sii902x *sii902x = bridge_to_sii902x(bridge);
return sii902x_get_edid(sii902x, connector);
}
static const struct drm_bridge_funcs sii902x_bridge_funcs = {
.attach = sii902x_bridge_attach,
.mode_set = sii902x_bridge_mode_set,
.disable = sii902x_bridge_disable,
.enable = sii902x_bridge_enable,
.detect = sii902x_bridge_detect,
.get_edid = sii902x_bridge_get_edid,
};
static int sii902x_mute(struct sii902x *sii902x, bool mute)
@ -829,8 +866,12 @@ static irqreturn_t sii902x_interrupt(int irq, void *data)
mutex_unlock(&sii902x->mutex);
if ((status & SII902X_HOTPLUG_EVENT) && sii902x->bridge.dev)
if ((status & SII902X_HOTPLUG_EVENT) && sii902x->bridge.dev) {
drm_helper_hpd_irq_event(sii902x->bridge.dev);
drm_bridge_hpd_notify(&sii902x->bridge, (status & SII902X_PLUGGED_STATUS)
? connector_status_connected
: connector_status_disconnected);
}
return IRQ_HANDLED;
}
@ -1001,6 +1042,11 @@ static int sii902x_init(struct sii902x *sii902x)
sii902x->bridge.funcs = &sii902x_bridge_funcs;
sii902x->bridge.of_node = dev->of_node;
sii902x->bridge.timings = &default_sii902x_timings;
sii902x->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID;
if (sii902x->i2c->irq > 0)
sii902x->bridge.ops |= DRM_BRIDGE_OP_HPD;
drm_bridge_add(&sii902x->bridge);
sii902x_audio_codec_init(sii902x, dev);
@ -1022,6 +1068,7 @@ static int sii902x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *endpoint;
struct sii902x *sii902x;
int ret;
@ -1049,6 +1096,28 @@ static int sii902x_probe(struct i2c_client *client,
return PTR_ERR(sii902x->reset_gpio);
}
endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1);
if (endpoint) {
struct device_node *remote = of_graph_get_remote_port_parent(endpoint);
of_node_put(endpoint);
if (!remote) {
dev_err(dev, "Endpoint in port@1 unconnected\n");
return -ENODEV;
}
if (!of_device_is_available(remote)) {
dev_err(dev, "port@1 remote device is disabled\n");
of_node_put(remote);
return -ENODEV;
}
sii902x->next_bridge = of_drm_find_bridge(remote);
of_node_put(remote);
if (!sii902x->next_bridge)
return -EPROBE_DEFER;
}
mutex_init(&sii902x->mutex);
sii902x->supplies[0].supply = "iovcc";

View File

@ -2120,7 +2120,7 @@ static void sii8620_init_rcp_input_dev(struct sii8620 *ctx)
if (ret) {
dev_err(ctx->dev, "Failed to register RC device\n");
ctx->error = ret;
rc_free_device(ctx->rc_dev);
rc_free_device(rc_dev);
return;
}
ctx->rc_dev = rc_dev;

View File

@ -2540,7 +2540,7 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
struct drm_display_mode *mode = &crtc_state->mode;
u8 max_bpc = conn_state->max_requested_bpc;
bool is_hdmi2_sink = info->hdmi.scdc.supported ||
(info->color_formats & DRM_COLOR_FORMAT_YCRCB420);
(info->color_formats & DRM_COLOR_FORMAT_YCBCR420);
u32 *output_fmts;
unsigned int i = 0;
@ -2594,36 +2594,36 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
*/
if (max_bpc >= 16 && info->bpc == 16) {
if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
}
if (max_bpc >= 12 && info->bpc >= 12) {
if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422)
output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
}
if (max_bpc >= 10 && info->bpc >= 10) {
if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422)
output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
}
if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422)
output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444)
output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
/* Default 8bit RGB fallback */

View File

@ -871,7 +871,8 @@ static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi)
dsi_write(dsi, DSI_INT_MSK1, 0);
}
static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
static void dw_mipi_dsi_bridge_post_atomic_disable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
@ -978,7 +979,8 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
dw_mipi_dsi_mode_set(dsi->slave, adjusted_mode);
}
static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge)
static void dw_mipi_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
@ -998,7 +1000,10 @@ dw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge,
enum drm_mode_status mode_status = MODE_OK;
if (pdata->mode_valid)
mode_status = pdata->mode_valid(pdata->priv_data, mode);
mode_status = pdata->mode_valid(pdata->priv_data, mode,
dsi->mode_flags,
dw_mipi_dsi_get_lanes(dsi),
dsi->format);
return mode_status;
}
@ -1032,11 +1037,14 @@ static int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge,
}
static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = {
.mode_set = dw_mipi_dsi_bridge_mode_set,
.enable = dw_mipi_dsi_bridge_enable,
.post_disable = dw_mipi_dsi_bridge_post_disable,
.mode_valid = dw_mipi_dsi_bridge_mode_valid,
.attach = dw_mipi_dsi_bridge_attach,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_enable = dw_mipi_dsi_bridge_atomic_enable,
.atomic_post_disable = dw_mipi_dsi_bridge_post_atomic_disable,
.mode_set = dw_mipi_dsi_bridge_mode_set,
.mode_valid = dw_mipi_dsi_bridge_mode_valid,
.attach = dw_mipi_dsi_bridge_attach,
};
#ifdef CONFIG_DEBUG_FS
@ -1199,6 +1207,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
ret = mipi_dsi_host_register(&dsi->dsi_host);
if (ret) {
dev_err(dev, "Failed to register MIPI host: %d\n", ret);
pm_runtime_disable(dev);
dw_mipi_dsi_debugfs_remove(dsi);
return ERR_PTR(ret);
}

View File

@ -27,7 +27,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>

View File

@ -22,7 +22,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
@ -241,7 +241,7 @@ static inline u32 TC358775_LVCFG_PCLKDIV(uint32_t val)
}
#define TC358775_LVCFG_LVDLINK__MASK 0x00000002
#define TC358775_LVCFG_LVDLINK__SHIFT 0
#define TC358775_LVCFG_LVDLINK__SHIFT 1
static inline u32 TC358775_LVCFG_LVDLINK(uint32_t val)
{
return ((val) << TC358775_LVCFG_LVDLINK__SHIFT) &

View File

@ -33,6 +33,7 @@
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
@ -143,6 +144,7 @@ struct sn65dsi83 {
struct mipi_dsi_device *dsi;
struct drm_bridge *panel_bridge;
struct gpio_desc *enable_gpio;
struct regulator *vcc;
int dsi_lanes;
bool lvds_dual_link;
bool lvds_dual_link_even_odd_swap;
@ -337,6 +339,12 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge,
u16 val;
int ret;
ret = regulator_enable(ctx->vcc);
if (ret) {
dev_err(ctx->dev, "Failed to enable vcc: %d\n", ret);
return;
}
/* Deassert reset */
gpiod_set_value(ctx->enable_gpio, 1);
usleep_range(1000, 1100);
@ -486,11 +494,16 @@ static void sn65dsi83_atomic_disable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
int ret;
/* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */
gpiod_set_value(ctx->enable_gpio, 0);
usleep_range(10000, 11000);
ret = regulator_disable(ctx->vcc);
if (ret)
dev_err(ctx->dev, "Failed to disable vcc: %d\n", ret);
regcache_mark_dirty(ctx->regmap);
}
@ -560,10 +573,14 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model)
ctx->host_node = of_graph_get_remote_port_parent(endpoint);
of_node_put(endpoint);
if (ctx->dsi_lanes < 0 || ctx->dsi_lanes > 4)
return -EINVAL;
if (!ctx->host_node)
return -ENODEV;
if (ctx->dsi_lanes < 0 || ctx->dsi_lanes > 4) {
ret = -EINVAL;
goto err_put_node;
}
if (!ctx->host_node) {
ret = -ENODEV;
goto err_put_node;
}
ctx->lvds_dual_link = false;
ctx->lvds_dual_link_even_odd_swap = false;
@ -590,16 +607,27 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model)
ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, &panel_bridge);
if (ret < 0)
return ret;
goto err_put_node;
if (panel) {
panel_bridge = devm_drm_panel_bridge_add(dev, panel);
if (IS_ERR(panel_bridge))
return PTR_ERR(panel_bridge);
if (IS_ERR(panel_bridge)) {
ret = PTR_ERR(panel_bridge);
goto err_put_node;
}
}
ctx->panel_bridge = panel_bridge;
ctx->vcc = devm_regulator_get(dev, "vcc");
if (IS_ERR(ctx->vcc))
return dev_err_probe(dev, PTR_ERR(ctx->vcc),
"Failed to get supply 'vcc'\n");
return 0;
err_put_node:
of_node_put(ctx->host_node);
return ret;
}
static int sn65dsi83_host_attach(struct sn65dsi83 *ctx)
@ -662,7 +690,8 @@ static int sn65dsi83_probe(struct i2c_client *client,
}
/* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */
ctx->enable_gpio = devm_gpiod_get(ctx->dev, "enable", GPIOD_OUT_LOW);
ctx->enable_gpio = devm_gpiod_get_optional(ctx->dev, "enable",
GPIOD_OUT_LOW);
if (IS_ERR(ctx->enable_gpio))
return PTR_ERR(ctx->enable_gpio);
@ -673,8 +702,10 @@ static int sn65dsi83_probe(struct i2c_client *client,
return ret;
ctx->regmap = devm_regmap_init_i2c(client, &sn65dsi83_regmap_config);
if (IS_ERR(ctx->regmap))
return PTR_ERR(ctx->regmap);
if (IS_ERR(ctx->regmap)) {
ret = PTR_ERR(ctx->regmap);
goto err_put_node;
}
dev_set_drvdata(dev, ctx);
i2c_set_clientdata(client, ctx);
@ -691,6 +722,8 @@ static int sn65dsi83_probe(struct i2c_client *client,
err_remove_bridge:
drm_bridge_remove(&ctx->bridge);
err_put_node:
of_node_put(ctx->host_node);
return ret;
}

View File

@ -26,8 +26,8 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_dp_aux_bus.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_aux_bus.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>

View File

@ -0,0 +1,9 @@
# SPDX-License-Identifier: MIT
obj-$(CONFIG_DRM_DP_AUX_BUS) += drm_dp_aux_bus.o
drm_dp_helper-y := drm_dp.o drm_dp_dual_mode_helper.o drm_dp_helper_mod.o drm_dp_mst_topology.o
drm_dp_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o
drm_dp_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o
obj-$(CONFIG_DRM_DP_HELPER) += drm_dp_helper.o

View File

@ -29,13 +29,13 @@
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <drm/drm_dp_mst_helper.h>
#include <drm/dp/drm_dp_mst_helper.h>
#include <drm/drm_panel.h>
#include "drm_crtc_helper_internal.h"
#include "drm_dp_helper_internal.h"
struct dp_aux_backlight {
struct backlight_device *base;

View File

@ -19,8 +19,8 @@
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <drm/drm_dp_aux_bus.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_aux_bus.h>
#include <drm/dp/drm_dp_helper.h>
/**
* dp_aux_ep_match() - The match function for the dp_aux_bus.

View File

@ -36,11 +36,11 @@
#include <linux/uio.h>
#include <drm/drm_crtc.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_dp_mst_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/dp/drm_dp_mst_helper.h>
#include <drm/drm_print.h>
#include "drm_crtc_helper_internal.h"
#include "drm_dp_helper_internal.h"
struct drm_dp_aux_dev {
unsigned index;

View File

@ -13,7 +13,7 @@
#include <drm/drm_connector.h>
#include <drm/drm_device.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
/*
* Unfortunately it turns out that we have a chicken-and-egg situation

View File

@ -28,7 +28,7 @@
#include <linux/string.h>
#include <drm/drm_device.h>
#include <drm/drm_dp_dual_mode_helper.h>
#include <drm/dp/drm_dp_dual_mode_helper.h>
#include <drm/drm_print.h>
/**

View File

@ -0,0 +1,33 @@
/* SPDX-License-Identifier: MIT */
#ifndef DRM_DP_HELPER_INTERNAL_H
#define DRM_DP_HELPER_INTERNAL_H
struct drm_dp_aux;
#ifdef CONFIG_DRM_DP_AUX_CHARDEV
int drm_dp_aux_dev_init(void);
void drm_dp_aux_dev_exit(void);
int drm_dp_aux_register_devnode(struct drm_dp_aux *aux);
void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux);
#else
static inline int drm_dp_aux_dev_init(void)
{
return 0;
}
static inline void drm_dp_aux_dev_exit(void)
{
}
static inline int drm_dp_aux_register_devnode(struct drm_dp_aux *aux)
{
return 0;
}
static inline void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux)
{
}
#endif
#endif

View File

@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT
#include <linux/module.h>
#include "drm_dp_helper_internal.h"
MODULE_DESCRIPTION("DRM DisplayPort helper");
MODULE_LICENSE("GPL and additional rights");
static int __init drm_dp_helper_module_init(void)
{
return drm_dp_aux_dev_init();
}
static void __exit drm_dp_helper_module_exit(void)
{
/* Call exit functions from specific dp helpers here */
drm_dp_aux_dev_exit();
}
module_init(drm_dp_helper_module_init);
module_exit(drm_dp_helper_module_exit);

View File

@ -38,14 +38,14 @@
#include <linux/math64.h>
#endif
#include <drm/dp/drm_dp_mst_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_dp_mst_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include "drm_crtc_helper_internal.h"
#include "drm_dp_helper_internal.h"
#include "drm_dp_mst_topology_internal.h"
/**
@ -4196,7 +4196,7 @@ int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handl
int ret = 0;
int sc;
*handled = false;
sc = esi[0] & 0x3f;
sc = DP_GET_SINK_COUNT(esi[0]);
if (sc != mgr->sink_count) {
mgr->sink_count = sc;
@ -4811,7 +4811,7 @@ static void drm_dp_mst_dump_mstb(struct seq_file *m,
seq_printf(m, "%smstb - [%p]: num_ports: %d\n", prefix, mstb, mstb->num_ports);
list_for_each_entry(port, &mstb->ports, next) {
seq_printf(m, "%sport %d - [%p] (%s - %s): ddps: %d, ldps: %d, sdp: %d/%d, fec: %s, conn: %p\n",
seq_printf(m, "%sport %d - [%p] (%s - %s): ddps: %d, ldps: %d, sdp: %d/%d, fec: %s, conn: %p\n",
prefix,
port->port_num,
port,

View File

@ -10,7 +10,7 @@
#ifndef _DRM_DP_MST_HELPER_INTERNAL_H_
#define _DRM_DP_MST_HELPER_INTERNAL_H_
#include <drm/drm_dp_mst_helper.h>
#include <drm/dp/drm_dp_mst_helper.h>
void
drm_dp_encode_sideband_req(const struct drm_dp_sideband_msg_req_body *req,

535
drivers/gpu/drm/drm_buddy.c Normal file
View File

@ -0,0 +1,535 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2021 Intel Corporation
*/
#include <linux/kmemleak.h>
#include <linux/module.h>
#include <linux/sizes.h>
#include <drm/drm_buddy.h>
static struct kmem_cache *slab_blocks;
static struct drm_buddy_block *drm_block_alloc(struct drm_buddy *mm,
struct drm_buddy_block *parent,
unsigned int order,
u64 offset)
{
struct drm_buddy_block *block;
BUG_ON(order > DRM_BUDDY_MAX_ORDER);
block = kmem_cache_zalloc(slab_blocks, GFP_KERNEL);
if (!block)
return NULL;
block->header = offset;
block->header |= order;
block->parent = parent;
BUG_ON(block->header & DRM_BUDDY_HEADER_UNUSED);
return block;
}
static void drm_block_free(struct drm_buddy *mm,
struct drm_buddy_block *block)
{
kmem_cache_free(slab_blocks, block);
}
static void mark_allocated(struct drm_buddy_block *block)
{
block->header &= ~DRM_BUDDY_HEADER_STATE;
block->header |= DRM_BUDDY_ALLOCATED;
list_del(&block->link);
}
static void mark_free(struct drm_buddy *mm,
struct drm_buddy_block *block)
{
block->header &= ~DRM_BUDDY_HEADER_STATE;
block->header |= DRM_BUDDY_FREE;
list_add(&block->link,
&mm->free_list[drm_buddy_block_order(block)]);
}
static void mark_split(struct drm_buddy_block *block)
{
block->header &= ~DRM_BUDDY_HEADER_STATE;
block->header |= DRM_BUDDY_SPLIT;
list_del(&block->link);
}
/**
* drm_buddy_init - init memory manager
*
* @mm: DRM buddy manager to initialize
* @size: size in bytes to manage
* @chunk_size: minimum page size in bytes for our allocations
*
* Initializes the memory manager and its resources.
*
* Returns:
* 0 on success, error code on failure.
*/
int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size)
{
unsigned int i;
u64 offset;
if (size < chunk_size)
return -EINVAL;
if (chunk_size < PAGE_SIZE)
return -EINVAL;
if (!is_power_of_2(chunk_size))
return -EINVAL;
size = round_down(size, chunk_size);
mm->size = size;
mm->avail = size;
mm->chunk_size = chunk_size;
mm->max_order = ilog2(size) - ilog2(chunk_size);
BUG_ON(mm->max_order > DRM_BUDDY_MAX_ORDER);
mm->free_list = kmalloc_array(mm->max_order + 1,
sizeof(struct list_head),
GFP_KERNEL);
if (!mm->free_list)
return -ENOMEM;
for (i = 0; i <= mm->max_order; ++i)
INIT_LIST_HEAD(&mm->free_list[i]);
mm->n_roots = hweight64(size);
mm->roots = kmalloc_array(mm->n_roots,
sizeof(struct drm_buddy_block *),
GFP_KERNEL);
if (!mm->roots)
goto out_free_list;
offset = 0;
i = 0;
/*
* Split into power-of-two blocks, in case we are given a size that is
* not itself a power-of-two.
*/
do {
struct drm_buddy_block *root;
unsigned int order;
u64 root_size;
root_size = rounddown_pow_of_two(size);
order = ilog2(root_size) - ilog2(chunk_size);
root = drm_block_alloc(mm, NULL, order, offset);
if (!root)
goto out_free_roots;
mark_free(mm, root);
BUG_ON(i > mm->max_order);
BUG_ON(drm_buddy_block_size(mm, root) < chunk_size);
mm->roots[i] = root;
offset += root_size;
size -= root_size;
i++;
} while (size);
return 0;
out_free_roots:
while (i--)
drm_block_free(mm, mm->roots[i]);
kfree(mm->roots);
out_free_list:
kfree(mm->free_list);
return -ENOMEM;
}
EXPORT_SYMBOL(drm_buddy_init);
/**
* drm_buddy_fini - tear down the memory manager
*
* @mm: DRM buddy manager to free
*
* Cleanup memory manager resources and the freelist
*/
void drm_buddy_fini(struct drm_buddy *mm)
{
int i;
for (i = 0; i < mm->n_roots; ++i) {
WARN_ON(!drm_buddy_block_is_free(mm->roots[i]));
drm_block_free(mm, mm->roots[i]);
}
WARN_ON(mm->avail != mm->size);
kfree(mm->roots);
kfree(mm->free_list);
}
EXPORT_SYMBOL(drm_buddy_fini);
static int split_block(struct drm_buddy *mm,
struct drm_buddy_block *block)
{
unsigned int block_order = drm_buddy_block_order(block) - 1;
u64 offset = drm_buddy_block_offset(block);
BUG_ON(!drm_buddy_block_is_free(block));
BUG_ON(!drm_buddy_block_order(block));
block->left = drm_block_alloc(mm, block, block_order, offset);
if (!block->left)
return -ENOMEM;
block->right = drm_block_alloc(mm, block, block_order,
offset + (mm->chunk_size << block_order));
if (!block->right) {
drm_block_free(mm, block->left);
return -ENOMEM;
}
mark_free(mm, block->left);
mark_free(mm, block->right);
mark_split(block);
return 0;
}
static struct drm_buddy_block *
get_buddy(struct drm_buddy_block *block)
{
struct drm_buddy_block *parent;
parent = block->parent;
if (!parent)
return NULL;
if (parent->left == block)
return parent->right;
return parent->left;
}
static void __drm_buddy_free(struct drm_buddy *mm,
struct drm_buddy_block *block)
{
struct drm_buddy_block *parent;
while ((parent = block->parent)) {
struct drm_buddy_block *buddy;
buddy = get_buddy(block);
if (!drm_buddy_block_is_free(buddy))
break;
list_del(&buddy->link);
drm_block_free(mm, block);
drm_block_free(mm, buddy);
block = parent;
}
mark_free(mm, block);
}
/**
* drm_buddy_free_block - free a block
*
* @mm: DRM buddy manager
* @block: block to be freed
*/
void drm_buddy_free_block(struct drm_buddy *mm,
struct drm_buddy_block *block)
{
BUG_ON(!drm_buddy_block_is_allocated(block));
mm->avail += drm_buddy_block_size(mm, block);
__drm_buddy_free(mm, block);
}
EXPORT_SYMBOL(drm_buddy_free_block);
/**
* drm_buddy_free_list - free blocks
*
* @mm: DRM buddy manager
* @objects: input list head to free blocks
*/
void drm_buddy_free_list(struct drm_buddy *mm, struct list_head *objects)
{
struct drm_buddy_block *block, *on;
list_for_each_entry_safe(block, on, objects, link) {
drm_buddy_free_block(mm, block);
cond_resched();
}
INIT_LIST_HEAD(objects);
}
EXPORT_SYMBOL(drm_buddy_free_list);
/**
* drm_buddy_alloc_blocks - allocate power-of-two blocks
*
* @mm: DRM buddy manager to allocate from
* @order: size of the allocation
*
* The order value here translates to:
*
* 0 = 2^0 * mm->chunk_size
* 1 = 2^1 * mm->chunk_size
* 2 = 2^2 * mm->chunk_size
*
* Returns:
* allocated ptr to the &drm_buddy_block on success
*/
struct drm_buddy_block *
drm_buddy_alloc_blocks(struct drm_buddy *mm, unsigned int order)
{
struct drm_buddy_block *block = NULL;
unsigned int i;
int err;
for (i = order; i <= mm->max_order; ++i) {
block = list_first_entry_or_null(&mm->free_list[i],
struct drm_buddy_block,
link);
if (block)
break;
}
if (!block)
return ERR_PTR(-ENOSPC);
BUG_ON(!drm_buddy_block_is_free(block));
while (i != order) {
err = split_block(mm, block);
if (unlikely(err))
goto out_free;
/* Go low */
block = block->left;
i--;
}
mark_allocated(block);
mm->avail -= drm_buddy_block_size(mm, block);
kmemleak_update_trace(block);
return block;
out_free:
if (i != order)
__drm_buddy_free(mm, block);
return ERR_PTR(err);
}
EXPORT_SYMBOL(drm_buddy_alloc_blocks);
static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2)
{
return s1 <= e2 && e1 >= s2;
}
static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2)
{
return s1 <= s2 && e1 >= e2;
}
/**
* drm_buddy_alloc_range - allocate range
*
* @mm: DRM buddy manager to allocate from
* @blocks: output list head to add allocated blocks
* @start: start of the allowed range for this block
* @size: size of the allocation
*
* Intended for pre-allocating portions of the address space, for example to
* reserve a block for the initial framebuffer or similar, hence the expectation
* here is that drm_buddy_alloc_blocks() is still the main vehicle for
* allocations, so if that's not the case then the drm_mm range allocator is
* probably a much better fit, and so you should probably go use that instead.
*
* Note that it's safe to chain together multiple alloc_ranges
* with the same blocks list
*
* Returns:
* 0 on success, error code on failure.
*/
int drm_buddy_alloc_range(struct drm_buddy *mm,
struct list_head *blocks,
u64 start, u64 size)
{
struct drm_buddy_block *block;
struct drm_buddy_block *buddy;
LIST_HEAD(allocated);
LIST_HEAD(dfs);
u64 end;
int err;
int i;
if (size < mm->chunk_size)
return -EINVAL;
if (!IS_ALIGNED(size | start, mm->chunk_size))
return -EINVAL;
if (range_overflows(start, size, mm->size))
return -EINVAL;
for (i = 0; i < mm->n_roots; ++i)
list_add_tail(&mm->roots[i]->tmp_link, &dfs);
end = start + size - 1;
do {
u64 block_start;
u64 block_end;
block = list_first_entry_or_null(&dfs,
struct drm_buddy_block,
tmp_link);
if (!block)
break;
list_del(&block->tmp_link);
block_start = drm_buddy_block_offset(block);
block_end = block_start + drm_buddy_block_size(mm, block) - 1;
if (!overlaps(start, end, block_start, block_end))
continue;
if (drm_buddy_block_is_allocated(block)) {
err = -ENOSPC;
goto err_free;
}
if (contains(start, end, block_start, block_end)) {
if (!drm_buddy_block_is_free(block)) {
err = -ENOSPC;
goto err_free;
}
mark_allocated(block);
mm->avail -= drm_buddy_block_size(mm, block);
list_add_tail(&block->link, &allocated);
continue;
}
if (!drm_buddy_block_is_split(block)) {
err = split_block(mm, block);
if (unlikely(err))
goto err_undo;
}
list_add(&block->right->tmp_link, &dfs);
list_add(&block->left->tmp_link, &dfs);
} while (1);
list_splice_tail(&allocated, blocks);
return 0;
err_undo:
/*
* We really don't want to leave around a bunch of split blocks, since
* bigger is better, so make sure we merge everything back before we
* free the allocated blocks.
*/
buddy = get_buddy(block);
if (buddy &&
(drm_buddy_block_is_free(block) &&
drm_buddy_block_is_free(buddy)))
__drm_buddy_free(mm, block);
err_free:
drm_buddy_free_list(mm, &allocated);
return err;
}
EXPORT_SYMBOL(drm_buddy_alloc_range);
/**
* drm_buddy_block_print - print block information
*
* @mm: DRM buddy manager
* @block: DRM buddy block
* @p: DRM printer to use
*/
void drm_buddy_block_print(struct drm_buddy *mm,
struct drm_buddy_block *block,
struct drm_printer *p)
{
u64 start = drm_buddy_block_offset(block);
u64 size = drm_buddy_block_size(mm, block);
drm_printf(p, "%#018llx-%#018llx: %llu\n", start, start + size, size);
}
EXPORT_SYMBOL(drm_buddy_block_print);
/**
* drm_buddy_print - print allocator state
*
* @mm: DRM buddy manager
* @p: DRM printer to use
*/
void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p)
{
int order;
drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB\n",
mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20);
for (order = mm->max_order; order >= 0; order--) {
struct drm_buddy_block *block;
u64 count = 0, free;
list_for_each_entry(block, &mm->free_list[order], link) {
BUG_ON(!drm_buddy_block_is_free(block));
count++;
}
drm_printf(p, "order-%d ", order);
free = count * (mm->chunk_size << order);
if (free < SZ_1M)
drm_printf(p, "free: %lluKiB", free >> 10);
else
drm_printf(p, "free: %lluMiB", free >> 20);
drm_printf(p, ", pages: %llu\n", count);
}
}
EXPORT_SYMBOL(drm_buddy_print);
static void drm_buddy_module_exit(void)
{
kmem_cache_destroy(slab_blocks);
}
static int __init drm_buddy_module_init(void)
{
slab_blocks = KMEM_CACHE(drm_buddy_block, 0);
if (!slab_blocks)
return -ENOMEM;
return 0;
}
module_init(drm_buddy_module_init);
module_exit(drm_buddy_module_exit);
MODULE_DESCRIPTION("DRM Buddy Allocator");
MODULE_LICENSE("Dual MIT/GPL");

View File

@ -82,6 +82,10 @@
* driver boot-up state too. Drivers can access this blob through
* &drm_crtc_state.gamma_lut.
*
* Note that for mostly historical reasons stemming from Xorg heritage,
* this is also used to store the color map (also sometimes color lut, CLUT
* or color palette) for indexed formats like DRM_FORMAT_C8.
*
* GAMMA_LUT_SIZE:
* Unsigned range property to give the size of the lookup table to be set
* on the GAMMA_LUT property (the size depends on the underlying hardware).

View File

@ -28,36 +28,9 @@
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_encoder.h>
#include <drm/drm_modes.h>
/* drm_dp_aux_dev.c */
#ifdef CONFIG_DRM_DP_AUX_CHARDEV
int drm_dp_aux_dev_init(void);
void drm_dp_aux_dev_exit(void);
int drm_dp_aux_register_devnode(struct drm_dp_aux *aux);
void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux);
#else
static inline int drm_dp_aux_dev_init(void)
{
return 0;
}
static inline void drm_dp_aux_dev_exit(void)
{
}
static inline int drm_dp_aux_register_devnode(struct drm_dp_aux *aux)
{
return 0;
}
static inline void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux)
{
}
#endif
/* drm_probe_helper.c */
enum drm_mode_status drm_crtc_mode_valid(struct drm_crtc *crtc,
const struct drm_display_mode *mode);

View File

@ -12,7 +12,7 @@
#include <linux/errno.h>
#include <linux/byteorder/generic.h>
#include <drm/drm_print.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/drm_dsc.h>
/**

View File

@ -93,6 +93,8 @@ static int oui(u8 first, u8 second, u8 third)
/* Non desktop display (i.e. HMD) */
#define EDID_QUIRK_NON_DESKTOP (1 << 12)
#define MICROSOFT_IEEE_OUI 0xca125c
struct detailed_mode_closure {
struct drm_connector *connector;
struct edid *edid;
@ -212,9 +214,7 @@ static const struct edid_quirk {
/* Windows Mixed Reality Headsets */
EDID_QUIRK('A', 'C', 'R', 0x7fce, EDID_QUIRK_NON_DESKTOP),
EDID_QUIRK('H', 'P', 'N', 0x3515, EDID_QUIRK_NON_DESKTOP),
EDID_QUIRK('L', 'E', 'N', 0x0408, EDID_QUIRK_NON_DESKTOP),
EDID_QUIRK('L', 'E', 'N', 0xb800, EDID_QUIRK_NON_DESKTOP),
EDID_QUIRK('F', 'U', 'J', 0x1970, EDID_QUIRK_NON_DESKTOP),
EDID_QUIRK('D', 'E', 'L', 0x7fce, EDID_QUIRK_NON_DESKTOP),
EDID_QUIRK('S', 'E', 'C', 0x144a, EDID_QUIRK_NON_DESKTOP),
@ -3776,7 +3776,7 @@ static int do_y420vdb_modes(struct drm_connector *connector,
}
if (modes > 0)
info->color_formats |= DRM_COLOR_FORMAT_YCRCB420;
info->color_formats |= DRM_COLOR_FORMAT_YCBCR420;
return modes;
}
@ -4222,6 +4222,17 @@ static bool cea_db_is_hdmi_forum_vsdb(const u8 *db)
return oui(db[3], db[2], db[1]) == HDMI_FORUM_IEEE_OUI;
}
static bool cea_db_is_microsoft_vsdb(const u8 *db)
{
if (cea_db_tag(db) != VENDOR_BLOCK)
return false;
if (cea_db_payload_len(db) != 21)
return false;
return oui(db[3], db[2], db[1]) == MICROSOFT_IEEE_OUI;
}
static bool cea_db_is_vcdb(const u8 *db)
{
if (cea_db_tag(db) != USE_EXTENDED_TAG)
@ -4279,7 +4290,7 @@ static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector,
if (map_len == 0) {
/* All CEA modes support ycbcr420 sampling also.*/
hdmi->y420_cmdb_map = U64_MAX;
info->color_formats |= DRM_COLOR_FORMAT_YCRCB420;
info->color_formats |= DRM_COLOR_FORMAT_YCBCR420;
return;
}
@ -4302,7 +4313,7 @@ static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector,
map |= (u64)db[2 + count] << (8 * count);
if (map)
info->color_formats |= DRM_COLOR_FORMAT_YCRCB420;
info->color_formats |= DRM_COLOR_FORMAT_YCBCR420;
hdmi->y420_cmdb_map = map;
}
@ -5075,21 +5086,21 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
if (hdmi[6] & DRM_EDID_HDMI_DC_30) {
dc_bpc = 10;
info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_30;
info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_30;
DRM_DEBUG("%s: HDMI sink does deep color 30.\n",
connector->name);
}
if (hdmi[6] & DRM_EDID_HDMI_DC_36) {
dc_bpc = 12;
info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_36;
info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_36;
DRM_DEBUG("%s: HDMI sink does deep color 36.\n",
connector->name);
}
if (hdmi[6] & DRM_EDID_HDMI_DC_48) {
dc_bpc = 16;
info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_48;
info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_48;
DRM_DEBUG("%s: HDMI sink does deep color 48.\n",
connector->name);
}
@ -5104,16 +5115,9 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
connector->name, dc_bpc);
info->bpc = dc_bpc;
/*
* Deep color support mandates RGB444 support for all video
* modes and forbids YCRCB422 support for all video modes per
* HDMI 1.3 spec.
*/
info->color_formats = DRM_COLOR_FORMAT_RGB444;
/* YCRCB444 is optional according to spec. */
if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) {
info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
info->edid_hdmi_ycbcr444_dc_modes = info->edid_hdmi_rgb444_dc_modes;
DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n",
connector->name);
}
@ -5149,6 +5153,25 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
drm_parse_hdmi_deep_color_info(connector, db);
}
/*
* See EDID extension for head-mounted and specialized monitors, specified at:
* https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
*/
static void drm_parse_microsoft_vsdb(struct drm_connector *connector,
const u8 *db)
{
struct drm_display_info *info = &connector->display_info;
u8 version = db[4];
bool desktop_usage = db[5] & BIT(6);
/* Version 1 and 2 for HMDs, version 3 flags desktop usage explicitly */
if (version == 1 || version == 2 || (version == 3 && !desktop_usage))
info->non_desktop = true;
drm_dbg_kms(connector->dev, "HMD or specialized display VSDB version %u: 0x%02x\n",
version, db[5]);
}
static void drm_parse_cea_ext(struct drm_connector *connector,
const struct edid *edid)
{
@ -5165,9 +5188,9 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
/* The existence of a CEA block should imply RGB support */
info->color_formats = DRM_COLOR_FORMAT_RGB444;
if (edid_ext[3] & EDID_CEA_YCRCB444)
info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
info->color_formats |= DRM_COLOR_FORMAT_YCBCR444;
if (edid_ext[3] & EDID_CEA_YCRCB422)
info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
info->color_formats |= DRM_COLOR_FORMAT_YCBCR422;
if (cea_db_offsets(edid_ext, &start, &end))
return;
@ -5179,6 +5202,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
drm_parse_hdmi_vsdb_video(connector, db);
if (cea_db_is_hdmi_forum_vsdb(db))
drm_parse_hdmi_forum_vsdb(connector, db);
if (cea_db_is_microsoft_vsdb(db))
drm_parse_microsoft_vsdb(connector, db);
if (cea_db_is_y420cmdb(db))
drm_parse_y420cmdb_bitmap(connector, db);
if (cea_db_is_vcdb(db))
@ -5333,17 +5358,13 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi
info->width_mm = edid->width_cm * 10;
info->height_mm = edid->height_cm * 10;
info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
drm_get_monitor_range(connector, edid);
DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop);
if (edid->revision < 3)
return quirks;
goto out;
if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
return quirks;
goto out;
drm_parse_cea_ext(connector, edid);
@ -5363,7 +5384,7 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi
/* Only defined for 1.4 with digital displays */
if (edid->revision < 4)
return quirks;
goto out;
switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
case DRM_EDID_DIGITAL_DEPTH_6:
@ -5395,17 +5416,25 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi
info->color_formats |= DRM_COLOR_FORMAT_RGB444;
if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444)
info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
info->color_formats |= DRM_COLOR_FORMAT_YCBCR444;
if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
info->color_formats |= DRM_COLOR_FORMAT_YCBCR422;
drm_update_mso(connector, edid);
out:
if (quirks & EDID_QUIRK_NON_DESKTOP) {
drm_dbg_kms(connector->dev, "Non-desktop display%s\n",
info->non_desktop ? " (redundant quirk)" : "");
info->non_desktop = true;
}
return quirks;
}
static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *dev,
struct displayid_detailed_timings_1 *timings)
struct displayid_detailed_timings_1 *timings,
bool type_7)
{
struct drm_display_mode *mode;
unsigned pixel_clock = (timings->pixel_clock[0] |
@ -5426,7 +5455,8 @@ static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *d
if (!mode)
return NULL;
mode->clock = pixel_clock * 10;
/* resolution is kHz for type VII, and 10 kHz for type I */
mode->clock = type_7 ? pixel_clock : pixel_clock * 10;
mode->hdisplay = hactive;
mode->hsync_start = mode->hdisplay + hsync;
mode->hsync_end = mode->hsync_start + hsync_width;
@ -5457,6 +5487,7 @@ static int add_displayid_detailed_1_modes(struct drm_connector *connector,
int num_timings;
struct drm_display_mode *newmode;
int num_modes = 0;
bool type_7 = block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING;
/* blocks must be multiple of 20 bytes length */
if (block->num_bytes % 20)
return 0;
@ -5465,7 +5496,7 @@ static int add_displayid_detailed_1_modes(struct drm_connector *connector,
for (i = 0; i < num_timings; i++) {
struct displayid_detailed_timings_1 *timings = &det->timings[i];
newmode = drm_mode_displayid_detailed(connector->dev, timings);
newmode = drm_mode_displayid_detailed(connector->dev, timings, type_7);
if (!newmode)
continue;
@ -5484,7 +5515,8 @@ static int add_displayid_detailed_modes(struct drm_connector *connector,
displayid_iter_edid_begin(edid, &iter);
displayid_iter_for_each(block, &iter) {
if (block->tag == DATA_BLOCK_TYPE_1_DETAILED_TIMING)
if (block->tag == DATA_BLOCK_TYPE_1_DETAILED_TIMING ||
block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING)
num_modes += add_displayid_detailed_1_modes(connector, block);
}
displayid_iter_end(&iter);
@ -5652,7 +5684,7 @@ static bool is_hdmi2_sink(const struct drm_connector *connector)
return true;
return connector->display_info.hdmi.scdc.supported ||
connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420;
connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR420;
}
static inline bool is_eotf_supported(u8 output_eotf, u8 sink_eotf)
@ -5891,13 +5923,13 @@ static const u32 hdmi_colorimetry_val[] = {
#undef ACE
/**
* drm_hdmi_avi_infoframe_colorspace() - fill the HDMI AVI infoframe
* colorspace information
* drm_hdmi_avi_infoframe_colorimetry() - fill the HDMI AVI infoframe
* colorimetry information
* @frame: HDMI AVI infoframe
* @conn_state: connector state
*/
void
drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame,
drm_hdmi_avi_infoframe_colorimetry(struct hdmi_avi_infoframe *frame,
const struct drm_connector_state *conn_state)
{
u32 colorimetry_val;
@ -5916,7 +5948,7 @@ drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame,
frame->extended_colorimetry = (colorimetry_val >> 2) &
EXTENDED_COLORIMETRY_MASK;
}
EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorspace);
EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorimetry);
/**
* drm_hdmi_avi_infoframe_quant_range() - fill the HDMI AVI infoframe

View File

@ -61,17 +61,3 @@ MODULE_PARM_DESC(edid_firmware,
"DEPRECATED. Use drm.edid_firmware module parameter instead.");
#endif
static int __init drm_kms_helper_init(void)
{
return drm_dp_aux_dev_init();
}
static void __exit drm_kms_helper_exit(void)
{
/* Call exit functions from specific kms helpers here */
drm_dp_aux_dev_exit();
}
module_init(drm_kms_helper_init);
module_exit(drm_kms_helper_exit);

View File

@ -202,17 +202,13 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane
memcpy(formats_ptr(blob_data), plane->format_types, formats_size);
/* If we can't determine support, just bail */
if (!plane->funcs->format_mod_supported)
goto done;
mod = modifiers_ptr(blob_data);
for (i = 0; i < plane->modifier_count; i++) {
for (j = 0; j < plane->format_count; j++) {
if (plane->funcs->format_mod_supported(plane,
if (!plane->funcs->format_mod_supported ||
plane->funcs->format_mod_supported(plane,
plane->format_types[j],
plane->modifiers[i])) {
mod->formats |= 1ULL << j;
}
}
@ -223,7 +219,6 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane
mod++;
}
done:
drm_object_attach_property(&plane->base, config->modifiers_property,
blob->base.id);

View File

@ -387,7 +387,8 @@ static void drm_privacy_screen_device_release(struct device *dev)
* * An ERR_PTR(errno) on failure.
*/
struct drm_privacy_screen *drm_privacy_screen_register(
struct device *parent, const struct drm_privacy_screen_ops *ops)
struct device *parent, const struct drm_privacy_screen_ops *ops,
void *data)
{
struct drm_privacy_screen *priv;
int ret;
@ -404,6 +405,7 @@ struct drm_privacy_screen *drm_privacy_screen_register(
priv->dev.parent = parent;
priv->dev.release = drm_privacy_screen_device_release;
dev_set_name(&priv->dev, "privacy_screen-%s", dev_name(parent));
priv->drvdata = data;
priv->ops = ops;
priv->ops->get_hw_state(priv);
@ -439,6 +441,7 @@ void drm_privacy_screen_unregister(struct drm_privacy_screen *priv)
mutex_unlock(&drm_privacy_screen_devs_lock);
mutex_lock(&priv->lock);
priv->drvdata = NULL;
priv->ops = NULL;
mutex_unlock(&priv->lock);

View File

@ -50,6 +50,13 @@ static bool __init detect_thinkpad_privacy_screen(void)
}
#endif
#if IS_ENABLED(CONFIG_CHROMEOS_PRIVACY_SCREEN)
static bool __init detect_chromeos_privacy_screen(void)
{
return acpi_dev_present("GOOG0010", NULL, -1);
}
#endif
static const struct arch_init_data arch_init_data[] __initconst = {
#if IS_ENABLED(CONFIG_THINKPAD_ACPI)
{
@ -61,6 +68,16 @@ static const struct arch_init_data arch_init_data[] __initconst = {
.detect = detect_thinkpad_privacy_screen,
},
#endif
#if IS_ENABLED(CONFIG_CHROMEOS_PRIVACY_SCREEN)
{
.lookup = {
.dev_id = NULL,
.con_id = NULL,
.provider = "privacy_screen-GOOG0010:00",
},
.detect = detect_chromeos_privacy_screen,
},
#endif
};
void __init drm_privacy_screen_lookup_init(void)

View File

@ -189,8 +189,7 @@ static int submit_fence_sync(struct etnaviv_gem_submit *submit)
continue;
if (bo->flags & ETNA_SUBMIT_BO_WRITE) {
ret = dma_resv_get_fences(robj, NULL,
&bo->nr_shared,
ret = dma_resv_get_fences(robj, true, &bo->nr_shared,
&bo->shared);
if (ret)
return ret;

View File

@ -66,6 +66,7 @@ config DRM_EXYNOS_DP
bool "Exynos specific extensions for Analogix DP driver"
depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON
select DRM_ANALOGIX_DP
select DRM_DP_HELPER
default DRM_EXYNOS
select DRM_PANEL
help

View File

@ -258,6 +258,7 @@ struct exynos_dsi {
struct list_head bridge_chain;
struct drm_bridge *out_bridge;
struct device *dev;
struct drm_display_mode mode;
void __iomem *reg_base;
struct phy *phy;
@ -881,7 +882,7 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi)
static void exynos_dsi_set_display_mode(struct exynos_dsi *dsi)
{
struct drm_display_mode *m = &dsi->encoder.crtc->state->adjusted_mode;
struct drm_display_mode *m = &dsi->mode;
unsigned int num_bits_resol = dsi->driver_data->num_bits_resol;
u32 reg;
@ -1446,6 +1447,15 @@ static void exynos_dsi_disable(struct drm_encoder *encoder)
pm_runtime_put_sync(dsi->dev);
}
static void exynos_dsi_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct exynos_dsi *dsi = encoder_to_dsi(encoder);
drm_mode_copy(&dsi->mode, adjusted_mode);
}
static enum drm_connector_status
exynos_dsi_detect(struct drm_connector *connector, bool force)
{
@ -1513,6 +1523,7 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = {
.enable = exynos_dsi_enable,
.disable = exynos_dsi_disable,
.mode_set = exynos_dsi_mode_set,
};
MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);

View File

@ -31,7 +31,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/dp/drm_dp_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include "gma_display.h"
@ -82,7 +82,6 @@ i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading)
{
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
int mode = MODE_I2C_START;
int ret;
if (reading)
mode |= MODE_I2C_READ;
@ -90,8 +89,7 @@ i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading)
mode |= MODE_I2C_WRITE;
algo_data->address = address;
algo_data->running = true;
ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
return ret;
return i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
}
/*
@ -122,13 +120,11 @@ static int
i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte)
{
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
int ret;
if (!algo_data->running)
return -EIO;
ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL);
return ret;
return i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL);
}
/*
@ -139,13 +135,11 @@ static int
i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret)
{
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
int ret;
if (!algo_data->running)
return -EIO;
ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret);
return ret;
return i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret);
}
static int

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