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:
commit
03a0a10408
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -17,7 +17,9 @@ description: |
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
const: ite,it66121
|
||||
enum:
|
||||
- ite,it66121
|
||||
- ite,it6610
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
---------------------------------
|
||||
|
||||
|
|
|
@ -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
|
||||
------------------------
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
===========================================
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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().
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
struct hmm_range;
|
||||
|
||||
struct drm_file;
|
||||
|
||||
struct amdgpu_device;
|
||||
struct amdgpu_bo;
|
||||
struct amdgpu_bo_va;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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 = <->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,
|
||||
<8912_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(<->connector);
|
||||
drm_connector_cleanup(<->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,
|
||||
};
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue