drm-misc-next for v6.3:

UAPI Changes:
 
  * connector: Support analog-TV mode property
 
  * media: Add MEDIA_BUS_FMT_RGB565_1X24_CPADHI,
    MEDIA_BUS_FMT_RGB666_1X18 and MEDIA_BUS_FMT_RGB666_1X24_CPADHI
 
 Cross-subsystem Changes:
 
  * dma-buf: Documentation fixes
 
  * i2c: Introduce i2c_client_get_device_id() helper
 
 Core Changes:
 
  * Improve support for analog TV output
 
  * bridge: Remove unused drm_bridge_chain functions
 
  * debugfs: Add per-device helpers and convert various DRM drivers
 
  * dp-mst: Various fixes
 
  * fbdev emulation: Always pick 32 bpp as default
 
  * KUnit: Add tests for managed helpers; Various cleanups
 
  * panel-orientation: Add quirks for Lenovo Yoga Tab 3 X90F and DynaBook K50
 
  * TTM: Open-code ttm_bo_wait() and remove the helper
 
 Driver Changes:
 
  * Fix preferred depth and bpp values throughout DRM drivers
 
  * Remove #CONFIG_PM guards throughout DRM drivers
 
  * ast: Various fixes
 
  * bridge: Implement i2c's probe_new in various drivers; Fixes; ite-it6505:
    Locking fixes, Cache EDID data; ite-it66121: Support IT6610 chip,
    Cleanups; lontium-tl9611: Fix HDMI on DragonBoard 845c; parade-ps8640:
    Use atomic bridge functions
 
  * gud: Convert to DRM shadow-plane helpers; Perform flushing synchronously
    during atomic update
 
  * ili9486: Support 16-bit pixel data
 
  * imx: Split off IPUv3 driver; Various fixes
 
  * mipi-dbi: Convert to DRM shadow-plane helpers plus rsp driver changes;i
    Support separate I/O-voltage supply
 
  * mxsfb: Depend on ARCH_MXS or ARCH_MXC
 
  * omapdrm: Various fixes
 
  * panel: Use ktime_get_boottime() to measure power-down delay in various
    drivers; Fix auto-suspend delay in various drivers; orisetech-ota5601a:
    Add support
 
  * sprd: Cleanups
 
  * sun4i: Convert to new TV-mode property
 
  * tidss: Various fixes
 
  * v3d: Various fixes
 
  * vc4: Convert to new TV-mode property; Support Kunit tests; Cleanups;
    dpi: Support RGB565 and RGB666 formats; dsi: Convert DSI driver to
    bridge
 
  * virtio: Improve tracing
 
  * vkms: Support small cursors in IGT tests; Various fixes
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEEchf7rIzpz2NEoWjlaA3BHVMLeiMFAmO0B0QACgkQaA3BHVML
 eiMKtAf9EXt5yaEonR4gsGNVD70VkebW+jPEWbEMg5hMFDHE9sjBja8T7bOxeeL1
 BVofJiAuEZW9176eqeWvShuwOuiE7lf4WQLMvXfFmtHF/Nac9HUtEvOcvc1vEDUB
 y6VFlVHe8mSp+Iy0WPLyZCtT4d7v2eM+VYm0HgFa74dSTzQTLGPiUI/XVb/YDaA7
 FHKB5NvsMX9S1XvjxCsq0jA5bo8SSzh5CVKerdAZkBJMCSmKiY09o2p5C7vw3EAz
 WUXL5CXqd9bwgvZa/9ZClQtpJaikNGoOaMSEl67rbWdVTk0LIpqx3nTY15py5LXd
 SG4Wtfor3Vf1REa9TrR2uCIOmh+1gQ==
 =0/PC
 -----END PGP SIGNATURE-----

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

drm-misc-next for v6.3:

UAPI Changes:

 * connector: Support analog-TV mode property
 * media: Add MEDIA_BUS_FMT_RGB565_1X24_CPADHI,
   MEDIA_BUS_FMT_RGB666_1X18 and MEDIA_BUS_FMT_RGB666_1X24_CPADHI

Cross-subsystem Changes:

 * dma-buf: Documentation fixes
 * i2c: Introduce i2c_client_get_device_id() helper

Core Changes:

 * Improve support for analog TV output
 * bridge: Remove unused drm_bridge_chain functions
 * debugfs: Add per-device helpers and convert various DRM drivers
 * dp-mst: Various fixes
 * fbdev emulation: Always pick 32 bpp as default
 * KUnit: Add tests for managed helpers; Various cleanups
 * panel-orientation: Add quirks for Lenovo Yoga Tab 3 X90F and DynaBook K50
 * TTM: Open-code ttm_bo_wait() and remove the helper

Driver Changes:

 * Fix preferred depth and bpp values throughout DRM drivers
 * Remove #CONFIG_PM guards throughout DRM drivers
 * ast: Various fixes
 * bridge: Implement i2c's probe_new in various drivers; Fixes; ite-it6505:
   Locking fixes, Cache EDID data; ite-it66121: Support IT6610 chip,
   Cleanups; lontium-tl9611: Fix HDMI on DragonBoard 845c; parade-ps8640:
   Use atomic bridge functions
 * gud: Convert to DRM shadow-plane helpers; Perform flushing synchronously
   during atomic update
 * ili9486: Support 16-bit pixel data
 * imx: Split off IPUv3 driver; Various fixes
 * mipi-dbi: Convert to DRM shadow-plane helpers plus rsp driver changes;i
   Support separate I/O-voltage supply
 * mxsfb: Depend on ARCH_MXS or ARCH_MXC
 * omapdrm: Various fixes
 * panel: Use ktime_get_boottime() to measure power-down delay in various
   drivers; Fix auto-suspend delay in various drivers; orisetech-ota5601a:
   Add support
 * sprd: Cleanups
 * sun4i: Convert to new TV-mode property
 * tidss: Various fixes
 * v3d: Various fixes
 * vc4: Convert to new TV-mode property; Support Kunit tests; Cleanups;
   dpi: Support RGB565 and RGB666 formats; dsi: Convert DSI driver to
   bridge
 * virtio: Improve tracing
 * vkms: Support small cursors in IGT tests; Various fixes

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/Y7QIwlfElAYWxRcR@linux-uq9g
This commit is contained in:
Daniel Vetter 2023-01-04 14:59:24 +01:00
commit 03a0a10408
253 changed files with 6907 additions and 2517 deletions

View File

@ -52,9 +52,49 @@ properties:
maxItems: 1
description: extcon specifier for the Power Delivery
port:
$ref: /schemas/graph.yaml#/properties/port
description: A port node pointing to DPI host port node
ports:
$ref: /schemas/graph.yaml#/properties/ports
properties:
port@0:
$ref: /schemas/graph.yaml#/$defs/port-base
unevaluatedProperties: false
description: A port node pointing to DPI host port node
properties:
endpoint:
$ref: /schemas/graph.yaml#/$defs/endpoint-base
unevaluatedProperties: false
properties:
link-frequencies:
minItems: 1
maxItems: 1
description: Allowed max link frequencies in Hz
port@1:
$ref: /schemas/graph.yaml#/$defs/port-base
unevaluatedProperties: false
description: Video port for DP output
properties:
endpoint:
$ref: /schemas/graph.yaml#/$defs/endpoint-base
unevaluatedProperties: false
properties:
data-lanes:
minItems: 1
uniqueItems: true
items:
- enum: [ 0, 1 ]
- const: 1
- const: 2
- const: 3
required:
- port@0
- port@1
required:
- compatible
@ -63,6 +103,7 @@ required:
- interrupts
- reset-gpios
- extcon
- ports
additionalProperties: false
@ -85,9 +126,24 @@ examples:
reset-gpios = <&pio 179 1>;
extcon = <&usbc_extcon>;
port {
it6505_in: endpoint {
remote-endpoint = <&dpi_out>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
it6505_in: endpoint {
remote-endpoint = <&dpi_out>;
link-frequencies = /bits/ 64 <150000000>;
};
};
port@1 {
reg = <1>;
it6505_out: endpoint {
remote-endpoint = <&dp_in>;
data-lanes = <0 1>;
};
};
};
};

View File

@ -17,7 +17,9 @@ description: |
properties:
compatible:
const: ite,it66121
enum:
- ite,it66121
- ite,it6610
reg:
maxItems: 1

View File

@ -0,0 +1,56 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/focaltech,gpt3.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Focaltech GPT3 3.0" (640x480 pixels) IPS LCD panel
maintainers:
- Christophe Branchereau <cbranchereau@gmail.com>
allOf:
- $ref: panel-common.yaml#
- $ref: /schemas/spi/spi-peripheral-props.yaml#
properties:
compatible:
const: focaltech,gpt3
reg:
maxItems: 1
required:
- compatible
- reg
- power-supply
- reset-gpios
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "focaltech,gpt3";
reg = <0>;
spi-max-frequency = <3125000>;
reset-gpios = <&gpe 2 GPIO_ACTIVE_LOW>;
backlight = <&backlight>;
power-supply = <&vcc>;
port {
panel_input: endpoint {
remote-endpoint = <&panel_output>;
};
};
};
};

View File

@ -22,8 +22,9 @@ description: |
The standard defines the following interface signals for type C:
- Power:
- Vdd: Power supply for display module
Called power-supply in this binding.
- Vddi: Logic level supply for interface signals
Combined into one in this binding called: power-supply
Called io-supply in this binding.
- Interface:
- CSx: Chip select
- SCL: Serial clock
@ -80,6 +81,11 @@ properties:
Controller data/command selection (D/CX) in 4-line SPI mode.
If not set, the controller is in 3-line SPI mode.
io-supply:
description: |
Logic level supply for interface signals (Vddi).
No need to set if this is the same as power-supply.
required:
- compatible
- reg

View File

@ -29,7 +29,10 @@ Things between square brackets are optional.
Valid names are::
- NSTC: 480i output, with the CCIR System-M TV mode and NTSC color encoding
- NTSC-J: 480i output, with the CCIR System-M TV mode, the NTSC color
encoding, and a black level equal to the blanking level.
- PAL: 576i output, with the CCIR System-B TV mode and PAL color encoding
- PAL-M: 480i output, with the CCIR System-M TV mode and PAL color encoding
If 'M' is specified in the mode_option argument (after <yres> and before
<bpp> and <refresh>, if specified) the timings will be calculated using
@ -70,6 +73,8 @@ Valid options are::
- reflect_y (boolean): Perform an axial symmetry on the Y axis
- rotate (integer): Rotate the initial framebuffer by x
degrees. Valid values are 0, 90, 180 and 270.
- tv_mode: Analog TV mode. One of "NTSC", "NTSC-443", "NTSC-J", "PAL",
"PAL-M", "PAL-N", or "SECAM".
- panel_orientation, one of "normal", "upside_down", "left_side_up", or
"right_side_up". For KMS drivers only, this sets the "panel orientation"
property on the kms connector as hint for kms users.

View File

@ -188,6 +188,13 @@ Bridge Helper Reference
.. kernel-doc:: drivers/gpu/drm/drm_bridge.c
:export:
MIPI-DSI bridge operation
-------------------------
.. kernel-doc:: drivers/gpu/drm/drm_bridge.c
:doc: dsi bridge operations
Bridge Connector Helper Reference
---------------------------------

View File

@ -520,6 +520,12 @@ HDMI Specific Connector Properties
.. kernel-doc:: drivers/gpu/drm/drm_connector.c
:doc: HDMI connector properties
Analog TV Specific Connector Properties
---------------------------------------
.. kernel-doc:: drivers/gpu/drm/drm_connector.c
:doc: Analog TV Connector Properties
Standard CRTC Properties
------------------------

View File

@ -508,17 +508,18 @@ Clean up the debugfs support
There's a bunch of issues with it:
- The drm_info_list ->show() function doesn't even bother to cast to the drm
structure for you. This is lazy.
- Convert drivers to support the drm_debugfs_add_files() function instead of
the drm_debugfs_create_files() function.
- Improve late-register debugfs by rolling out the same debugfs pre-register
infrastructure for connector and crtc too. That way, the drivers won't need to
split their setup code into init and register anymore.
- We probably want to have some support for debugfs files on crtc/connectors and
maybe other kms objects directly in core. There's even drm_print support in
the funcs for these objects to dump kms state, so it's all there. And then the
->show() functions should obviously give you a pointer to the right object.
- The drm_info_list stuff is centered on drm_minor instead of drm_device. For
anything we want to print drm_device (or maybe drm_file) is the right thing.
- The drm_driver->debugfs_init hooks we have is just an artifact of the old
midlayered load sequence. DRM debugfs should work more like sysfs, where you
can create properties/files for an object anytime you want, and the core
@ -527,8 +528,6 @@ There's a bunch of issues with it:
this (together with the drm_minor->drm_device move) would allow us to remove
debugfs_init.
Previous RFC that hasn't landed yet: https://lore.kernel.org/dri-devel/20200513114130.28641-2-wambui.karugax@gmail.com/
Contact: Daniel Vetter
Level: Intermediate

View File

@ -54,6 +54,25 @@ VEC (Composite TV out) encoder
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_vec.c
:doc: VC4 SDTV module
KUnit Tests
===========
The VC4 Driver uses KUnit to perform driver-specific unit and
integration tests.
These tests are using a mock driver and can be ran using the
command below, on either arm or arm64 architectures,
.. code-block:: bash
$ ./tools/testing/kunit/kunit.py run \
--kunitconfig=drivers/gpu/drm/vc4/tests/.kunitconfig \
--cross_compile aarch64-linux-gnu- --arch arm64
Parts of the driver that are currently covered by tests are:
* The HVS to PixelValve dynamic FIFO assignment, for the BCM2835-7
and BCM2711.
Memory Management and 3D Command Submission
===========================================

View File

@ -949,6 +949,43 @@ The following tables list existing packed RGB formats.
- b\ :sub:`2`
- b\ :sub:`1`
- b\ :sub:`0`
* .. _MEDIA-BUS-FMT-BGR666-1X18:
- MEDIA_BUS_FMT_BGR666_1X18
- 0x1023
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- b\ :sub:`5`
- b\ :sub:`4`
- b\ :sub:`3`
- b\ :sub:`2`
- b\ :sub:`1`
- b\ :sub:`0`
- g\ :sub:`5`
- g\ :sub:`4`
- g\ :sub:`3`
- g\ :sub:`2`
- g\ :sub:`1`
- g\ :sub:`0`
- r\ :sub:`5`
- r\ :sub:`4`
- r\ :sub:`3`
- r\ :sub:`2`
- r\ :sub:`1`
- r\ :sub:`0`
* .. _MEDIA-BUS-FMT-RBG888-1X24:
- MEDIA_BUS_FMT_RBG888_1X24
@ -1023,6 +1060,80 @@ The following tables list existing packed RGB formats.
- b\ :sub:`2`
- b\ :sub:`1`
- b\ :sub:`0`
* .. _MEDIA-BUS-FMT-BGR666-1X24_CPADHI:
- MEDIA_BUS_FMT_BGR666_1X24_CPADHI
- 0x1024
-
-
-
-
-
-
-
-
-
- 0
- 0
- b\ :sub:`5`
- b\ :sub:`4`
- b\ :sub:`3`
- b\ :sub:`2`
- b\ :sub:`1`
- b\ :sub:`0`
- 0
- 0
- g\ :sub:`5`
- g\ :sub:`4`
- g\ :sub:`3`
- g\ :sub:`2`
- g\ :sub:`1`
- g\ :sub:`0`
- 0
- 0
- r\ :sub:`5`
- r\ :sub:`4`
- r\ :sub:`3`
- r\ :sub:`2`
- r\ :sub:`1`
- r\ :sub:`0`
* .. _MEDIA-BUS-FMT-RGB565-1X24_CPADHI:
- MEDIA_BUS_FMT_RGB565_1X24_CPADHI
- 0x1022
-
-
-
-
-
-
-
-
-
- 0
- 0
- 0
- r\ :sub:`4`
- r\ :sub:`3`
- r\ :sub:`2`
- r\ :sub:`1`
- r\ :sub:`0`
- 0
- 0
- g\ :sub:`5`
- g\ :sub:`4`
- g\ :sub:`3`
- g\ :sub:`2`
- g\ :sub:`1`
- g\ :sub:`0`
- 0
- 0
- 0
- b\ :sub:`4`
- b\ :sub:`3`
- b\ :sub:`2`
- b\ :sub:`1`
- b\ :sub:`0`
* .. _MEDIA-BUS-FMT-BGR888-1X24:
- MEDIA_BUS_FMT_BGR888_1X24

View File

@ -6984,7 +6984,7 @@ M: Philipp Zabel <p.zabel@pengutronix.de>
L: dri-devel@lists.freedesktop.org
S: Maintained
F: Documentation/devicetree/bindings/display/imx/
F: drivers/gpu/drm/imx/
F: drivers/gpu/drm/imx/ipuv3/
F: drivers/gpu/ipu-v3/
DRM DRIVERS FOR FREESCALE IMX BRIDGE

View File

@ -1263,7 +1263,7 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_attachment_unlocked, DMA_BUF);
*
* @dmabuf: [in] buffer which is moving
*
* Informs all attachmenst that they need to destroy and recreated all their
* Informs all attachments that they need to destroy and recreate all their
* mappings.
*/
void dma_buf_move_notify(struct dma_buf *dmabuf)
@ -1281,11 +1281,11 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_move_notify, DMA_BUF);
/**
* DOC: cpu access
*
* There are mutliple reasons for supporting CPU access to a dma buffer object:
* There are multiple reasons for supporting CPU access to a dma buffer object:
*
* - Fallback operations in the kernel, for example when a device is connected
* over USB and the kernel needs to shuffle the data around first before
* sending it away. Cache coherency is handled by braketing any transactions
* sending it away. Cache coherency is handled by bracketing any transactions
* with calls to dma_buf_begin_cpu_access() and dma_buf_end_cpu_access()
* access.
*
@ -1312,7 +1312,7 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_move_notify, DMA_BUF);
* replace ION buffers mmap support was needed.
*
* There is no special interfaces, userspace simply calls mmap on the dma-buf
* fd. But like for CPU access there's a need to braket the actual access,
* fd. But like for CPU access there's a need to bracket the actual access,
* which is handled by the ioctl (DMA_BUF_IOCTL_SYNC). Note that
* DMA_BUF_IOCTL_SYNC can fail with -EAGAIN or -EINTR, in which case it must
* be restarted.
@ -1386,10 +1386,10 @@ static int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
* preparations. Coherency is only guaranteed in the specified range for the
* specified access direction.
* @dmabuf: [in] buffer to prepare cpu access for.
* @direction: [in] length of range for cpu access.
* @direction: [in] direction of access.
*
* After the cpu access is complete the caller should call
* dma_buf_end_cpu_access(). Only when cpu access is braketed by both calls is
* dma_buf_end_cpu_access(). Only when cpu access is bracketed by both calls is
* it guaranteed to be coherent with other DMA access.
*
* This function will also wait for any DMA transactions tracked through
@ -1429,7 +1429,7 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_begin_cpu_access, DMA_BUF);
* actions. Coherency is only guaranteed in the specified range for the
* specified access direction.
* @dmabuf: [in] buffer to complete cpu access for.
* @direction: [in] length of range for cpu access.
* @direction: [in] direction of access.
*
* This terminates CPU access started with dma_buf_begin_cpu_access().
*

View File

@ -63,6 +63,12 @@ config DRM_USE_DYNAMIC_DEBUG
bytes per callsite, the .data costs can be substantial, and
are therefore configurable.
config DRM_KUNIT_TEST_HELPERS
tristate
depends on DRM && KUNIT
help
KUnit Helpers for KMS drivers.
config DRM_KUNIT_TEST
tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS
depends on DRM && KUNIT
@ -73,6 +79,7 @@ config DRM_KUNIT_TEST
select DRM_KMS_HELPER
select DRM_BUDDY
select DRM_EXPORT_FOR_TESTS if m
select DRM_KUNIT_TEST_HELPERS
default KUNIT_ALL_TESTS
help
This builds unit tests for DRM. This option is not useful for

View File

@ -126,7 +126,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
# Drivers and the rest
#
obj-$(CONFIG_DRM_KUNIT_TEST) += tests/
obj-y += tests/
obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o

View File

@ -52,8 +52,7 @@
#include <linux/pci.h>
#include <linux/aer.h>
#include <drm/ttm/ttm_bo_api.h>
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_execbuf_util.h>

View File

@ -25,6 +25,7 @@
#include <linux/pagemap.h>
#include <linux/sched/mm.h>
#include <linux/sched/task.h>
#include <drm/ttm/ttm_tt.h>
#include "amdgpu_object.h"
#include "amdgpu_gem.h"

View File

@ -28,6 +28,8 @@
struct hmm_range;
struct drm_file;
struct amdgpu_device;
struct amdgpu_bo;
struct amdgpu_bo_va;

View File

@ -32,6 +32,8 @@
#include <drm/amdgpu_drm.h>
#include <drm/drm_syncobj.h>
#include <drm/ttm/ttm_tt.h>
#include "amdgpu_cs.h"
#include "amdgpu.h"
#include "amdgpu_trace.h"

View File

@ -23,6 +23,8 @@
#ifndef __AMDGPU_CS_H__
#define __AMDGPU_CS_H__
#include <linux/ww_mutex.h>
#include "amdgpu_job.h"
#include "amdgpu_bo_list.h"
#include "amdgpu_ring.h"

View File

@ -1717,7 +1717,7 @@ no_preempt:
static int amdgpu_debugfs_ib_preempt(void *data, u64 val)
{
int r, resched, length;
int r, length;
struct amdgpu_ring *ring;
struct dma_fence **fences = NULL;
struct amdgpu_device *adev = (struct amdgpu_device *)data;
@ -1747,8 +1747,6 @@ static int amdgpu_debugfs_ib_preempt(void *data, u64 val)
/* stop the scheduler */
kthread_park(ring->sched.thread);
resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev);
/* preempt the IB */
r = amdgpu_ring_preempt_ib(ring);
if (r) {
@ -1785,8 +1783,6 @@ failure:
up_read(&adev->reset_domain->sem);
ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched);
pro_end:
kfree(fences);

View File

@ -3989,10 +3989,8 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
}
amdgpu_fence_driver_hw_fini(adev);
if (adev->mman.initialized) {
flush_delayed_work(&adev->mman.bdev.wq);
ttm_bo_lock_delayed_workqueue(&adev->mman.bdev);
}
if (adev->mman.initialized)
drain_workqueue(adev->mman.bdev.wq);
if (adev->pm_sysfs_en)
amdgpu_pm_sysfs_fini(adev);

View File

@ -37,6 +37,7 @@
#include "amdgpu_dma_buf.h"
#include "amdgpu_xgmi.h"
#include <drm/amdgpu_drm.h>
#include <drm/ttm/ttm_tt.h>
#include <linux/dma-buf.h>
#include <linux/dma-fence-array.h>
#include <linux/pci-p2pdma.h>

View File

@ -30,7 +30,6 @@
#include <linux/rbtree.h>
#include <drm/gpu_scheduler.h>
#include <drm/drm_file.h>
#include <drm/ttm/ttm_bo_driver.h>
#include <linux/sched/mm.h>
#include "amdgpu_sync.h"

View File

@ -34,6 +34,7 @@
#include <drm/amdgpu_drm.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem_ttm_helper.h>
#include <drm/ttm/ttm_tt.h>
#include "amdgpu.h"
#include "amdgpu_display.h"

View File

@ -35,6 +35,7 @@
#include "amdgpu_xgmi.h"
#include <drm/drm_drv.h>
#include <drm/ttm/ttm_tt.h>
/**
* amdgpu_gmc_pdb0_alloc - allocate vram for pdb0

View File

@ -44,10 +44,10 @@
#include <linux/module.h>
#include <drm/drm_drv.h>
#include <drm/ttm/ttm_bo_api.h>
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_range_manager.h>
#include <drm/ttm/ttm_tt.h>
#include <drm/amdgpu_drm.h>
#include <drm/drm_drv.h>

View File

@ -33,6 +33,7 @@
#include <drm/amdgpu_drm.h>
#include <drm/drm_drv.h>
#include <drm/ttm/ttm_tt.h>
#include "amdgpu.h"
#include "amdgpu_trace.h"
#include "amdgpu_amdkfd.h"

View File

@ -29,7 +29,7 @@
#include <linux/rbtree.h>
#include <drm/gpu_scheduler.h>
#include <drm/drm_file.h>
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_bo.h>
#include <linux/sched/mm.h>
#include "amdgpu_sync.h"

View File

@ -23,6 +23,7 @@
#include <linux/types.h>
#include <linux/sched/task.h>
#include <drm/ttm/ttm_tt.h>
#include "amdgpu_sync.h"
#include "amdgpu_object.h"
#include "amdgpu_vm.h"

View File

@ -636,7 +636,7 @@ static void ast_handle_damage(struct ast_plane *ast_plane, struct iosys_map *src
struct drm_framebuffer *fb,
const struct drm_rect *clip)
{
struct iosys_map dst = IOSYS_MAP_INIT_VADDR(ast_plane->vaddr);
struct iosys_map dst = IOSYS_MAP_INIT_VADDR_IOMEM(ast_plane->vaddr);
iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, clip));
drm_fb_memcpy(&dst, fb->pitches, src, fb, clip);

View File

@ -784,7 +784,6 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int atmel_hlcdc_dc_drm_suspend(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
@ -815,10 +814,10 @@ static int atmel_hlcdc_dc_drm_resume(struct device *dev)
return drm_atomic_helper_resume(drm_dev, dc->suspend.state);
}
#endif
static SIMPLE_DEV_PM_OPS(atmel_hlcdc_dc_drm_pm_ops,
atmel_hlcdc_dc_drm_suspend, atmel_hlcdc_dc_drm_resume);
static DEFINE_SIMPLE_DEV_PM_OPS(atmel_hlcdc_dc_drm_pm_ops,
atmel_hlcdc_dc_drm_suspend,
atmel_hlcdc_dc_drm_resume);
static const struct of_device_id atmel_hlcdc_dc_of_match[] = {
{ .compatible = "atmel,hlcdc-display-controller" },
@ -830,7 +829,7 @@ static struct platform_driver atmel_hlcdc_dc_platform_driver = {
.remove = atmel_hlcdc_dc_drm_remove,
.driver = {
.name = "atmel-hlcdc-display-controller",
.pm = &atmel_hlcdc_dc_drm_pm_ops,
.pm = pm_sleep_ptr(&atmel_hlcdc_dc_drm_pm_ops),
.of_match_table = atmel_hlcdc_dc_of_match,
},
};

View File

@ -1185,8 +1185,9 @@ static int adv7511_parse_dt(struct device_node *np,
return 0;
}
static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
static int adv7511_probe(struct i2c_client *i2c)
{
const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
struct adv7511_link_config link_config;
struct adv7511 *adv7511;
struct device *dev = &i2c->dev;
@ -1392,7 +1393,7 @@ static struct i2c_driver adv7511_driver = {
.of_match_table = adv7511_of_ids,
},
.id_table = adv7511_i2c_ids,
.probe = adv7511_probe,
.probe_new = adv7511_probe,
.remove = adv7511_remove,
};

View File

@ -692,8 +692,7 @@ static bool anx6345_get_chip_id(struct anx6345 *anx6345)
return false;
}
static int anx6345_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int anx6345_i2c_probe(struct i2c_client *client)
{
struct anx6345 *anx6345;
struct device *dev;
@ -817,7 +816,7 @@ static struct i2c_driver anx6345_driver = {
.name = "anx6345",
.of_match_table = of_match_ptr(anx6345_match_table),
},
.probe = anx6345_i2c_probe,
.probe_new = anx6345_i2c_probe,
.remove = anx6345_i2c_remove,
.id_table = anx6345_id,
};

View File

@ -1214,8 +1214,7 @@ static const u16 anx78xx_chipid_list[] = {
0x7818,
};
static int anx78xx_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int anx78xx_i2c_probe(struct i2c_client *client)
{
struct anx78xx *anx78xx;
struct anx78xx_platform_data *pdata;
@ -1390,7 +1389,7 @@ static struct i2c_driver anx78xx_driver = {
.name = "anx7814",
.of_match_table = of_match_ptr(anx78xx_match_table),
},
.probe = anx78xx_i2c_probe,
.probe_new = anx78xx_i2c_probe,
.remove = anx78xx_i2c_remove,
.id_table = anx78xx_id,
};

View File

@ -1403,7 +1403,6 @@ static void anx7625_stop_dp_work(struct anx7625_data *ctx)
{
ctx->hpd_status = 0;
ctx->hpd_high_cnt = 0;
ctx->display_timing_valid = 0;
}
static void anx7625_start_dp_work(struct anx7625_data *ctx)
@ -2562,8 +2561,7 @@ static void anx7625_runtime_disable(void *data)
pm_runtime_disable(data);
}
static int anx7625_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int anx7625_i2c_probe(struct i2c_client *client)
{
struct anx7625_data *platform;
struct anx7625_platform_data *pdata;
@ -2756,7 +2754,7 @@ static struct i2c_driver anx7625_driver = {
.of_match_table = anx_match_table,
.pm = &anx7625_pm_ops,
},
.probe = anx7625_i2c_probe,
.probe_new = anx7625_i2c_probe,
.remove = anx7625_i2c_remove,
.id_table = anx7625_id,

View File

@ -740,8 +740,7 @@ static int chipone_dsi_probe(struct mipi_dsi_device *dsi)
return ret;
}
static int chipone_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int chipone_i2c_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct chipone *icn;
@ -796,7 +795,7 @@ static struct i2c_device_id chipone_i2c_id[] = {
MODULE_DEVICE_TABLE(i2c, chipone_i2c_id);
static struct i2c_driver chipone_i2c_driver = {
.probe = chipone_i2c_probe,
.probe_new = chipone_i2c_probe,
.id_table = chipone_i2c_id,
.driver = {
.name = "chipone-icn6211-i2c",

View File

@ -528,8 +528,7 @@ static const struct regmap_config ch7033_regmap_config = {
.max_register = 0x7f,
};
static int ch7033_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int ch7033_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct ch7033_priv *priv;
@ -604,7 +603,7 @@ static const struct i2c_device_id ch7033_ids[] = {
MODULE_DEVICE_TABLE(i2c, ch7033_ids);
static struct i2c_driver ch7033_driver = {
.probe = ch7033_probe,
.probe_new = ch7033_probe,
.remove = ch7033_remove,
.driver = {
.name = "ch7033",

View File

@ -412,7 +412,6 @@ struct it6505 {
* Mutex protects extcon and interrupt functions from interfering
* each other.
*/
struct mutex irq_lock;
struct mutex extcon_lock;
struct mutex mode_lock; /* used to bridge_detect */
struct mutex aux_lock; /* used to aux data transfers */
@ -438,6 +437,8 @@ struct it6505 {
bool powered;
bool hpd_state;
u32 afe_setting;
u32 max_dpi_pixel_clock;
u32 max_lane_count;
enum hdcp_state hdcp_status;
struct delayed_work hdcp_work;
struct work_struct hdcp_wait_ksv_list;
@ -457,6 +458,8 @@ struct it6505 {
/* it6505 driver hold option */
bool enable_drv_hold;
struct edid *cached_edid;
};
struct it6505_step_train_para {
@ -1463,7 +1466,8 @@ static void it6505_parse_link_capabilities(struct it6505 *it6505)
it6505->lane_count = link->num_lanes;
DRM_DEV_DEBUG_DRIVER(dev, "Sink support %d lanes training",
it6505->lane_count);
it6505->lane_count = min_t(int, it6505->lane_count, MAX_LANE_COUNT);
it6505->lane_count = min_t(int, it6505->lane_count,
it6505->max_lane_count);
it6505->branch_device = drm_dp_is_branch(it6505->dpcd);
DRM_DEV_DEBUG_DRIVER(dev, "Sink %sbranch device",
@ -2244,6 +2248,12 @@ static void it6505_plugged_status_to_codec(struct it6505 *it6505)
status == connector_status_connected);
}
static void it6505_remove_edid(struct it6505 *it6505)
{
kfree(it6505->cached_edid);
it6505->cached_edid = NULL;
}
static int it6505_process_hpd_irq(struct it6505 *it6505)
{
struct device *dev = &it6505->client->dev;
@ -2270,6 +2280,7 @@ static int it6505_process_hpd_irq(struct it6505 *it6505)
it6505_reset_logic(it6505);
it6505_int_mask_enable(it6505);
it6505_init(it6505);
it6505_remove_edid(it6505);
return 0;
}
@ -2353,6 +2364,7 @@ static void it6505_irq_hpd(struct it6505 *it6505)
it6505_video_reset(it6505);
} else {
memset(it6505->dpcd, 0, sizeof(it6505->dpcd));
it6505_remove_edid(it6505);
if (it6505->hdcp_desired)
it6505_stop_hdcp(it6505);
@ -2494,10 +2506,8 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
};
int int_status[3], i;
mutex_lock(&it6505->irq_lock);
if (it6505->enable_drv_hold || !it6505->powered)
goto unlock;
if (it6505->enable_drv_hold || pm_runtime_get_if_in_use(dev) <= 0)
return IRQ_HANDLED;
int_status[0] = it6505_read(it6505, INT_STATUS_01);
int_status[1] = it6505_read(it6505, INT_STATUS_02);
@ -2515,16 +2525,14 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
if (it6505_test_bit(irq_vec[0].bit, (unsigned int *)int_status))
irq_vec[0].handler(it6505);
if (!it6505->hpd_state)
goto unlock;
for (i = 1; i < ARRAY_SIZE(irq_vec); i++) {
if (it6505_test_bit(irq_vec[i].bit, (unsigned int *)int_status))
irq_vec[i].handler(it6505);
if (it6505->hpd_state) {
for (i = 1; i < ARRAY_SIZE(irq_vec); i++) {
if (it6505_test_bit(irq_vec[i].bit, (unsigned int *)int_status))
irq_vec[i].handler(it6505);
}
}
unlock:
mutex_unlock(&it6505->irq_lock);
pm_runtime_put_sync(dev);
return IRQ_HANDLED;
}
@ -2902,7 +2910,7 @@ it6505_bridge_mode_valid(struct drm_bridge *bridge,
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
return MODE_NO_INTERLACE;
if (mode->clock > DPI_PIXEL_CLK_MAX)
if (mode->clock > it6505->max_dpi_pixel_clock)
return MODE_CLOCK_HIGH;
it6505->video_info.clock = mode->clock;
@ -3016,16 +3024,18 @@ static struct edid *it6505_bridge_get_edid(struct drm_bridge *bridge,
{
struct it6505 *it6505 = bridge_to_it6505(bridge);
struct device *dev = &it6505->client->dev;
struct edid *edid;
edid = drm_do_get_edid(connector, it6505_get_edid_block, it6505);
if (!it6505->cached_edid) {
it6505->cached_edid = drm_do_get_edid(connector, it6505_get_edid_block,
it6505);
if (!edid) {
DRM_DEV_DEBUG_DRIVER(dev, "failed to get edid!");
return NULL;
if (!it6505->cached_edid) {
DRM_DEV_DEBUG_DRIVER(dev, "failed to get edid!");
return NULL;
}
}
return edid;
return drm_edid_duplicate(it6505->cached_edid);
}
static const struct drm_bridge_funcs it6505_bridge_funcs = {
@ -3089,10 +3099,32 @@ static int it6505_init_pdata(struct it6505 *it6505)
return 0;
}
static int it6505_get_data_lanes_count(const struct device_node *endpoint,
const unsigned int min,
const unsigned int max)
{
int ret;
ret = of_property_count_u32_elems(endpoint, "data-lanes");
if (ret < 0)
return ret;
if (ret < min || ret > max)
return -EINVAL;
return ret;
}
static void it6505_parse_dt(struct it6505 *it6505)
{
struct device *dev = &it6505->client->dev;
struct device_node *np = dev->of_node, *ep = NULL;
int len;
u64 link_frequencies;
u32 data_lanes[4];
u32 *afe_setting = &it6505->afe_setting;
u32 *max_lane_count = &it6505->max_lane_count;
u32 *max_dpi_pixel_clock = &it6505->max_dpi_pixel_clock;
it6505->lane_swap_disabled =
device_property_read_bool(dev, "no-laneswap");
@ -3108,7 +3140,56 @@ static void it6505_parse_dt(struct it6505 *it6505)
} else {
*afe_setting = 0;
}
DRM_DEV_DEBUG_DRIVER(dev, "using afe_setting: %d", *afe_setting);
ep = of_graph_get_endpoint_by_regs(np, 1, 0);
of_node_put(ep);
if (ep) {
len = it6505_get_data_lanes_count(ep, 1, 4);
if (len > 0 && len != 3) {
of_property_read_u32_array(ep, "data-lanes",
data_lanes, len);
*max_lane_count = len;
} else {
*max_lane_count = MAX_LANE_COUNT;
dev_err(dev, "error data-lanes, use default");
}
} else {
*max_lane_count = MAX_LANE_COUNT;
dev_err(dev, "error endpoint, use default");
}
ep = of_graph_get_endpoint_by_regs(np, 0, 0);
of_node_put(ep);
if (ep) {
len = of_property_read_variable_u64_array(ep,
"link-frequencies",
&link_frequencies, 0,
1);
if (len >= 0) {
do_div(link_frequencies, 1000);
if (link_frequencies > 297000) {
dev_err(dev,
"max pixel clock error, use default");
*max_dpi_pixel_clock = DPI_PIXEL_CLK_MAX;
} else {
*max_dpi_pixel_clock = link_frequencies;
}
} else {
dev_err(dev, "error link frequencies, use default");
*max_dpi_pixel_clock = DPI_PIXEL_CLK_MAX;
}
} else {
dev_err(dev, "error endpoint, use default");
*max_dpi_pixel_clock = DPI_PIXEL_CLK_MAX;
}
DRM_DEV_DEBUG_DRIVER(dev, "using afe_setting: %u, max_lane_count: %u",
it6505->afe_setting, it6505->max_lane_count);
DRM_DEV_DEBUG_DRIVER(dev, "using max_dpi_pixel_clock: %u kHz",
it6505->max_dpi_pixel_clock);
}
static ssize_t receive_timing_debugfs_show(struct file *file, char __user *buf,
@ -3265,8 +3346,7 @@ static void it6505_shutdown(struct i2c_client *client)
it6505_lane_off(it6505);
}
static int it6505_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int it6505_i2c_probe(struct i2c_client *client)
{
struct it6505 *it6505;
struct device *dev = &client->dev;
@ -3277,7 +3357,6 @@ static int it6505_i2c_probe(struct i2c_client *client,
if (!it6505)
return -ENOMEM;
mutex_init(&it6505->irq_lock);
mutex_init(&it6505->extcon_lock);
mutex_init(&it6505->mode_lock);
mutex_init(&it6505->aux_lock);
@ -3367,6 +3446,7 @@ static void it6505_i2c_remove(struct i2c_client *client)
drm_dp_aux_unregister(&it6505->aux);
it6505_debugfs_remove(it6505);
it6505_poweroff(it6505);
it6505_remove_edid(it6505);
}
static const struct i2c_device_id it6505_id[] = {
@ -3387,7 +3467,7 @@ static struct i2c_driver it6505_i2c_driver = {
.of_match_table = it6505_of_match,
.pm = &it6505_bridge_pm_ops,
},
.probe = it6505_i2c_probe,
.probe_new = it6505_i2c_probe,
.remove = it6505_i2c_remove,
.shutdown = it6505_shutdown,
.id_table = it6505_id,

View File

@ -35,10 +35,6 @@
#define IT66121_DEVICE_ID0_REG 0x02
#define IT66121_DEVICE_ID1_REG 0x03
#define IT66121_VENDOR_ID0 0x54
#define IT66121_VENDOR_ID1 0x49
#define IT66121_DEVICE_ID0 0x12
#define IT66121_DEVICE_ID1 0x06
#define IT66121_REVISION_MASK GENMASK(7, 4)
#define IT66121_DEVICE_ID1_MASK GENMASK(3, 0)
@ -72,6 +68,7 @@
#define IT66121_AFE_XP_ENO BIT(4)
#define IT66121_AFE_XP_RESETB BIT(3)
#define IT66121_AFE_XP_PWDI BIT(2)
#define IT6610_AFE_XP_BYPASS BIT(0)
#define IT66121_AFE_IP_REG 0x64
#define IT66121_AFE_IP_GAINBIT BIT(7)
@ -286,13 +283,18 @@
#define IT66121_AUD_SWL_16BIT 0x2
#define IT66121_AUD_SWL_NOT_INDICATED 0x0
#define IT66121_VENDOR_ID0 0x54
#define IT66121_VENDOR_ID1 0x49
#define IT66121_DEVICE_ID0 0x12
#define IT66121_DEVICE_ID1 0x06
#define IT66121_DEVICE_MASK 0x0F
#define IT66121_AFE_CLK_HIGH 80000 /* Khz */
enum chip_id {
ID_IT6610,
ID_IT66121,
};
struct it66121_chip_info {
enum chip_id id;
u16 vid, pid;
};
struct it66121_ctx {
struct regmap *regmap;
struct drm_bridge bridge;
@ -301,7 +303,6 @@ struct it66121_ctx {
struct device *dev;
struct gpio_desc *gpio_reset;
struct i2c_client *client;
struct regulator_bulk_data supplies[3];
u32 bus_width;
struct mutex lock; /* Protects fields below and device registers */
struct hdmi_avi_infoframe hdmi_avi_infoframe;
@ -312,6 +313,7 @@ struct it66121_ctx {
u8 swl;
bool auto_cts;
} audio;
const struct it66121_chip_info *info;
};
static const struct regmap_range_cfg it66121_regmap_banks[] = {
@ -342,16 +344,6 @@ static void it66121_hw_reset(struct it66121_ctx *ctx)
gpiod_set_value(ctx->gpio_reset, 0);
}
static inline int ite66121_power_on(struct it66121_ctx *ctx)
{
return regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
}
static inline int ite66121_power_off(struct it66121_ctx *ctx)
{
return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
}
static inline int it66121_preamble_ddc(struct it66121_ctx *ctx)
{
return regmap_write(ctx->regmap, IT66121_MASTER_SEL_REG, IT66121_MASTER_SEL_HOST);
@ -406,16 +398,22 @@ static int it66121_configure_afe(struct it66121_ctx *ctx,
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG,
IT66121_AFE_IP_GAINBIT |
IT66121_AFE_IP_ER0 |
IT66121_AFE_IP_EC1,
IT66121_AFE_IP_ER0,
IT66121_AFE_IP_GAINBIT);
if (ret)
return ret;
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG,
IT66121_AFE_XP_EC1_LOWCLK, 0x80);
if (ret)
return ret;
if (ctx->info->id == ID_IT66121) {
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG,
IT66121_AFE_IP_EC1, 0);
if (ret)
return ret;
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG,
IT66121_AFE_XP_EC1_LOWCLK, 0x80);
if (ret)
return ret;
}
} else {
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG,
IT66121_AFE_XP_GAINBIT |
@ -426,17 +424,24 @@ static int it66121_configure_afe(struct it66121_ctx *ctx,
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG,
IT66121_AFE_IP_GAINBIT |
IT66121_AFE_IP_ER0 |
IT66121_AFE_IP_EC1, IT66121_AFE_IP_ER0 |
IT66121_AFE_IP_EC1);
IT66121_AFE_IP_ER0,
IT66121_AFE_IP_ER0);
if (ret)
return ret;
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG,
IT66121_AFE_XP_EC1_LOWCLK,
IT66121_AFE_XP_EC1_LOWCLK);
if (ret)
return ret;
if (ctx->info->id == ID_IT66121) {
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG,
IT66121_AFE_IP_EC1,
IT66121_AFE_IP_EC1);
if (ret)
return ret;
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG,
IT66121_AFE_XP_EC1_LOWCLK,
IT66121_AFE_XP_EC1_LOWCLK);
if (ret)
return ret;
}
}
/* Clear reset flags */
@ -445,38 +450,36 @@ static int it66121_configure_afe(struct it66121_ctx *ctx,
if (ret)
return ret;
if (ctx->info->id == ID_IT6610) {
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG,
IT6610_AFE_XP_BYPASS,
IT6610_AFE_XP_BYPASS);
if (ret)
return ret;
}
return it66121_fire_afe(ctx);
}
static inline int it66121_wait_ddc_ready(struct it66121_ctx *ctx)
{
int ret, val;
u32 busy = IT66121_DDC_STATUS_NOACK | IT66121_DDC_STATUS_WAIT_BUS |
IT66121_DDC_STATUS_ARBI_LOSE;
u32 error = IT66121_DDC_STATUS_NOACK | IT66121_DDC_STATUS_WAIT_BUS |
IT66121_DDC_STATUS_ARBI_LOSE;
u32 done = IT66121_DDC_STATUS_TX_DONE;
ret = regmap_read_poll_timeout(ctx->regmap, IT66121_DDC_STATUS_REG, val, true,
IT66121_EDID_SLEEP_US, IT66121_EDID_TIMEOUT_US);
ret = regmap_read_poll_timeout(ctx->regmap, IT66121_DDC_STATUS_REG, val,
val & (error | done), IT66121_EDID_SLEEP_US,
IT66121_EDID_TIMEOUT_US);
if (ret)
return ret;
if (val & busy)
if (val & error)
return -EAGAIN;
return 0;
}
static int it66121_clear_ddc_fifo(struct it66121_ctx *ctx)
{
int ret;
ret = it66121_preamble_ddc(ctx);
if (ret)
return ret;
return regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG,
IT66121_DDC_COMMAND_FIFO_CLR);
}
static int it66121_abort_ddc_ops(struct it66121_ctx *ctx)
{
int ret;
@ -516,7 +519,6 @@ static int it66121_get_edid_block(void *context, u8 *buf,
unsigned int block, size_t len)
{
struct it66121_ctx *ctx = context;
unsigned int val;
int remain = len;
int offset = 0;
int ret, cnt;
@ -524,26 +526,9 @@ static int it66121_get_edid_block(void *context, u8 *buf,
offset = (block % 2) * len;
block = block / 2;
ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val);
if (ret)
return ret;
if (val & IT66121_INT_STATUS1_DDC_BUSHANG) {
ret = it66121_abort_ddc_ops(ctx);
if (ret)
return ret;
}
ret = it66121_clear_ddc_fifo(ctx);
if (ret)
return ret;
while (remain > 0) {
cnt = (remain > IT66121_EDID_FIFO_SIZE) ?
IT66121_EDID_FIFO_SIZE : remain;
ret = it66121_preamble_ddc(ctx);
if (ret)
return ret;
ret = regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG,
IT66121_DDC_COMMAND_FIFO_CLR);
@ -554,25 +539,6 @@ static int it66121_get_edid_block(void *context, u8 *buf,
if (ret)
return ret;
ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val);
if (ret)
return ret;
if (val & IT66121_INT_STATUS1_DDC_BUSHANG) {
ret = it66121_abort_ddc_ops(ctx);
if (ret)
return ret;
}
ret = it66121_preamble_ddc(ctx);
if (ret)
return ret;
ret = regmap_write(ctx->regmap, IT66121_DDC_HEADER_REG,
IT66121_DDC_HEADER_EDID);
if (ret)
return ret;
ret = regmap_write(ctx->regmap, IT66121_DDC_OFFSET_REG, offset);
if (ret)
return ret;
@ -593,20 +559,18 @@ static int it66121_get_edid_block(void *context, u8 *buf,
offset += cnt;
remain -= cnt;
/* Per programming manual, sleep here before emptying the FIFO */
msleep(20);
ret = it66121_wait_ddc_ready(ctx);
if (ret) {
it66121_abort_ddc_ops(ctx);
return ret;
}
ret = regmap_noinc_read(ctx->regmap, IT66121_DDC_RD_FIFO_REG,
buf, cnt);
if (ret)
return ret;
do {
ret = regmap_read(ctx->regmap, IT66121_DDC_RD_FIFO_REG, &val);
if (ret)
return ret;
*(buf++) = val;
cnt--;
} while (cnt > 0);
buf += cnt;
}
return 0;
@ -635,10 +599,12 @@ static int it66121_bridge_attach(struct drm_bridge *bridge,
if (ret)
return ret;
ret = regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
IT66121_CLK_BANK_PWROFF_RCLK, 0);
if (ret)
return ret;
if (ctx->info->id == ID_IT66121) {
ret = regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
IT66121_CLK_BANK_PWROFF_RCLK, 0);
if (ret)
return ret;
}
ret = regmap_write_bits(ctx->regmap, IT66121_INT_REG,
IT66121_INT_TX_CLK_OFF, 0);
@ -684,11 +650,7 @@ static int it66121_bridge_attach(struct drm_bridge *bridge,
/* Per programming manual, sleep here for bridge to settle */
msleep(50);
/* Start interrupts */
return regmap_write_bits(ctx->regmap, IT66121_INT_MASK1_REG,
IT66121_INT_MASK1_DDC_NOACK |
IT66121_INT_MASK1_DDC_FIFOERR |
IT66121_INT_MASK1_DDC_BUSHANG, 0);
return 0;
}
static int it66121_set_mute(struct it66121_ctx *ctx, bool mute)
@ -780,29 +742,32 @@ static void it66121_bridge_disable(struct drm_bridge *bridge,
ctx->connector = NULL;
}
static int it66121_bridge_check(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
if (ctx->info->id == ID_IT6610) {
/* The IT6610 only supports these settings */
bridge_state->input_bus_cfg.flags |= DRM_BUS_FLAG_DE_HIGH |
DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
bridge_state->input_bus_cfg.flags &=
~DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
}
return 0;
}
static
void it66121_bridge_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
const struct drm_display_mode *adjusted_mode)
{
int ret, i;
u8 buf[HDMI_INFOFRAME_SIZE(AVI)];
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
const u16 aviinfo_reg[HDMI_AVI_INFOFRAME_SIZE] = {
IT66121_AVIINFO_DB1_REG,
IT66121_AVIINFO_DB2_REG,
IT66121_AVIINFO_DB3_REG,
IT66121_AVIINFO_DB4_REG,
IT66121_AVIINFO_DB5_REG,
IT66121_AVIINFO_DB6_REG,
IT66121_AVIINFO_DB7_REG,
IT66121_AVIINFO_DB8_REG,
IT66121_AVIINFO_DB9_REG,
IT66121_AVIINFO_DB10_REG,
IT66121_AVIINFO_DB11_REG,
IT66121_AVIINFO_DB12_REG,
IT66121_AVIINFO_DB13_REG
};
int ret;
mutex_lock(&ctx->lock);
@ -822,10 +787,12 @@ void it66121_bridge_mode_set(struct drm_bridge *bridge,
}
/* Write new AVI infoframe packet */
for (i = 0; i < HDMI_AVI_INFOFRAME_SIZE; i++) {
if (regmap_write(ctx->regmap, aviinfo_reg[i], buf[i + HDMI_INFOFRAME_HEADER_SIZE]))
goto unlock;
}
ret = regmap_bulk_write(ctx->regmap, IT66121_AVIINFO_DB1_REG,
&buf[HDMI_INFOFRAME_HEADER_SIZE],
HDMI_AVI_INFOFRAME_SIZE);
if (ret)
goto unlock;
if (regmap_write(ctx->regmap, IT66121_AVIINFO_CSUM_REG, buf[3]))
goto unlock;
@ -838,9 +805,12 @@ void it66121_bridge_mode_set(struct drm_bridge *bridge,
if (regmap_write(ctx->regmap, IT66121_HDMI_MODE_REG, IT66121_HDMI_MODE_HDMI))
goto unlock;
if (regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
IT66121_CLK_BANK_PWROFF_TXCLK, IT66121_CLK_BANK_PWROFF_TXCLK))
if (ctx->info->id == ID_IT66121 &&
regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
IT66121_CLK_BANK_PWROFF_TXCLK,
IT66121_CLK_BANK_PWROFF_TXCLK)) {
goto unlock;
}
if (it66121_configure_input(ctx))
goto unlock;
@ -848,7 +818,11 @@ void it66121_bridge_mode_set(struct drm_bridge *bridge,
if (it66121_configure_afe(ctx, adjusted_mode))
goto unlock;
regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, IT66121_CLK_BANK_PWROFF_TXCLK, 0);
if (ctx->info->id == ID_IT66121 &&
regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
IT66121_CLK_BANK_PWROFF_TXCLK, 0)) {
goto unlock;
}
unlock:
mutex_unlock(&ctx->lock);
@ -906,9 +880,25 @@ static struct edid *it66121_bridge_get_edid(struct drm_bridge *bridge,
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
struct edid *edid;
int ret;
mutex_lock(&ctx->lock);
ret = it66121_preamble_ddc(ctx);
if (ret) {
edid = ERR_PTR(ret);
goto out_unlock;
}
ret = regmap_write(ctx->regmap, IT66121_DDC_HEADER_REG,
IT66121_DDC_HEADER_EDID);
if (ret) {
edid = ERR_PTR(ret);
goto out_unlock;
}
edid = drm_do_get_edid(connector, it66121_get_edid_block, ctx);
out_unlock:
mutex_unlock(&ctx->lock);
return edid;
@ -923,6 +913,7 @@ static const struct drm_bridge_funcs it66121_bridge_funcs = {
.atomic_get_input_bus_fmts = it66121_bridge_atomic_get_input_bus_fmts,
.atomic_enable = it66121_bridge_enable,
.atomic_disable = it66121_bridge_disable,
.atomic_check = it66121_bridge_check,
.mode_set = it66121_bridge_mode_set,
.mode_valid = it66121_bridge_mode_valid,
.detect = it66121_bridge_detect,
@ -952,21 +943,14 @@ static irqreturn_t it66121_irq_threaded_handler(int irq, void *dev_id)
ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val);
if (ret) {
dev_err(dev, "Cannot read STATUS1_REG %d\n", ret);
} else {
if (val & IT66121_INT_STATUS1_DDC_FIFOERR)
it66121_clear_ddc_fifo(ctx);
if (val & (IT66121_INT_STATUS1_DDC_BUSHANG |
IT66121_INT_STATUS1_DDC_NOACK))
it66121_abort_ddc_ops(ctx);
if (val & IT66121_INT_STATUS1_HPD_STATUS) {
regmap_write_bits(ctx->regmap, IT66121_INT_CLR1_REG,
IT66121_INT_CLR1_HPD, IT66121_INT_CLR1_HPD);
} else if (val & IT66121_INT_STATUS1_HPD_STATUS) {
regmap_write_bits(ctx->regmap, IT66121_INT_CLR1_REG,
IT66121_INT_CLR1_HPD, IT66121_INT_CLR1_HPD);
status = it66121_is_hpd_detect(ctx) ? connector_status_connected
: connector_status_disconnected;
status = it66121_is_hpd_detect(ctx) ? connector_status_connected
: connector_status_disconnected;
event = true;
}
event = true;
}
regmap_write_bits(ctx->regmap, IT66121_SYS_STATUS_REG,
@ -1512,9 +1496,13 @@ static int it66121_audio_codec_init(struct it66121_ctx *ctx, struct device *dev)
return PTR_ERR_OR_ZERO(ctx->audio.pdev);
}
static int it66121_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static const char * const it66121_supplies[] = {
"vcn33", "vcn18", "vrf12"
};
static int it66121_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
u32 revision_id, vendor_ids[2] = { 0 }, device_ids[2] = { 0 };
struct device_node *ep;
int ret;
@ -1536,6 +1524,7 @@ static int it66121_probe(struct i2c_client *client,
ctx->dev = dev;
ctx->client = client;
ctx->info = (const struct it66121_chip_info *) id->driver_data;
of_property_read_u32(ep, "bus-width", &ctx->bus_width);
of_node_put(ep);
@ -1565,26 +1554,18 @@ static int it66121_probe(struct i2c_client *client,
i2c_set_clientdata(client, ctx);
mutex_init(&ctx->lock);
ctx->supplies[0].supply = "vcn33";
ctx->supplies[1].supply = "vcn18";
ctx->supplies[2].supply = "vrf12";
ret = devm_regulator_bulk_get(ctx->dev, 3, ctx->supplies);
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(it66121_supplies),
it66121_supplies);
if (ret) {
dev_err(ctx->dev, "regulator_bulk failed\n");
dev_err(dev, "Failed to enable power supplies\n");
return ret;
}
ret = ite66121_power_on(ctx);
if (ret)
return ret;
it66121_hw_reset(ctx);
ctx->regmap = devm_regmap_init_i2c(client, &it66121_regmap_config);
if (IS_ERR(ctx->regmap)) {
ite66121_power_off(ctx);
if (IS_ERR(ctx->regmap))
return PTR_ERR(ctx->regmap);
}
regmap_read(ctx->regmap, IT66121_VENDOR_ID0_REG, &vendor_ids[0]);
regmap_read(ctx->regmap, IT66121_VENDOR_ID1_REG, &vendor_ids[1]);
@ -1595,9 +1576,8 @@ static int it66121_probe(struct i2c_client *client,
revision_id = FIELD_GET(IT66121_REVISION_MASK, device_ids[1]);
device_ids[1] &= IT66121_DEVICE_ID1_MASK;
if (vendor_ids[0] != IT66121_VENDOR_ID0 || vendor_ids[1] != IT66121_VENDOR_ID1 ||
device_ids[0] != IT66121_DEVICE_ID0 || device_ids[1] != IT66121_DEVICE_ID1) {
ite66121_power_off(ctx);
if ((vendor_ids[1] << 8 | vendor_ids[0]) != ctx->info->vid ||
(device_ids[1] << 8 | device_ids[0]) != ctx->info->pid) {
return -ENODEV;
}
@ -1610,7 +1590,6 @@ static int it66121_probe(struct i2c_client *client,
IRQF_ONESHOT, dev_name(dev), ctx);
if (ret < 0) {
dev_err(dev, "Failed to request irq %d:%d\n", client->irq, ret);
ite66121_power_off(ctx);
return ret;
}
@ -1627,19 +1606,32 @@ static void it66121_remove(struct i2c_client *client)
{
struct it66121_ctx *ctx = i2c_get_clientdata(client);
ite66121_power_off(ctx);
drm_bridge_remove(&ctx->bridge);
mutex_destroy(&ctx->lock);
}
static const struct of_device_id it66121_dt_match[] = {
{ .compatible = "ite,it66121" },
{ .compatible = "ite,it6610" },
{ }
};
MODULE_DEVICE_TABLE(of, it66121_dt_match);
static const struct it66121_chip_info it66121_chip_info = {
.id = ID_IT66121,
.vid = 0x4954,
.pid = 0x0612,
};
static const struct it66121_chip_info it6610_chip_info = {
.id = ID_IT6610,
.vid = 0xca00,
.pid = 0x0611,
};
static const struct i2c_device_id it66121_id[] = {
{ "it66121", 0 },
{ "it66121", (kernel_ulong_t) &it66121_chip_info },
{ "it6610", (kernel_ulong_t) &it6610_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, it66121_id);
@ -1649,7 +1641,7 @@ static struct i2c_driver it66121_driver = {
.name = "it66121",
.of_match_table = it66121_dt_match,
},
.probe = it66121_probe,
.probe_new = it66121_probe,
.remove = it66121_remove,
.id_table = it66121_id,
};

View File

@ -517,14 +517,27 @@ static int lt8912_attach_dsi(struct lt8912 *lt)
return 0;
}
static void lt8912_bridge_hpd_cb(void *data, enum drm_connector_status status)
{
struct lt8912 *lt = data;
if (lt->bridge.dev)
drm_helper_hpd_irq_event(lt->bridge.dev);
}
static int lt8912_bridge_connector_init(struct drm_bridge *bridge)
{
int ret;
struct lt8912 *lt = bridge_to_lt8912(bridge);
struct drm_connector *connector = &lt->connector;
connector->polled = DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT;
if (lt->hdmi_port->ops & DRM_BRIDGE_OP_HPD) {
drm_bridge_hpd_enable(lt->hdmi_port, lt8912_bridge_hpd_cb, lt);
connector->polled = DRM_CONNECTOR_POLL_HPD;
} else {
connector->polled = DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT;
}
ret = drm_connector_init(bridge->dev, connector,
&lt8912_connector_funcs,
@ -578,6 +591,10 @@ static void lt8912_bridge_detach(struct drm_bridge *bridge)
if (lt->is_attached) {
lt8912_hard_power_off(lt);
if (lt->hdmi_port->ops & DRM_BRIDGE_OP_HPD)
drm_bridge_hpd_disable(lt->hdmi_port);
drm_connector_unregister(&lt->connector);
drm_connector_cleanup(&lt->connector);
}
@ -685,8 +702,7 @@ static int lt8912_put_dt(struct lt8912 *lt)
return 0;
}
static int lt8912_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int lt8912_probe(struct i2c_client *client)
{
static struct lt8912 *lt;
int ret = 0;
@ -758,7 +774,7 @@ static struct i2c_driver lt8912_i2c_driver = {
.name = "lt8912",
.of_match_table = lt8912_dt_match,
},
.probe = lt8912_probe,
.probe_new = lt8912_probe,
.remove = lt8912_remove,
.id_table = lt8912_id,
};

View File

@ -720,8 +720,7 @@ static int lt9211_host_attach(struct lt9211 *ctx)
return 0;
}
static int lt9211_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int lt9211_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct lt9211 *ctx;
@ -786,7 +785,7 @@ static const struct of_device_id lt9211_match_table[] = {
MODULE_DEVICE_TABLE(of, lt9211_match_table);
static struct i2c_driver lt9211_driver = {
.probe = lt9211_probe,
.probe_new = lt9211_probe,
.remove = lt9211_remove,
.id_table = lt9211_id,
.driver = {

View File

@ -259,6 +259,7 @@ static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode
{ 0x8126, 0x55 },
{ 0x8127, 0x66 },
{ 0x8128, 0x88 },
{ 0x812a, 0x20 },
};
regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));
@ -1108,8 +1109,7 @@ static void lt9611_audio_exit(struct lt9611 *lt9611)
}
}
static int lt9611_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int lt9611_probe(struct i2c_client *client)
{
struct lt9611 *lt9611;
struct device *dev = &client->dev;
@ -1248,7 +1248,7 @@ static struct i2c_driver lt9611_driver = {
.name = "lt9611",
.of_match_table = lt9611_match_table,
},
.probe = lt9611_probe,
.probe_new = lt9611_probe,
.remove = lt9611_remove,
.id_table = lt9611_id,
};

View File

@ -844,8 +844,7 @@ static const struct attribute_group *lt9611uxc_attr_groups[] = {
NULL,
};
static int lt9611uxc_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int lt9611uxc_probe(struct i2c_client *client)
{
struct lt9611uxc *lt9611uxc;
struct device *dev = &client->dev;
@ -1012,7 +1011,7 @@ static struct i2c_driver lt9611uxc_driver = {
.of_match_table = lt9611uxc_match_table,
.dev_groups = lt9611uxc_attr_groups,
},
.probe = lt9611uxc_probe,
.probe_new = lt9611uxc_probe,
.remove = lt9611uxc_remove,
.id_table = lt9611uxc_id,
};

View File

@ -336,8 +336,7 @@ static int ge_b850v3_register(void)
"ge-b850v3-lvds-dp", ge_b850v3_lvds_ptr);
}
static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c,
const struct i2c_device_id *id)
static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c)
{
struct device *dev = &stdp4028_i2c->dev;
int ret;
@ -376,7 +375,7 @@ MODULE_DEVICE_TABLE(of, stdp4028_ge_b850v3_fw_match);
static struct i2c_driver stdp4028_ge_b850v3_fw_driver = {
.id_table = stdp4028_ge_b850v3_fw_i2c_table,
.probe = stdp4028_ge_b850v3_fw_probe,
.probe_new = stdp4028_ge_b850v3_fw_probe,
.remove = stdp4028_ge_b850v3_fw_remove,
.driver = {
.name = "stdp4028-ge-b850v3-fw",
@ -384,8 +383,7 @@ static struct i2c_driver stdp4028_ge_b850v3_fw_driver = {
},
};
static int stdp2690_ge_b850v3_fw_probe(struct i2c_client *stdp2690_i2c,
const struct i2c_device_id *id)
static int stdp2690_ge_b850v3_fw_probe(struct i2c_client *stdp2690_i2c)
{
struct device *dev = &stdp2690_i2c->dev;
int ret;
@ -424,7 +422,7 @@ MODULE_DEVICE_TABLE(of, stdp2690_ge_b850v3_fw_match);
static struct i2c_driver stdp2690_ge_b850v3_fw_driver = {
.id_table = stdp2690_ge_b850v3_fw_i2c_table,
.probe = stdp2690_ge_b850v3_fw_probe,
.probe_new = stdp2690_ge_b850v3_fw_probe,
.remove = stdp2690_ge_b850v3_fw_remove,
.driver = {
.name = "stdp2690-ge-b850v3-fw",
@ -440,7 +438,11 @@ static int __init stdpxxxx_ge_b850v3_init(void)
if (ret)
return ret;
return i2c_add_driver(&stdp2690_ge_b850v3_fw_driver);
ret = i2c_add_driver(&stdp2690_ge_b850v3_fw_driver);
if (ret)
i2c_del_driver(&stdp4028_ge_b850v3_fw_driver);
return ret;
}
module_init(stdpxxxx_ge_b850v3_init);

View File

@ -257,8 +257,7 @@ static const struct drm_bridge_funcs ptn3460_bridge_funcs = {
.get_edid = ptn3460_get_edid,
};
static int ptn3460_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int ptn3460_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct ptn3460_bridge *ptn_bridge;
@ -336,7 +335,7 @@ MODULE_DEVICE_TABLE(of, ptn3460_match);
static struct i2c_driver ptn3460_driver = {
.id_table = ptn3460_i2c_table,
.probe = ptn3460_probe,
.probe_new = ptn3460_probe,
.remove = ptn3460_remove,
.driver = {
.name = "nxp,ptn3460",

View File

@ -364,6 +364,8 @@ struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
devres_free(ptr);
}
bridge->pre_enable_prev_first = panel->prepare_prev_first;
return bridge;
}
EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
@ -402,6 +404,8 @@ struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,
if (ret)
return ERR_PTR(ret);
bridge->pre_enable_prev_first = panel->prepare_prev_first;
return bridge;
}
EXPORT_SYMBOL(drmm_panel_bridge_add);

View File

@ -442,9 +442,9 @@ static const struct of_device_id ps8622_devices[] = {
};
MODULE_DEVICE_TABLE(of, ps8622_devices);
static int ps8622_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int ps8622_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct ps8622_bridge *ps8622;
struct drm_bridge *panel_bridge;
@ -538,7 +538,7 @@ MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table);
static struct i2c_driver ps8622_driver = {
.id_table = ps8622_i2c_table,
.probe = ps8622_probe,
.probe_new = ps8622_probe,
.remove = ps8622_remove,
.driver = {
.name = "ps8622",

View File

@ -15,6 +15,7 @@
#include <drm/display/drm_dp_aux_bus.h>
#include <drm/display/drm_dp_helper.h>
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_edid.h>
#include <drm/drm_mipi_dsi.h>
@ -442,7 +443,8 @@ static const struct dev_pm_ops ps8640_pm_ops = {
pm_runtime_force_resume)
};
static void ps8640_pre_enable(struct drm_bridge *bridge)
static void ps8640_atomic_pre_enable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL];
@ -476,7 +478,8 @@ static void ps8640_pre_enable(struct drm_bridge *bridge)
ps_bridge->pre_enabled = true;
}
static void ps8640_post_disable(struct drm_bridge *bridge)
static void ps8640_atomic_post_disable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
@ -554,7 +557,7 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
* EDID, for this chip, we need to do a full poweron, otherwise it will
* fail.
*/
drm_bridge_chain_pre_enable(bridge);
drm_atomic_bridge_chain_pre_enable(bridge, connector->state->state);
edid = drm_get_edid(connector,
ps_bridge->page[PAGE0_DP_CNTL]->adapter);
@ -564,7 +567,7 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
* before, return the chip to its original power state.
*/
if (poweroff)
drm_bridge_chain_post_disable(bridge);
drm_atomic_bridge_chain_post_disable(bridge, connector->state->state);
return edid;
}
@ -579,8 +582,11 @@ static const struct drm_bridge_funcs ps8640_bridge_funcs = {
.attach = ps8640_bridge_attach,
.detach = ps8640_bridge_detach,
.get_edid = ps8640_bridge_get_edid,
.post_disable = ps8640_post_disable,
.pre_enable = ps8640_pre_enable,
.atomic_post_disable = ps8640_atomic_post_disable,
.atomic_pre_enable = ps8640_atomic_pre_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,
};
static int ps8640_bridge_get_dsi_resources(struct device *dev, struct ps8640 *ps_bridge)
@ -734,13 +740,13 @@ static int ps8640_probe(struct i2c_client *client)
pm_runtime_enable(dev);
/*
* Powering on ps8640 takes ~300ms. To avoid wasting time on power
* cycling ps8640 too often, set autosuspend_delay to 1000ms to ensure
* cycling ps8640 too often, set autosuspend_delay to 2000ms to ensure
* the bridge wouldn't suspend in between each _aux_transfer_msg() call
* during EDID read (~20ms in my experiment) and in between the last
* _aux_transfer_msg() call during EDID read and the _pre_enable() call
* (~100ms in my experiment).
*/
pm_runtime_set_autosuspend_delay(dev, 1000);
pm_runtime_set_autosuspend_delay(dev, 2000);
pm_runtime_use_autosuspend(dev);
pm_suspend_ignore_children(dev, true);
ret = devm_add_action_or_reset(dev, ps8640_runtime_disable, dev);

View File

@ -171,7 +171,6 @@ struct sii902x {
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
@ -1066,12 +1065,12 @@ static int sii902x_init(struct sii902x *sii902x)
return i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0);
}
static int sii902x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int sii902x_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct device_node *endpoint;
struct sii902x *sii902x;
static const char * const supplies[] = {"iovcc", "cvcc12"};
int ret;
ret = i2c_check_functionality(client->adapter,
@ -1122,27 +1121,11 @@ static int sii902x_probe(struct i2c_client *client,
mutex_init(&sii902x->mutex);
sii902x->supplies[0].supply = "iovcc";
sii902x->supplies[1].supply = "cvcc12";
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(sii902x->supplies),
sii902x->supplies);
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(supplies), supplies);
if (ret < 0)
return ret;
return dev_err_probe(dev, ret, "Failed to enable supplies");
ret = regulator_bulk_enable(ARRAY_SIZE(sii902x->supplies),
sii902x->supplies);
if (ret < 0) {
dev_err_probe(dev, ret, "Failed to enable supplies");
return ret;
}
ret = sii902x_init(sii902x);
if (ret < 0) {
regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies),
sii902x->supplies);
}
return ret;
return sii902x_init(sii902x);
}
static void sii902x_remove(struct i2c_client *client)
@ -1152,8 +1135,6 @@ static void sii902x_remove(struct i2c_client *client)
i2c_mux_del_adapters(sii902x->i2cmux);
drm_bridge_remove(&sii902x->bridge);
regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies),
sii902x->supplies);
}
static const struct of_device_id sii902x_dt_ids[] = {
@ -1169,7 +1150,7 @@ static const struct i2c_device_id sii902x_i2c_ids[] = {
MODULE_DEVICE_TABLE(i2c, sii902x_i2c_ids);
static struct i2c_driver sii902x_driver = {
.probe = sii902x_probe,
.probe_new = sii902x_probe,
.remove = sii902x_remove,
.driver = {
.name = "sii902x",

View File

@ -886,8 +886,7 @@ static const struct drm_bridge_funcs sii9234_bridge_funcs = {
.mode_valid = sii9234_mode_valid,
};
static int sii9234_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int sii9234_probe(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
struct sii9234 *ctx;
@ -961,7 +960,7 @@ static struct i2c_driver sii9234_driver = {
.name = "sii9234",
.of_match_table = sii9234_dt_match,
},
.probe = sii9234_probe,
.probe_new = sii9234_probe,
.remove = sii9234_remove,
.id_table = sii9234_id,
};

View File

@ -2284,8 +2284,7 @@ static const struct drm_bridge_funcs sii8620_bridge_funcs = {
.mode_valid = sii8620_mode_valid,
};
static int sii8620_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int sii8620_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct sii8620 *ctx;
@ -2379,7 +2378,7 @@ static struct i2c_driver sii8620_driver = {
.name = "sii8620",
.of_match_table = of_match_ptr(sii8620_dt_match),
},
.probe = sii8620_probe,
.probe_new = sii8620_probe,
.remove = sii8620_remove,
.id_table = sii8620_id,
};

View File

@ -2029,7 +2029,7 @@ static void tc_clk_disable(void *data)
clk_disable_unprepare(refclk);
}
static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
static int tc_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct tc_data *tc;
@ -2209,7 +2209,7 @@ static struct i2c_driver tc358767_driver = {
.of_match_table = tc358767_of_ids,
},
.id_table = tc358767_i2c_ids,
.probe = tc_probe,
.probe_new = tc_probe,
.remove = tc_remove,
};
module_i2c_driver(tc358767_driver);

View File

@ -1018,8 +1018,7 @@ static int tc358768_get_regulators(struct tc358768_priv *priv)
return ret;
}
static int tc358768_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int tc358768_i2c_probe(struct i2c_client *client)
{
struct tc358768_priv *priv;
struct device *dev = &client->dev;
@ -1085,7 +1084,7 @@ static struct i2c_driver tc358768_driver = {
.of_match_table = tc358768_of_ids,
},
.id_table = tc358768_i2c_ids,
.probe = tc358768_i2c_probe,
.probe_new = tc358768_i2c_probe,
.remove = tc358768_i2c_remove,
};
module_i2c_driver(tc358768_driver);

View File

@ -637,7 +637,7 @@ static int tc_attach_host(struct tc_data *tc)
return 0;
}
static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
static int tc_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct tc_data *tc;
@ -729,7 +729,7 @@ static struct i2c_driver tc358775_driver = {
.of_match_table = tc358775_of_ids,
},
.id_table = tc358775_i2c_ids,
.probe = tc_probe,
.probe_new = tc_probe,
.remove = tc_remove,
};
module_i2c_driver(tc358775_driver);

View File

@ -346,7 +346,7 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge,
/* Deassert reset */
gpiod_set_value_cansleep(ctx->enable_gpio, 1);
usleep_range(1000, 1100);
usleep_range(10000, 11000);
/* Get the LVDS format from the bridge state. */
bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
@ -653,9 +653,9 @@ static int sn65dsi83_host_attach(struct sn65dsi83 *ctx)
return 0;
}
static int sn65dsi83_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int sn65dsi83_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
enum sn65dsi83_model model;
struct sn65dsi83 *ctx;
@ -730,7 +730,7 @@ static const struct of_device_id sn65dsi83_match_table[] = {
MODULE_DEVICE_TABLE(of, sn65dsi83_match_table);
static struct i2c_driver sn65dsi83_driver = {
.probe = sn65dsi83_probe,
.probe_new = sn65dsi83_probe,
.remove = sn65dsi83_remove,
.id_table = sn65dsi83_id,
.driver = {

View File

@ -1852,8 +1852,7 @@ static int ti_sn65dsi86_parse_regulators(struct ti_sn65dsi86 *pdata)
pdata->supplies);
}
static int ti_sn65dsi86_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int ti_sn65dsi86_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct ti_sn65dsi86 *pdata;
@ -1952,7 +1951,7 @@ static struct i2c_driver ti_sn65dsi86_driver = {
.of_match_table = ti_sn65dsi86_match_table,
.pm = &ti_sn65dsi86_pm_ops,
},
.probe = ti_sn65dsi86_probe,
.probe_new = ti_sn65dsi86_probe,
.id_table = ti_sn65dsi86_id,
};

View File

@ -379,8 +379,7 @@ static struct platform_driver tfp410_platform_driver = {
#if IS_ENABLED(CONFIG_I2C)
/* There is currently no i2c functionality. */
static int tfp410_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int tfp410_i2c_probe(struct i2c_client *client)
{
int reg;
@ -411,7 +410,7 @@ static struct i2c_driver tfp410_i2c_driver = {
.of_match_table = of_match_ptr(tfp410_match),
},
.id_table = tfp410_i2c_ids,
.probe = tfp410_i2c_probe,
.probe_new = tfp410_i2c_probe,
.remove = tfp410_i2c_remove,
};
#endif /* IS_ENABLED(CONFIG_I2C) */

View File

@ -3309,8 +3309,13 @@ int drm_dp_add_payload_part1(struct drm_dp_mst_topology_mgr *mgr,
int ret;
port = drm_dp_mst_topology_get_port_validated(mgr, payload->port);
if (!port)
if (!port) {
drm_dbg_kms(mgr->dev,
"VCPI %d for port %p not in topology, not creating a payload\n",
payload->vcpi, payload->port);
payload->vc_start_slot = -1;
return 0;
}
if (mgr->payload_count == 0)
mgr->next_start_slot = mst_state->start_slot;
@ -3641,6 +3646,9 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, 0);
ret = 0;
mgr->payload_id_table_cleared = false;
memset(&mgr->down_rep_recv, 0, sizeof(mgr->down_rep_recv));
memset(&mgr->up_req_recv, 0, sizeof(mgr->up_req_recv));
}
out_unlock:
@ -3853,7 +3861,7 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
struct drm_dp_sideband_msg_rx *msg = &mgr->down_rep_recv;
if (!drm_dp_get_one_sb_msg(mgr, false, &mstb))
goto out;
goto out_clear_reply;
/* Multi-packet message transmission, don't clear the reply */
if (!msg->have_eomt)

View File

@ -880,7 +880,7 @@ EXPORT_SYMBOL(drm_atomic_get_private_obj_state);
* or NULL if the private_obj is not part of the global atomic state.
*/
struct drm_private_state *
drm_atomic_get_old_private_obj_state(struct drm_atomic_state *state,
drm_atomic_get_old_private_obj_state(const struct drm_atomic_state *state,
struct drm_private_obj *obj)
{
int i;
@ -902,7 +902,7 @@ EXPORT_SYMBOL(drm_atomic_get_old_private_obj_state);
* or NULL if the private_obj is not part of the global atomic state.
*/
struct drm_private_state *
drm_atomic_get_new_private_obj_state(struct drm_atomic_state *state,
drm_atomic_get_new_private_obj_state(const struct drm_atomic_state *state,
struct drm_private_obj *obj)
{
int i;
@ -934,7 +934,7 @@ EXPORT_SYMBOL(drm_atomic_get_new_private_obj_state);
* not connected.
*/
struct drm_connector *
drm_atomic_get_old_connector_for_encoder(struct drm_atomic_state *state,
drm_atomic_get_old_connector_for_encoder(const struct drm_atomic_state *state,
struct drm_encoder *encoder)
{
struct drm_connector_state *conn_state;
@ -968,7 +968,7 @@ EXPORT_SYMBOL(drm_atomic_get_old_connector_for_encoder);
* not connected.
*/
struct drm_connector *
drm_atomic_get_new_connector_for_encoder(struct drm_atomic_state *state,
drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
struct drm_encoder *encoder)
{
struct drm_connector_state *conn_state;
@ -1117,7 +1117,7 @@ EXPORT_SYMBOL(drm_atomic_get_bridge_state);
* the bridge is not part of the global atomic state.
*/
struct drm_bridge_state *
drm_atomic_get_old_bridge_state(struct drm_atomic_state *state,
drm_atomic_get_old_bridge_state(const struct drm_atomic_state *state,
struct drm_bridge *bridge)
{
struct drm_private_state *obj_state;
@ -1139,7 +1139,7 @@ EXPORT_SYMBOL(drm_atomic_get_old_bridge_state);
* the bridge is not part of the global atomic state.
*/
struct drm_bridge_state *
drm_atomic_get_new_bridge_state(struct drm_atomic_state *state,
drm_atomic_get_new_bridge_state(const struct drm_atomic_state *state,
struct drm_bridge *bridge)
{
struct drm_private_state *obj_state;
@ -1756,8 +1756,8 @@ EXPORT_SYMBOL(drm_state_dump);
#ifdef CONFIG_DEBUG_FS
static int drm_state_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_debugfs_entry *entry = m->private;
struct drm_device *dev = entry->dev;
struct drm_printer p = drm_seq_file_printer(m);
__drm_state_dump(dev, &p, true);
@ -1766,14 +1766,13 @@ static int drm_state_info(struct seq_file *m, void *data)
}
/* any use in debugfs files to dump individual planes/crtc/etc? */
static const struct drm_info_list drm_atomic_debugfs_list[] = {
static const struct drm_debugfs_info drm_atomic_debugfs_list[] = {
{"state", drm_state_info, 0},
};
void drm_atomic_debugfs_init(struct drm_minor *minor)
{
drm_debugfs_create_files(drm_atomic_debugfs_list,
ARRAY_SIZE(drm_atomic_debugfs_list),
minor->debugfs_root, minor);
drm_debugfs_add_files(minor->dev, drm_atomic_debugfs_list,
ARRAY_SIZE(drm_atomic_debugfs_list));
}
#endif

View File

@ -481,6 +481,130 @@ void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector *connecto
}
EXPORT_SYMBOL(drm_atomic_helper_connector_tv_margins_reset);
/**
* drm_atomic_helper_connector_tv_reset - Resets Analog TV connector properties
* @connector: DRM connector
*
* Resets the analog TV properties attached to a connector
*/
void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
struct drm_connector_state *state = connector->state;
struct drm_property *prop;
uint64_t val;
prop = dev->mode_config.tv_mode_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.mode = val;
if (cmdline->tv_mode_specified)
state->tv.mode = cmdline->tv_mode;
prop = dev->mode_config.tv_select_subconnector_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.select_subconnector = val;
prop = dev->mode_config.tv_subconnector_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.subconnector = val;
prop = dev->mode_config.tv_brightness_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.brightness = val;
prop = dev->mode_config.tv_contrast_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.contrast = val;
prop = dev->mode_config.tv_flicker_reduction_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.flicker_reduction = val;
prop = dev->mode_config.tv_overscan_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.overscan = val;
prop = dev->mode_config.tv_saturation_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.saturation = val;
prop = dev->mode_config.tv_hue_property;
if (prop)
if (!drm_object_property_get_default_value(&connector->base,
prop, &val))
state->tv.hue = val;
drm_atomic_helper_connector_tv_margins_reset(connector);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
/**
* @drm_atomic_helper_connector_tv_check: Validate an analog TV connector state
* @connector: DRM Connector
* @state: the DRM State object
*
* Checks the state object to see if the requested state is valid for an
* analog TV connector.
*
* Returns:
* Zero for success, a negative error code on error.
*/
int drm_atomic_helper_connector_tv_check(struct drm_connector *connector,
struct drm_atomic_state *state)
{
struct drm_connector_state *old_conn_state =
drm_atomic_get_old_connector_state(state, connector);
struct drm_connector_state *new_conn_state =
drm_atomic_get_new_connector_state(state, connector);
struct drm_crtc_state *crtc_state;
struct drm_crtc *crtc;
crtc = new_conn_state->crtc;
if (!crtc)
return 0;
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
if (!crtc_state)
return -EINVAL;
if (old_conn_state->tv.mode != new_conn_state->tv.mode)
crtc_state->mode_changed = true;
if (old_conn_state->tv.margins.left != new_conn_state->tv.margins.left ||
old_conn_state->tv.margins.right != new_conn_state->tv.margins.right ||
old_conn_state->tv.margins.top != new_conn_state->tv.margins.top ||
old_conn_state->tv.margins.bottom != new_conn_state->tv.margins.bottom ||
old_conn_state->tv.mode != new_conn_state->tv.mode ||
old_conn_state->tv.brightness != new_conn_state->tv.brightness ||
old_conn_state->tv.contrast != new_conn_state->tv.contrast ||
old_conn_state->tv.flicker_reduction != new_conn_state->tv.flicker_reduction ||
old_conn_state->tv.overscan != new_conn_state->tv.overscan ||
old_conn_state->tv.saturation != new_conn_state->tv.saturation ||
old_conn_state->tv.hue != new_conn_state->tv.hue)
crtc_state->connectors_changed = true;
return 0;
}
EXPORT_SYMBOL(drm_atomic_helper_connector_tv_check);
/**
* __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
* @connector: connector object

View File

@ -698,6 +698,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
state->tv.margins.top = val;
} else if (property == config->tv_bottom_margin_property) {
state->tv.margins.bottom = val;
} else if (property == config->legacy_tv_mode_property) {
state->tv.legacy_mode = val;
} else if (property == config->tv_mode_property) {
state->tv.mode = val;
} else if (property == config->tv_brightness_property) {
@ -808,6 +810,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
*val = state->tv.margins.top;
} else if (property == config->tv_bottom_margin_property) {
*val = state->tv.margins.bottom;
} else if (property == config->legacy_tv_mode_property) {
*val = state->tv.legacy_mode;
} else if (property == config->tv_mode_property) {
*val = state->tv.mode;
} else if (property == config->tv_brightness_property) {

View File

@ -153,6 +153,45 @@
* situation when probing.
*/
/**
* DOC: dsi bridge operations
*
* DSI host interfaces are expected to be implemented as bridges rather than
* encoders, however there are a few aspects of their operation that need to
* be defined in order to provide a consistent interface.
*
* A DSI host should keep the PHY powered down until the pre_enable operation is
* called. All lanes are in an undefined idle state up to this point, and it
* must not be assumed that it is LP-11.
* pre_enable should initialise the PHY, set the data lanes to LP-11, and the
* clock lane to either LP-11 or HS depending on the mode_flag
* %MIPI_DSI_CLOCK_NON_CONTINUOUS.
*
* Ordinarily the downstream bridge DSI peripheral pre_enable will have been
* called before the DSI host. If the DSI peripheral requires LP-11 and/or
* the clock lane to be in HS mode prior to pre_enable, then it can set the
* &pre_enable_prev_first flag to request the pre_enable (and
* post_disable) order to be altered to enable the DSI host first.
*
* Either the CRTC being enabled, or the DSI host enable operation should switch
* the host to actively transmitting video on the data lanes.
*
* The reverse also applies. The DSI host disable operation or stopping the CRTC
* should stop transmitting video, and the data lanes should return to the LP-11
* state. The DSI host &post_disable operation should disable the PHY.
* If the &pre_enable_prev_first flag is set, then the DSI peripheral's
* bridge &post_disable will be called before the DSI host's post_disable.
*
* Whilst it is valid to call &host_transfer prior to pre_enable or after
* post_disable, the exact state of the lanes is undefined at this point. The
* DSI host should initialise the interface, transmit the data, and then disable
* the interface again.
*
* Ultra Low Power State (ULPS) is not explicitly supported by DRM. If
* implemented, it therefore needs to be handled entirely within the DSI Host
* driver.
*/
static DEFINE_MUTEX(bridge_lock);
static LIST_HEAD(bridge_list);
@ -509,61 +548,6 @@ drm_bridge_chain_mode_valid(struct drm_bridge *bridge,
}
EXPORT_SYMBOL(drm_bridge_chain_mode_valid);
/**
* drm_bridge_chain_disable - disables all bridges in the encoder chain
* @bridge: bridge control structure
*
* Calls &drm_bridge_funcs.disable op for all the bridges in the encoder
* chain, starting from the last bridge to the first. These are called before
* calling the encoder's prepare op.
*
* Note: the bridge passed should be the one closest to the encoder
*/
void drm_bridge_chain_disable(struct drm_bridge *bridge)
{
struct drm_encoder *encoder;
struct drm_bridge *iter;
if (!bridge)
return;
encoder = bridge->encoder;
list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
if (iter->funcs->disable)
iter->funcs->disable(iter);
if (iter == bridge)
break;
}
}
EXPORT_SYMBOL(drm_bridge_chain_disable);
/**
* drm_bridge_chain_post_disable - cleans up after disabling all bridges in the
* encoder chain
* @bridge: bridge control structure
*
* Calls &drm_bridge_funcs.post_disable op for all the bridges in the
* encoder chain, starting from the first bridge to the last. These are called
* after completing the encoder's prepare op.
*
* Note: the bridge passed should be the one closest to the encoder
*/
void drm_bridge_chain_post_disable(struct drm_bridge *bridge)
{
struct drm_encoder *encoder;
if (!bridge)
return;
encoder = bridge->encoder;
list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
if (bridge->funcs->post_disable)
bridge->funcs->post_disable(bridge);
}
}
EXPORT_SYMBOL(drm_bridge_chain_post_disable);
/**
* drm_bridge_chain_mode_set - set proposed mode for all bridges in the
* encoder chain
@ -593,61 +577,6 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge,
}
EXPORT_SYMBOL(drm_bridge_chain_mode_set);
/**
* drm_bridge_chain_pre_enable - prepares for enabling all bridges in the
* encoder chain
* @bridge: bridge control structure
*
* Calls &drm_bridge_funcs.pre_enable op for all the bridges in the encoder
* chain, starting from the last bridge to the first. These are called
* before calling the encoder's commit op.
*
* Note: the bridge passed should be the one closest to the encoder
*/
void drm_bridge_chain_pre_enable(struct drm_bridge *bridge)
{
struct drm_encoder *encoder;
struct drm_bridge *iter;
if (!bridge)
return;
encoder = bridge->encoder;
list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
if (iter->funcs->pre_enable)
iter->funcs->pre_enable(iter);
if (iter == bridge)
break;
}
}
EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
/**
* drm_bridge_chain_enable - enables all bridges in the encoder chain
* @bridge: bridge control structure
*
* Calls &drm_bridge_funcs.enable op for all the bridges in the encoder
* chain, starting from the first bridge to the last. These are called
* after completing the encoder's commit op.
*
* Note that the bridge passed should be the one closest to the encoder
*/
void drm_bridge_chain_enable(struct drm_bridge *bridge)
{
struct drm_encoder *encoder;
if (!bridge)
return;
encoder = bridge->encoder;
list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
if (bridge->funcs->enable)
bridge->funcs->enable(bridge);
}
}
EXPORT_SYMBOL(drm_bridge_chain_enable);
/**
* drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain
* @bridge: bridge control structure
@ -691,6 +620,25 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
}
EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
static void drm_atomic_bridge_call_post_disable(struct drm_bridge *bridge,
struct drm_atomic_state *old_state)
{
if (old_state && bridge->funcs->atomic_post_disable) {
struct drm_bridge_state *old_bridge_state;
old_bridge_state =
drm_atomic_get_old_bridge_state(old_state,
bridge);
if (WARN_ON(!old_bridge_state))
return;
bridge->funcs->atomic_post_disable(bridge,
old_bridge_state);
} else if (bridge->funcs->post_disable) {
bridge->funcs->post_disable(bridge);
}
}
/**
* drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges
* in the encoder chain
@ -702,36 +650,86 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
* starting from the first bridge to the last. These are called after completing
* &drm_encoder_helper_funcs.atomic_disable
*
* If a bridge sets @pre_enable_prev_first, then the @post_disable for that
* bridge will be called before the previous one to reverse the @pre_enable
* calling direction.
*
* Note: the bridge passed should be the one closest to the encoder
*/
void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
struct drm_atomic_state *old_state)
{
struct drm_encoder *encoder;
struct drm_bridge *next, *limit;
if (!bridge)
return;
encoder = bridge->encoder;
list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
if (bridge->funcs->atomic_post_disable) {
struct drm_bridge_state *old_bridge_state;
limit = NULL;
old_bridge_state =
drm_atomic_get_old_bridge_state(old_state,
bridge);
if (WARN_ON(!old_bridge_state))
return;
if (!list_is_last(&bridge->chain_node, &encoder->bridge_chain)) {
next = list_next_entry(bridge, chain_node);
bridge->funcs->atomic_post_disable(bridge,
old_bridge_state);
} else if (bridge->funcs->post_disable) {
bridge->funcs->post_disable(bridge);
if (next->pre_enable_prev_first) {
/* next bridge had requested that prev
* was enabled first, so disabled last
*/
limit = next;
/* Find the next bridge that has NOT requested
* prev to be enabled first / disabled last
*/
list_for_each_entry_from(next, &encoder->bridge_chain,
chain_node) {
if (next->pre_enable_prev_first) {
next = list_prev_entry(next, chain_node);
limit = next;
break;
}
}
/* Call these bridges in reverse order */
list_for_each_entry_from_reverse(next, &encoder->bridge_chain,
chain_node) {
if (next == bridge)
break;
drm_atomic_bridge_call_post_disable(next,
old_state);
}
}
}
drm_atomic_bridge_call_post_disable(bridge, old_state);
if (limit)
/* Jump all bridges that we have already post_disabled */
bridge = limit;
}
}
EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
static void drm_atomic_bridge_call_pre_enable(struct drm_bridge *bridge,
struct drm_atomic_state *old_state)
{
if (old_state && bridge->funcs->atomic_pre_enable) {
struct drm_bridge_state *old_bridge_state;
old_bridge_state =
drm_atomic_get_old_bridge_state(old_state,
bridge);
if (WARN_ON(!old_bridge_state))
return;
bridge->funcs->atomic_pre_enable(bridge, old_bridge_state);
} else if (bridge->funcs->pre_enable) {
bridge->funcs->pre_enable(bridge);
}
}
/**
* drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in
* the encoder chain
@ -743,33 +741,61 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
* starting from the last bridge to the first. These are called before calling
* &drm_encoder_helper_funcs.atomic_enable
*
* If a bridge sets @pre_enable_prev_first, then the pre_enable for the
* prev bridge will be called before pre_enable of this bridge.
*
* Note: the bridge passed should be the one closest to the encoder
*/
void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
struct drm_atomic_state *old_state)
{
struct drm_encoder *encoder;
struct drm_bridge *iter;
struct drm_bridge *iter, *next, *limit;
if (!bridge)
return;
encoder = bridge->encoder;
list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
if (iter->funcs->atomic_pre_enable) {
struct drm_bridge_state *old_bridge_state;
if (iter->pre_enable_prev_first) {
next = iter;
limit = bridge;
list_for_each_entry_from_reverse(next,
&encoder->bridge_chain,
chain_node) {
if (next == bridge)
break;
old_bridge_state =
drm_atomic_get_old_bridge_state(old_state,
iter);
if (WARN_ON(!old_bridge_state))
return;
if (!next->pre_enable_prev_first) {
/* Found first bridge that does NOT
* request prev to be enabled first
*/
limit = list_prev_entry(next, chain_node);
break;
}
}
iter->funcs->atomic_pre_enable(iter, old_bridge_state);
} else if (iter->funcs->pre_enable) {
iter->funcs->pre_enable(iter);
list_for_each_entry_from(next, &encoder->bridge_chain, chain_node) {
/* Call requested prev bridge pre_enable
* in order.
*/
if (next == iter)
/* At the first bridge to request prev
* bridges called first.
*/
break;
drm_atomic_bridge_call_pre_enable(next, old_state);
}
}
drm_atomic_bridge_call_pre_enable(iter, old_state);
if (iter->pre_enable_prev_first)
/* Jump all bridges that we have already pre_enabled */
iter = limit;
if (iter == bridge)
break;
}

View File

@ -480,8 +480,8 @@ EXPORT_SYMBOL(drm_client_framebuffer_flush);
#ifdef CONFIG_DEBUG_FS
static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data)
{
struct drm_info_node *node = m->private;
struct drm_device *dev = node->minor->dev;
struct drm_debugfs_entry *entry = m->private;
struct drm_device *dev = entry->dev;
struct drm_printer p = drm_seq_file_printer(m);
struct drm_client_dev *client;
@ -493,14 +493,13 @@ static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data)
return 0;
}
static const struct drm_info_list drm_client_debugfs_list[] = {
static const struct drm_debugfs_info drm_client_debugfs_list[] = {
{ "internal_clients", drm_client_debugfs_internal_clients, 0 },
};
void drm_client_debugfs_init(struct drm_minor *minor)
{
drm_debugfs_create_files(drm_client_debugfs_list,
ARRAY_SIZE(drm_client_debugfs_list),
minor->debugfs_root, minor);
drm_debugfs_add_files(minor->dev, drm_client_debugfs_list,
ARRAY_SIZE(drm_client_debugfs_list));
}
#endif

View File

@ -188,10 +188,6 @@ static struct drm_display_mode *drm_connector_pick_cmdline_mode(struct drm_conne
prefer_non_interlace = !cmdline_mode->interlace;
again:
list_for_each_entry(mode, &connector->modes, head) {
/* Check (optional) mode name first */
if (!strcmp(mode->name, cmdline_mode->name))
return mode;
/* check width/height */
if (mode->hdisplay != cmdline_mode->xres ||
mode->vdisplay != cmdline_mode->yres)

View File

@ -984,6 +984,41 @@ static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = {
DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
drm_dvi_i_subconnector_enum_list)
static const struct drm_prop_enum_list drm_tv_mode_enum_list[] = {
{ DRM_MODE_TV_MODE_NTSC, "NTSC" },
{ DRM_MODE_TV_MODE_NTSC_443, "NTSC-443" },
{ DRM_MODE_TV_MODE_NTSC_J, "NTSC-J" },
{ DRM_MODE_TV_MODE_PAL, "PAL" },
{ DRM_MODE_TV_MODE_PAL_M, "PAL-M" },
{ DRM_MODE_TV_MODE_PAL_N, "PAL-N" },
{ DRM_MODE_TV_MODE_SECAM, "SECAM" },
};
DRM_ENUM_NAME_FN(drm_get_tv_mode_name, drm_tv_mode_enum_list)
/**
* drm_get_tv_mode_from_name - Translates a TV mode name into its enum value
* @name: TV Mode name we want to convert
* @len: Length of @name
*
* Translates @name into an enum drm_connector_tv_mode.
*
* Returns: the enum value on success, a negative errno otherwise.
*/
int drm_get_tv_mode_from_name(const char *name, size_t len)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(drm_tv_mode_enum_list); i++) {
const struct drm_prop_enum_list *item = &drm_tv_mode_enum_list[i];
if (strlen(item->name) == len && !strncmp(item->name, name, len))
return item->type;
}
return -EINVAL;
}
EXPORT_SYMBOL(drm_get_tv_mode_from_name);
static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
@ -1552,6 +1587,71 @@ EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property);
* infoframe values is done through drm_hdmi_avi_infoframe_content_type().
*/
/*
* TODO: Document the properties:
* - left margin
* - right margin
* - top margin
* - bottom margin
* - brightness
* - contrast
* - flicker reduction
* - hue
* - mode
* - overscan
* - saturation
* - select subconnector
* - subconnector
*/
/**
* DOC: Analog TV Connector Properties
*
* TV Mode:
* Indicates the TV Mode used on an analog TV connector. The value
* of this property can be one of the following:
*
* NTSC:
* TV Mode is CCIR System M (aka 525-lines) together with
* the NTSC Color Encoding.
*
* NTSC-443:
*
* TV Mode is CCIR System M (aka 525-lines) together with
* the NTSC Color Encoding, but with a color subcarrier
* frequency of 4.43MHz
*
* NTSC-J:
*
* TV Mode is CCIR System M (aka 525-lines) together with
* the NTSC Color Encoding, but with a black level equal to
* the blanking level.
*
* PAL:
*
* TV Mode is CCIR System B (aka 625-lines) together with
* the PAL Color Encoding.
*
* PAL-M:
*
* TV Mode is CCIR System M (aka 525-lines) together with
* the PAL Color Encoding.
*
* PAL-N:
*
* TV Mode is CCIR System N together with the PAL Color
* Encoding, a color subcarrier frequency of 3.58MHz, the
* SECAM color space, and narrower channels than other PAL
* variants.
*
* SECAM:
*
* TV Mode is CCIR System B (aka 625-lines) together with
* the SECAM Color Encoding.
*
* Drivers can set up this property by calling
* drm_mode_create_tv_properties().
*/
/**
* drm_connector_attach_content_type_property - attach content-type property
* @connector: connector to attach content type property on.
@ -1604,7 +1704,7 @@ EXPORT_SYMBOL(drm_connector_attach_tv_margin_properties);
* Called by a driver's HDMI connector initialization routine, this function
* creates the TV margin properties for a given device. No need to call this
* function for an SDTV connector, it's already called from
* drm_mode_create_tv_properties().
* drm_mode_create_tv_properties_legacy().
*
* Returns:
* 0 on success or a negative error code on failure.
@ -1639,7 +1739,7 @@ int drm_mode_create_tv_margin_properties(struct drm_device *dev)
EXPORT_SYMBOL(drm_mode_create_tv_margin_properties);
/**
* drm_mode_create_tv_properties - create TV specific connector properties
* drm_mode_create_tv_properties_legacy - create TV specific connector properties
* @dev: DRM device
* @num_modes: number of different TV formats (modes) supported
* @modes: array of pointers to strings containing name of each format
@ -1649,12 +1749,16 @@ EXPORT_SYMBOL(drm_mode_create_tv_margin_properties);
* responsible for allocating a list of format names and passing them to
* this routine.
*
* NOTE: This functions registers the deprecated "mode" connector
* property to select the analog TV mode (ie, NTSC, PAL, etc.). New
* drivers must use drm_mode_create_tv_properties() instead.
*
* Returns:
* 0 on success or a negative error code on failure.
*/
int drm_mode_create_tv_properties(struct drm_device *dev,
unsigned int num_modes,
const char * const modes[])
int drm_mode_create_tv_properties_legacy(struct drm_device *dev,
unsigned int num_modes,
const char * const modes[])
{
struct drm_property *tv_selector;
struct drm_property *tv_subconnector;
@ -1690,15 +1794,17 @@ int drm_mode_create_tv_properties(struct drm_device *dev,
if (drm_mode_create_tv_margin_properties(dev))
goto nomem;
dev->mode_config.tv_mode_property =
drm_property_create(dev, DRM_MODE_PROP_ENUM,
"mode", num_modes);
if (!dev->mode_config.tv_mode_property)
goto nomem;
if (num_modes) {
dev->mode_config.legacy_tv_mode_property =
drm_property_create(dev, DRM_MODE_PROP_ENUM,
"mode", num_modes);
if (!dev->mode_config.legacy_tv_mode_property)
goto nomem;
for (i = 0; i < num_modes; i++)
drm_property_add_enum(dev->mode_config.tv_mode_property,
i, modes[i]);
for (i = 0; i < num_modes; i++)
drm_property_add_enum(dev->mode_config.legacy_tv_mode_property,
i, modes[i]);
}
dev->mode_config.tv_brightness_property =
drm_property_create_range(dev, 0, "brightness", 0, 100);
@ -1734,6 +1840,47 @@ int drm_mode_create_tv_properties(struct drm_device *dev,
nomem:
return -ENOMEM;
}
EXPORT_SYMBOL(drm_mode_create_tv_properties_legacy);
/**
* drm_mode_create_tv_properties - create TV specific connector properties
* @dev: DRM device
* @supported_tv_modes: Bitmask of TV modes supported (See DRM_MODE_TV_MODE_*)
* Called by a driver's TV initialization routine, this function creates
* the TV specific connector properties for a given device.
*
* Returns:
* 0 on success or a negative error code on failure.
*/
int drm_mode_create_tv_properties(struct drm_device *dev,
unsigned int supported_tv_modes)
{
struct drm_prop_enum_list tv_mode_list[DRM_MODE_TV_MODE_MAX];
struct drm_property *tv_mode;
unsigned int i, len = 0;
if (dev->mode_config.tv_mode_property)
return 0;
for (i = 0; i < DRM_MODE_TV_MODE_MAX; i++) {
if (!(supported_tv_modes & BIT(i)))
continue;
tv_mode_list[len].type = i;
tv_mode_list[len].name = drm_get_tv_mode_name(i);
len++;
}
tv_mode = drm_property_create_enum(dev, 0, "TV mode",
tv_mode_list, len);
if (!tv_mode)
return -ENOMEM;
dev->mode_config.tv_mode_property = tv_mode;
return drm_mode_create_tv_properties_legacy(dev, 0, NULL);
}
EXPORT_SYMBOL(drm_mode_create_tv_properties);
/**

View File

@ -38,6 +38,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_file.h>
#include <drm/drm_gem.h>
#include <drm/drm_managed.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"
@ -50,9 +51,8 @@
static int drm_name_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_minor *minor = node->minor;
struct drm_device *dev = minor->dev;
struct drm_debugfs_entry *entry = m->private;
struct drm_device *dev = entry->dev;
struct drm_master *master;
mutex_lock(&dev->master_mutex);
@ -72,8 +72,8 @@ static int drm_name_info(struct seq_file *m, void *data)
static int drm_clients_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_debugfs_entry *entry = m->private;
struct drm_device *dev = entry->dev;
struct drm_file *priv;
kuid_t uid;
@ -124,8 +124,8 @@ static int drm_gem_one_name_info(int id, void *ptr, void *data)
static int drm_gem_name_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_debugfs_entry *entry = m->private;
struct drm_device *dev = entry->dev;
seq_printf(m, " name size handles refcount\n");
@ -136,7 +136,7 @@ static int drm_gem_name_info(struct seq_file *m, void *data)
return 0;
}
static const struct drm_info_list drm_debugfs_list[] = {
static const struct drm_debugfs_info drm_debugfs_list[] = {
{"name", drm_name_info, 0},
{"clients", drm_clients_info, 0},
{"gem_names", drm_gem_name_info, DRIVER_GEM},
@ -151,6 +151,21 @@ static int drm_debugfs_open(struct inode *inode, struct file *file)
return single_open(file, node->info_ent->show, node);
}
static int drm_debugfs_entry_open(struct inode *inode, struct file *file)
{
struct drm_debugfs_entry *entry = inode->i_private;
struct drm_debugfs_info *node = &entry->file;
return single_open(file, node->show, entry);
}
static const struct file_operations drm_debugfs_entry_fops = {
.owner = THIS_MODULE,
.open = drm_debugfs_entry_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static const struct file_operations drm_debugfs_fops = {
.owner = THIS_MODULE,
@ -207,6 +222,7 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
struct dentry *root)
{
struct drm_device *dev = minor->dev;
struct drm_debugfs_entry *entry, *tmp;
char name[64];
INIT_LIST_HEAD(&minor->debugfs_list);
@ -214,8 +230,7 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
sprintf(name, "%d", minor_id);
minor->debugfs_root = debugfs_create_dir(name, root);
drm_debugfs_create_files(drm_debugfs_list, DRM_DEBUGFS_ENTRIES,
minor->debugfs_root, minor);
drm_debugfs_add_files(minor->dev, drm_debugfs_list, DRM_DEBUGFS_ENTRIES);
if (drm_drv_uses_atomic_modeset(dev)) {
drm_atomic_debugfs_init(minor);
@ -230,9 +245,29 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
if (dev->driver->debugfs_init)
dev->driver->debugfs_init(minor);
list_for_each_entry_safe(entry, tmp, &dev->debugfs_list, list) {
debugfs_create_file(entry->file.name, S_IFREG | S_IRUGO,
minor->debugfs_root, entry, &drm_debugfs_entry_fops);
list_del(&entry->list);
}
return 0;
}
void drm_debugfs_late_register(struct drm_device *dev)
{
struct drm_minor *minor = dev->primary;
struct drm_debugfs_entry *entry, *tmp;
if (!minor)
return;
list_for_each_entry_safe(entry, tmp, &dev->debugfs_list, list) {
debugfs_create_file(entry->file.name, S_IFREG | S_IRUGO,
minor->debugfs_root, entry, &drm_debugfs_entry_fops);
list_del(&entry->list);
}
}
int drm_debugfs_remove_files(const struct drm_info_list *files, int count,
struct drm_minor *minor)
@ -281,6 +316,53 @@ void drm_debugfs_cleanup(struct drm_minor *minor)
minor->debugfs_root = NULL;
}
/**
* drm_debugfs_add_file - Add a given file to the DRM device debugfs file list
* @dev: drm device for the ioctl
* @name: debugfs file name
* @show: show callback
* @data: driver-private data, should not be device-specific
*
* Add a given file entry to the DRM device debugfs file list to be created on
* drm_debugfs_init.
*/
void drm_debugfs_add_file(struct drm_device *dev, const char *name,
int (*show)(struct seq_file*, void*), void *data)
{
struct drm_debugfs_entry *entry = drmm_kzalloc(dev, sizeof(*entry), GFP_KERNEL);
if (!entry)
return;
entry->file.name = name;
entry->file.show = show;
entry->file.data = data;
entry->dev = dev;
mutex_lock(&dev->debugfs_mutex);
list_add(&entry->list, &dev->debugfs_list);
mutex_unlock(&dev->debugfs_mutex);
}
EXPORT_SYMBOL(drm_debugfs_add_file);
/**
* drm_debugfs_add_files - Add an array of files to the DRM device debugfs file list
* @dev: drm device for the ioctl
* @files: The array of files to create
* @count: The number of files given
*
* Add a given set of debugfs files represented by an array of
* &struct drm_debugfs_info in the DRM device debugfs file list.
*/
void drm_debugfs_add_files(struct drm_device *dev, const struct drm_debugfs_info *files, int count)
{
int i;
for (i = 0; i < count; i++)
drm_debugfs_add_file(dev, files[i].name, files[i].show, files[i].data);
}
EXPORT_SYMBOL(drm_debugfs_add_files);
static int connector_show(struct seq_file *m, void *data)
{
struct drm_connector *connector = m->private;

View File

@ -598,6 +598,7 @@ static void drm_dev_init_release(struct drm_device *dev, void *res)
mutex_destroy(&dev->clientlist_mutex);
mutex_destroy(&dev->filelist_mutex);
mutex_destroy(&dev->struct_mutex);
mutex_destroy(&dev->debugfs_mutex);
drm_legacy_destroy_members(dev);
}
@ -638,12 +639,14 @@ static int drm_dev_init(struct drm_device *dev,
INIT_LIST_HEAD(&dev->filelist_internal);
INIT_LIST_HEAD(&dev->clientlist);
INIT_LIST_HEAD(&dev->vblank_event_list);
INIT_LIST_HEAD(&dev->debugfs_list);
spin_lock_init(&dev->event_lock);
mutex_init(&dev->struct_mutex);
mutex_init(&dev->filelist_mutex);
mutex_init(&dev->clientlist_mutex);
mutex_init(&dev->master_mutex);
mutex_init(&dev->debugfs_mutex);
ret = drmm_add_action_or_reset(dev, drm_dev_init_release, NULL);
if (ret)
@ -929,8 +932,8 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
dev->registered = true;
if (dev->driver->load) {
ret = dev->driver->load(dev, flags);
if (driver->load) {
ret = driver->load(dev, flags);
if (ret)
goto err_minors;
}

View File

@ -431,7 +431,6 @@ static const struct drm_client_funcs drm_fbdev_client_funcs = {
* drm_fbdev_generic_setup() - Setup generic fbdev emulation
* @dev: DRM device
* @preferred_bpp: Preferred bits per pixel for the device.
* @dev->mode_config.preferred_depth is used if this is zero.
*
* This function sets up generic fbdev emulation for drivers that supports
* dumb buffers with a virtual address and that can be mmap'ed.
@ -475,12 +474,16 @@ void drm_fbdev_generic_setup(struct drm_device *dev,
}
/*
* FIXME: This mixes up depth with bpp, which results in a glorious
* mess, resulting in some drivers picking wrong fbdev defaults and
* others wrong preferred_depth defaults.
* Pick a preferred bpp of 32 if no value has been given. This
* will select XRGB8888 for the framebuffer formats. All drivers
* have to support XRGB8888 for backwards compatibility with legacy
* userspace, so it's the safe choice here.
*
* TODO: Replace struct drm_mode_config.preferred_depth and this
* bpp value with a preferred format that is given as struct
* drm_format_info. Then derive all other values from the
* format.
*/
if (!preferred_bpp)
preferred_bpp = dev->mode_config.preferred_depth;
if (!preferred_bpp)
preferred_bpp = 32;
fb_helper->preferred_bpp = preferred_bpp;

View File

@ -1203,8 +1203,8 @@ void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent,
#ifdef CONFIG_DEBUG_FS
static int drm_framebuffer_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = m->private;
struct drm_device *dev = node->minor->dev;
struct drm_debugfs_entry *entry = m->private;
struct drm_device *dev = entry->dev;
struct drm_printer p = drm_seq_file_printer(m);
struct drm_framebuffer *fb;
@ -1218,14 +1218,13 @@ static int drm_framebuffer_info(struct seq_file *m, void *data)
return 0;
}
static const struct drm_info_list drm_framebuffer_debugfs_list[] = {
static const struct drm_debugfs_info drm_framebuffer_debugfs_list[] = {
{ "framebuffer", drm_framebuffer_info, 0 },
};
void drm_framebuffer_debugfs_init(struct drm_minor *minor)
{
drm_debugfs_create_files(drm_framebuffer_debugfs_list,
ARRAY_SIZE(drm_framebuffer_debugfs_list),
minor->debugfs_root, minor);
drm_debugfs_add_files(minor->dev, drm_framebuffer_debugfs_list,
ARRAY_SIZE(drm_framebuffer_debugfs_list));
}
#endif

View File

@ -26,11 +26,8 @@
* call drm_gem_plane_helper_prepare_fb() from their implementation of
* struct &drm_plane_helper.prepare_fb . It sets the plane's fence from
* the framebuffer so that the DRM core can synchronize access automatically.
*
* drm_gem_plane_helper_prepare_fb() can also be used directly as
* implementation of prepare_fb. For drivers based on
* struct drm_simple_display_pipe, drm_gem_simple_display_pipe_prepare_fb()
* provides equivalent functionality.
* implementation of prepare_fb.
*
* .. code-block:: c
*
@ -41,11 +38,6 @@
* . prepare_fb = drm_gem_plane_helper_prepare_fb,
* };
*
* struct drm_simple_display_pipe_funcs driver_pipe_funcs = {
* ...,
* . prepare_fb = drm_gem_simple_display_pipe_prepare_fb,
* };
*
* A driver using a shadow buffer copies the content of the shadow buffers
* into the HW's framebuffer memory during an atomic update. This requires
* a mapping of the shadow buffer into kernel address space. The mappings
@ -205,27 +197,6 @@ error:
}
EXPORT_SYMBOL_GPL(drm_gem_plane_helper_prepare_fb);
/**
* drm_gem_simple_display_pipe_prepare_fb - prepare_fb helper for &drm_simple_display_pipe
* @pipe: Simple display pipe
* @plane_state: Plane state
*
* This function uses drm_gem_plane_helper_prepare_fb() to extract the fences
* from &drm_gem_object.resv and attaches them to the plane state for the atomic
* helper to wait on. This is necessary to correctly implement implicit
* synchronization for any buffers shared as a struct &dma_buf. Drivers can use
* this as their &drm_simple_display_pipe_funcs.prepare_fb callback.
*
* See drm_gem_plane_helper_prepare_fb() for a discussion of implicit and
* explicit fencing in atomic modeset updates.
*/
int drm_gem_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *plane_state)
{
return drm_gem_plane_helper_prepare_fb(&pipe->plane, plane_state);
}
EXPORT_SYMBOL(drm_gem_simple_display_pipe_prepare_fb);
/*
* Shadow-buffered Planes
*/

View File

@ -3,6 +3,8 @@
#include <linux/module.h>
#include <drm/drm_gem_ttm_helper.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_tt.h>
/**
* DOC: overview

View File

@ -19,6 +19,7 @@
#include <drm/drm_simple_kms_helper.h>
#include <drm/ttm/ttm_range_manager.h>
#include <drm/ttm/ttm_tt.h>
static const struct drm_gem_object_funcs drm_gem_vram_object_funcs;
@ -956,8 +957,8 @@ static struct ttm_device_funcs bo_driver = {
static int drm_vram_mm_debugfs(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_vram_mm *vmm = node->minor->dev->vram_mm;
struct drm_debugfs_entry *entry = m->private;
struct drm_vram_mm *vmm = entry->dev->vram_mm;
struct ttm_resource_manager *man = ttm_manager_type(&vmm->bdev, TTM_PL_VRAM);
struct drm_printer p = drm_seq_file_printer(m);
@ -965,7 +966,7 @@ static int drm_vram_mm_debugfs(struct seq_file *m, void *data)
return 0;
}
static const struct drm_info_list drm_vram_mm_debugfs_list[] = {
static const struct drm_debugfs_info drm_vram_mm_debugfs_list[] = {
{ "vram-mm", drm_vram_mm_debugfs, 0, NULL },
};
@ -977,9 +978,8 @@ static const struct drm_info_list drm_vram_mm_debugfs_list[] = {
*/
void drm_vram_mm_debugfs_init(struct drm_minor *minor)
{
drm_debugfs_create_files(drm_vram_mm_debugfs_list,
ARRAY_SIZE(drm_vram_mm_debugfs_list),
minor->debugfs_root, minor);
drm_debugfs_add_files(minor->dev, drm_vram_mm_debugfs_list,
ARRAY_SIZE(drm_vram_mm_debugfs_list));
}
EXPORT_SYMBOL(drm_vram_mm_debugfs_init);

View File

@ -186,6 +186,7 @@ int drm_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev,
int drm_debugfs_init(struct drm_minor *minor, int minor_id,
struct dentry *root);
void drm_debugfs_cleanup(struct drm_minor *minor);
void drm_debugfs_late_register(struct drm_device *dev);
void drm_debugfs_connector_add(struct drm_connector *connector);
void drm_debugfs_connector_remove(struct drm_connector *connector);
void drm_debugfs_crtc_add(struct drm_crtc *crtc);
@ -202,6 +203,10 @@ static inline void drm_debugfs_cleanup(struct drm_minor *minor)
{
}
static inline void drm_debugfs_late_register(struct drm_device *dev)
{
}
static inline void drm_debugfs_connector_add(struct drm_connector *connector)
{
}

View File

@ -21,6 +21,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_mipi_dbi.h>
#include <drm/drm_modes.h>
@ -192,6 +193,7 @@ EXPORT_SYMBOL(mipi_dbi_command_stackbuf);
/**
* mipi_dbi_buf_copy - Copy a framebuffer, transforming it if necessary
* @dst: The destination buffer
* @src: The source buffer
* @fb: The source framebuffer
* @clip: Clipping rectangle of the area to be copied
* @swap: When true, swap MSB/LSB of 16-bit values
@ -199,12 +201,10 @@ EXPORT_SYMBOL(mipi_dbi_command_stackbuf);
* Returns:
* Zero on success, negative error code on failure.
*/
int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
int mipi_dbi_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer *fb,
struct drm_rect *clip, bool swap)
{
struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
struct iosys_map map[DRM_FORMAT_MAX_PLANES];
struct iosys_map data[DRM_FORMAT_MAX_PLANES];
struct iosys_map dst_map = IOSYS_MAP_INIT_VADDR(dst);
int ret;
@ -212,19 +212,15 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
if (ret)
return ret;
ret = drm_gem_fb_vmap(fb, map, data);
if (ret)
goto out_drm_gem_fb_end_cpu_access;
switch (fb->format->format) {
case DRM_FORMAT_RGB565:
if (swap)
drm_fb_swab(&dst_map, NULL, data, fb, clip, !gem->import_attach);
drm_fb_swab(&dst_map, NULL, src, fb, clip, !gem->import_attach);
else
drm_fb_memcpy(&dst_map, NULL, data, fb, clip);
drm_fb_memcpy(&dst_map, NULL, src, fb, clip);
break;
case DRM_FORMAT_XRGB8888:
drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, data, fb, clip, swap);
drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip, swap);
break;
default:
drm_err_once(fb->dev, "Format is not supported: %p4cc\n",
@ -232,8 +228,6 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
ret = -EINVAL;
}
drm_gem_fb_vunmap(fb, map);
out_drm_gem_fb_end_cpu_access:
drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
return ret;
@ -257,29 +251,18 @@ static void mipi_dbi_set_window_address(struct mipi_dbi_dev *dbidev,
ys & 0xff, (ye >> 8) & 0xff, ye & 0xff);
}
static void mipi_dbi_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
static void mipi_dbi_fb_dirty(struct iosys_map *src, struct drm_framebuffer *fb,
struct drm_rect *rect)
{
struct iosys_map map[DRM_FORMAT_MAX_PLANES];
struct iosys_map data[DRM_FORMAT_MAX_PLANES];
struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev);
unsigned int height = rect->y2 - rect->y1;
unsigned int width = rect->x2 - rect->x1;
struct mipi_dbi *dbi = &dbidev->dbi;
bool swap = dbi->swap_bytes;
int idx, ret = 0;
int ret = 0;
bool full;
void *tr;
if (WARN_ON(!fb))
return;
if (!drm_dev_enter(fb->dev, &idx))
return;
ret = drm_gem_fb_vmap(fb, map, data);
if (ret)
goto err_drm_dev_exit;
full = width == fb->width && height == fb->height;
DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect));
@ -287,11 +270,11 @@ static void mipi_dbi_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
if (!dbi->dc || !full || swap ||
fb->format->format == DRM_FORMAT_XRGB8888) {
tr = dbidev->tx_buf;
ret = mipi_dbi_buf_copy(dbidev->tx_buf, fb, rect, swap);
ret = mipi_dbi_buf_copy(tr, src, fb, rect, swap);
if (ret)
goto err_msg;
} else {
tr = data[0].vaddr; /* TODO: Use mapping abstraction properly */
tr = src->vaddr; /* TODO: Use mapping abstraction properly */
}
mipi_dbi_set_window_address(dbidev, rect->x1, rect->x2 - 1, rect->y1,
@ -302,11 +285,6 @@ static void mipi_dbi_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
err_msg:
if (ret)
drm_err_once(fb->dev, "Failed to update display %d\n", ret);
drm_gem_fb_vunmap(fb, map);
err_drm_dev_exit:
drm_dev_exit(idx);
}
/**
@ -339,13 +317,24 @@ void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *old_state)
{
struct drm_plane_state *state = pipe->plane.state;
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
struct drm_framebuffer *fb = state->fb;
struct drm_rect rect;
int idx;
if (!pipe->crtc.state->active)
return;
if (WARN_ON(!fb))
return;
if (!drm_dev_enter(fb->dev, &idx))
return;
if (drm_atomic_helper_damage_merged(old_state, state, &rect))
mipi_dbi_fb_dirty(state->fb, &rect);
mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect);
drm_dev_exit(idx);
}
EXPORT_SYMBOL(mipi_dbi_pipe_update);
@ -366,6 +355,7 @@ void mipi_dbi_enable_flush(struct mipi_dbi_dev *dbidev,
struct drm_crtc_state *crtc_state,
struct drm_plane_state *plane_state)
{
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
struct drm_framebuffer *fb = plane_state->fb;
struct drm_rect rect = {
.x1 = 0,
@ -378,7 +368,7 @@ void mipi_dbi_enable_flush(struct mipi_dbi_dev *dbidev,
if (!drm_dev_enter(&dbidev->drm, &idx))
return;
mipi_dbi_fb_dirty(fb, &rect);
mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect);
backlight_enable(dbidev->backlight);
drm_dev_exit(idx);
@ -427,9 +417,95 @@ void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe)
if (dbidev->regulator)
regulator_disable(dbidev->regulator);
if (dbidev->io_regulator)
regulator_disable(dbidev->io_regulator);
}
EXPORT_SYMBOL(mipi_dbi_pipe_disable);
/**
* mipi_dbi_pipe_begin_fb_access - MIPI DBI pipe begin-access helper
* @pipe: Display pipe
* @plane_state: Plane state
*
* This function implements struct &drm_simple_display_funcs.begin_fb_access.
*
* See drm_gem_begin_shadow_fb_access() for details and mipi_dbi_pipe_cleanup_fb()
* for cleanup.
*
* Returns:
* 0 on success, or a negative errno code otherwise.
*/
int mipi_dbi_pipe_begin_fb_access(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *plane_state)
{
return drm_gem_begin_shadow_fb_access(&pipe->plane, plane_state);
}
EXPORT_SYMBOL(mipi_dbi_pipe_begin_fb_access);
/**
* mipi_dbi_pipe_end_fb_access - MIPI DBI pipe end-access helper
* @pipe: Display pipe
* @plane_state: Plane state
*
* This function implements struct &drm_simple_display_funcs.end_fb_access.
*
* See mipi_dbi_pipe_begin_fb_access().
*/
void mipi_dbi_pipe_end_fb_access(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *plane_state)
{
drm_gem_end_shadow_fb_access(&pipe->plane, plane_state);
}
EXPORT_SYMBOL(mipi_dbi_pipe_end_fb_access);
/**
* mipi_dbi_pipe_reset_plane - MIPI DBI plane-reset helper
* @pipe: Display pipe
*
* This function implements struct &drm_simple_display_funcs.reset_plane
* for MIPI DBI planes.
*/
void mipi_dbi_pipe_reset_plane(struct drm_simple_display_pipe *pipe)
{
drm_gem_reset_shadow_plane(&pipe->plane);
}
EXPORT_SYMBOL(mipi_dbi_pipe_reset_plane);
/**
* mipi_dbi_pipe_duplicate_plane_state - duplicates MIPI DBI plane state
* @pipe: Display pipe
*
* This function implements struct &drm_simple_display_funcs.duplicate_plane_state
* for MIPI DBI planes.
*
* See drm_gem_duplicate_shadow_plane_state() for additional details.
*
* Returns:
* A pointer to a new plane state on success, or NULL otherwise.
*/
struct drm_plane_state *mipi_dbi_pipe_duplicate_plane_state(struct drm_simple_display_pipe *pipe)
{
return drm_gem_duplicate_shadow_plane_state(&pipe->plane);
}
EXPORT_SYMBOL(mipi_dbi_pipe_duplicate_plane_state);
/**
* mipi_dbi_pipe_destroy_plane_state - cleans up MIPI DBI plane state
* @pipe: Display pipe
* @plane_state: Plane state
*
* This function implements struct drm_simple_display_funcs.destroy_plane_state
* for MIPI DBI planes.
*
* See drm_gem_destroy_shadow_plane_state() for additional details.
*/
void mipi_dbi_pipe_destroy_plane_state(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *plane_state)
{
drm_gem_destroy_shadow_plane_state(&pipe->plane, plane_state);
}
EXPORT_SYMBOL(mipi_dbi_pipe_destroy_plane_state);
static int mipi_dbi_connector_get_modes(struct drm_connector *connector)
{
struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(connector->dev);
@ -652,6 +728,16 @@ static int mipi_dbi_poweron_reset_conditional(struct mipi_dbi_dev *dbidev, bool
}
}
if (dbidev->io_regulator) {
ret = regulator_enable(dbidev->io_regulator);
if (ret) {
DRM_DEV_ERROR(dev, "Failed to enable I/O regulator (%d)\n", ret);
if (dbidev->regulator)
regulator_disable(dbidev->regulator);
return ret;
}
}
if (cond && mipi_dbi_display_is_on(dbi))
return 1;
@ -661,6 +747,8 @@ static int mipi_dbi_poweron_reset_conditional(struct mipi_dbi_dev *dbidev, bool
DRM_DEV_ERROR(dev, "Failed to send reset command (%d)\n", ret);
if (dbidev->regulator)
regulator_disable(dbidev->regulator);
if (dbidev->io_regulator)
regulator_disable(dbidev->io_regulator);
return ret;
}

View File

@ -54,6 +54,8 @@ int drm_modeset_register_all(struct drm_device *dev)
if (ret)
goto err_connector;
drm_debugfs_late_register(dev);
return 0;
err_connector:

View File

@ -116,6 +116,482 @@ void drm_mode_probed_add(struct drm_connector *connector,
}
EXPORT_SYMBOL(drm_mode_probed_add);
enum drm_mode_analog {
DRM_MODE_ANALOG_NTSC, /* 525 lines, 60Hz */
DRM_MODE_ANALOG_PAL, /* 625 lines, 50Hz */
};
/*
* The timings come from:
* - https://web.archive.org/web/20220406232708/http://www.kolumbus.fi/pami1/video/pal_ntsc.html
* - https://web.archive.org/web/20220406124914/http://martin.hinner.info/vga/pal.html
* - https://web.archive.org/web/20220609202433/http://www.batsocks.co.uk/readme/video_timing.htm
*/
#define NTSC_LINE_DURATION_NS 63556U
#define NTSC_LINES_NUMBER 525
#define NTSC_HBLK_DURATION_TYP_NS 10900U
#define NTSC_HBLK_DURATION_MIN_NS (NTSC_HBLK_DURATION_TYP_NS - 200)
#define NTSC_HBLK_DURATION_MAX_NS (NTSC_HBLK_DURATION_TYP_NS + 200)
#define NTSC_HACT_DURATION_TYP_NS (NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_TYP_NS)
#define NTSC_HACT_DURATION_MIN_NS (NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_MAX_NS)
#define NTSC_HACT_DURATION_MAX_NS (NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_MIN_NS)
#define NTSC_HFP_DURATION_TYP_NS 1500
#define NTSC_HFP_DURATION_MIN_NS 1270
#define NTSC_HFP_DURATION_MAX_NS 2220
#define NTSC_HSLEN_DURATION_TYP_NS 4700
#define NTSC_HSLEN_DURATION_MIN_NS (NTSC_HSLEN_DURATION_TYP_NS - 100)
#define NTSC_HSLEN_DURATION_MAX_NS (NTSC_HSLEN_DURATION_TYP_NS + 100)
#define NTSC_HBP_DURATION_TYP_NS 4700
/*
* I couldn't find the actual tolerance for the back porch, so let's
* just reuse the sync length ones.
*/
#define NTSC_HBP_DURATION_MIN_NS (NTSC_HBP_DURATION_TYP_NS - 100)
#define NTSC_HBP_DURATION_MAX_NS (NTSC_HBP_DURATION_TYP_NS + 100)
#define PAL_LINE_DURATION_NS 64000U
#define PAL_LINES_NUMBER 625
#define PAL_HACT_DURATION_TYP_NS 51950U
#define PAL_HACT_DURATION_MIN_NS (PAL_HACT_DURATION_TYP_NS - 100)
#define PAL_HACT_DURATION_MAX_NS (PAL_HACT_DURATION_TYP_NS + 400)
#define PAL_HBLK_DURATION_TYP_NS (PAL_LINE_DURATION_NS - PAL_HACT_DURATION_TYP_NS)
#define PAL_HBLK_DURATION_MIN_NS (PAL_LINE_DURATION_NS - PAL_HACT_DURATION_MAX_NS)
#define PAL_HBLK_DURATION_MAX_NS (PAL_LINE_DURATION_NS - PAL_HACT_DURATION_MIN_NS)
#define PAL_HFP_DURATION_TYP_NS 1650
#define PAL_HFP_DURATION_MIN_NS (PAL_HFP_DURATION_TYP_NS - 100)
#define PAL_HFP_DURATION_MAX_NS (PAL_HFP_DURATION_TYP_NS + 400)
#define PAL_HSLEN_DURATION_TYP_NS 4700
#define PAL_HSLEN_DURATION_MIN_NS (PAL_HSLEN_DURATION_TYP_NS - 200)
#define PAL_HSLEN_DURATION_MAX_NS (PAL_HSLEN_DURATION_TYP_NS + 200)
#define PAL_HBP_DURATION_TYP_NS 5700
#define PAL_HBP_DURATION_MIN_NS (PAL_HBP_DURATION_TYP_NS - 200)
#define PAL_HBP_DURATION_MAX_NS (PAL_HBP_DURATION_TYP_NS + 200)
struct analog_param_field {
unsigned int even, odd;
};
#define PARAM_FIELD(_odd, _even) \
{ .even = _even, .odd = _odd }
struct analog_param_range {
unsigned int min, typ, max;
};
#define PARAM_RANGE(_min, _typ, _max) \
{ .min = _min, .typ = _typ, .max = _max }
struct analog_parameters {
unsigned int num_lines;
unsigned int line_duration_ns;
struct analog_param_range hact_ns;
struct analog_param_range hfp_ns;
struct analog_param_range hslen_ns;
struct analog_param_range hbp_ns;
struct analog_param_range hblk_ns;
unsigned int bt601_hfp;
struct analog_param_field vfp_lines;
struct analog_param_field vslen_lines;
struct analog_param_field vbp_lines;
};
#define TV_MODE_PARAMETER(_mode, _lines, _line_dur, _hact, _hfp, \
_hslen, _hbp, _hblk, _bt601_hfp, _vfp, \
_vslen, _vbp) \
[_mode] = { \
.num_lines = _lines, \
.line_duration_ns = _line_dur, \
.hact_ns = _hact, \
.hfp_ns = _hfp, \
.hslen_ns = _hslen, \
.hbp_ns = _hbp, \
.hblk_ns = _hblk, \
.bt601_hfp = _bt601_hfp, \
.vfp_lines = _vfp, \
.vslen_lines = _vslen, \
.vbp_lines = _vbp, \
}
static const struct analog_parameters tv_modes_parameters[] = {
TV_MODE_PARAMETER(DRM_MODE_ANALOG_NTSC,
NTSC_LINES_NUMBER,
NTSC_LINE_DURATION_NS,
PARAM_RANGE(NTSC_HACT_DURATION_MIN_NS,
NTSC_HACT_DURATION_TYP_NS,
NTSC_HACT_DURATION_MAX_NS),
PARAM_RANGE(NTSC_HFP_DURATION_MIN_NS,
NTSC_HFP_DURATION_TYP_NS,
NTSC_HFP_DURATION_MAX_NS),
PARAM_RANGE(NTSC_HSLEN_DURATION_MIN_NS,
NTSC_HSLEN_DURATION_TYP_NS,
NTSC_HSLEN_DURATION_MAX_NS),
PARAM_RANGE(NTSC_HBP_DURATION_MIN_NS,
NTSC_HBP_DURATION_TYP_NS,
NTSC_HBP_DURATION_MAX_NS),
PARAM_RANGE(NTSC_HBLK_DURATION_MIN_NS,
NTSC_HBLK_DURATION_TYP_NS,
NTSC_HBLK_DURATION_MAX_NS),
16,
PARAM_FIELD(3, 3),
PARAM_FIELD(3, 3),
PARAM_FIELD(16, 17)),
TV_MODE_PARAMETER(DRM_MODE_ANALOG_PAL,
PAL_LINES_NUMBER,
PAL_LINE_DURATION_NS,
PARAM_RANGE(PAL_HACT_DURATION_MIN_NS,
PAL_HACT_DURATION_TYP_NS,
PAL_HACT_DURATION_MAX_NS),
PARAM_RANGE(PAL_HFP_DURATION_MIN_NS,
PAL_HFP_DURATION_TYP_NS,
PAL_HFP_DURATION_MAX_NS),
PARAM_RANGE(PAL_HSLEN_DURATION_MIN_NS,
PAL_HSLEN_DURATION_TYP_NS,
PAL_HSLEN_DURATION_MAX_NS),
PARAM_RANGE(PAL_HBP_DURATION_MIN_NS,
PAL_HBP_DURATION_TYP_NS,
PAL_HBP_DURATION_MAX_NS),
PARAM_RANGE(PAL_HBLK_DURATION_MIN_NS,
PAL_HBLK_DURATION_TYP_NS,
PAL_HBLK_DURATION_MAX_NS),
12,
/*
* The front porch is actually 6 short sync
* pulses for the even field, and 5 for the
* odd field. Each sync takes half a life so
* the odd field front porch is shorter by
* half a line.
*
* In progressive, we're supposed to use 6
* pulses, so we're fine there
*/
PARAM_FIELD(3, 2),
/*
* The vsync length is 5 long sync pulses,
* each field taking half a line. We're
* shorter for both fields by half a line.
*
* In progressive, we're supposed to use 5
* pulses, so we're off by half
* a line.
*
* In interlace, we're now off by half a line
* for the even field and one line for the odd
* field.
*/
PARAM_FIELD(3, 3),
/*
* The back porch starts with post-equalizing
* pulses, consisting in 5 short sync pulses
* for the even field, 4 for the odd field. In
* progressive, it's 5 short syncs.
*
* In progressive, we thus have 2.5 lines,
* plus the 0.5 line we were missing
* previously, so we should use 3 lines.
*
* In interlace, the even field is in the
* exact same case than progressive. For the
* odd field, we should be using 2 lines but
* we're one line short, so we'll make up for
* it here by using 3.
*
* The entire blanking area is supposed to
* take 25 lines, so we also need to account
* for the rest of the blanking area that
* can't be in either the front porch or sync
* period.
*/
PARAM_FIELD(19, 20)),
};
static int fill_analog_mode(struct drm_device *dev,
struct drm_display_mode *mode,
const struct analog_parameters *params,
unsigned long pixel_clock_hz,
unsigned int hactive,
unsigned int vactive,
bool interlace)
{
unsigned long pixel_duration_ns = NSEC_PER_SEC / pixel_clock_hz;
unsigned int htotal, vtotal;
unsigned int max_hact, hact_duration_ns;
unsigned int hblk, hblk_duration_ns;
unsigned int hfp, hfp_duration_ns;
unsigned int hslen, hslen_duration_ns;
unsigned int hbp, hbp_duration_ns;
unsigned int porches, porches_duration_ns;
unsigned int vfp, vfp_min;
unsigned int vbp, vbp_min;
unsigned int vslen;
bool bt601 = false;
int porches_rem;
u64 result;
drm_dbg_kms(dev,
"Generating a %ux%u%c, %u-line mode with a %lu kHz clock\n",
hactive, vactive,
interlace ? 'i' : 'p',
params->num_lines,
pixel_clock_hz / 1000);
max_hact = params->hact_ns.max / pixel_duration_ns;
if (pixel_clock_hz == 13500000 && hactive > max_hact && hactive <= 720) {
drm_dbg_kms(dev, "Trying to generate a BT.601 mode. Disabling checks.\n");
bt601 = true;
}
/*
* Our pixel duration is going to be round down by the division,
* so rounding up is probably going to introduce even more
* deviation.
*/
result = (u64)params->line_duration_ns * pixel_clock_hz;
do_div(result, NSEC_PER_SEC);
htotal = result;
drm_dbg_kms(dev, "Total Horizontal Number of Pixels: %u\n", htotal);
hact_duration_ns = hactive * pixel_duration_ns;
if (!bt601 &&
(hact_duration_ns < params->hact_ns.min ||
hact_duration_ns > params->hact_ns.max)) {
DRM_ERROR("Invalid horizontal active area duration: %uns (min: %u, max %u)\n",
hact_duration_ns, params->hact_ns.min, params->hact_ns.max);
return -EINVAL;
}
hblk = htotal - hactive;
drm_dbg_kms(dev, "Horizontal Blanking Period: %u\n", hblk);
hblk_duration_ns = hblk * pixel_duration_ns;
if (!bt601 &&
(hblk_duration_ns < params->hblk_ns.min ||
hblk_duration_ns > params->hblk_ns.max)) {
DRM_ERROR("Invalid horizontal blanking duration: %uns (min: %u, max %u)\n",
hblk_duration_ns, params->hblk_ns.min, params->hblk_ns.max);
return -EINVAL;
}
hslen = DIV_ROUND_UP(params->hslen_ns.typ, pixel_duration_ns);
drm_dbg_kms(dev, "Horizontal Sync Period: %u\n", hslen);
hslen_duration_ns = hslen * pixel_duration_ns;
if (!bt601 &&
(hslen_duration_ns < params->hslen_ns.min ||
hslen_duration_ns > params->hslen_ns.max)) {
DRM_ERROR("Invalid horizontal sync duration: %uns (min: %u, max %u)\n",
hslen_duration_ns, params->hslen_ns.min, params->hslen_ns.max);
return -EINVAL;
}
porches = hblk - hslen;
drm_dbg_kms(dev, "Remaining horizontal pixels for both porches: %u\n", porches);
porches_duration_ns = porches * pixel_duration_ns;
if (!bt601 &&
(porches_duration_ns > (params->hfp_ns.max + params->hbp_ns.max) ||
porches_duration_ns < (params->hfp_ns.min + params->hbp_ns.min))) {
DRM_ERROR("Invalid horizontal porches duration: %uns\n", porches_duration_ns);
return -EINVAL;
}
if (bt601) {
hfp = params->bt601_hfp;
} else {
unsigned int hfp_min = DIV_ROUND_UP(params->hfp_ns.min,
pixel_duration_ns);
unsigned int hbp_min = DIV_ROUND_UP(params->hbp_ns.min,
pixel_duration_ns);
int porches_rem = porches - hfp_min - hbp_min;
hfp = hfp_min + DIV_ROUND_UP(porches_rem, 2);
}
drm_dbg_kms(dev, "Horizontal Front Porch: %u\n", hfp);
hfp_duration_ns = hfp * pixel_duration_ns;
if (!bt601 &&
(hfp_duration_ns < params->hfp_ns.min ||
hfp_duration_ns > params->hfp_ns.max)) {
DRM_ERROR("Invalid horizontal front porch duration: %uns (min: %u, max %u)\n",
hfp_duration_ns, params->hfp_ns.min, params->hfp_ns.max);
return -EINVAL;
}
hbp = porches - hfp;
drm_dbg_kms(dev, "Horizontal Back Porch: %u\n", hbp);
hbp_duration_ns = hbp * pixel_duration_ns;
if (!bt601 &&
(hbp_duration_ns < params->hbp_ns.min ||
hbp_duration_ns > params->hbp_ns.max)) {
DRM_ERROR("Invalid horizontal back porch duration: %uns (min: %u, max %u)\n",
hbp_duration_ns, params->hbp_ns.min, params->hbp_ns.max);
return -EINVAL;
}
if (htotal != (hactive + hfp + hslen + hbp))
return -EINVAL;
mode->clock = pixel_clock_hz / 1000;
mode->hdisplay = hactive;
mode->hsync_start = mode->hdisplay + hfp;
mode->hsync_end = mode->hsync_start + hslen;
mode->htotal = mode->hsync_end + hbp;
if (interlace) {
vfp_min = params->vfp_lines.even + params->vfp_lines.odd;
vbp_min = params->vbp_lines.even + params->vbp_lines.odd;
vslen = params->vslen_lines.even + params->vslen_lines.odd;
} else {
/*
* By convention, NTSC (aka 525/60) systems start with
* the even field, but PAL (aka 625/50) systems start
* with the odd one.
*
* PAL systems also have asymmetric timings between the
* even and odd field, while NTSC is symmetric.
*
* Moreover, if we want to create a progressive mode for
* PAL, we need to use the odd field timings.
*
* Since odd == even for NTSC, we can just use the odd
* one all the time to simplify the code a bit.
*/
vfp_min = params->vfp_lines.odd;
vbp_min = params->vbp_lines.odd;
vslen = params->vslen_lines.odd;
}
drm_dbg_kms(dev, "Vertical Sync Period: %u\n", vslen);
porches = params->num_lines - vactive - vslen;
drm_dbg_kms(dev, "Remaining vertical pixels for both porches: %u\n", porches);
porches_rem = porches - vfp_min - vbp_min;
vfp = vfp_min + (porches_rem / 2);
drm_dbg_kms(dev, "Vertical Front Porch: %u\n", vfp);
vbp = porches - vfp;
drm_dbg_kms(dev, "Vertical Back Porch: %u\n", vbp);
vtotal = vactive + vfp + vslen + vbp;
if (params->num_lines != vtotal) {
DRM_ERROR("Invalid vertical total: %upx (expected %upx)\n",
vtotal, params->num_lines);
return -EINVAL;
}
mode->vdisplay = vactive;
mode->vsync_start = mode->vdisplay + vfp;
mode->vsync_end = mode->vsync_start + vslen;
mode->vtotal = mode->vsync_end + vbp;
if (mode->vtotal != params->num_lines)
return -EINVAL;
mode->type = DRM_MODE_TYPE_DRIVER;
mode->flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC;
if (interlace)
mode->flags |= DRM_MODE_FLAG_INTERLACE;
drm_mode_set_name(mode);
drm_dbg_kms(dev, "Generated mode " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
return 0;
}
/**
* drm_analog_tv_mode - create a display mode for an analog TV
* @dev: drm device
* @tv_mode: TV Mode standard to create a mode for. See DRM_MODE_TV_MODE_*.
* @pixel_clock_hz: Pixel Clock Frequency, in Hertz
* @hdisplay: hdisplay size
* @vdisplay: vdisplay size
* @interlace: whether to compute an interlaced mode
*
* This function creates a struct drm_display_mode instance suited for
* an analog TV output, for one of the usual analog TV mode.
*
* Note that @hdisplay is larger than the usual constraints for the PAL
* and NTSC timings, and we'll choose to ignore most timings constraints
* to reach those resolutions.
*
* Returns:
*
* A pointer to the mode, allocated with drm_mode_create(). Returns NULL
* on error.
*/
struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev,
enum drm_connector_tv_mode tv_mode,
unsigned long pixel_clock_hz,
unsigned int hdisplay,
unsigned int vdisplay,
bool interlace)
{
struct drm_display_mode *mode;
enum drm_mode_analog analog;
int ret;
switch (tv_mode) {
case DRM_MODE_TV_MODE_NTSC:
fallthrough;
case DRM_MODE_TV_MODE_NTSC_443:
fallthrough;
case DRM_MODE_TV_MODE_NTSC_J:
fallthrough;
case DRM_MODE_TV_MODE_PAL_M:
analog = DRM_MODE_ANALOG_NTSC;
break;
case DRM_MODE_TV_MODE_PAL:
fallthrough;
case DRM_MODE_TV_MODE_PAL_N:
fallthrough;
case DRM_MODE_TV_MODE_SECAM:
analog = DRM_MODE_ANALOG_PAL;
break;
default:
return NULL;
}
mode = drm_mode_create(dev);
if (!mode)
return NULL;
ret = fill_analog_mode(dev, mode,
&tv_modes_parameters[analog],
pixel_clock_hz, hdisplay, vdisplay, interlace);
if (ret)
goto err_free_mode;
return mode;
err_free_mode:
drm_mode_destroy(dev, mode);
return NULL;
}
EXPORT_SYMBOL(drm_analog_tv_mode);
/**
* drm_cvt_mode -create a modeline based on the CVT algorithm
* @dev: drm device
@ -1659,6 +2135,30 @@ static int drm_mode_parse_panel_orientation(const char *delim,
return 0;
}
static int drm_mode_parse_tv_mode(const char *delim,
struct drm_cmdline_mode *mode)
{
const char *value;
int ret;
if (*delim != '=')
return -EINVAL;
value = delim + 1;
delim = strchr(value, ',');
if (!delim)
delim = value + strlen(value);
ret = drm_get_tv_mode_from_name(value, delim - value);
if (ret < 0)
return ret;
mode->tv_mode_specified = true;
mode->tv_mode = ret;
return 0;
}
static int drm_mode_parse_cmdline_options(const char *str,
bool freestanding,
const struct drm_connector *connector,
@ -1728,6 +2228,9 @@ static int drm_mode_parse_cmdline_options(const char *str,
} else if (!strncmp(option, "panel_orientation", delim - option)) {
if (drm_mode_parse_panel_orientation(delim, mode))
return -EINVAL;
} else if (!strncmp(option, "tv_mode", delim - option)) {
if (drm_mode_parse_tv_mode(delim, mode))
return -EINVAL;
} else {
return -EINVAL;
}
@ -1756,20 +2259,24 @@ struct drm_named_mode {
unsigned int xres;
unsigned int yres;
unsigned int flags;
unsigned int tv_mode;
};
#define NAMED_MODE(_name, _pclk, _x, _y, _flags) \
#define NAMED_MODE(_name, _pclk, _x, _y, _flags, _mode) \
{ \
.name = _name, \
.pixel_clock_khz = _pclk, \
.xres = _x, \
.yres = _y, \
.flags = _flags, \
.tv_mode = _mode, \
}
static const struct drm_named_mode drm_named_modes[] = {
NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE),
NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE),
NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_NTSC),
NAMED_MODE("NTSC-J", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_NTSC_J),
NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL),
NAMED_MODE("PAL-M", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL_M),
};
static int drm_mode_parse_cmdline_named_mode(const char *name,
@ -1809,11 +2316,13 @@ static int drm_mode_parse_cmdline_named_mode(const char *name,
if (ret != name_end)
continue;
strcpy(cmdline_mode->name, mode->name);
strscpy(cmdline_mode->name, mode->name, sizeof(cmdline_mode->name));
cmdline_mode->pixel_clock = mode->pixel_clock_khz;
cmdline_mode->xres = mode->xres;
cmdline_mode->yres = mode->yres;
cmdline_mode->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
cmdline_mode->tv_mode = mode->tv_mode;
cmdline_mode->tv_mode_specified = true;
cmdline_mode->specified = true;
return 1;
@ -1992,6 +2501,31 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
}
EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
static struct drm_display_mode *drm_named_mode(struct drm_device *dev,
struct drm_cmdline_mode *cmd)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(drm_named_modes); i++) {
const struct drm_named_mode *named_mode = &drm_named_modes[i];
if (strcmp(cmd->name, named_mode->name))
continue;
if (!cmd->tv_mode_specified)
continue;
return drm_analog_tv_mode(dev,
named_mode->tv_mode,
named_mode->pixel_clock_khz * 1000,
named_mode->xres,
named_mode->yres,
named_mode->flags & DRM_MODE_FLAG_INTERLACE);
}
return NULL;
}
/**
* drm_mode_create_from_cmdline_mode - convert a command line modeline into a DRM display mode
* @dev: DRM device to create the new mode for
@ -2009,7 +2543,9 @@ drm_mode_create_from_cmdline_mode(struct drm_device *dev,
if (cmd->xres == 0 || cmd->yres == 0)
return NULL;
if (cmd->cvt)
if (strlen(cmd->name))
mode = drm_named_mode(dev, cmd);
else if (cmd->cvt)
mode = drm_cvt_mode(dev,
cmd->xres, cmd->yres,
cmd->refresh_specified ? cmd->refresh : 60,

View File

@ -30,12 +30,6 @@ struct drm_dmi_panel_orientation_data {
int orientation;
};
static const struct drm_dmi_panel_orientation_data asus_t100ha = {
.width = 800,
.height = 1280,
.orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP,
};
static const struct drm_dmi_panel_orientation_data gpd_micropc = {
.width = 720,
.height = 1280,
@ -97,6 +91,12 @@ static const struct drm_dmi_panel_orientation_data lcd720x1280_rightside_up = {
.orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
};
static const struct drm_dmi_panel_orientation_data lcd800x1280_leftside_up = {
.width = 800,
.height = 1280,
.orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP,
};
static const struct drm_dmi_panel_orientation_data lcd800x1280_rightside_up = {
.width = 800,
.height = 1280,
@ -127,6 +127,12 @@ static const struct drm_dmi_panel_orientation_data lcd1600x2560_leftside_up = {
.orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP,
};
static const struct drm_dmi_panel_orientation_data lcd1600x2560_rightside_up = {
.width = 1600,
.height = 2560,
.orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
};
static const struct dmi_system_id orientation_data[] = {
{ /* Acer One 10 (S1003) */
.matches = {
@ -151,7 +157,7 @@ static const struct dmi_system_id orientation_data[] = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100HAN"),
},
.driver_data = (void *)&asus_t100ha,
.driver_data = (void *)&lcd800x1280_leftside_up,
}, { /* Asus T101HA */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
@ -196,6 +202,12 @@ static const struct dmi_system_id orientation_data[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Hi10 pro tablet"),
},
.driver_data = (void *)&lcd1200x1920_rightside_up,
}, { /* Dynabook K50 */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dynabook Inc."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "dynabook K50/FR"),
},
.driver_data = (void *)&lcd800x1280_leftside_up,
}, { /* GPD MicroPC (generic strings, also match on bios date) */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string"),
@ -325,6 +337,13 @@ static const struct dmi_system_id orientation_data[] = {
DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"),
},
.driver_data = (void *)&lcd1200x1920_rightside_up,
}, { /* Lenovo Yoga Tab 3 X90F */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"),
},
.driver_data = (void *)&lcd1600x2560_rightside_up,
}, { /* Nanote UMPC-01 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "RWC CO.,LTD"),

View File

@ -1146,3 +1146,85 @@ int drm_connector_helper_get_modes(struct drm_connector *connector)
return count;
}
EXPORT_SYMBOL(drm_connector_helper_get_modes);
/**
* drm_connector_helper_tv_get_modes - Fills the modes availables to a TV connector
* @connector: The connector
*
* Fills the available modes for a TV connector based on the supported
* TV modes, and the default mode expressed by the kernel command line.
*
* This can be used as the default TV connector helper .get_modes() hook
* if the driver does not need any special processing.
*
* Returns:
* The number of modes added to the connector.
*/
int drm_connector_helper_tv_get_modes(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_property *tv_mode_property =
dev->mode_config.tv_mode_property;
struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
unsigned int ntsc_modes = BIT(DRM_MODE_TV_MODE_NTSC) |
BIT(DRM_MODE_TV_MODE_NTSC_443) |
BIT(DRM_MODE_TV_MODE_NTSC_J) |
BIT(DRM_MODE_TV_MODE_PAL_M);
unsigned int pal_modes = BIT(DRM_MODE_TV_MODE_PAL) |
BIT(DRM_MODE_TV_MODE_PAL_N) |
BIT(DRM_MODE_TV_MODE_SECAM);
unsigned int tv_modes[2] = { UINT_MAX, UINT_MAX };
unsigned int i, supported_tv_modes = 0;
if (!tv_mode_property)
return 0;
for (i = 0; i < tv_mode_property->num_values; i++)
supported_tv_modes |= BIT(tv_mode_property->values[i]);
if ((supported_tv_modes & ntsc_modes) &&
(supported_tv_modes & pal_modes)) {
uint64_t default_mode;
if (drm_object_property_get_default_value(&connector->base,
tv_mode_property,
&default_mode))
return 0;
if (cmdline->tv_mode_specified)
default_mode = cmdline->tv_mode;
if (BIT(default_mode) & ntsc_modes) {
tv_modes[0] = DRM_MODE_TV_MODE_NTSC;
tv_modes[1] = DRM_MODE_TV_MODE_PAL;
} else {
tv_modes[0] = DRM_MODE_TV_MODE_PAL;
tv_modes[1] = DRM_MODE_TV_MODE_NTSC;
}
} else if (supported_tv_modes & ntsc_modes) {
tv_modes[0] = DRM_MODE_TV_MODE_NTSC;
} else if (supported_tv_modes & pal_modes) {
tv_modes[0] = DRM_MODE_TV_MODE_PAL;
} else {
return 0;
}
for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
struct drm_display_mode *mode;
if (tv_modes[i] == DRM_MODE_TV_MODE_NTSC)
mode = drm_mode_analog_ntsc_480i(dev);
else if (tv_modes[i] == DRM_MODE_TV_MODE_PAL)
mode = drm_mode_analog_pal_576i(dev);
else
break;
if (!mode)
return i;
if (!i)
mode->type |= DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode);
}
return i;
}
EXPORT_SYMBOL(drm_connector_helper_tv_get_modes);

View File

@ -267,7 +267,7 @@ static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane,
WARN_ON_ONCE(pipe->funcs && pipe->funcs->cleanup_fb);
return drm_gem_simple_display_pipe_prepare_fb(pipe, state);
return drm_gem_plane_helper_prepare_fb(plane, state);
}
return pipe->funcs->prepare_fb(pipe, state);

View File

@ -710,7 +710,6 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
#ifdef CONFIG_PM
static int exynos5433_decon_suspend(struct device *dev)
{
struct decon_context *ctx = dev_get_drvdata(dev);
@ -741,14 +740,10 @@ err:
return ret;
}
#endif
static const struct dev_pm_ops exynos5433_decon_pm_ops = {
SET_RUNTIME_PM_OPS(exynos5433_decon_suspend, exynos5433_decon_resume,
NULL)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};
static DEFINE_RUNTIME_DEV_PM_OPS(exynos5433_decon_pm_ops,
exynos5433_decon_suspend,
exynos5433_decon_resume, NULL);
static const struct of_device_id exynos5433_decon_driver_dt_match[] = {
{
@ -881,7 +876,7 @@ struct platform_driver exynos5433_decon_driver = {
.remove = exynos5433_decon_remove,
.driver = {
.name = "exynos5433-decon",
.pm = &exynos5433_decon_pm_ops,
.pm = pm_ptr(&exynos5433_decon_pm_ops),
.of_match_table = exynos5433_decon_driver_dt_match,
},
};

View File

@ -779,7 +779,6 @@ static int decon_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int exynos7_decon_suspend(struct device *dev)
{
struct decon_context *ctx = dev_get_drvdata(dev);
@ -836,21 +835,16 @@ err_aclk_enable:
err_pclk_enable:
return ret;
}
#endif
static const struct dev_pm_ops exynos7_decon_pm_ops = {
SET_RUNTIME_PM_OPS(exynos7_decon_suspend, exynos7_decon_resume,
NULL)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};
static DEFINE_RUNTIME_DEV_PM_OPS(exynos7_decon_pm_ops, exynos7_decon_suspend,
exynos7_decon_resume, NULL);
struct platform_driver decon_driver = {
.probe = decon_probe,
.remove = decon_remove,
.driver = {
.name = "exynos-decon",
.pm = &exynos7_decon_pm_ops,
.pm = pm_ptr(&exynos7_decon_pm_ops),
.of_match_table = decon_driver_dt_match,
},
};

View File

@ -260,7 +260,6 @@ static int exynos_dp_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int exynos_dp_suspend(struct device *dev)
{
struct exynos_dp_device *dp = dev_get_drvdata(dev);
@ -274,13 +273,9 @@ static int exynos_dp_resume(struct device *dev)
return analogix_dp_resume(dp->adp);
}
#endif
static const struct dev_pm_ops exynos_dp_pm_ops = {
SET_RUNTIME_PM_OPS(exynos_dp_suspend, exynos_dp_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};
static DEFINE_RUNTIME_DEV_PM_OPS(exynos_dp_pm_ops, exynos_dp_suspend,
exynos_dp_resume, NULL);
static const struct of_device_id exynos_dp_match[] = {
{ .compatible = "samsung,exynos5-dp" },
@ -294,7 +289,7 @@ struct platform_driver dp_driver = {
.driver = {
.name = "exynos-dp",
.owner = THIS_MODULE,
.pm = &exynos_dp_pm_ops,
.pm = pm_ptr(&exynos_dp_pm_ops),
.of_match_table = exynos_dp_match,
},
};

View File

@ -1381,7 +1381,6 @@ static int fimc_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int fimc_runtime_suspend(struct device *dev)
{
struct fimc_context *ctx = get_fimc_context(dev);
@ -1398,13 +1397,9 @@ static int fimc_runtime_resume(struct device *dev)
DRM_DEV_DEBUG_KMS(dev, "id[%d]\n", ctx->id);
return clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]);
}
#endif
static const struct dev_pm_ops fimc_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL)
};
static DEFINE_RUNTIME_DEV_PM_OPS(fimc_pm_ops, fimc_runtime_suspend,
fimc_runtime_resume, NULL);
static const struct of_device_id fimc_of_match[] = {
{ .compatible = "samsung,exynos4210-fimc" },
@ -1420,6 +1415,6 @@ struct platform_driver fimc_driver = {
.of_match_table = fimc_of_match,
.name = "exynos-drm-fimc",
.owner = THIS_MODULE,
.pm = &fimc_pm_ops,
.pm = pm_ptr(&fimc_pm_ops),
},
};

View File

@ -1287,7 +1287,6 @@ static int fimd_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int exynos_fimd_suspend(struct device *dev)
{
struct fimd_context *ctx = dev_get_drvdata(dev);
@ -1321,13 +1320,9 @@ static int exynos_fimd_resume(struct device *dev)
return 0;
}
#endif
static const struct dev_pm_ops exynos_fimd_pm_ops = {
SET_RUNTIME_PM_OPS(exynos_fimd_suspend, exynos_fimd_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};
static DEFINE_RUNTIME_DEV_PM_OPS(exynos_fimd_pm_ops, exynos_fimd_suspend,
exynos_fimd_resume, NULL);
struct platform_driver fimd_driver = {
.probe = fimd_probe,
@ -1335,7 +1330,7 @@ struct platform_driver fimd_driver = {
.driver = {
.name = "exynos4-fb",
.owner = THIS_MODULE,
.pm = &exynos_fimd_pm_ops,
.pm = pm_ptr(&exynos_fimd_pm_ops),
.of_match_table = fimd_driver_dt_match,
},
};

View File

@ -1549,7 +1549,6 @@ static int g2d_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int g2d_suspend(struct device *dev)
{
struct g2d_data *g2d = dev_get_drvdata(dev);
@ -1574,9 +1573,7 @@ static int g2d_resume(struct device *dev)
return 0;
}
#endif
#ifdef CONFIG_PM
static int g2d_runtime_suspend(struct device *dev)
{
struct g2d_data *g2d = dev_get_drvdata(dev);
@ -1597,11 +1594,10 @@ static int g2d_runtime_resume(struct device *dev)
return ret;
}
#endif
static const struct dev_pm_ops g2d_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(g2d_suspend, g2d_resume)
SET_RUNTIME_PM_OPS(g2d_runtime_suspend, g2d_runtime_resume, NULL)
SYSTEM_SLEEP_PM_OPS(g2d_suspend, g2d_resume)
RUNTIME_PM_OPS(g2d_runtime_suspend, g2d_runtime_resume, NULL)
};
static const struct of_device_id exynos_g2d_match[] = {
@ -1617,7 +1613,7 @@ struct platform_driver g2d_driver = {
.driver = {
.name = "exynos-drm-g2d",
.owner = THIS_MODULE,
.pm = &g2d_pm_ops,
.pm = pm_ptr(&g2d_pm_ops),
.of_match_table = exynos_g2d_match,
},
};

View File

@ -340,7 +340,6 @@ static const struct component_ops exynos_mic_component_ops = {
.unbind = exynos_mic_unbind,
};
#ifdef CONFIG_PM
static int exynos_mic_suspend(struct device *dev)
{
struct exynos_mic *mic = dev_get_drvdata(dev);
@ -369,13 +368,9 @@ static int exynos_mic_resume(struct device *dev)
}
return 0;
}
#endif
static const struct dev_pm_ops exynos_mic_pm_ops = {
SET_RUNTIME_PM_OPS(exynos_mic_suspend, exynos_mic_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};
static DEFINE_RUNTIME_DEV_PM_OPS(exynos_mic_pm_ops, exynos_mic_suspend,
exynos_mic_resume, NULL);
static int exynos_mic_probe(struct platform_device *pdev)
{
@ -470,7 +465,7 @@ struct platform_driver mic_driver = {
.remove = exynos_mic_remove,
.driver = {
.name = "exynos-mic",
.pm = &exynos_mic_pm_ops,
.pm = pm_ptr(&exynos_mic_pm_ops),
.owner = THIS_MODULE,
.of_match_table = exynos_mic_of_match,
},

View File

@ -340,7 +340,6 @@ static int rotator_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int rotator_runtime_suspend(struct device *dev)
{
struct rot_context *rot = dev_get_drvdata(dev);
@ -355,7 +354,6 @@ static int rotator_runtime_resume(struct device *dev)
return clk_prepare_enable(rot->clock);
}
#endif
static const struct drm_exynos_ipp_limit rotator_s5pv210_rbg888_limits[] = {
{ IPP_SIZE_LIMIT(BUFFER, .h = { 8, SZ_16K }, .v = { 8, SZ_16K }) },
@ -450,12 +448,8 @@ static const struct of_device_id exynos_rotator_match[] = {
};
MODULE_DEVICE_TABLE(of, exynos_rotator_match);
static const struct dev_pm_ops rotator_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(rotator_runtime_suspend, rotator_runtime_resume,
NULL)
};
static DEFINE_RUNTIME_DEV_PM_OPS(rotator_pm_ops, rotator_runtime_suspend,
rotator_runtime_resume, NULL);
struct platform_driver rotator_driver = {
.probe = rotator_probe,
@ -463,7 +457,7 @@ struct platform_driver rotator_driver = {
.driver = {
.name = "exynos-rotator",
.owner = THIS_MODULE,
.pm = &rotator_pm_ops,
.pm = pm_ptr(&rotator_pm_ops),
.of_match_table = exynos_rotator_match,
},
};

View File

@ -550,8 +550,6 @@ static int scaler_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int clk_disable_unprepare_wrapper(struct clk *clk)
{
clk_disable_unprepare(clk);
@ -584,13 +582,9 @@ static int scaler_runtime_resume(struct device *dev)
return scaler_clk_ctrl(scaler, true);
}
#endif
static const struct dev_pm_ops scaler_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(scaler_runtime_suspend, scaler_runtime_resume, NULL)
};
static DEFINE_RUNTIME_DEV_PM_OPS(scaler_pm_ops, scaler_runtime_suspend,
scaler_runtime_resume, NULL);
static const struct drm_exynos_ipp_limit scaler_5420_two_pixel_hv_limits[] = {
{ IPP_SIZE_LIMIT(BUFFER, .h = { 16, SZ_8K }, .v = { 16, SZ_8K }) },
@ -731,7 +725,7 @@ struct platform_driver scaler_driver = {
.driver = {
.name = "exynos-scaler",
.owner = THIS_MODULE,
.pm = &scaler_pm_ops,
.pm = pm_ptr(&scaler_pm_ops),
.of_match_table = exynos_scaler_match,
},
};

View File

@ -303,7 +303,7 @@ static int gud_connector_atomic_check(struct drm_connector *connector,
old_state->tv.margins.right != new_state->tv.margins.right ||
old_state->tv.margins.top != new_state->tv.margins.top ||
old_state->tv.margins.bottom != new_state->tv.margins.bottom ||
old_state->tv.mode != new_state->tv.mode ||
old_state->tv.legacy_mode != new_state->tv.legacy_mode ||
old_state->tv.brightness != new_state->tv.brightness ||
old_state->tv.contrast != new_state->tv.contrast ||
old_state->tv.flicker_reduction != new_state->tv.flicker_reduction ||
@ -400,7 +400,7 @@ static int gud_connector_add_tv_mode(struct gud_device *gdrm, struct drm_connect
for (i = 0; i < num_modes; i++)
modes[i] = &buf[i * GUD_CONNECTOR_TV_MODE_NAME_LEN];
ret = drm_mode_create_tv_properties(connector->dev, num_modes, modes);
ret = drm_mode_create_tv_properties_legacy(connector->dev, num_modes, modes);
free:
kfree(buf);
if (ret < 0)
@ -424,7 +424,7 @@ gud_connector_property_lookup(struct drm_connector *connector, u16 prop)
case GUD_PROPERTY_TV_BOTTOM_MARGIN:
return config->tv_bottom_margin_property;
case GUD_PROPERTY_TV_MODE:
return config->tv_mode_property;
return config->legacy_tv_mode_property;
case GUD_PROPERTY_TV_BRIGHTNESS:
return config->tv_brightness_property;
case GUD_PROPERTY_TV_CONTRAST:
@ -454,7 +454,7 @@ static unsigned int *gud_connector_tv_state_val(u16 prop, struct drm_tv_connecto
case GUD_PROPERTY_TV_BOTTOM_MARGIN:
return &state->margins.bottom;
case GUD_PROPERTY_TV_MODE:
return &state->mode;
return &state->legacy_mode;
case GUD_PROPERTY_TV_BRIGHTNESS:
return &state->brightness;
case GUD_PROPERTY_TV_CONTRAST:
@ -539,7 +539,7 @@ static int gud_connector_add_properties(struct gud_device *gdrm, struct gud_conn
fallthrough;
case GUD_PROPERTY_TV_HUE:
/* This is a no-op if already added. */
ret = drm_mode_create_tv_properties(drm, 0, NULL);
ret = drm_mode_create_tv_properties_legacy(drm, 0, NULL);
if (ret)
goto out;
break;

View File

@ -365,6 +365,7 @@ static void gud_debugfs_init(struct drm_minor *minor)
static const struct drm_simple_display_pipe_funcs gud_pipe_funcs = {
.check = gud_pipe_check,
.update = gud_pipe_update,
DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS
};
static const struct drm_mode_config_funcs gud_mode_config_funcs = {

View File

@ -43,6 +43,7 @@ struct gud_device {
struct drm_framebuffer *fb;
struct drm_rect damage;
bool prev_flush_failed;
void *shadow_buf;
};
static inline struct gud_device *to_gud_device(struct drm_device *drm)

View File

@ -5,6 +5,7 @@
#include <linux/lz4.h>
#include <linux/usb.h>
#include <linux/vmalloc.h>
#include <linux/workqueue.h>
#include <drm/drm_atomic.h>
@ -15,6 +16,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_rect.h>
@ -24,17 +26,13 @@
#include "gud_internal.h"
/*
* Some userspace rendering loops runs all displays in the same loop.
* Some userspace rendering loops run all displays in the same loop.
* This means that a fast display will have to wait for a slow one.
* For this reason gud does flushing asynchronous by default.
* The down side is that in e.g. a single display setup userspace thinks
* the display is insanely fast since the driver reports back immediately
* that the flush/pageflip is done. This wastes CPU and power.
* Such users might want to set this module parameter to false.
* Such users might want to enable this module parameter.
*/
static bool gud_async_flush = true;
static bool gud_async_flush;
module_param_named(async_flush, gud_async_flush, bool, 0644);
MODULE_PARM_DESC(async_flush, "Enable asynchronous flushing [default=true]");
MODULE_PARM_DESC(async_flush, "Enable asynchronous flushing [default=0]");
/*
* FIXME: The driver is probably broken on Big Endian machines.
@ -152,32 +150,21 @@ static size_t gud_xrgb8888_to_color(u8 *dst, const struct drm_format_info *forma
}
static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb,
const struct iosys_map *src, bool cached_reads,
const struct drm_format_info *format, struct drm_rect *rect,
struct gud_set_buffer_req *req)
{
struct dma_buf_attachment *import_attach = fb->obj[0]->import_attach;
u8 compression = gdrm->compression;
struct iosys_map map[DRM_FORMAT_MAX_PLANES];
struct iosys_map map_data[DRM_FORMAT_MAX_PLANES];
struct iosys_map dst;
void *vaddr, *buf;
size_t pitch, len;
int ret = 0;
pitch = drm_format_info_min_pitch(format, 0, drm_rect_width(rect));
len = pitch * drm_rect_height(rect);
if (len > gdrm->bulk_len)
return -E2BIG;
ret = drm_gem_fb_vmap(fb, map, map_data);
if (ret)
return ret;
vaddr = map_data[0].vaddr;
ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
if (ret)
goto vunmap;
vaddr = src[0].vaddr;
retry:
if (compression)
buf = gdrm->compress_buf;
@ -192,29 +179,27 @@ retry:
if (format != fb->format) {
if (format->format == GUD_DRM_FORMAT_R1) {
len = gud_xrgb8888_to_r124(buf, format, vaddr, fb, rect);
if (!len) {
ret = -ENOMEM;
goto end_cpu_access;
}
if (!len)
return -ENOMEM;
} else if (format->format == DRM_FORMAT_R8) {
drm_fb_xrgb8888_to_gray8(&dst, NULL, map_data, fb, rect);
drm_fb_xrgb8888_to_gray8(&dst, NULL, src, fb, rect);
} else if (format->format == DRM_FORMAT_RGB332) {
drm_fb_xrgb8888_to_rgb332(&dst, NULL, map_data, fb, rect);
drm_fb_xrgb8888_to_rgb332(&dst, NULL, src, fb, rect);
} else if (format->format == DRM_FORMAT_RGB565) {
drm_fb_xrgb8888_to_rgb565(&dst, NULL, map_data, fb, rect,
drm_fb_xrgb8888_to_rgb565(&dst, NULL, src, fb, rect,
gud_is_big_endian());
} else if (format->format == DRM_FORMAT_RGB888) {
drm_fb_xrgb8888_to_rgb888(&dst, NULL, map_data, fb, rect);
drm_fb_xrgb8888_to_rgb888(&dst, NULL, src, fb, rect);
} else {
len = gud_xrgb8888_to_color(buf, format, vaddr, fb, rect);
}
} else if (gud_is_big_endian() && format->cpp[0] > 1) {
drm_fb_swab(&dst, NULL, map_data, fb, rect, !import_attach);
} else if (compression && !import_attach && pitch == fb->pitches[0]) {
drm_fb_swab(&dst, NULL, src, fb, rect, cached_reads);
} else if (compression && cached_reads && pitch == fb->pitches[0]) {
/* can compress directly from the framebuffer */
buf = vaddr + rect->y1 * pitch;
} else {
drm_fb_memcpy(&dst, NULL, map_data, fb, rect);
drm_fb_memcpy(&dst, NULL, src, fb, rect);
}
memset(req, 0, sizeof(*req));
@ -237,12 +222,7 @@ retry:
req->compressed_length = cpu_to_le32(complen);
}
end_cpu_access:
drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
vunmap:
drm_gem_fb_vunmap(fb, map);
return ret;
return 0;
}
struct gud_usb_bulk_context {
@ -285,6 +265,7 @@ static int gud_usb_bulk(struct gud_device *gdrm, size_t len)
}
static int gud_flush_rect(struct gud_device *gdrm, struct drm_framebuffer *fb,
const struct iosys_map *src, bool cached_reads,
const struct drm_format_info *format, struct drm_rect *rect)
{
struct gud_set_buffer_req req;
@ -293,7 +274,7 @@ static int gud_flush_rect(struct gud_device *gdrm, struct drm_framebuffer *fb,
drm_dbg(&gdrm->drm, "Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect));
ret = gud_prep_flush(gdrm, fb, format, rect, &req);
ret = gud_prep_flush(gdrm, fb, src, cached_reads, format, rect, &req);
if (ret)
return ret;
@ -333,46 +314,51 @@ void gud_clear_damage(struct gud_device *gdrm)
gdrm->damage.y2 = 0;
}
static void gud_add_damage(struct gud_device *gdrm, struct drm_rect *damage)
static void gud_flush_damage(struct gud_device *gdrm, struct drm_framebuffer *fb,
const struct iosys_map *src, bool cached_reads,
struct drm_rect *damage)
{
gdrm->damage.x1 = min(gdrm->damage.x1, damage->x1);
gdrm->damage.y1 = min(gdrm->damage.y1, damage->y1);
gdrm->damage.x2 = max(gdrm->damage.x2, damage->x2);
gdrm->damage.y2 = max(gdrm->damage.y2, damage->y2);
}
const struct drm_format_info *format;
unsigned int i, lines;
size_t pitch;
int ret;
static void gud_retry_failed_flush(struct gud_device *gdrm, struct drm_framebuffer *fb,
struct drm_rect *damage)
{
/*
* pipe_update waits for the worker when the display mode is going to change.
* This ensures that the width and height is still the same making it safe to
* add back the damage.
*/
format = fb->format;
if (format->format == DRM_FORMAT_XRGB8888 && gdrm->xrgb8888_emulation_format)
format = gdrm->xrgb8888_emulation_format;
mutex_lock(&gdrm->damage_lock);
if (!gdrm->fb) {
drm_framebuffer_get(fb);
gdrm->fb = fb;
/* Split update if it's too big */
pitch = drm_format_info_min_pitch(format, 0, drm_rect_width(damage));
lines = drm_rect_height(damage);
if (gdrm->bulk_len < lines * pitch)
lines = gdrm->bulk_len / pitch;
for (i = 0; i < DIV_ROUND_UP(drm_rect_height(damage), lines); i++) {
struct drm_rect rect = *damage;
rect.y1 += i * lines;
rect.y2 = min_t(u32, rect.y1 + lines, damage->y2);
ret = gud_flush_rect(gdrm, fb, src, cached_reads, format, &rect);
if (ret) {
if (ret != -ENODEV && ret != -ECONNRESET &&
ret != -ESHUTDOWN && ret != -EPROTO)
dev_err_ratelimited(fb->dev->dev,
"Failed to flush framebuffer: error=%d\n", ret);
gdrm->prev_flush_failed = true;
break;
}
}
gud_add_damage(gdrm, damage);
mutex_unlock(&gdrm->damage_lock);
/* Retry only once to avoid a possible storm in case of continues errors. */
if (!gdrm->prev_flush_failed)
queue_work(system_long_wq, &gdrm->work);
gdrm->prev_flush_failed = true;
}
void gud_flush_work(struct work_struct *work)
{
struct gud_device *gdrm = container_of(work, struct gud_device, work);
const struct drm_format_info *format;
struct iosys_map shadow_map;
struct drm_framebuffer *fb;
struct drm_rect damage;
unsigned int i, lines;
int idx, ret = 0;
size_t pitch;
int idx;
if (!drm_dev_enter(&gdrm->drm, &idx))
return;
@ -380,6 +366,7 @@ void gud_flush_work(struct work_struct *work)
mutex_lock(&gdrm->damage_lock);
fb = gdrm->fb;
gdrm->fb = NULL;
iosys_map_set_vaddr(&shadow_map, gdrm->shadow_buf);
damage = gdrm->damage;
gud_clear_damage(gdrm);
mutex_unlock(&gdrm->damage_lock);
@ -387,59 +374,43 @@ void gud_flush_work(struct work_struct *work)
if (!fb)
goto out;
format = fb->format;
if (format->format == DRM_FORMAT_XRGB8888 && gdrm->xrgb8888_emulation_format)
format = gdrm->xrgb8888_emulation_format;
/* Split update if it's too big */
pitch = drm_format_info_min_pitch(format, 0, drm_rect_width(&damage));
lines = drm_rect_height(&damage);
if (gdrm->bulk_len < lines * pitch)
lines = gdrm->bulk_len / pitch;
for (i = 0; i < DIV_ROUND_UP(drm_rect_height(&damage), lines); i++) {
struct drm_rect rect = damage;
rect.y1 += i * lines;
rect.y2 = min_t(u32, rect.y1 + lines, damage.y2);
ret = gud_flush_rect(gdrm, fb, format, &rect);
if (ret) {
if (ret != -ENODEV && ret != -ECONNRESET &&
ret != -ESHUTDOWN && ret != -EPROTO) {
bool prev_flush_failed = gdrm->prev_flush_failed;
gud_retry_failed_flush(gdrm, fb, &damage);
if (!prev_flush_failed)
dev_err_ratelimited(fb->dev->dev,
"Failed to flush framebuffer: error=%d\n", ret);
}
break;
}
gdrm->prev_flush_failed = false;
}
gud_flush_damage(gdrm, fb, &shadow_map, true, &damage);
drm_framebuffer_put(fb);
out:
drm_dev_exit(idx);
}
static void gud_fb_queue_damage(struct gud_device *gdrm, struct drm_framebuffer *fb,
struct drm_rect *damage)
static int gud_fb_queue_damage(struct gud_device *gdrm, struct drm_framebuffer *fb,
const struct iosys_map *src, struct drm_rect *damage)
{
struct drm_framebuffer *old_fb = NULL;
struct iosys_map shadow_map;
mutex_lock(&gdrm->damage_lock);
if (!gdrm->shadow_buf) {
gdrm->shadow_buf = vzalloc(fb->pitches[0] * fb->height);
if (!gdrm->shadow_buf) {
mutex_unlock(&gdrm->damage_lock);
return -ENOMEM;
}
}
iosys_map_set_vaddr(&shadow_map, gdrm->shadow_buf);
iosys_map_incr(&shadow_map, drm_fb_clip_offset(fb->pitches[0], fb->format, damage));
drm_fb_memcpy(&shadow_map, fb->pitches, src, fb, damage);
if (fb != gdrm->fb) {
old_fb = gdrm->fb;
drm_framebuffer_get(fb);
gdrm->fb = fb;
}
gud_add_damage(gdrm, damage);
gdrm->damage.x1 = min(gdrm->damage.x1, damage->x1);
gdrm->damage.y1 = min(gdrm->damage.y1, damage->y1);
gdrm->damage.x2 = max(gdrm->damage.x2, damage->x2);
gdrm->damage.y2 = max(gdrm->damage.y2, damage->y2);
mutex_unlock(&gdrm->damage_lock);
@ -447,6 +418,26 @@ static void gud_fb_queue_damage(struct gud_device *gdrm, struct drm_framebuffer
if (old_fb)
drm_framebuffer_put(old_fb);
return 0;
}
static void gud_fb_handle_damage(struct gud_device *gdrm, struct drm_framebuffer *fb,
const struct iosys_map *src, struct drm_rect *damage)
{
int ret;
if (gdrm->flags & GUD_DISPLAY_FLAG_FULL_UPDATE)
drm_rect_init(damage, 0, 0, fb->width, fb->height);
if (gud_async_flush) {
ret = gud_fb_queue_damage(gdrm, fb, src, damage);
if (ret != -ENOMEM)
return;
}
/* Imported buffers are assumed to be WriteCombined with uncached reads */
gud_flush_damage(gdrm, fb, src, !fb->obj[0]->import_attach, damage);
}
int gud_pipe_check(struct drm_simple_display_pipe *pipe,
@ -571,10 +562,11 @@ void gud_pipe_update(struct drm_simple_display_pipe *pipe,
struct drm_device *drm = pipe->crtc.dev;
struct gud_device *gdrm = to_gud_device(drm);
struct drm_plane_state *state = pipe->plane.state;
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
struct drm_framebuffer *fb = state->fb;
struct drm_crtc *crtc = &pipe->crtc;
struct drm_rect damage;
int idx;
int ret, idx;
if (crtc->state->mode_changed || !crtc->state->enable) {
cancel_work_sync(&gdrm->work);
@ -584,6 +576,8 @@ void gud_pipe_update(struct drm_simple_display_pipe *pipe,
gdrm->fb = NULL;
}
gud_clear_damage(gdrm);
vfree(gdrm->shadow_buf);
gdrm->shadow_buf = NULL;
mutex_unlock(&gdrm->damage_lock);
}
@ -599,14 +593,19 @@ void gud_pipe_update(struct drm_simple_display_pipe *pipe,
if (crtc->state->active_changed)
gud_usb_set_u8(gdrm, GUD_REQ_SET_DISPLAY_ENABLE, crtc->state->active);
if (drm_atomic_helper_damage_merged(old_state, state, &damage)) {
if (gdrm->flags & GUD_DISPLAY_FLAG_FULL_UPDATE)
drm_rect_init(&damage, 0, 0, fb->width, fb->height);
gud_fb_queue_damage(gdrm, fb, &damage);
if (!gud_async_flush)
flush_work(&gdrm->work);
}
if (!fb)
goto ctrl_disable;
ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
if (ret)
goto ctrl_disable;
if (drm_atomic_helper_damage_merged(old_state, state, &damage))
gud_fb_handle_damage(gdrm, fb, &shadow_plane_state->data[0], &damage);
drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
ctrl_disable:
if (!crtc->state->enable)
gud_usb_set_u8(gdrm, GUD_REQ_SET_CONTROLLER_ENABLE, 0);

View File

@ -106,7 +106,7 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv)
dev->mode_config.max_width = 1920;
dev->mode_config.max_height = 1200;
dev->mode_config.preferred_depth = 32;
dev->mode_config.preferred_depth = 24;
dev->mode_config.prefer_shadow = 1;
dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
@ -340,7 +340,7 @@ static int hibmc_pci_probe(struct pci_dev *pdev,
goto err_unload;
}
drm_fbdev_generic_setup(dev, dev->mode_config.preferred_depth);
drm_fbdev_generic_setup(dev, 32);
return 0;

View File

@ -250,7 +250,7 @@ static int ch7006_encoder_create_resources(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev;
struct drm_mode_config *conf = &dev->mode_config;
drm_mode_create_tv_properties(dev, NUM_TV_NORMS, ch7006_tv_norm_names);
drm_mode_create_tv_properties_legacy(dev, NUM_TV_NORMS, ch7006_tv_norm_names);
priv->scale_property = drm_property_create_range(dev, 0, "scale", 0, 2);
if (!priv->scale_property)
@ -264,8 +264,8 @@ static int ch7006_encoder_create_resources(struct drm_encoder *encoder,
priv->hmargin);
drm_object_attach_property(&connector->base, conf->tv_bottom_margin_property,
priv->vmargin);
drm_object_attach_property(&connector->base, conf->tv_mode_property,
priv->norm);
drm_object_attach_property(&connector->base, conf->legacy_tv_mode_property,
priv->norm);
drm_object_attach_property(&connector->base, conf->tv_brightness_property,
priv->brightness);
drm_object_attach_property(&connector->base, conf->tv_contrast_property,
@ -315,7 +315,7 @@ static int ch7006_encoder_set_property(struct drm_encoder *encoder,
ch7006_load_reg(client, state, CH7006_POV);
ch7006_load_reg(client, state, CH7006_VPOS);
} else if (property == conf->tv_mode_property) {
} else if (property == conf->legacy_tv_mode_property) {
if (connector->dpms != DRM_MODE_DPMS_OFF)
return -EINVAL;

View File

@ -1905,10 +1905,10 @@ static void intel_tv_add_properties(struct drm_connector *connector)
tv_format_names[i] = tv_modes[i].name;
}
drm_mode_create_tv_properties(&i915->drm, i, tv_format_names);
drm_mode_create_tv_properties_legacy(&i915->drm, i, tv_format_names);
drm_object_attach_property(&connector->base,
i915->drm.mode_config.tv_mode_property,
i915->drm.mode_config.legacy_tv_mode_property,
conn_state->tv.mode);
drm_object_attach_property(&connector->base,
i915->drm.mode_config.tv_left_margin_property,

View File

@ -10,7 +10,7 @@
#include <linux/mmu_notifier.h>
#include <drm/drm_gem.h>
#include <drm/ttm/ttm_bo_api.h>
#include <drm/ttm/ttm_bo.h>
#include <uapi/drm/i915_drm.h>
#include "i915_active.h"

View File

@ -5,8 +5,8 @@
#include <linux/shmem_fs.h>
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_tt.h>
#include <drm/drm_buddy.h>
#include "i915_drv.h"
@ -599,13 +599,16 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
static int i915_ttm_truncate(struct drm_i915_gem_object *obj)
{
struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
int err;
long err;
WARN_ON_ONCE(obj->mm.madv == I915_MADV_WILLNEED);
err = ttm_bo_wait(bo, true, false);
if (err)
err = dma_resv_wait_timeout(bo->base.resv, DMA_RESV_USAGE_BOOKKEEP,
true, 15 * HZ);
if (err < 0)
return err;
if (err == 0)
return -EBUSY;
err = i915_ttm_move_notify(bo);
if (err)

View File

@ -3,7 +3,7 @@
* Copyright © 2021 Intel Corporation
*/
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_tt.h>
#include "i915_deps.h"
#include "i915_drv.h"

View File

@ -164,7 +164,6 @@ sysfs_gt_attribute_r_func(struct kobject *kobj, struct attribute *attr,
NULL); \
INTEL_GT_ATTR_RO(_name)
#ifdef CONFIG_PM
static u32 get_residency(struct intel_gt *gt, enum intel_rc6_res_type id)
{
intel_wakeref_t wakeref;
@ -300,7 +299,7 @@ static void intel_sysfs_rc6_init(struct intel_gt *gt, struct kobject *kobj)
{
int ret;
if (!HAS_RC6(gt->i915))
if (!IS_ENABLED(CONFIG_PM) || !HAS_RC6(gt->i915))
return;
ret = __intel_gt_sysfs_create_group(kobj, rc6_attr_group);
@ -329,11 +328,6 @@ static void intel_sysfs_rc6_init(struct intel_gt *gt, struct kobject *kobj)
gt->info.id, ERR_PTR(ret));
}
}
#else
static void intel_sysfs_rc6_init(struct intel_gt *gt, struct kobject *kobj)
{
}
#endif /* CONFIG_PM */
static u32 __act_freq_mhz_show(struct intel_gt *gt)
{

View File

@ -6,7 +6,7 @@
#include <linux/dma-fence.h>
#include <linux/slab.h>
#include <drm/ttm/ttm_bo_api.h>
#include <drm/ttm/ttm_bo.h>
#include "i915_deps.h"

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